Rev 5422: (mbp) improve scriptrunner handling of blanks, newlines, in file:///home/pqm/archives/thelove/bzr/%2Btrunk/

Canonical.com Patch Queue Manager pqm at pqm.ubuntu.com
Mon Sep 13 13:30:54 BST 2010


At file:///home/pqm/archives/thelove/bzr/%2Btrunk/

------------------------------------------------------------
revno: 5422 [merge]
revision-id: pqm at pqm.ubuntu.com-20100913123052-cxsnsnc6bca12cq8
parent: pqm at pqm.ubuntu.com-20100913111142-4d29z7oy3z5o7vrd
parent: mbp at sourcefrog.net-20100913090003-5mvnc50tdwppqxtl
committer: Canonical.com Patch Queue Manager <pqm at pqm.ubuntu.com>
branch nick: +trunk
timestamp: Mon 2010-09-13 13:30:52 +0100
message:
  (mbp) improve scriptrunner handling of blanks, newlines,
   and lines without newlines (Martin Pool)
modified:
  bzrlib/tests/script.py         script.py-20090901081155-yk3tiy1nunxg16ne-1
  bzrlib/tests/test_script.py    test_script.py-20090901081156-y90z4w2t62fv7e7b-1
  doc/developers/testing.txt     testing.txt-20080812140359-i70zzh6v2z7grqex-1
=== modified file 'bzrlib/tests/script.py'
--- a/bzrlib/tests/script.py	2010-06-11 06:33:15 +0000
+++ b/bzrlib/tests/script.py	2010-09-13 08:14:44 +0000
@@ -56,6 +56,10 @@
     Input lines start with '<'.
     Output lines start with nothing.
     Error lines start with '2>'.
+
+    :return: A sequence of ([args], input, output, errors), where the args are
+        split in to words, and the input, output, and errors are just strings,
+        typically containing newlines.
     """
 
     commands = []
@@ -75,18 +79,26 @@
     lineno = 0
     input, output, error = None, None, None
     text = textwrap.dedent(text)
-    for line in text.split('\n'):
+    lines = text.split('\n')
+    # to make use of triple-quoted strings easier, we ignore a blank line
+    # right at the start and right at the end; the rest are meaningful
+    if lines and lines[0] == '':
+        del lines[0]
+    if lines and lines[-1] == '':
+        del lines[-1]
+    for line in lines:
         lineno += 1
         # Keep a copy for error reporting
         orig = line
         comment =  line.find('#')
         if comment >= 0:
             # Delete comments
+            # NB: this syntax means comments are allowed inside output, which
+            # may be confusing...
             line = line[0:comment]
             line = line.rstrip()
-        if line == '':
-            # Ignore empty lines
-            continue
+            if line == '':
+                continue
         if line.startswith('$'):
             # Time to output the current command
             add_command(cmd_cur, input, output, error)
@@ -232,7 +244,15 @@
             # 'expected' parameter. So we just fallback to our good old
             # assertEqualDiff since we know there *are* differences and the
             # output should be decently readable.
-            test_case.assertEqualDiff(expected, actual)
+            #
+            # As a special case, we allow output that's missing a final
+            # newline to match an expected string that does have one, so that
+            # we can match a prompt printed on one line, then input given on
+            # the next line.
+            if expected == actual + '\n':
+                pass
+            else:
+                test_case.assertEqualDiff(expected, actual)
 
     def _pre_process_args(self, args):
         new_args = []

=== modified file 'bzrlib/tests/test_script.py'
--- a/bzrlib/tests/test_script.py	2010-06-11 06:33:15 +0000
+++ b/bzrlib/tests/test_script.py	2010-09-13 09:00:03 +0000
@@ -16,8 +16,10 @@
 
 
 from bzrlib import (
+    commands,
     osutils,
     tests,
+    ui,
     )
 from bzrlib.tests import script
 
@@ -27,8 +29,33 @@
     def test_comment_is_ignored(self):
         self.assertEquals([], script._script_to_commands('#comment\n'))
 
-    def test_empty_line_is_ignored(self):
-        self.assertEquals([], script._script_to_commands('\n'))
+    def test_comment_multiple_lines(self):
+        self.assertEquals([
+            (['bar'], None, None, None),
+            ],
+            script._script_to_commands("""
+            # this comment is ignored
+            # so is this
+            # no we run bar
+            $ bar
+            """))
+
+    def test_trim_blank_lines(self):
+        """Blank lines are respected, but trimmed at the start and end.
+
+        Python triple-quoted syntax is going to give stubby/empty blank lines 
+        right at the start and the end.  These are cut off so that callers don't 
+        need special syntax to avoid them.
+
+        However we do want to be able to match commands that emit blank lines.
+        """
+        self.assertEquals([
+            (['bar'], None, '\n', None),
+            ],
+            script._script_to_commands("""
+            $bar
+
+            """))
 
     def test_simple_command(self):
         self.assertEquals([(['cd', 'trunk'], None, None, None)],
@@ -377,6 +404,14 @@
         self.assertEquals(None, err)
         self.assertFileEqual('hello\nhappy\n', 'file')
 
+    def test_empty_line_in_output_is_respected(self):
+        self.run_script("""
+            $ echo
+
+            $ echo bar
+            bar
+            """)
+
 
 class TestRm(script.TestCaseWithTransportAndScript):
 
@@ -459,3 +494,39 @@
         self.failIfExists('file')
         self.failUnlessExists('dir/file')
 
+
+class cmd_test_confirm(commands.Command):
+
+    def run(self):
+        if ui.ui_factory.get_boolean(
+            'Really do it',
+            # 'bzrlib.tests.test_script.confirm',
+            # {}
+            ):
+            self.outf.write('Do it!\n')
+        else:
+            print 'ok, no'
+
+
+class TestUserInteraction(script.TestCaseWithMemoryTransportAndScript):
+
+    def test_confirm_action(self):
+        """You can write tests that demonstrate user confirmation.
+        
+        Specifically, ScriptRunner does't care if the output line for the prompt
+        isn't terminated by a newline from the program; it's implicitly terminated 
+        by the input.
+        """
+        commands.builtin_command_registry.register(cmd_test_confirm)
+        self.addCleanup(commands.builtin_command_registry.remove, 'test-confirm')
+        self.run_script("""
+            $ bzr test-confirm
+            2>Really do it? [y/n]: 
+            <yes
+            Do it!
+            $ bzr test-confirm
+            2>Really do it? [y/n]: 
+            <no
+            ok, no
+            """)
+

=== modified file 'doc/developers/testing.txt'
--- a/doc/developers/testing.txt	2010-07-16 20:52:54 +0000
+++ b/doc/developers/testing.txt	2010-09-13 04:20:14 +0000
@@ -446,6 +446,18 @@
             contents of file
             ''')
 
+You can also test commands that read user interaction::
+
+    def test_confirm_action(self):
+        """You can write tests that demonstrate user confirmation"""
+        commands.builtin_command_registry.register(cmd_test_confirm)
+        self.addCleanup(commands.builtin_command_registry.remove, 'test-confirm')
+        self.run_script("""
+            $ bzr test-confirm
+            2>Really do it? [y/n]: 
+            <yes
+            yes
+            """)
 
 Import tariff tests
 -------------------




More information about the bazaar-commits mailing list