Rev 4685: Fixed as per Martin's review. in file:///home/vila/src/bzr/experimental/shell-like-tests/
Vincent Ladeuil
v.ladeuil+lp at free.fr
Thu Sep 17 15:15:15 BST 2009
At file:///home/vila/src/bzr/experimental/shell-like-tests/
------------------------------------------------------------
revno: 4685
revision-id: v.ladeuil+lp at free.fr-20090917141515-6e3yzx8v0oirgeyd
parent: v.ladeuil+lp at free.fr-20090911141915-spdcayvr91ighbzs
committer: Vincent Ladeuil <v.ladeuil+lp at free.fr>
branch nick: shell-like-tests
timestamp: Thu 2009-09-17 16:15:15 +0200
message:
Fixed as per Martin's review.
* doc/developers/testing.txt:
Add a shelli-like tests section.
* bzrlib/tests/test_script.py:
Update scripts for new prefixes and fix echo tests.
* bzrlib/tests/script.py: Move doc to doc/developers/testing.txt.
(_script_to_commands): Commands are prefixed by '$', expected
output are not prefixed anymore.
(ScriptRunner.do_echo): Put spaces between arguments.
-------------- next part --------------
=== modified file 'bzrlib/tests/script.py'
--- a/bzrlib/tests/script.py 2009-09-11 14:19:15 +0000
+++ b/bzrlib/tests/script.py 2009-09-17 14:15:15 +0000
@@ -13,86 +13,10 @@
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+
"""Shell-like test scripts.
-This allows users to write tests in a syntax very close to a shell session,
-using a restricted and limited set of commands that should be enough to mimic
-most of the behaviours.
-
-A script is a set of commands, each command is composed of:
-- one mandatory command line,
-- one optional set of input lines to feed the command,
-- one optional set of output expected lines,
-- one optional set of error expected lines.
-
-The optional lines starts with a special string (mnemonic: shell redirection):
-- '<' for input,
-- '>' for output,
-- '2>' for errors,
-
-The execution stops as soon as an expected output or an expected error is not
-matched.
-
-When no output is specified, any ouput from the command is accepted
-and let the execution continue.
-
-If an error occurs and no expected error is specified, the execution stops.
-
-An error is defined by a returned status different from zero, not by the
-presence of text on the error stream.
-
-The matching is done on a full string comparison basis unless '...' is used, in
-which case expected output/errors can be lees precise.
-
-Examples:
-
-The following will succeeds only if 'bzr add' outputs 'adding file'.
-
- bzr add file
- >adding file
-
-If you want the command to succeed for any output, just use:
-
- bzr add file
-
-The following will stop with an error:
-
- bzr not-a-command
-
-If you want it to succeed, use:
-
- bzr not-a-command
- 2> bzr: ERROR: unknown command "not-a-command"
-
-You can use ellipsis (...) to replace any piece of text you don't want to be
-matched exactly:
-
- bzr branch not-a-branch
- 2>bzr: ERROR: Not a branch...not-a-branch/".
-
-
-This can be used to ignore entire lines too:
-
-cat
-<first line
-<second line
-<third line
-<fourth line
-<last line
->first line
->...
->last line
-
-You can check the content of a file with cat:
-
- cat <file
- >expected content
-
-You can also check the existence of a file with cat, the following will fail if
-the file doesn't exist:
-
- cat file
-
+See developpers/testing.html for more explanations.
"""
import doctest
@@ -158,22 +82,20 @@
if line == '':
# Ignore empty lines
continue
- if line.startswith('<'):
+ if line.startswith('$'):
+ # Time to output the current command
+ add_command(cmd_cur, input, output, error)
+ # And start a new one
+ cmd_cur = list(split(line[1:]))
+ cmd_line = lineno
+ input, output, error = None, None, None
+ elif line.startswith('<'):
if input is None:
if cmd_cur is None:
raise SyntaxError('No command for that input',
(file_name, lineno, 1, orig))
input = []
input.append(line[1:] + '\n')
- continue
- elif line.startswith('>'):
- if output is None:
- if cmd_cur is None:
- raise SyntaxError('No command for that output',
- (file_name, lineno, 1, orig))
- output = []
- output.append(line[1:] + '\n')
- continue
elif line.startswith('2>'):
if error is None:
if cmd_cur is None:
@@ -181,14 +103,13 @@
(file_name, lineno, 1, orig))
error = []
error.append(line[2:] + '\n')
- continue
else:
- # Time to output the current command
- add_command(cmd_cur, input, output, error)
- # And start a new one
- cmd_cur = list(split(line))
- cmd_line = lineno
- input, output, error = None, None, None
+ if output is None:
+ if cmd_cur is None:
+ raise SyntaxError('No command for that output',
+ (file_name, lineno, 1, orig))
+ output = []
+ output.append(line + '\n')
# Add the last seen command
add_command(cmd_cur, input, output, error)
return commands
@@ -359,7 +280,7 @@
if input and args:
raise SyntaxError('Specify parameters OR use redirection')
if args:
- input = ''.join(args)
+ input = ' '.join(args)
try:
input = self._read_input(input, in_name)
except IOError, e:
=== modified file 'bzrlib/tests/test_script.py'
--- a/bzrlib/tests/test_script.py 2009-09-11 14:19:15 +0000
+++ b/bzrlib/tests/test_script.py 2009-09-17 14:15:15 +0000
@@ -32,29 +32,30 @@
def test_simple_command(self):
self.assertEquals([(['cd', 'trunk'], None, None, None)],
- script._script_to_commands('cd trunk'))
+ script._script_to_commands('$ cd trunk'))
def test_command_with_single_quoted_param(self):
- story = """bzr commit -m 'two words'"""
+ story = """$ 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" """
+ story = """$ bzr commit -m "two words" """
self.assertEquals([(['bzr', 'commit', '-m', '"two words"'],
None, None, None)],
script._script_to_commands(story))
def test_command_with_input(self):
- self.assertEquals([(['cat', '>file'], 'content\n', None, None)],
- script._script_to_commands('cat >file\n<content\n'))
+ self.assertEquals(
+ [(['cat', '>file'], 'content\n', None, None)],
+ script._script_to_commands('$ cat >file\n<content\n'))
def test_command_with_output(self):
story = """
-bzr add
->adding file
->adding file2
+$ bzr add
+adding file
+adding file2
"""
self.assertEquals([(['bzr', 'add'], None,
'adding file\nadding file2\n', None)],
@@ -62,7 +63,7 @@
def test_command_with_error(self):
story = """
-bzr branch foo
+$ bzr branch foo
2>bzr: ERROR: Not a branch: "foo"
"""
self.assertEquals([(['bzr', 'branch', 'foo'],
@@ -77,7 +78,7 @@
def test_command_with_backquotes(self):
story = """
-foo = `bzr file-id toto`
+$ foo = `bzr file-id toto`
"""
self.assertEquals([(['foo', '=', '`bzr file-id toto`'],
None, None, None)],
@@ -124,24 +125,24 @@
def test_stops_on_unexpected_output(self):
story = """
-mkdir dir
-cd dir
->The cd command ouputs nothing
+$ mkdir dir
+$ cd dir
+The cd command ouputs nothing
"""
self.assertRaises(AssertionError, self.run_script, story)
def test_stops_on_unexpected_error(self):
story = """
-cat
+$ cat
<Hello
-bzr not-a-command
+$ bzr not-a-command
"""
self.assertRaises(AssertionError, self.run_script, story)
def test_continue_on_expected_error(self):
story = """
-bzr not-a-command
+$ bzr not-a-command
2>..."not-a-command"
"""
self.run_script(story)
@@ -149,33 +150,33 @@
def test_continue_on_error_output(self):
# The status matters, not the output
story = """
-bzr init
-cat >file
+$ bzr init
+$ cat >file
<Hello
-bzr add file
-bzr commit -m 'adding file'
+$ bzr add file
+$ bzr commit -m 'adding file'
"""
self.run_script(story)
def test_ellipsis_output(self):
story = """
-cat
+$ cat
<first line
<second line
<last line
->first line
->...
->last line
+first line
+...
+last line
"""
self.run_script(story)
story = """
-bzr not-a-command
+$ bzr not-a-command
2>..."not-a-command"
"""
self.run_script(story)
story = """
-bzr branch not-a-branch
+$ bzr branch not-a-branch
2>bzr: ERROR: Not a branch...not-a-branch/".
"""
self.run_script(story)
@@ -185,24 +186,24 @@
def test_globing(self):
self.run_script("""
-echo cat >cat
-echo dog >dog
-cat *
->cat
->dog
+$ echo cat >cat
+$ echo dog >dog
+$ cat *
+cat
+dog
""")
def test_quoted_globbing(self):
self.run_script("""
-echo cat >cat
-cat '*'
+$ 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'
+$ echo 'cat' "dog" '"chicken"' "'dragon'"
+cat dog "chicken" 'dragon'
""")
@@ -251,13 +252,13 @@
def test_cat_bogus_input_file(self):
self.run_script("""
-cat <file
+$ cat <file
2>file: No such file or directory
""")
def test_cat_bogus_output_file(self):
self.run_script("""
-cat >
+$ cat >
2>: No such file or directory
""")
@@ -265,7 +266,7 @@
# We need a backing file sysytem for that test so it can't be in
# TestEcho
self.run_script("""
-echo <file
+$ echo <file
2>file: No such file or directory
""")
@@ -273,7 +274,7 @@
# We need a backing file sysytem for that test so it can't be in
# TestEcho
self.run_script("""
-echo >
+$ echo >
2>: No such file or directory
""")
@@ -281,19 +282,19 @@
class TestMkdir(script.TestCaseWithTransportAndScript):
def test_mkdir_usage(self):
- self.assertRaises(SyntaxError, self.run_script, 'mkdir')
- self.assertRaises(SyntaxError, self.run_script, 'mkdir foo bar')
+ self.assertRaises(SyntaxError, self.run_script, '$ mkdir')
+ self.assertRaises(SyntaxError, self.run_script, '$ mkdir foo bar')
def test_mkdir_jailed(self):
- self.assertRaises(ValueError, self.run_script, 'mkdir /out-of-jail')
- self.assertRaises(ValueError, self.run_script, 'mkdir ../out-of-jail')
+ self.assertRaises(ValueError, self.run_script, '$ mkdir /out-of-jail')
+ self.assertRaises(ValueError, self.run_script, '$ mkdir ../out-of-jail')
def test_mkdir_in_jail(self):
self.run_script("""
-mkdir dir
-cd dir
-mkdir ../dir2
-cd ..
+$ mkdir dir
+$ cd dir
+$ mkdir ../dir2
+$ cd ..
""")
self.failUnlessExists('dir')
self.failUnlessExists('dir2')
@@ -302,29 +303,29 @@
class TestCd(script.TestCaseWithTransportAndScript):
def test_cd_usage(self):
- self.assertRaises(SyntaxError, self.run_script, 'cd foo bar')
+ self.assertRaises(SyntaxError, self.run_script, '$ cd foo bar')
def test_cd_out_of_jail(self):
- self.assertRaises(ValueError, self.run_script, 'cd /out-of-jail')
- self.assertRaises(ValueError, self.run_script, 'cd ..')
+ self.assertRaises(ValueError, self.run_script, '$ cd /out-of-jail')
+ self.assertRaises(ValueError, self.run_script, '$ cd ..')
def test_cd_dir_and_back_home(self):
self.assertEquals(self.test_dir, osutils.getcwd())
self.run_script("""
-mkdir dir
-cd dir
+$ mkdir dir
+$ cd dir
""")
self.assertEquals(osutils.pathjoin(self.test_dir, 'dir'),
osutils.getcwd())
- self.run_script('cd')
+ self.run_script('$ cd')
self.assertEquals(self.test_dir, osutils.getcwd())
class TestBzr(script.TestCaseWithTransportAndScript):
def test_bzr_smoke(self):
- self.run_script('bzr init branch')
+ self.run_script('$ bzr init branch')
self.failUnlessExists('branch')
@@ -332,7 +333,7 @@
def test_echo_usage(self):
story = """
-echo foo
+$ echo foo
<bar
"""
self.assertRaises(SyntaxError, self.run_script, story)
@@ -351,8 +352,8 @@
def test_echo_more_output(self):
retcode, out, err = self.run_command(
['echo', 'hello', 'happy', 'world'],
- None, 'hellohappyworld\n', None)
- self.assertEquals('hellohappyworld\n', out)
+ None, 'hello happy world\n', None)
+ self.assertEquals('hello happy world\n', out)
self.assertEquals(None, err)
def test_echo_appended(self):
@@ -371,41 +372,41 @@
class TestRm(script.TestCaseWithTransportAndScript):
def test_rm_usage(self):
- self.assertRaises(SyntaxError, self.run_script, 'rm')
- self.assertRaises(SyntaxError, self.run_script, 'rm -ff foo')
+ self.assertRaises(SyntaxError, self.run_script, '$ rm')
+ self.assertRaises(SyntaxError, self.run_script, '$ rm -ff foo')
def test_rm_file(self):
- self.run_script('echo content >file')
+ self.run_script('$ echo content >file')
self.failUnlessExists('file')
- self.run_script('rm file')
+ self.run_script('$ rm file')
self.failIfExists('file')
def test_rm_file_force(self):
self.failIfExists('file')
- self.run_script('rm -f file')
+ self.run_script('$ rm -f file')
self.failIfExists('file')
def test_rm_files(self):
self.run_script("""
-echo content >file
-echo content >file2
+$ echo content >file
+$ echo content >file2
""")
self.failUnlessExists('file2')
- self.run_script('rm file file2')
+ self.run_script('$ rm file file2')
self.failIfExists('file2')
def test_rm_dir(self):
- self.run_script('mkdir dir')
+ self.run_script('$ mkdir dir')
self.failUnlessExists('dir')
self.run_script("""
-rm dir
+$ rm dir
2>rm: cannot remove 'dir': Is a directory
""")
self.failUnlessExists('dir')
def test_rm_dir_recursive(self):
self.run_script("""
-mkdir dir
-rm -r dir
+$ mkdir dir
+$ rm -r dir
""")
self.failIfExists('dir')
=== modified file 'doc/developers/testing.txt'
--- a/doc/developers/testing.txt 2009-09-02 23:45:04 +0000
+++ b/doc/developers/testing.txt 2009-09-17 14:15:15 +0000
@@ -201,6 +201,98 @@
__ http://docs.python.org/lib/module-doctest.html
+Shell-like tests
+~~~~~~~~~~~~~~~~
+
+``bzrlib/tests/script.py`` allows users to write tests in a syntax very close to a shell session,
+using a restricted and limited set of commands that should be enough to mimic
+most of the behaviours.
+
+A script is a set of commands, each command is composed of:
+
+ * one mandatory command line,
+ * one optional set of input lines to feed the command,
+ * one optional set of output expected lines,
+ * one optional set of error expected lines.
+
+Input, output and error lines can be specified in any order.
+
+Except for the expected output, all lines start with a special
+string (based on their origin when used under a Unix shell):
+
+ * '$ ' for the command,
+ * '<' for input,
+ * nothing for output,
+ * '2>' for errors,
+
+Comments can be added anywhere, they start with '#' and end with
+the line.
+
+The execution stops as soon as an expected output or an expected error is not
+matched.
+
+When no output is specified, any ouput from the command is accepted
+and execution continue.
+
+If an error occurs and no expected error is specified, the execution stops.
+
+An error is defined by a returned status different from zero, not by the
+presence of text on the error stream.
+
+The matching is done on a full string comparison basis unless '...' is used, in
+which case expected output/errors can be less precise.
+
+Examples:
+
+The following will succeeds only if 'bzr add' outputs 'adding file'::
+
+ $ bzr add file
+ >adding file
+
+If you want the command to succeed for any output, just use::
+
+ $ bzr add file
+
+The following will stop with an error::
+
+ $ bzr not-a-command
+
+If you want it to succeed, use::
+
+ $ bzr not-a-command
+ 2> bzr: ERROR: unknown command "not-a-command"
+
+You can use ellipsis (...) to replace any piece of text you don't want to be
+matched exactly::
+
+ $ bzr branch not-a-branch
+ 2>bzr: ERROR: Not a branch...not-a-branch/".
+
+This can be used to ignore entire lines too::
+
+ $ cat
+ <first line
+ <second line
+ <third line
+ # And here we explain that surprising fourth line
+ <fourth line
+ <last line
+ >first line
+ >...
+ >last line
+
+You can check the content of a file with cat::
+
+ $ cat <file
+ >expected content
+
+You can also check the existence of a file with cat, the following will fail if
+the file doesn't exist::
+
+ $ cat file
+
+
+
.. Effort tests
.. ~~~~~~~~~~~~
More information about the bazaar-commits
mailing list