Rev 4684: Implement globbing and enhance cat to accept multiple files. in file:///home/vila/src/bzr/experimental/shell-like-tests/

Vincent Ladeuil v.ladeuil+lp at free.fr
Fri Sep 11 15:19:15 BST 2009


At file:///home/vila/src/bzr/experimental/shell-like-tests/

------------------------------------------------------------
revno: 4684
revision-id: v.ladeuil+lp at free.fr-20090911141915-spdcayvr91ighbzs
parent: v.ladeuil+lp at free.fr-20090911121609-4ag5y8wqmpkrqus1
committer: Vincent Ladeuil <v.ladeuil+lp at free.fr>
branch nick: shell-like-tests
timestamp: Fri 2009-09-11 16:19:15 +0200
message:
  Implement globbing and enhance cat to accept multiple files.
  
  * bzrlib/tests/test_script.py:
  (TestSyntax.test_command_with_single_quoted_param,
  TestSyntax.test_command_with_double_quoted_param): Quotes are left
  in place during command splitting.
  (TestArgumentProcessing): Test quote removal and globbing.
  (TestCat.test_cat_files_to_file): Cat accepts multiple files now.
  
  * bzrlib/tests/script.py:
  (split): Delay quote removal until the command is ready to be
  executed.
  (ScriptRunner._pre_process_args): Globbing should happen just
  before command execution, which imply that quotes removal should
  happen at the same time.
  (ScriptRunner.run_command): Process arguments for quote and
  globbing just before execution or globbing will not be correct.
  (ScriptRunner.do_cat): Allow multiple files to be specified.
-------------- next part --------------
=== modified file 'bzrlib/tests/script.py'
--- a/bzrlib/tests/script.py	2009-09-11 12:16:09 +0000
+++ b/bzrlib/tests/script.py	2009-09-11 14:19:15 +0000
@@ -97,6 +97,7 @@
 
 import doctest
 import errno
+import glob
 import os
 import shlex
 from cStringIO import StringIO
@@ -113,13 +114,7 @@
     scanner.quotes = '\'"`'
     scanner.whitespace_split = True
     for t in list(scanner):
-        # Strip the simple and double quotes since we don't care about them.
-        # We leave the backquotes in place though since they have a different
-        # semantic.
-        if t[0] in  ('"', "'") and t[0] == t[-1]:
-            yield t[1:-1]
-        else:
-            yield t
+        yield t
 
 
 def _script_to_commands(text, file_name=None):
@@ -266,6 +261,26 @@
             # output should be decently readable.
             self.test_case.assertEqualDiff(expected, actual)
 
+    def _pre_process_args(self, args):
+        new_args = []
+        for arg in args:
+            # Strip the simple and double quotes since we don't care about
+            # them.  We leave the backquotes in place though since they have a
+            # different semantic.
+            if arg[0] in  ('"', "'") and arg[0] == arg[-1]:
+                yield arg[1:-1]
+            else:
+                if glob.has_magic(arg):
+                    matches = glob.glob(arg)
+                    if matches:
+                        # We care more about order stability than performance
+                        # here
+                        matches.sort()
+                        for m in matches:
+                            yield m
+                else:
+                    yield arg
+
     def run_command(self, cmd, input, output, error):
         mname = 'do_' + cmd[0]
         method = getattr(self, mname, None)
@@ -276,7 +291,8 @@
             str_input = ''
         else:
             str_input = ''.join(input)
-        retcode, actual_output, actual_error = method(str_input, cmd[1:])
+        args = list(self._pre_process_args(cmd[1:]))
+        retcode, actual_output, actual_error = method(str_input, args)
 
         self._check_output(output, actual_output)
         self._check_output(error, actual_error)
@@ -312,19 +328,24 @@
 
     def do_cat(self, input, args):
         (in_name, out_name, out_mode, args) = _scan_redirection_options(args)
-        if len(args) > 1:
-            raise SyntaxError('Usage: cat [file1]')
-        if args:
-            if in_name is not None:
-                raise SyntaxError('Specify a file OR use redirection')
-            in_name = args[0]
-        try:
-            input = self._read_input(input, in_name)
-        except IOError, e:
-            if e.errno == errno.ENOENT:
-                return 1, None, '%s: No such file or directory\n' % (in_name,)
+        if args and in_name is not None:
+            raise SyntaxError('Specify a file OR use redirection')
+
+        inputs = []
+        if input:
+            inputs.append(input)
+        input_names = args
+        if in_name:
+            args.append(in_name)
+        for in_name in input_names:
+            try:
+                inputs.append(self._read_input(None, in_name))
+            except IOError, e:
+                if e.errno == errno.ENOENT:
+                    return (1, None,
+                            '%s: No such file or directory\n' % (in_name,))
         # Basically cat copy input to output
-        output = input
+        output = ''.join(inputs)
         # Handle output redirections
         try:
             output = self._write_output(output, out_name, out_mode)

=== modified file 'bzrlib/tests/test_script.py'
--- a/bzrlib/tests/test_script.py	2009-09-11 12:16:09 +0000
+++ b/bzrlib/tests/test_script.py	2009-09-11 14:19:15 +0000
@@ -22,7 +22,7 @@
 from bzrlib.tests import script
 
 
-class TestScriptSyntax(tests.TestCase):
+class TestSyntax(tests.TestCase):
 
     def test_comment_is_ignored(self):
         self.assertEquals([], script._script_to_commands('#comment\n'))
@@ -36,13 +36,13 @@
 
     def test_command_with_single_quoted_param(self):
         story = """bzr commit -m 'two words'"""
-        self.assertEquals([(['bzr', 'commit', '-m', 'two words'],
+        self.assertEquals([(['bzr', 'commit', '-m', "'two words'"],
                             None, None, None)],
                            script._script_to_commands(story))
 
     def test_command_with_double_quoted_param(self):
         story = """bzr commit -m "two words" """
-        self.assertEquals([(['bzr', 'commit', '-m', 'two words'],
+        self.assertEquals([(['bzr', 'commit', '-m', '"two words"'],
                             None, None, None)],
                            script._script_to_commands(story))
 
@@ -117,7 +117,7 @@
 
 
 
-class TestScriptExecution(script.TestCaseWithTransportAndScript):
+class TestExecution(script.TestCaseWithTransportAndScript):
 
     def test_unknown_command(self):
         self.assertRaises(SyntaxError, self.run_script, 'foo')
@@ -181,10 +181,34 @@
         self.run_script(story)
 
 
+class TestArgumentProcessing(script.TestCaseWithTransportAndScript):
+
+    def test_globing(self):
+        self.run_script("""
+echo cat >cat
+echo dog >dog
+cat *
+>cat
+>dog
+""")
+
+    def test_quoted_globbing(self):
+        self.run_script("""
+echo cat >cat
+cat '*'
+2>*: No such file or directory
+""")
+
+    def test_quotes_removal(self):
+        self.run_script("""
+echo 'cat' "dog" '"chicken"' "'dragon'"
+>catdog"chicken"'dragon'
+""")
+
+
 class TestCat(script.TestCaseWithTransportAndScript):
 
     def test_cat_usage(self):
-        self.assertRaises(SyntaxError, self.run_script, 'cat foo bar baz')
         self.assertRaises(SyntaxError, self.run_script, 'cat foo <bar')
 
     def test_cat_input_to_output(self):
@@ -218,6 +242,13 @@
                                              None, None, None)
         self.assertFileEqual('content\n', 'file2')
 
+    def test_cat_files_to_file(self):
+        self.build_tree_contents([('cat', 'cat\n')])
+        self.build_tree_contents([('dog', 'dog\n')])
+        retcode, out, err = self.run_command(['cat', 'cat', 'dog', '>file'],
+                                             None, None, None)
+        self.assertFileEqual('cat\ndog\n', 'file')
+
     def test_cat_bogus_input_file(self):
         self.run_script("""
 cat <file



More information about the bazaar-commits mailing list