subdir = 'subdir',
verbose = Boolean,
match = default_match_function,
+ diff = default_diff_function,
combine = Boolean)
There are a bunch of methods that let you do different things:
test.symlink(target, link)
+ test.banner(string)
+ test.banner(string, width)
+
+ test.diff(actual, expected)
+
test.match(actual, expected)
test.match_exact("actual 1\nactual 2\n", "expected 1\nexpected 2\n")
test = TestCmd.TestCmd(match = TestCmd.match_re_dotall)
+The TestCmd module provides unbound functions that can be used for the
+"diff" argument to TestCmd.TestCmd instantiation:
+
+ import TestCmd
+
+ test = TestCmd.TestCmd(match = TestCmd.match_re,
+ diff = TestCmd.diff_re)
+
+ test = TestCmd.TestCmd(diff = TestCmd.simple_diff)
+
+The "diff" argument can also be used with standard difflib functions:
+
+ import difflib
+
+ test = TestCmd.TestCmd(diff = difflib.context_diff)
+
+ test = TestCmd.TestCmd(diff = difflib.unified_diff)
+
Lastly, the where_is() method also exists in an unbound function
version.
TestCmd.where_is('foo', 'PATH1;PATH2', '.suffix3;.suffix4')
"""
-# Copyright 2000, 2001, 2002, 2003, 2004 Steven Knight
+# Copyright 2000-2010 Steven Knight
# This module is free software, and you may redistribute it and/or modify
# it under the same terms as Python itself, so long as this copyright message
# and disclaimer are retained in their original form.
# PARTICULAR PURPOSE. THE CODE PROVIDED HEREUNDER IS ON AN "AS IS" BASIS,
# AND THERE IS NO OBLIGATION WHATSOEVER TO PROVIDE MAINTENANCE,
# SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
+from __future__ import generators ### KEEP FOR COMPATIBILITY FIXERS
__author__ = "Steven Knight <knight at baldmt dot com>"
-__revision__ = "TestCmd.py 0.35.D001 2009/02/08 07:10:39 knight"
-__version__ = "0.35"
+__revision__ = "TestCmd.py 0.37.D001 2010/01/11 16:55:50 knight"
+__version__ = "0.37"
import errno
import os
import re
import shutil
import stat
-import string
import sys
import tempfile
import time
import traceback
-import types
import UserList
__all__ = [
'TestCmd'
]
+try:
+ import difflib
+except ImportError:
+ __all__.append('simple_diff')
+
def is_List(e):
- return type(e) is types.ListType \
+ return isinstance(e, list) \
or isinstance(e, UserList.UserList)
try:
class UserString:
pass
-if hasattr(types, 'UnicodeType'):
+try: unicode
+except NameError:
def is_String(e):
- return type(e) is types.StringType \
- or type(e) is types.UnicodeType \
- or isinstance(e, UserString)
+ return isinstance(e, str) or isinstance(e, UserString)
else:
def is_String(e):
- return type(e) is types.StringType or isinstance(e, UserString)
+ return isinstance(e, str) \
+ or isinstance(e, unicode) \
+ or isinstance(e, UserString)
tempfile.template = 'testcmd.'
if os.name in ('posix', 'nt'):
def _clean():
global _Cleanup
- cleanlist = filter(None, _Cleanup)
+ cleanlist = [_f for _f in _Cleanup if _f]
del _Cleanup[:]
cleanlist.reverse()
for test in cleanlist:
except NameError:
def zip(*lists):
result = []
- for i in xrange(min(map(len, lists))):
- result.append(tuple(map(lambda l, i=i: l[i], lists)))
+ for i in xrange(min(list(map(len, lists)))):
+ result.append(tuple([l[i] for l in lists]))
return result
class Collector:
def __init__(self, top):
self.entries = [top]
def __call__(self, arg, dirname, names):
- pathjoin = lambda n, d=dirname: os.path.join(d, n)
- self.entries.extend(map(pathjoin, names))
+ pathjoin = lambda n: os.path.join(dirname, n)
+ self.entries.extend(list(map(pathjoin, names)))
def _caller(tblist, skip):
string = ""
"""
"""
if not is_List(lines):
- lines = string.split(lines, "\n")
+ lines = lines.split("\n")
if not is_List(matches):
- matches = string.split(matches, "\n")
+ matches = matches.split("\n")
if len(lines) != len(matches):
return
for i in range(len(lines)):
"""
"""
if not is_List(lines):
- lines = string.split(lines, "\n")
+ lines = lines.split("\n")
if not is_List(res):
- res = string.split(res, "\n")
+ res = res.split("\n")
if len(lines) != len(res):
return
for i in range(len(lines)):
def match_re_dotall(lines = None, res = None):
"""
"""
- if not type(lines) is type(""):
- lines = string.join(lines, "\n")
- if not type(res) is type(""):
- res = string.join(res, "\n")
+ if not isinstance(lines, str):
+ lines = "\n".join(lines)
+ if not isinstance(res, str):
+ res = "\n".join(res)
s = "^" + res + "$"
try:
expr = re.compile(s, re.DOTALL)
if expr.match(lines):
return 1
+try:
+ import difflib
+except ImportError:
+ pass
+else:
+ def simple_diff(a, b, fromfile='', tofile='',
+ fromfiledate='', tofiledate='', n=3, lineterm='\n'):
+ """
+ A function with the same calling signature as difflib.context_diff
+ (diff -c) and difflib.unified_diff (diff -u) but which prints
+ output like the simple, unadorned 'diff" command.
+ """
+ sm = difflib.SequenceMatcher(None, a, b)
+ def comma(x1, x2):
+ return x1+1 == x2 and str(x2) or '%s,%s' % (x1+1, x2)
+ result = []
+ for op, a1, a2, b1, b2 in sm.get_opcodes():
+ if op == 'delete':
+ result.append("%sd%d" % (comma(a1, a2), b1))
+ result.extend(['< ' + l for l in a[a1:a2]])
+ elif op == 'insert':
+ result.append("%da%s" % (a1, comma(b1, b2)))
+ result.extend(['> ' + l for l in b[b1:b2]])
+ elif op == 'replace':
+ result.append("%sc%s" % (comma(a1, a2), comma(b1, b2)))
+ result.extend(['< ' + l for l in a[a1:a2]])
+ result.append('---')
+ result.extend(['> ' + l for l in b[b1:b2]])
+ return result
+
def diff_re(a, b, fromfile='', tofile='',
fromfiledate='', tofiledate='', n=3, lineterm='\n'):
"""
if path is None:
path = os.environ['PATH']
if is_String(path):
- path = string.split(path, os.pathsep)
+ path = path.split(os.pathsep)
if pathext is None:
pathext = os.environ['PATHEXT']
if is_String(pathext):
- pathext = string.split(pathext, os.pathsep)
+ pathext = pathext.split(os.pathsep)
for ext in pathext:
- if string.lower(ext) == string.lower(file[-len(ext):]):
+ if ext.lower() == file[-len(ext):].lower():
pathext = ['']
break
for dir in path:
if path is None:
path = os.environ['PATH']
if is_String(path):
- path = string.split(path, os.pathsep)
+ path = path.split(os.pathsep)
for dir in path:
f = os.path.join(dir, file)
if os.path.isfile(f):
universal_newlines = 1
def __init__(self, command, **kw):
if kw.get('stderr') == 'STDOUT':
- apply(popen2.Popen4.__init__, (self, command, 1))
+ popen2.Popen4.__init__(self, command, 1)
else:
- apply(popen2.Popen3.__init__, (self, command, 1))
+ popen2.Popen3.__init__(self, command, 1)
self.stdin = self.tochild
self.stdout = self.fromchild
self.stderr = self.childerr
def wait(self, *args, **kw):
- resultcode = apply(popen2.Popen3.wait, (self,)+args, kw)
+ resultcode = popen2.Popen3.wait(self, *args, **kw)
if os.WIFEXITED(resultcode):
return os.WEXITSTATUS(resultcode)
elif os.WIFSIGNALED(resultcode):
time.sleep(max((x-time.time())/tr, 0))
return ''.join(y)
+# TODO(3.0: rewrite to use memoryview()
def send_all(p, data):
while len(data):
sent = p.send(data)
-class TestCmd:
+try:
+ object
+except NameError:
+ class object:
+ pass
+
+
+
+class TestCmd(object):
"""Class TestCmd
"""
subdir = None,
verbose = None,
match = None,
+ diff = None,
combine = 0,
universal_newlines = 1):
self._cwd = os.getcwd()
self.combine = combine
self.universal_newlines = universal_newlines
if not match is None:
- self.match_func = match
+ self.match_function = match
else:
- self.match_func = match_re
+ self.match_function = match_re
+ if not diff is None:
+ self.diff_function = diff
+ else:
+ try:
+ difflib
+ except NameError:
+ pass
+ else:
+ self.diff_function = simple_diff
+ #self.diff_function = difflib.context_diff
+ #self.diff_function = difflib.unified_diff
self._dirlist = []
self._preserve = {'pass_test': 0, 'fail_test': 0, 'no_result': 0}
- if os.environ.has_key('PRESERVE') and not os.environ['PRESERVE'] is '':
+ if 'PRESERVE' in os.environ and not os.environ['PRESERVE'] is '':
self._preserve['pass_test'] = os.environ['PRESERVE']
self._preserve['fail_test'] = os.environ['PRESERVE']
self._preserve['no_result'] = os.environ['PRESERVE']
def __repr__(self):
return "%x" % id(self)
+ banner_char = '='
+ banner_width = 80
+
+ def banner(self, s, width=None):
+ if width is None:
+ width = self.banner_width
+ return s + self.banner_char * (width - len(s))
+
if os.name == 'posix':
def escape(self, arg):
slash = '\\'
special = '"$'
- arg = string.replace(arg, slash, slash+slash)
+ arg = arg.replace(slash, slash+slash)
for c in special:
- arg = string.replace(arg, c, slash+c)
+ arg = arg.replace(c, slash+c)
if re_space.search(arg):
arg = '"' + arg + '"'
def canonicalize(self, path):
if is_List(path):
- path = apply(os.path.join, tuple(path))
+ path = os.path.join(*tuple(path))
if not os.path.isabs(path):
path = os.path.join(self.workdir, path)
return path
interpreter = None,
arguments = None):
if program:
- if type(program) == type('') and not os.path.isabs(program):
+ if isinstance(program, str) and not os.path.isabs(program):
program = os.path.join(self._cwd, program)
else:
program = self.program
if not interpreter:
interpreter = self.interpreter
- if not type(program) in [type([]), type(())]:
+ if not type(program) in [list, tuple]:
program = [program]
cmd = list(program)
if interpreter:
- if not type(interpreter) in [type([]), type(())]:
+ if not type(interpreter) in [list, tuple]:
interpreter = [interpreter]
cmd = list(interpreter) + cmd
if arguments:
- if type(arguments) == type(''):
- arguments = string.split(arguments)
+ if isinstance(arguments, str):
+ arguments = arguments.split()
cmd.extend(arguments)
return cmd
"""
self.description = description
-# def diff(self):
-# """Diff two arrays.
-# """
+ try:
+ difflib
+ except NameError:
+ def diff(self, a, b, name, *args, **kw):
+ print self.banner('Expected %s' % name)
+ print a
+ print self.banner('Actual %s' % name)
+ print b
+ else:
+ def diff(self, a, b, name, *args, **kw):
+ print self.banner(name)
+ args = (a.splitlines(), b.splitlines()) + args
+ lines = self.diff_function(*args, **kw)
+ for l in lines:
+ print l
def fail_test(self, condition = 1, function = None, skip = 0):
"""Cause the test to fail.
def match(self, lines, matches):
"""Compare actual and expected file contents.
"""
- return self.match_func(lines, matches)
+ return self.match_function(lines, matches)
def match_exact(self, lines, matches):
"""Compare actual and expected file contents.
prepended unless it is enclosed in a [list].
"""
cmd = self.command_args(program, interpreter, arguments)
- cmd_string = string.join(map(self.escape, cmd), ' ')
+ cmd_string = ' '.join(map(self.escape, cmd))
if self.verbose:
sys.stderr.write(cmd_string + "\n")
if universal_newlines is None:
universal_newlines = self.universal_newlines
+ # On Windows, if we make stdin a pipe when we plan to send
+ # no input, and the test program exits before
+ # Popen calls msvcrt.open_osfhandle, that call will fail.
+ # So don't use a pipe for stdin if we don't need one.
+ stdin = kw.get('stdin', None)
+ if stdin is not None:
+ stdin = subprocess.PIPE
+
combine = kw.get('combine', self.combine)
if combine:
stderr_value = subprocess.STDOUT
stderr_value = subprocess.PIPE
return Popen(cmd,
- stdin=subprocess.PIPE,
+ stdin=stdin,
stdout=subprocess.PIPE,
stderr=stderr_value,
universal_newlines=universal_newlines)
if self.verbose:
sys.stderr.write("chdir(" + chdir + ")\n")
os.chdir(chdir)
- p = self.start(program, interpreter, arguments, universal_newlines)
+ p = self.start(program,
+ interpreter,
+ arguments,
+ universal_newlines,
+ stdin=stdin)
if stdin:
if is_List(stdin):
for line in stdin:
p.stdin.write(line)
else:
p.stdin.write(stdin)
- p.stdin.close()
+ p.stdin.close()
out = p.stdout.read()
if p.stderr is None:
if sub is None:
continue
if is_List(sub):
- sub = apply(os.path.join, tuple(sub))
+ sub = os.path.join(*tuple(sub))
new = os.path.join(self.workdir, sub)
try:
os.mkdir(new)
# letters is pretty much random on win32:
drive,rest = os.path.splitdrive(path)
if drive:
- path = string.upper(drive) + rest
+ path = drive.upper() + rest
#
self._dirlist.append(path)
"""Find an executable file.
"""
if is_List(file):
- file = apply(os.path.join, tuple(file))
+ file = os.path.join(*tuple(file))
if not os.path.isabs(file):
file = where_is(file, path, pathext)
return file
the temporary working directory name with the specified
arguments using the os.path.join() method.
"""
- return apply(os.path.join, (self.workdir,) + tuple(args))
+ return os.path.join(self.workdir, *tuple(args))
def readable(self, top, read=1):
"""Make the specified directory tree readable (read == 1)
if mode[0] != 'w':
raise ValueError, "mode must begin with 'w'"
open(file, mode).write(content)
+
+# Local Variables:
+# tab-width:4
+# indent-tabs-mode:nil
+# End:
+# vim: set expandtab tabstop=4 shiftwidth=4: