You are viewing a plain text version of this content. The canonical link for it is here.
Posted to dev@subversion.apache.org by Blair Zajac <bl...@orcaware.com> on 2002/04/05 21:38:12 UTC

[PATCH FOR REVIEW] add tests for svn getopt processing

I'm working on a patch to svn to factor our the command line processing code
and before I check that in, I built this test to codify svn's current behavior
and make certain my mods don't change it.

Given this is my first python script (!!!) can somebody check it out.  Also,
let me know if the new subversion/tests/clients/cmdline/getopt_tests_data
directory should be different.

I put this test first before the others because it doesn't do anything
significant and in my experience, simple tests go before more complicated
ones.

Thanks,
Blair

-- 
Blair Zajac <bl...@orcaware.com>
Web and OS performance plots - http://www.orcaware.com/orca/


Index: ./build.conf
===================================================================
--- ./build.conf
+++ ./build.conf	Fri Apr  5 12:26:01 2002
@@ -32,6 +32,8 @@
 	subversion/tests/libsvn_fs/run-fs-tests.sh
 # C: test svn_repos_update() in libsvn_repos
 	subversion/tests/libsvn_repos/run-repos-tests.sh
+# Python: command line processing tests
+        subversion/tests/clients/cmdline/getopt_tests.py
 # Python: general blackbox tests
         subversion/tests/clients/cmdline/basic_tests.py
 # Python: commit-related tests
Index: ./subversion/tests/clients/cmdline/README
===================================================================
--- ./subversion/tests/clients/cmdline/README
+++ ./subversion/tests/clients/cmdline/README	Fri Apr  5 12:27:01 2002
@@ -65,6 +65,7 @@
 Directory Contents
 ==================
 
+* getopt_tests.py:       tests: command line option processing.
 
 * basic_tests.py:        tests: general client subcommands.
 
Index: ./subversion/tests/clients/cmdline/getopt_tests.py
===================================================================
--- ./subversion/tests/clients/cmdline/getopt_tests.py
+++ ./subversion/tests/clients/cmdline/getopt_tests.py	Fri Apr  5 13:28:03 2002
@@ -0,0 +1,174 @@
+#!/usr/bin/env python
+#
+#  getopt_tests.py:  testing the svn command line processing
+#
+#  Subversion is a tool for revision control. 
+#  See http://subversion.tigris.org for more information.
+#    
+# ====================================================================
+# Copyright (c) 2000-2002 CollabNet.  All rights reserved.
+#
+# This software is licensed as described in the file COPYING, which
+# you should have received as part of this distribution.  The terms
+# are also available at http://subversion.tigris.org/license-1.html.
+# If newer versions of this license are posted there, you may use a
+# newer version instead, at your option.
+#
+######################################################################
+
+# General modules
+import string, sys, re, os.path
+
+# Our testing module
+import svntest
+
+
+######################################################################
+# Tests
+#
+#   Each test must return 0 on success or non-zero on failure.
+
+#----------------------------------------------------------------------
+
+# This directory contains all the expected output from svn.
+getopt_output_dir = 'getopt_tests_data'
+
+def load_expected_output(basename):
+  "load the expected standard output and standard error"
+
+  stdout_filename = os.path.join(getopt_output_dir, basename + '_stdout')
+  stderr_filename = os.path.join(getopt_output_dir, basename + '_stderr')
+
+  file = open(stdout_filename, 'r')
+  exp_stdout = file.readlines()
+  file.close
+
+  file = open(stderr_filename, 'r')
+  exp_stderr = file.readlines()
+  file.close
+
+  return exp_stdout, exp_stderr
+
+# This is a list of lines to delete.
+delete_lines_res = [ re.compile(r'\s+compiled\s+'),
+                     re.compile(r"- handles '(https|file)' schema"),
+                   ]
+
+# This is a list of lines to search and replace text on.
+replace_lines_res = [ re.compile(r'version \d+\.\d+\.\d+ '), 'version X.Y.Z '
+                    ]
+
+def delete_line(line):
+  "determine if a line should be removed from the output"
+
+  for delete_re in delete_lines_res:
+    if delete_re.search(line, 1):
+      return 0
+
+  return 1
+  
+def search_replace_line(line):
+  "search and replace portions of lines that may change between builds"
+
+  for i in range(0, len(replace_lines_res), 2):
+    replace_re  = replace_lines_res[i]
+    replace_str = replace_lines_res[i+1]
+    new_line = replace_re.sub(replace_str, line)
+    if new_line != line:
+      return new_line
+
+  return line
+
+def run_one_test(sbox, basename, *varargs):
+  "run svn with args and compare against the specified output files"
+
+  if sbox.build():
+    return 1
+
+  exp_stdout, exp_stderr = load_expected_output(basename)
+
+  varargs = map(None, varargs)
+  varargs.insert(0, 1)
+  actual_stdout, actual_stderr = apply(svntest.main.run_svn, varargs)
+
+  # Delete and perform search and replaces on the lines from the
+  # actual and expected output that may differ between build
+  # environments.
+  exp_stdout    = map(search_replace_line, filter(delete_line, exp_stdout))
+  exp_stderr    = map(search_replace_line, filter(delete_line, exp_stderr))
+  actual_stdout = map(search_replace_line, filter(delete_line, actual_stdout))
+  actual_stderr = map(search_replace_line, filter(delete_line, actual_stderr))
+
+  if exp_stdout != actual_stdout:
+    print "Standard output does not match"
+    print "Expected standard output: ", exp_stdout, "\n"
+    print "Actual standard output: ", actual_stdout, "\n"
+    return 1
+
+  if exp_stderr != actual_stderr:
+    print exp_stderr
+    print actual_stderr
+    print "Standard error does not match"
+    return 1
+
+  return 0
+
+def getopt_no_args(sbox):
+  "run svn with no arguments"
+
+  return run_one_test(sbox, 'svn')
+
+def getopt__version(sbox):
+  "run svn --version"
+
+  return run_one_test(sbox, 'svn--version', '--version')
+
+def getopt__help(sbox):
+  "run svn --help"
+
+  return run_one_test(sbox, 'svn--help', '--help')
+
+def getopt_help(sbox):
+  "run svn help"
+
+  return run_one_test(sbox, 'svn_help', 'help')
+
+def getopt_help__version(sbox):
+  "run svn help --version"
+
+  return run_one_test(sbox, 'svn_help--version', 'help', '--version')
+
+def getopt_help_log_switch(sbox):
+  "run svn help log switch"
+
+  return run_one_test(sbox, 'svn_help_log_switch', 'help', 'log', 'switch')
+
+def getopt_help_bogus_cmd(sbox):
+  "run svn help bogus-cmd"
+
+  return run_one_test(sbox, 'svn_help_bogus-cmd', 'help', 'bogus-cmd')
+
+########################################################################
+# Run the tests
+
+
+# list all tests here, starting with None:
+test_list = [ None,
+              getopt_no_args,
+              getopt__version,
+              getopt__help,
+              getopt_help,
+              getopt_help__version,
+              getopt_help_bogus_cmd,
+              getopt_help_log_switch
+            ]
+
+if __name__ == '__main__':
+  svntest.main.run_tests(test_list)
+  # NOTREACHED
+
+
+### End of file.
+# local variables:
+# eval: (load-file "../../../../tools/dev/svn-dev.el")
+# end:
Index: ./subversion/tests/clients/cmdline/getopt_tests_data/svn_help_bogus-cmd_stdout
===================================================================
Index: ./subversion/tests/clients/cmdline/getopt_tests_data/svn_help_stdout
===================================================================
--- ./subversion/tests/clients/cmdline/getopt_tests_data/svn_help_stdout
+++ ./subversion/tests/clients/cmdline/getopt_tests_data/svn_help_stdout	Fri Apr  5 12:09:00 2002
@@ -0,0 +1,36 @@
+usage: svn <subcommand> [options] [args]
+Type "svn help <subcommand>" for help on a specific subcommand.
+
+Most subcommands take file and/or directory arguments, recursing
+on the directories.  If no arguments are supplied to such a
+command, it will recurse on the current directory (inclusive) by
+default.
+
+Available subcommands:
+   add
+   checkout (co)
+   cleanup
+   commit (ci)
+   copy (cp)
+   delete (del, remove, rm)
+   diff (di)
+   help (?, h)
+   import
+   log
+   merge
+   mkdir
+   move (mv, rename, ren)
+   propdel (pdel)
+   propedit (pedit, pe)
+   propget (pget, pg)
+   proplist (plist, pl)
+   propset (pset, ps)
+   revert
+   resolve
+   status (stat, st)
+   switch (sw)
+   update (up)
+
+Subversion is a tool for revision control.
+For additional information, see http://subversion.tigris.org
+
Index: ./subversion/tests/clients/cmdline/getopt_tests_data/svn_help--version_stdout
===================================================================
--- ./subversion/tests/clients/cmdline/getopt_tests_data/svn_help--version_stdout
+++ ./subversion/tests/clients/cmdline/getopt_tests_data/svn_help--version_stdout	Fri Apr  5 12:14:19 2002
@@ -0,0 +1,6 @@
+help (?, h): Display this usage message.
+usage: svn help [SUBCOMMAND1 [SUBCOMMAND2] ...]
+
+Valid options:
+  --version:	print client version info
+
Index: ./subversion/tests/clients/cmdline/getopt_tests_data/svn_help_bogus-cmd_stderr
===================================================================
--- ./subversion/tests/clients/cmdline/getopt_tests_data/svn_help_bogus-cmd_stderr
+++ ./subversion/tests/clients/cmdline/getopt_tests_data/svn_help_bogus-cmd_stderr	Fri Apr  5 12:18:00 2002
@@ -0,0 +1,2 @@
+"bogus-cmd": unknown command.
+
Index: ./subversion/tests/clients/cmdline/getopt_tests_data/svn_help_stderr
===================================================================
Index: ./subversion/tests/clients/cmdline/getopt_tests_data/svn_help--version_stderr
===================================================================
Index: ./subversion/tests/clients/cmdline/getopt_tests_data/svn_help_log_switch_stdout
===================================================================
--- ./subversion/tests/clients/cmdline/getopt_tests_data/svn_help_log_switch_stdout
+++ ./subversion/tests/clients/cmdline/getopt_tests_data/svn_help_log_switch_stdout	Fri Apr  5 12:19:01 2002
@@ -0,0 +1,33 @@
+log: Show the log messages for a set of revision(s) and/or file(s).
+usage: svn log [URL] [PATH1 [PATH2] ...] 
+    Either get the log messages for local PATHs or PATHs at the
+    URL. If URL is given by itself, then log messages are output for
+    that specific path. The -v option will include a list of affected
+    files for each log message. Examples are:
+
+    svn log
+
+    svn log foo.c
+
+    svn log http://www.example.com/repo/project/foo.c
+
+    svn log http://www.example.com/repo/project foo.c bar.c
+
+Valid options:
+  -r [--revision] arg:	specify revision number ARG (or X:Y range)
+  -D [--date] arg:	specify a date ARG (instead of a revision)
+  -v [--verbose]:	print extra information
+  --targets arg:	pass contents of file "ARG" as additional args
+  --username arg:	specify a username ARG
+  --password arg:	specify a password ARG
+
+switch (sw): Update working copy to mirror a new URL
+usage: switch [TARGET] REPOS_URL
+
+   Note:  this is the way to move a working copy to a new branch.
+
+Valid options:
+  -r [--revision] arg:	specify revision number ARG (or X:Y range)
+  -n [--nonrecursive]:	operate on single directory only
+  --force:	force operation to run
+
Index: ./subversion/tests/clients/cmdline/getopt_tests_data/svn_help_log_switch_stderr
===================================================================
Index: ./subversion/tests/clients/cmdline/getopt_tests_data/svn_stdout
===================================================================
Index: ./subversion/tests/clients/cmdline/getopt_tests_data/svn--version_stdout
===================================================================
--- ./subversion/tests/clients/cmdline/getopt_tests_data/svn--version_stdout
+++ ./subversion/tests/clients/cmdline/getopt_tests_data/svn--version_stdout	Fri Apr  5 12:11:50 2002
@@ -0,0 +1,14 @@
+Subversion Client, version 0.10.2 (dev build)
+   compiled Apr  5 2002, 10:08:45
+
+Copyright (C) 2000-2002 CollabNet.
+Subversion is open source software, see http://subversion.tigris.org/
+
+The following repository access (RA) modules are available:
+
+* ra_dav : Module for accessing a repository via WebDAV (DeltaV) protocol.
+  - handles 'http' schema
+  - handles 'https' schema
+* ra_local : Module for accessing a repository on local disk.
+  - handles 'file' schema
+
Index: ./subversion/tests/clients/cmdline/getopt_tests_data/svn_stderr
===================================================================
--- ./subversion/tests/clients/cmdline/getopt_tests_data/svn_stderr
+++ ./subversion/tests/clients/cmdline/getopt_tests_data/svn_stderr	Fri Apr  5 10:53:41 2002
@@ -0,0 +1,36 @@
+usage: svn <subcommand> [options] [args]
+Type "svn help <subcommand>" for help on a specific subcommand.
+
+Most subcommands take file and/or directory arguments, recursing
+on the directories.  If no arguments are supplied to such a
+command, it will recurse on the current directory (inclusive) by
+default.
+
+Available subcommands:
+   add
+   checkout (co)
+   cleanup
+   commit (ci)
+   copy (cp)
+   delete (del, remove, rm)
+   diff (di)
+   help (?, h)
+   import
+   log
+   merge
+   mkdir
+   move (mv, rename, ren)
+   propdel (pdel)
+   propedit (pedit, pe)
+   propget (pget, pg)
+   proplist (plist, pl)
+   propset (pset, ps)
+   revert
+   resolve
+   status (stat, st)
+   switch (sw)
+   update (up)
+
+Subversion is a tool for revision control.
+For additional information, see http://subversion.tigris.org
+
Index: ./subversion/tests/clients/cmdline/getopt_tests_data/svn--version_stderr
===================================================================
Index: ./subversion/tests/clients/cmdline/getopt_tests_data/svn--help_stdout
===================================================================
--- ./subversion/tests/clients/cmdline/getopt_tests_data/svn--help_stdout
+++ ./subversion/tests/clients/cmdline/getopt_tests_data/svn--help_stdout	Fri Apr  5 11:09:54 2002
@@ -0,0 +1,6 @@
+help (?, h): Display this usage message.
+usage: svn help [SUBCOMMAND1 [SUBCOMMAND2] ...]
+
+Valid options:
+  --version:	print client version info
+
Index: ./subversion/tests/clients/cmdline/getopt_tests_data/svn--help_stderr
===================================================================
--- ./subversion/tests/clients/cmdline/getopt_tests_data/svn--help_stderr
+++ ./subversion/tests/clients/cmdline/getopt_tests_data/svn--help_stderr	Fri Apr  5 11:09:54 2002
@@ -0,0 +1,3 @@
+
+Error: subcommand 'help' doesn't accept option '-h [--help]'
+

---------------------------------------------------------------------
To unsubscribe, e-mail: dev-unsubscribe@subversion.tigris.org
For additional commands, e-mail: dev-help@subversion.tigris.org

Re: [PATCH FOR REVIEW] add tests for svn getopt processing

Posted by Blair Zajac <bl...@orcaware.com>.
Ben Collins-Sussman wrote:
> 
> Blair Zajac <bl...@orcaware.com> writes:
> 
> > I'm working on a patch to svn to factor our the command line
> > processing code [...]
> 
> Just curious, what problem are you solving, and how?
> 
> I ask, because the problem isn't obvious to me.  :-)

This came out of the --long option being applied to one of the
svnadmin options.  Right now the command line processing code in
svn is heavily tied to it and the other programs have their
own separate command line processing code.

This project is to factor out the command line processing
code in svn and make it available to the other programs.

Blair

-- 
Blair Zajac <bl...@orcaware.com>
Web and OS performance plots - http://www.orcaware.com/orca/

---------------------------------------------------------------------
To unsubscribe, e-mail: dev-unsubscribe@subversion.tigris.org
For additional commands, e-mail: dev-help@subversion.tigris.org

Re: [PATCH FOR REVIEW] add tests for svn getopt processing

Posted by Ben Collins-Sussman <su...@collab.net>.
Blair Zajac <bl...@orcaware.com> writes:

> I'm working on a patch to svn to factor our the command line
> processing code [...]

Just curious, what problem are you solving, and how?

I ask, because the problem isn't obvious to me.  :-)


---------------------------------------------------------------------
To unsubscribe, e-mail: dev-unsubscribe@subversion.tigris.org
For additional commands, e-mail: dev-help@subversion.tigris.org

Re: [PATCH FOR REVIEW] add tests for svn getopt processing

Posted by Blair Zajac <bl...@orcaware.com>.
Greg,

Thanks for the input.  Mods made and checked in.

Best,
Blair

Greg Stein wrote:
> 
> On Fri, Apr 05, 2002 at 01:38:12PM -0800, Blair Zajac wrote:
> >...
> > +++ ./subversion/tests/clients/cmdline/getopt_tests.py        Fri Apr  5 13:28:03 2002
> >...
> > +def load_expected_output(basename):
> > +  "load the expected standard output and standard error"
> > +
> > +  stdout_filename = os.path.join(getopt_output_dir, basename + '_stdout')
> > +  stderr_filename = os.path.join(getopt_output_dir, basename + '_stderr')
> > +
> > +  file = open(stdout_filename, 'r')
> > +  exp_stdout = file.readlines()
> > +  file.close
> 
> You're only referring to the file.close method -- not actually invoking it.
> You need to put parens on there: file.close()
> 
> But even simpler:
> 
>     exp_stdout = open(stdout_filename).readlines()
> 
> That opens it ('r' is default), then reads all the lines in one shot. Since
> the file object loses all references once the statement ends, it goes away
> which closes the file automatically.
> 
> [ note that file.close() wasn't even needed in your function since the files
>   would be closed on exit from the function since the variables referring to
>   the file went out of scope ]
> 
> >...
> > +replace_lines_res = [ re.compile(r'version \d+\.\d+\.\d+ '), 'version X.Y.Z '
> > +                    ]
> >...
> > +def search_replace_line(line):
> > +  "search and replace portions of lines that may change between builds"
> > +
> > +  for i in range(0, len(replace_lines_res), 2):
> > +    replace_re  = replace_lines_res[i]
> > +    replace_str = replace_lines_res[i+1]
> > +    new_line = replace_re.sub(replace_str, line)
> > +    if new_line != line:
> > +      return new_line
> 
> It would be a lot simpler if you used a tuple in that list:
> 
>   replace_lines_res = [ (re.compile(...), 'version ...'),
>                       ]
> 
> Then you can do:
> 
>   for replace_re, replace_str in replace_lines_res:
>     new_line = replace_re...
> 
> Much clearer...
> 
> >...
> > +def run_one_test(sbox, basename, *varargs):
> > +  "run svn with args and compare against the specified output files"
> > +
> > +  if sbox.build():
> > +    return 1
> > +
> > +  exp_stdout, exp_stderr = load_expected_output(basename)
> > +
> > +  varargs = map(None, varargs)
> 
> To change the varargs tuple to a list, use: list(varargs). That is much
> clearer what your real intent is.
> 
> > +  varargs.insert(0, 1)
> > +  actual_stdout, actual_stderr = apply(svntest.main.run_svn, varargs)
> 
> Usually, when I need to add an argument like the above, I'll do the
> following:
> 
>   apply(svntest.main.run_svn, (1,) + varargs)
> 
> This is clearer about the intent: inserting an argument at the beginning of
> whatever was passed to you.
> 
> > +  # Delete and perform search and replaces on the lines from the
> > +  # actual and expected output that may differ between build
> > +  # environments.
> > +  exp_stdout    = map(search_replace_line, filter(delete_line, exp_stdout))
> 
> Personally, I'd find this clearer if you used one function to post-process
> the lines. That function would look something like:
> 
>   def process_lines(lines):
>     output = [ ]
>     for line in lines:
>       if line is to be deleted:
>         continue
>       line = do the replace thing
>       output.append(line)
>     return output
> 
> Then you just do:
> 
>     exp_stdout = process_lines(exp_stdout)
> 
> That makes the calls clearer, reduces the two functions to one, and
> simplifies the overall logic.
> 
> Cheers,
> -g
> 
> --
> Greg Stein, http://www.lyra.org/
> 
> ---------------------------------------------------------------------
> To unsubscribe, e-mail: dev-unsubscribe@subversion.tigris.org
> For additional commands, e-mail: dev-help@subversion.tigris.org

-- 
Blair Zajac <bl...@orcaware.com>
Web and OS performance plots - http://www.orcaware.com/orca/

---------------------------------------------------------------------
To unsubscribe, e-mail: dev-unsubscribe@subversion.tigris.org
For additional commands, e-mail: dev-help@subversion.tigris.org

Re: [PATCH FOR REVIEW] add tests for svn getopt processing

Posted by Greg Stein <gs...@lyra.org>.
On Fri, Apr 05, 2002 at 01:38:12PM -0800, Blair Zajac wrote:
>...
> +++ ./subversion/tests/clients/cmdline/getopt_tests.py	Fri Apr  5 13:28:03 2002
>...
> +def load_expected_output(basename):
> +  "load the expected standard output and standard error"
> +
> +  stdout_filename = os.path.join(getopt_output_dir, basename + '_stdout')
> +  stderr_filename = os.path.join(getopt_output_dir, basename + '_stderr')
> +
> +  file = open(stdout_filename, 'r')
> +  exp_stdout = file.readlines()
> +  file.close

You're only referring to the file.close method -- not actually invoking it.
You need to put parens on there: file.close()

But even simpler:

    exp_stdout = open(stdout_filename).readlines()

That opens it ('r' is default), then reads all the lines in one shot. Since
the file object loses all references once the statement ends, it goes away
which closes the file automatically.

[ note that file.close() wasn't even needed in your function since the files
  would be closed on exit from the function since the variables referring to
  the file went out of scope ]

>...
> +replace_lines_res = [ re.compile(r'version \d+\.\d+\.\d+ '), 'version X.Y.Z '
> +                    ]
>...
> +def search_replace_line(line):
> +  "search and replace portions of lines that may change between builds"
> +
> +  for i in range(0, len(replace_lines_res), 2):
> +    replace_re  = replace_lines_res[i]
> +    replace_str = replace_lines_res[i+1]
> +    new_line = replace_re.sub(replace_str, line)
> +    if new_line != line:
> +      return new_line

It would be a lot simpler if you used a tuple in that list:

  replace_lines_res = [ (re.compile(...), 'version ...'),
                      ]

Then you can do:

  for replace_re, replace_str in replace_lines_res:
    new_line = replace_re...

Much clearer...

>...
> +def run_one_test(sbox, basename, *varargs):
> +  "run svn with args and compare against the specified output files"
> +
> +  if sbox.build():
> +    return 1
> +
> +  exp_stdout, exp_stderr = load_expected_output(basename)
> +
> +  varargs = map(None, varargs)

To change the varargs tuple to a list, use: list(varargs). That is much
clearer what your real intent is.

> +  varargs.insert(0, 1)
> +  actual_stdout, actual_stderr = apply(svntest.main.run_svn, varargs)

Usually, when I need to add an argument like the above, I'll do the
following:

  apply(svntest.main.run_svn, (1,) + varargs)

This is clearer about the intent: inserting an argument at the beginning of
whatever was passed to you.

> +  # Delete and perform search and replaces on the lines from the
> +  # actual and expected output that may differ between build
> +  # environments.
> +  exp_stdout    = map(search_replace_line, filter(delete_line, exp_stdout))

Personally, I'd find this clearer if you used one function to post-process
the lines. That function would look something like:

  def process_lines(lines):
    output = [ ]
    for line in lines:
      if line is to be deleted:
        continue
      line = do the replace thing
      output.append(line)
    return output

Then you just do:

    exp_stdout = process_lines(exp_stdout)

That makes the calls clearer, reduces the two functions to one, and
simplifies the overall logic.

Cheers,
-g

-- 
Greg Stein, http://www.lyra.org/

---------------------------------------------------------------------
To unsubscribe, e-mail: dev-unsubscribe@subversion.tigris.org
For additional commands, e-mail: dev-help@subversion.tigris.org