Use a vault(1)-compatible naive notes editing system
Marco Ricci

Marco Ricci commited on 2025-02-05 14:44:16
Zeige 3 geänderte Dateien mit 45 Einfügungen und 20 Löschungen.


We originally provided a modern git-like editor interface, with a marker
for explanatory texts and with support for aborting the edit by leaving
the file empty.  vault(1) however takes the contents of the notes file
literally.  For compatibility, we must do the same.
... ...
@@ -101,6 +101,7 @@ exclude_also = [
101 101
     '(?:typing\.)?assert_never\(',
102 102
     '@overload',
103 103
     'class .*\(Protocol\):',
104
+    '@(?:(?:pytest\.)?mark\.)?xfail\(',
104 105
 ]
105 106
 
106 107
 [tool.coverage.run]
... ...
@@ -987,7 +987,7 @@ def derivepassphrase_vault(  # noqa: C901,PLR0912,PLR0913,PLR0914,PLR0915
987 987
             extra={'color': ctx.color},
988 988
         )
989 989
 
990
-    if delete_service_settings:  # noqa: PLR1702
990
+    if delete_service_settings:
991 991
         assert service is not None
992 992
         configuration = get_config()
993 993
         if service in configuration['services']:
... ...
@@ -1395,23 +1395,8 @@ def derivepassphrase_vault(  # noqa: C901,PLR0912,PLR0913,PLR0914,PLR0915
1395 1395
                 ])
1396 1396
                 notes_value = click.edit(text=text, require_save=False)
1397 1397
                 assert notes_value is not None
1398
-                if notes_value != text:
1399
-                    notes_lines = collections.deque(
1400
-                        notes_value.splitlines(True)  # noqa: FBT003
1401
-                    )
1402
-                    while notes_lines:
1403
-                        line = notes_lines.popleft()
1404
-                        if line.startswith(str(notes_marker)):
1405
-                            notes_value = ''.join(notes_lines)
1406
-                            break
1407
-                    else:
1408
-                        if not notes_value.strip():
1409
-                            err(
1410
-                                _msg.TranslatedString(
1411
-                                    _msg.ErrMsgTemplate.USER_ABORTED_EDIT
1412
-                                )
1413
-                            )
1414
-                    subtree['notes'] = notes_value.strip('\n')
1398
+                if notes_value.strip() != old_notes_value.strip():
1399
+                    subtree['notes'] = notes_value.strip()
1415 1400
             put_config(configuration)
1416 1401
         else:
1417 1402
             assert service is not None
... ...
@@ -2517,10 +2517,34 @@ class TestCLI:
2517 2517
                 config = json.load(infile)
2518 2518
             assert config == {
2519 2519
                 'global': {'phrase': 'abc'},
2520
-                'services': {'sv': {'notes': notes.strip()}},
2520
+                'services': {'sv': {'notes': edit_result.strip()}},
2521 2521
             }
2522 2522
 
2523
-    @pytest.mark.parametrize('edit_func_name', ['empty', 'space'])
2523
+    @pytest.mark.parametrize(
2524
+        'edit_func_name',
2525
+        [
2526
+            pytest.param(
2527
+                'empty',
2528
+                marks=[
2529
+                    pytest.mark.xfail(reason='incompatibility with vault(1)')
2530
+                ],
2531
+            ),
2532
+            'space',
2533
+        ],
2534
+    )
2535
+    # Skip the "target", "shrink" and "explain" phases on this test because
2536
+    # one of its parametrizations is marked xfail, and we don't want to do
2537
+    # a lot of extra work that will be thrown away anyway.
2538
+    #
2539
+    # TODO(the-13th-letter): remove this settings decorator once the
2540
+    # xfail'ing parametrization is fixed.
2541
+    @hypothesis.settings(
2542
+        phases=[
2543
+            hypothesis.Phase.explicit,
2544
+            hypothesis.Phase.reuse,
2545
+            hypothesis.Phase.generate,
2546
+        ],
2547
+    )
2524 2548
     @hypothesis.given(
2525 2549
         notes=strategies.text(
2526 2550
             strategies.characters(
... ...
@@ -2636,6 +2660,20 @@ class TestCLI:
2636 2660
                 'services': {'sv': {'notes': notes.strip()}},
2637 2661
             }
2638 2662
 
2663
+    @pytest.mark.xfail(reason='incompatibility with vault(1)')
2664
+    # Skip the "target", "shrink" and "explain" phases on this test because
2665
+    # this test is marked xfail, and we don't want to do a lot of extra work
2666
+    # that will be thrown away anyway.
2667
+    #
2668
+    # TODO(the-13th-letter): remove this settings decorator once the xfail
2669
+    # is fixed.
2670
+    @hypothesis.settings(
2671
+        phases=[
2672
+            hypothesis.Phase.explicit,
2673
+            hypothesis.Phase.reuse,
2674
+            hypothesis.Phase.generate,
2675
+        ],
2676
+    )
2639 2677
     @hypothesis.given(
2640 2678
         notes=strategies.text(
2641 2679
             strategies.characters(
... ...
@@ -2685,6 +2723,7 @@ class TestCLI:
2685 2723
                 'services': {'sv': {'notes': notes.strip()}},
2686 2724
             }
2687 2725
 
2726
+    @pytest.mark.xfail(reason='incompatibility with vault(1)')
2688 2727
     def test_223a_edit_empty_notes_abort(
2689 2728
         self,
2690 2729
     ) -> None:
2691 2730