summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorSteven Knight <knight@baldmt.com>2010-06-15 17:01:27 (GMT)
committerSteven Knight <knight@baldmt.com>2010-06-15 17:01:27 (GMT)
commit894e7eb8ee6f062f076bec3b33d13d19c475faaa (patch)
tree64467db0c059aa39aaf6f44dfa207394865947b1
parenta571ee0bb24bcaf976cd8b313688a7287c4edbeb (diff)
downloadSCons-894e7eb8ee6f062f076bec3b33d13d19c475faaa.zip
SCons-894e7eb8ee6f062f076bec3b33d13d19c475faaa.tar.gz
SCons-894e7eb8ee6f062f076bec3b33d13d19c475faaa.tar.bz2
Merged revisions 4727-4729,4731-4938,4940-5028 via svnmerge from
http://scons.tigris.org/svn/scons/branches/pending ........ r4942 | stevenknight | 2010-06-03 12:41:20 -0700 (Thu, 03 Jun 2010) | 13 lines Isseu 2641: Latest drop of the TestCmd infrastructure, v. 1.3, including: * Support for test timeouts. * Ability to set separate match_stdout and match_stderr functions. * Ability to set separate diff_stdout and diff_stderr functions. * Static methods for the various underlying match* and diff* functionality. * Ability to get at the various match* and diff* functions by attribute name. * Got rid of checks for difflib now that Python 2.3 is the floor (for this infrastructure, anyway). Ripple effects in two test scripts. Added upstream unit test modules (QMTest/Test{Cmd,Common}Tests.py). Added a README.txt file. ........ r4943 | stevenknight | 2010-06-03 13:00:31 -0700 (Thu, 03 Jun 2010) | 2 lines Grab the correct TestCmd files with the updated version number. ........ r4946 | managan | 2010-06-04 09:39:20 -0700 (Fri, 04 Jun 2010) | 4 lines On Windows add a '/D' to the command line so it recognizes drive letters in the source or target file paths ........ r4947 | managan | 2010-06-04 09:51:48 -0700 (Fri, 04 Jun 2010) | 5 lines The scanner was not parsing the dependencies in \includegraphics commands when there was whitespace (including carriage returns) in the command. While we need a better long term fix this covers this concern. ........ r4948 | managan | 2010-06-04 11:13:12 -0700 (Fri, 04 Jun 2010) | 3 lines Dropped an import line that is needed by the last commit of mine for Windows depenedant option on latex command lines ........ r4949 | managan | 2010-06-04 12:27:48 -0700 (Fri, 04 Jun 2010) | 7 lines Some latex packages break up commands where you normally could not by using a comment character at the end of the first line. Our current scanner broke on this and lost some dependecies. While we need general fix, this patch solves this problem ........ r4950 | managan | 2010-06-04 15:51:36 -0700 (Fri, 04 Jun 2010) | 5 lines Tweak how we handle comments within Latex source files when scanning and looking for dependencies. We were adding a space when a comment broke a line and we should not have. ........ r4984 | managan | 2010-06-07 09:37:40 -0700 (Mon, 07 Jun 2010) | 6 lines The multi-line_include-options test failed to check for the existence of latex. Added that so this test is skipped on systems without latex. ........
-rw-r--r--QMTest/README.txt55
-rw-r--r--QMTest/TestCmd.py367
-rw-r--r--QMTest/TestCmdTests.py3457
-rw-r--r--QMTest/TestCommon.py4
-rw-r--r--QMTest/TestCommonTests.py2094
-rw-r--r--src/engine/SCons/Scanner/LaTeX.py28
-rw-r--r--src/engine/SCons/Tool/tex.py24
-rw-r--r--src/test_strings.py2
-rw-r--r--test/SConstruct.py7
-rw-r--r--test/TEX/eps_graphics2.py6
-rw-r--r--test/TEX/multi-line_include_options.py90
-rw-r--r--test/option-n.py4
12 files changed, 6017 insertions, 121 deletions
diff --git a/QMTest/README.txt b/QMTest/README.txt
new file mode 100644
index 0000000..992a45b
--- /dev/null
+++ b/QMTest/README.txt
@@ -0,0 +1,55 @@
+This directory contains testing infrastructure. Note that not all of
+the pieces here are local to SCons.
+
+ README.txt
+
+ What you're looking at right now.
+
+ SConscript
+
+ Configuration for our packaging build, to copy the necessary
+ parts of the infrastructure into a build directory.
+
+ TestCmd.py
+ TestCmdTests.py
+ TestCommon.py
+ TestCommonTests.py
+
+ The TestCmd infrastructure for testing external commands.
+ These are for generic command testing, are used by some
+ other projects, and are developed separately from SCons.
+ (They're developed by SK, but still...)
+
+ We've captured the unit tests (Test*Tests.py) for these files
+ along with the actual modules themselves to make it a little
+ easier to hack on them for our purposes. Note, however,
+ that any SCons-specific functionality should be implemented
+ in one of the
+
+ TestRuntest.py
+
+ Test infrastructure for our runtest.py script.
+
+ TestSCons.py
+
+ Test infrastructure for SCons itself.
+
+ TestSConsMSVS.py
+
+ Test infrastructure for SCons' Visual Studio support.
+
+ TestSCons_time.py
+
+ Test infrastructure for the scons-time.py script.
+
+ TestSConsign.py
+
+ Test infrastructure for the sconsign.py script.
+
+ classes.qmc
+ configuration
+ scons-tdb.py
+
+ Pieces for the use of QMTest to test SCons. We're moving away
+ from this infrastructure, in no small part because we're not
+ really using it as originally envisioned.
diff --git a/QMTest/TestCmd.py b/QMTest/TestCmd.py
index 3fca4ec..2c90302 100644
--- a/QMTest/TestCmd.py
+++ b/QMTest/TestCmd.py
@@ -25,7 +25,11 @@ There are a bunch of keyword arguments available at instantiation:
subdir = 'subdir',
verbose = Boolean,
match = default_match_function,
- diff = default_diff_function,
+ match_stdout = default_match_stdout_function,
+ match_stderr = default_match_stderr_function,
+ diff = default_diff_stderr_function,
+ diff_stdout = default_diff_stdout_function,
+ diff_stderr = default_diff_stderr_function,
combine = Boolean)
There are a bunch of methods that let you do different things:
@@ -109,8 +113,18 @@ There are a bunch of methods that let you do different things:
test.diff(actual, expected)
+ test.diff_stderr(actual, expected)
+
+ test.diff_stdout(actual, expected)
+
test.match(actual, expected)
+ test.match_stderr(actual, expected)
+
+ test.match_stdout(actual, expected)
+
+ test.set_match_function(match, stdout, stderr)
+
test.match_exact("actual 1\nactual 2\n", "expected 1\nexpected 2\n")
test.match_exact(["actual 1\n", "actual 2\n"],
["expected 1\n", "expected 2\n"])
@@ -159,8 +173,8 @@ or incorrect permissions).
TestCmd.no_result(condition, function)
TestCmd.no_result(condition, function, skip)
-The TestCmd module also provides unbound functions that handle matching
-in the same way as the match_*() methods described above.
+The TestCmd module also provides unbound global functions that handle
+matching in the same way as the match_*() methods described above.
import TestCmd
@@ -170,8 +184,28 @@ in the same way as the match_*() methods described above.
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:
+These functions are also available as static methods:
+
+ import TestCmd
+
+ test = TestCmd.TestCmd(match = TestCmd.TestCmd.match_exact)
+
+ test = TestCmd.TestCmd(match = TestCmd.TestCmd.match_re)
+
+ test = TestCmd.TestCmd(match = TestCmd.TestCmd.match_re_dotall)
+
+These static methods can be accessed by a string naming the method:
+
+ import TestCmd
+
+ test = TestCmd.TestCmd(match = 'match_exact')
+
+ test = TestCmd.TestCmd(match = 'match_re')
+
+ test = TestCmd.TestCmd(match = 'match_re_dotall')
+
+The TestCmd module provides unbound global functions that can be used
+for the "diff" argument to TestCmd.TestCmd instantiation:
import TestCmd
@@ -180,6 +214,35 @@ The TestCmd module provides unbound functions that can be used for the
test = TestCmd.TestCmd(diff = TestCmd.simple_diff)
+ test = TestCmd.TestCmd(diff = TestCmd.context_diff)
+
+ test = TestCmd.TestCmd(diff = TestCmd.unified_diff)
+
+These functions are also available as static methods:
+
+ import TestCmd
+
+ test = TestCmd.TestCmd(match = TestCmd.TestCmd.match_re,
+ diff = TestCmd.TestCmd.diff_re)
+
+ test = TestCmd.TestCmd(diff = TestCmd.TestCmd.simple_diff)
+
+ test = TestCmd.TestCmd(diff = TestCmd.TestCmd.context_diff)
+
+ test = TestCmd.TestCmd(diff = TestCmd.TestCmd.unified_diff)
+
+These static methods can be accessed by a string naming the method:
+
+ import TestCmd
+
+ test = TestCmd.TestCmd(match = 'match_re', diff = 'diff_re')
+
+ test = TestCmd.TestCmd(diff = 'simple_diff')
+
+ test = TestCmd.TestCmd(diff = 'context_diff')
+
+ test = TestCmd.TestCmd(diff = 'unified_diff')
+
The "diff" argument can also be used with standard difflib functions:
import difflib
@@ -216,19 +279,27 @@ version.
from __future__ import division
__author__ = "Steven Knight <knight at baldmt dot com>"
-__revision__ = "TestCmd.py 1.1.D002 2010/05/27 14:47:22 knight"
-__version__ = "1.1"
+__revision__ = "TestCmd.py 1.3.D001 2010/06/03 12:58:27 knight"
+__version__ = "1.3"
import atexit
+import difflib
import errno
import os
import re
import shutil
+import signal
import stat
import sys
import tempfile
+import threading
import time
import traceback
+import types
+
+class null(object):
+ pass
+_Null = null()
try:
from collections import UserList, UserString
@@ -264,11 +335,6 @@ __all__ = [
'TestCmd'
]
-try:
- import difflib
-except ImportError:
- __all__.append('simple_diff')
-
def is_List(e):
return isinstance(e, (list, UserList))
@@ -435,35 +501,30 @@ def match_re_dotall(lines = None, res = None):
raise re.error(msg % (repr(s), e.args[0]))
return expr.match(lines)
-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 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'):
@@ -576,7 +637,6 @@ except ImportError:
# so we're going to cobble up something that looks just enough
# like its API for our purposes below.
import popen2
- import types
subprocess = types.ModuleType('subprocess')
subprocess.PIPE = 'PIPE'
@@ -607,16 +667,31 @@ except ImportError:
self.stderr.close()
self.returncode = self.wait()
return (out, err)
+ def terminate(self):
+ os.kill(self.pid, signal.SIGTERM)
def wait(self, *args, **kw):
resultcode = popen2.Popen3.wait(self, *args, **kw)
- if os.WIFEXITED(resultcode):
+ if os.WIFSIGNALED(resultcode):
+ return (- os.WTERMSIG(resultcode))
+ elif os.WIFEXITED(resultcode):
return os.WEXITSTATUS(resultcode)
- elif os.WIFSIGNALED(resultcode):
- return os.WTERMSIG(resultcode)
else:
return None
subprocess.Popen = Popen
+else:
+ try:
+ subprocess.Popen.terminate
+ except AttributeError:
+ if sys.platform == 'win32':
+ import win32process
+ def terminate(self):
+ win32process.TerminateProcess(self._handle, 1)
+ else:
+ def terminate(self):
+ os.kill(self.pid, signal.SIGTERM)
+ method = types.MethodType(terminate, None, subprocess.Popen)
+ setattr(subprocess.Popen, 'terminate', method)
@@ -790,9 +865,14 @@ class TestCmd(object):
subdir = None,
verbose = None,
match = None,
+ match_stdout = None,
+ match_stderr = None,
diff = None,
+ diff_stdout = None,
+ diff_stderr = None,
combine = 0,
- universal_newlines = 1):
+ universal_newlines = 1,
+ timeout = None):
self._cwd = os.getcwd()
self.description_set(description)
self.program_set(program)
@@ -805,21 +885,10 @@ class TestCmd(object):
self.verbose_set(verbose)
self.combine = combine
self.universal_newlines = universal_newlines
- if not match is None:
- self.match_function = match
- else:
- 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.process = None
+ self.set_timeout(timeout)
+ self.set_match_function(match, match_stdout, match_stderr)
+ self.set_diff_function(diff, diff_stdout, diff_stderr)
self._dirlist = []
self._preserve = {'pass_test': 0, 'fail_test': 0, 'no_result': 0}
if 'PRESERVE' in os.environ and not os.environ['PRESERVE'] is '':
@@ -941,21 +1010,55 @@ class TestCmd(object):
"""
self.description = description
- 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):
+ def set_diff_function(self, diff=_Null, stdout=_Null, stderr=_Null):
+ """Sets the specified diff functions.
+ """
+ if diff is not _Null:
+ self._diff_function = diff
+ if stdout is not _Null:
+ self._diff_stdout_function = stdout
+ if stderr is not _Null:
+ self._diff_stderr_function = stderr
+
+ def diff(self, a, b, name=None, diff_function=None, *args, **kw):
+ if diff_function is None:
+ try:
+ diff_function = getattr(self, self._diff_function)
+ except TypeError:
+ diff_function = self._diff_function
+ if diff_function is None:
+ diff_function = self.simple_diff
+ if name is not None:
print self.banner(name)
- args = (a.splitlines(), b.splitlines()) + args
- lines = self.diff_function(*args, **kw)
- for l in lines:
- print l
+ args = (a.splitlines(), b.splitlines()) + args
+ for line in diff_function(*args, **kw):
+ print line
+
+ def diff_stderr(self, a, b, *args, **kw):
+ """Compare actual and expected file contents.
+ """
+ try:
+ diff_stderr_function = getattr(self, self._diff_stderr_function)
+ except TypeError:
+ diff_stderr_function = self._diff_stderr_function
+ return self.diff(a, b, diff_function=diff_stderr_function, *args, **kw)
+
+ def diff_stdout(self, a, b, *args, **kw):
+ """Compare actual and expected file contents.
+ """
+ try:
+ diff_stdout_function = getattr(self, self._diff_stdout_function)
+ except TypeError:
+ diff_stdout_function = self._diff_stdout_function
+ return self.diff(a, b, diff_function=diff_stdout_function, *args, **kw)
+
+ simple_diff = staticmethod(simple_diff)
+
+ diff_re = staticmethod(diff_re)
+
+ context_diff = staticmethod(difflib.context_diff)
+
+ unified_diff = staticmethod(difflib.unified_diff)
def fail_test(self, condition = 1, function = None, skip = 0):
"""Cause the test to fail.
@@ -974,25 +1077,57 @@ class TestCmd(object):
"""
self.interpreter = interpreter
- def match(self, lines, matches):
- """Compare actual and expected file contents.
+ def set_match_function(self, match=_Null, stdout=_Null, stderr=_Null):
+ """Sets the specified match functions.
"""
- return self.match_function(lines, matches)
+ if match is not _Null:
+ self._match_function = match
+ if stdout is not _Null:
+ self._match_stdout_function = stdout
+ if stderr is not _Null:
+ self._match_stderr_function = stderr
- def match_exact(self, lines, matches):
+ def match(self, lines, matches):
"""Compare actual and expected file contents.
"""
- return match_exact(lines, matches)
-
- def match_re(self, lines, res):
+ try:
+ match_function = getattr(self, self._match_function)
+ except TypeError:
+ match_function = self._match_function
+ if match_function is None:
+ # Default is regular expression matches.
+ match_function = self.match_re
+ return match_function(lines, matches)
+
+ def match_stderr(self, lines, matches):
"""Compare actual and expected file contents.
"""
- return match_re(lines, res)
-
- def match_re_dotall(self, lines, res):
+ try:
+ match_stderr_function = getattr(self, self._match_stderr_function)
+ except TypeError:
+ match_stderr_function = self._match_stderr_function
+ if match_stderr_function is None:
+ # Default is to use whatever match= is set to.
+ match_stderr_function = self.match
+ return match_stderr_function(lines, matches)
+
+ def match_stdout(self, lines, matches):
"""Compare actual and expected file contents.
"""
- return match_re_dotall(lines, res)
+ try:
+ match_stdout_function = getattr(self, self._match_stdout_function)
+ except TypeError:
+ match_stdout_function = self._match_stdout_function
+ if match_stdout_function is None:
+ # Default is to use whatever match= is set to.
+ match_stdout_function = self.match
+ return match_stdout_function(lines, matches)
+
+ match_exact = staticmethod(match_exact)
+
+ match_re = staticmethod(match_re)
+
+ match_re_dotall = staticmethod(match_re_dotall)
def no_result(self, condition = 1, function = None, skip = 0):
"""Report that the test could not be run.
@@ -1057,10 +1192,20 @@ class TestCmd(object):
dir = self.canonicalize(dir)
os.rmdir(dir)
+ def _timeout(self):
+ self.process.terminate()
+ self.timer.cancel()
+ self.timer = None
+
+ def set_timeout(self, timeout):
+ self.timeout = timeout
+ self.timer = None
+
def start(self, program = None,
interpreter = None,
arguments = None,
universal_newlines = None,
+ timeout = _Null,
**kw):
"""
Starts a program or script for the test environment.
@@ -1089,20 +1234,33 @@ class TestCmd(object):
else:
stderr_value = subprocess.PIPE
- return Popen(cmd,
- stdin=stdin,
- stdout=subprocess.PIPE,
- stderr=stderr_value,
- universal_newlines=universal_newlines)
-
- def finish(self, popen, **kw):
+ if timeout is _Null:
+ timeout = self.timeout
+ if timeout:
+ self.timer = threading.Timer(float(timeout), self._timeout)
+ self.timer.start()
+ p = Popen(cmd,
+ stdin=stdin,
+ stdout=subprocess.PIPE,
+ stderr=stderr_value,
+ universal_newlines=universal_newlines)
+ self.process = p
+ return p
+
+ def finish(self, popen=None, **kw):
"""
Finishes and waits for the process being run under control of
the specified popen argument, recording the exit status,
standard output and error output.
"""
+ if popen is None:
+ popen = self.process
stdout, stderr = popen.communicate()
+ if self.timer:
+ self.timer.cancel()
+ self.timer = None
self.status = popen.returncode
+ self.process = None
self._stdout.append(stdout or '')
self._stderr.append(stderr or '')
@@ -1111,7 +1269,8 @@ class TestCmd(object):
arguments = None,
chdir = None,
stdin = None,
- universal_newlines = None):
+ universal_newlines = None,
+ timeout = _Null):
"""Runs a test of the program or script for the test
environment. Standard output and error output are saved for
future retrieval via the stdout() and stderr() methods.
@@ -1126,15 +1285,25 @@ class TestCmd(object):
if self.verbose:
sys.stderr.write("chdir(" + chdir + ")\n")
os.chdir(chdir)
- p = self.start(program,
- interpreter,
- arguments,
- universal_newlines,
- stdin=stdin)
+ p = self.start(program = program,
+ interpreter = interpreter,
+ arguments = arguments,
+ universal_newlines = universal_newlines,
+ timeout = timeout,
+ stdin = stdin)
if is_List(stdin):
stdin = ''.join(stdin)
+ # TODO(sgk): figure out how to re-use the logic in the .finish()
+ # method above. Just calling it from here causes problems with
+ # subclasses that redefine .finish(). We could abstract this
+ # into Yet Another common method called both here and by .finish(),
+ # but that seems ill-thought-out.
stdout, stderr = p.communicate(input=stdin)
+ if self.timer:
+ self.timer.cancel()
+ self.timer = None
self.status = p.returncode
+ self.process = None
self._stdout.append(stdout or '')
self._stderr.append(stderr or '')
diff --git a/QMTest/TestCmdTests.py b/QMTest/TestCmdTests.py
new file mode 100644
index 0000000..357413f
--- /dev/null
+++ b/QMTest/TestCmdTests.py
@@ -0,0 +1,3457 @@
+#!/usr/bin/env python
+"""
+TestCmdTests.py: Unit tests for the TestCmd.py module.
+
+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.
+
+IN NO EVENT SHALL THE AUTHOR BE LIABLE TO ANY PARTY FOR DIRECT, INDIRECT,
+SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OF
+THIS CODE, EVEN IF THE AUTHOR HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
+DAMAGE.
+
+THE AUTHOR SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, BUT NOT
+LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
+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.
+"""
+
+__author__ = "Steven Knight <knight at baldmt dot com>"
+__revision__ = "TestCmdTests.py 1.3.D001 2010/06/03 12:58:27 knight"
+
+import os
+import shutil
+import signal
+import stat
+import StringIO
+import sys
+import tempfile
+import time
+import types
+import unittest
+import UserList
+
+# Strip the current directory so we get the right TestCmd.py module.
+sys.path = sys.path[1:]
+
+import TestCmd
+
+def _is_readable(path):
+ # XXX this doesn't take into account UID, it assumes it's our file
+ return os.stat(path)[stat.ST_MODE] & stat.S_IREAD
+
+def _is_writable(path):
+ # XXX this doesn't take into account UID, it assumes it's our file
+ return os.stat(path)[stat.ST_MODE] & stat.S_IWRITE
+
+def _is_executable(path):
+ # XXX this doesn't take into account UID, it assumes it's our file
+ return os.stat(path)[stat.ST_MODE] & stat.S_IEXEC
+
+def _clear_dict(dict, *keys):
+ for key in keys:
+ try:
+ dict[key] = '' # del dict[key]
+ except KeyError:
+ pass
+
+try:
+ import subprocess
+except ImportError:
+ # The subprocess module doesn't exist in this version of Python,
+ # so we're going to cobble up something that looks just enough
+ # like its API for our purposes below.
+ import popen2
+ subprocess = types.ModuleType('subprocess')
+
+ subprocess.PIPE = 'PIPE'
+ subprocess.STDOUT = 'STDOUT'
+ subprocess.mswindows = (sys.platform == 'win32')
+
+ class Popen(popen2.Popen3, popen2.Popen4):
+ universal_newlines = 1
+ def __init__(self, command, **kw):
+ if kw.get('stderr') == 'STDOUT':
+ popen2.Popen4.__init__(self, command, 1)
+ else:
+ popen2.Popen3.__init__(self, command, 1)
+ self.stdin = self.tochild
+ self.stdout = self.fromchild
+ self.stderr = self.childerr
+ def communicate(self, input=None):
+ if input:
+ self.stdin.write(input)
+ self.stdin.close()
+ out = self.stdout.read()
+ if self.stderr is None:
+ err = None
+ else:
+ err = self.stderr.read()
+ self.stdout.close()
+ if self.stderr is not None:
+ self.stderr.close()
+ self.returncode = self.wait()
+ return (out, err)
+ def terminate(self):
+ os.kill(self.pid, signal.SIGTERM)
+ def wait(self, *args, **kw):
+ resultcode = popen2.Popen3.wait(self, *args, **kw)
+ if os.WIFEXITED(resultcode):
+ return os.WEXITSTATUS(resultcode)
+ elif os.WIFSIGNALED(resultcode):
+ return os.WTERMSIG(resultcode)
+ else:
+ return None
+
+ subprocess.Popen = Popen
+else:
+ try:
+ subprocess.Popen.terminate
+ except AttributeError:
+ if sys.platform == 'win32':
+ import win32process
+ def terminate(self):
+ win32process.TerminateProcess(self._handle, 1)
+ else:
+ def terminate(self):
+ os.kill(self.pid, signal.SIGTERM)
+ method = types.MethodType(terminate, None, subprocess.Popen)
+ setattr(subprocess.Popen, 'terminate', method)
+
+class ExitError(Exception):
+ pass
+
+class TestCmdTestCase(unittest.TestCase):
+ """Base class for TestCmd test cases, with fixture and utility methods."""
+
+ def setUp(self):
+ self.orig_cwd = os.getcwd()
+
+ def tearDown(self):
+ os.chdir(self.orig_cwd)
+
+ def setup_run_scripts(self):
+ class T:
+ pass
+
+ t = T()
+
+ t.script = 'script'
+ t.scriptx = 'scriptx.bat'
+ t.script1 = 'script_1.txt'
+ t.scriptout = 'scriptout'
+ t.scripterr = 'scripterr'
+ fmt = "import os, sys; cwd = os.getcwd(); " + \
+ "sys.stdout.write('%s: STDOUT: %%s: %%s\\n' %% (cwd, sys.argv[1:])); " + \
+ "sys.stderr.write('%s: STDERR: %%s: %%s\\n' %% (cwd, sys.argv[1:]))"
+ fmtout = "import os, sys; cwd = os.getcwd(); " + \
+ "sys.stdout.write('%s: STDOUT: %%s: %%s\\n' %% (cwd, sys.argv[1:]))"
+ fmterr = "import os, sys; cwd = os.getcwd(); " + \
+ "sys.stderr.write('%s: STDERR: %%s: %%s\\n' %% (cwd, sys.argv[1:]))"
+ text = fmt % (t.script, t.script)
+ textx = fmt % (t.scriptx, t.scriptx)
+ if sys.platform == 'win32':
+ textx = textx.replace('%', '%%')
+ textx = '@python -c "%s"' % textx + ' %1 %2 %3 %4 %5 %6 %7 %8 %9\n'
+ else:
+ textx = '#! /usr/bin/env python\n' + textx + '\n'
+ text1 = 'A first line to be ignored!\n' + fmt % (t.script1, t.script1)
+ textout = fmtout % (t.scriptout)
+ texterr = fmterr % (t.scripterr)
+
+ run_env = TestCmd.TestCmd(workdir = '')
+ run_env.subdir('sub dir')
+ t.run_env = run_env
+
+ t.sub_dir = run_env.workpath('sub dir')
+ t.script_path = run_env.workpath('sub dir', t.script)
+ t.scriptx_path = run_env.workpath('sub dir', t.scriptx)
+ t.script1_path = run_env.workpath('sub dir', t.script1)
+ t.scriptout_path = run_env.workpath('sub dir', t.scriptout)
+ t.scripterr_path = run_env.workpath('sub dir', t.scripterr)
+
+ run_env.write(t.script_path, text)
+ run_env.write(t.scriptx_path, textx)
+ run_env.write(t.script1_path, text1)
+ run_env.write(t.scriptout_path, textout)
+ run_env.write(t.scripterr_path, texterr)
+
+ os.chmod(t.script_path, 0644) # XXX UNIX-specific
+ os.chmod(t.scriptx_path, 0755) # XXX UNIX-specific
+ os.chmod(t.script1_path, 0644) # XXX UNIX-specific
+ os.chmod(t.scriptout_path, 0644) # XXX UNIX-specific
+ os.chmod(t.scripterr_path, 0644) # XXX UNIX-specific
+
+ t.orig_cwd = os.getcwd()
+
+ t.workdir = run_env.workpath('sub dir')
+ os.chdir(t.workdir)
+
+ return t
+
+ def translate_newlines(self, data):
+ data = data.replace("\r\n", "\n")
+ return data
+
+ def call_python(self, input, python=None):
+ if python is None:
+ python = sys.executable
+ p = subprocess.Popen(python,
+ stdin=subprocess.PIPE,
+ stderr=subprocess.PIPE,
+ stdout=subprocess.PIPE)
+ stdout, stderr = p.communicate(input)
+ stdout = self.translate_newlines(stdout)
+ stderr = self.translate_newlines(stderr)
+ return stdout, stderr, p.returncode
+
+ def popen_python(self, input, status=0, stdout="", stderr="", python=None):
+ if python is None:
+ python = sys.executable
+ _stdout, _stderr, _status = self.call_python(input, python)
+ _stdout = self.translate_newlines(_stdout)
+ _stderr = self.translate_newlines(_stderr)
+ assert _status == status, \
+ "status = %s, expected %s\n" % (str(_status), str(status)) + \
+ "STDOUT ===================\n" + _stdout + \
+ "STDERR ===================\n" + _stderr
+ assert _stdout == stdout, \
+ "Expected STDOUT ==========\n" + stdout + \
+ "Actual STDOUT ============\n" + _stdout + \
+ "STDERR ===================\n" + _stderr
+ assert _stderr == stderr, \
+ "Expected STDERR ==========\n" + stderr + \
+ "Actual STDERR ============\n" + _stderr
+
+ def run_match(self, content, *args):
+ expect = "%s: %s: %s: %s\n" % args
+ content = self.translate_newlines(content)
+ assert content == expect, \
+ "Expected %s ==========\n" % args[1] + expect + \
+ "Actual %s ============\n" % args[1] + content
+
+
+
+class __init__TestCase(TestCmdTestCase):
+ def test_init(self):
+ """Test init()"""
+ test = TestCmd.TestCmd()
+ test = TestCmd.TestCmd(description = 'test')
+ test = TestCmd.TestCmd(description = 'test', program = 'foo')
+ test = TestCmd.TestCmd(description = 'test',
+ program = 'foo',
+ universal_newlines=None)
+
+
+
+class basename_TestCase(TestCmdTestCase):
+ def test_basename(self):
+ """Test basename() [XXX TO BE WRITTEN]"""
+ assert 1 == 1
+
+
+
+class cleanup_TestCase(TestCmdTestCase):
+ def test_cleanup(self):
+ """Test cleanup()"""
+ test = TestCmd.TestCmd(workdir = '')
+ wdir = test.workdir
+ test.write('file1', "Test file #1\n")
+ test.cleanup()
+ assert not os.path.exists(wdir)
+
+ def test_writable(self):
+ """Test cleanup() when the directory isn't writable"""
+ test = TestCmd.TestCmd(workdir = '')
+ wdir = test.workdir
+ test.write('file2', "Test file #2\n")
+ os.chmod(test.workpath('file2'), 0400)
+ os.chmod(wdir, 0500)
+ test.cleanup()
+ assert not os.path.exists(wdir)
+
+ def test_shutil(self):
+ """Test cleanup() when used with shutil"""
+ test = TestCmd.TestCmd(workdir = '')
+ wdir = test.workdir
+ os.chdir(wdir)
+
+ import shutil
+ save_rmtree = shutil.rmtree
+ def my_rmtree(dir, ignore_errors=0, wdir=wdir, _rmtree=save_rmtree):
+ assert os.getcwd() != wdir
+ return _rmtree(dir, ignore_errors=ignore_errors)
+ try:
+ shutil.rmtree = my_rmtree
+ test.cleanup()
+ finally:
+ shutil.rmtree = save_rmtree
+
+ def test_atexit(self):
+ """Test cleanup() when atexit is used"""
+ self.popen_python("""import sys
+sys.path = ['%s'] + sys.path
+import atexit
+def my_exitfunc():
+ print "my_exitfunc()"
+atexit.register(my_exitfunc)
+import TestCmd
+result = TestCmd.TestCmd(workdir = '')
+sys.exit(0)
+""" % self.orig_cwd, stdout='my_exitfunc()\n')
+
+ def test_exitfunc(self):
+ """Test cleanup() when sys.exitfunc is set"""
+ self.popen_python("""import sys
+sys.path = ['%s'] + sys.path
+def my_exitfunc():
+ print "my_exitfunc()"
+sys.exitfunc = my_exitfunc
+import TestCmd
+result = TestCmd.TestCmd(workdir = '')
+sys.exit(0)
+""" % self.orig_cwd, stdout='my_exitfunc()\n')
+
+
+
+class chmod_TestCase(TestCmdTestCase):
+ def test_chmod(self):
+ """Test chmod()"""
+ test = TestCmd.TestCmd(workdir = '', subdir = 'sub')
+
+ wdir_file1 = os.path.join(test.workdir, 'file1')
+ wdir_sub_file2 = os.path.join(test.workdir, 'sub', 'file2')
+
+ open(wdir_file1, 'w').write("")
+ open(wdir_sub_file2, 'w').write("")
+
+ if sys.platform == 'win32':
+
+ test.chmod(wdir_file1, stat.S_IREAD)
+ test.chmod(['sub', 'file2'], stat.S_IWRITE)
+
+ file1_mode = stat.S_IMODE(os.stat(wdir_file1)[stat.ST_MODE])
+ assert file1_mode == 0444, '0%o' % file1_mode
+ file2_mode = stat.S_IMODE(os.stat(wdir_sub_file2)[stat.ST_MODE])
+ assert file2_mode == 0666, '0%o' % file2_mode
+
+ test.chmod('file1', stat.S_IWRITE)
+ test.chmod(wdir_sub_file2, stat.S_IREAD)
+
+ file1_mode = stat.S_IMODE(os.stat(wdir_file1)[stat.ST_MODE])
+ assert file1_mode == 0666, '0%o' % file1_mode
+ file2_mode = stat.S_IMODE(os.stat(wdir_sub_file2)[stat.ST_MODE])
+ assert file2_mode == 0444, '0%o' % file2_mode
+
+ else:
+
+ test.chmod(wdir_file1, 0700)
+ test.chmod(['sub', 'file2'], 0760)
+
+ file1_mode = stat.S_IMODE(os.stat(wdir_file1)[stat.ST_MODE])
+ assert file1_mode == 0700, '0%o' % file1_mode
+ file2_mode = stat.S_IMODE(os.stat(wdir_sub_file2)[stat.ST_MODE])
+ assert file2_mode == 0760, '0%o' % file2_mode
+
+ test.chmod('file1', 0765)
+ test.chmod(wdir_sub_file2, 0567)
+
+ file1_mode = stat.S_IMODE(os.stat(wdir_file1)[stat.ST_MODE])
+ assert file1_mode == 0765, '0%o' % file1_mode
+ file2_mode = stat.S_IMODE(os.stat(wdir_sub_file2)[stat.ST_MODE])
+ assert file2_mode == 0567, '0%o' % file2_mode
+
+
+
+class combine_TestCase(TestCmdTestCase):
+ def test_combine(self):
+ """Test combining stdout and stderr"""
+ run_env = TestCmd.TestCmd(workdir = '')
+ run_env.write('run1', """import sys
+sys.stdout.write("run1 STDOUT %s\\n" % sys.argv[1:])
+sys.stdout.write("run1 STDOUT second line\\n")
+sys.stderr.write("run1 STDERR %s\\n" % sys.argv[1:])
+sys.stderr.write("run1 STDERR second line\\n")
+sys.stdout.write("run1 STDOUT third line\\n")
+sys.stderr.write("run1 STDERR third line\\n")
+""")
+ run_env.write('run2', """import sys
+sys.stdout.write("run2 STDOUT %s\\n" % sys.argv[1:])
+sys.stdout.write("run2 STDOUT second line\\n")
+sys.stderr.write("run2 STDERR %s\\n" % sys.argv[1:])
+sys.stderr.write("run2 STDERR second line\\n")
+sys.stdout.write("run2 STDOUT third line\\n")
+sys.stderr.write("run2 STDERR third line\\n")
+""")
+ cwd = os.getcwd()
+ os.chdir(run_env.workdir)
+ # Everything before this prepared our "source directory."
+ # Now do the real test.
+ try:
+ test = TestCmd.TestCmd(interpreter = 'python',
+ workdir = '',
+ combine = 1)
+ try:
+ output = test.stdout()
+ except IndexError:
+ pass
+ else:
+ raise IndexError("got unexpected output:\n\t`%s'\n" % output)
+
+ # The underlying system subprocess implementations can combine
+ # stdout and stderr in different orders, so we accomodate both.
+
+ test.program_set('run1')
+ test.run(arguments = 'foo bar')
+ stdout_lines = """\
+run1 STDOUT ['foo', 'bar']
+run1 STDOUT second line
+run1 STDOUT third line
+"""
+ stderr_lines = """\
+run1 STDERR ['foo', 'bar']
+run1 STDERR second line
+run1 STDERR third line
+"""
+ foo_bar_expect = (stdout_lines + stderr_lines,
+ stderr_lines + stdout_lines)
+
+ test.program_set('run2')
+ test.run(arguments = 'snafu')
+ stdout_lines = """\
+run2 STDOUT ['snafu']
+run2 STDOUT second line
+run2 STDOUT third line
+"""
+ stderr_lines = """\
+run2 STDERR ['snafu']
+run2 STDERR second line
+run2 STDERR third line
+"""
+ snafu_expect = (stdout_lines + stderr_lines,
+ stderr_lines + stdout_lines)
+
+ # XXX SHOULD TEST ABSOLUTE NUMBER AS WELL
+ output = test.stdout()
+ output = self.translate_newlines(output)
+ assert output in snafu_expect, output
+ error = test.stderr()
+ assert error == '', error
+
+ output = test.stdout(run = -1)
+ output = self.translate_newlines(output)
+ assert output in foo_bar_expect, output
+ error = test.stderr(-1)
+ assert error == '', error
+ finally:
+ os.chdir(cwd)
+
+
+
+class description_TestCase(TestCmdTestCase):
+ def test_description(self):
+ """Test description()"""
+ test = TestCmd.TestCmd()
+ assert test.description is None, 'initialized description?'
+ test = TestCmd.TestCmd(description = 'test')
+ assert test.description == 'test', 'uninitialized description'
+ test.description_set('foo')
+ assert test.description == 'foo', 'did not set description'
+
+
+
+class diff_TestCase(TestCmdTestCase):
+ def test_diff_re(self):
+ """Test diff_re()"""
+ result = TestCmd.diff_re(["abcde"], ["abcde"])
+ assert result == [], result
+ result = TestCmd.diff_re(["a.*e"], ["abcde"])
+ assert result == [], result
+ result = TestCmd.diff_re(["a.*e"], ["xxx"])
+ assert result == ['1c1', "< 'a.*e'", '---', "> 'xxx'"], result
+
+ def test_diff_custom_function(self):
+ """Test diff() using a custom function"""
+ self.popen_python("""import sys
+sys.path = ['%s'] + sys.path
+import TestCmd
+def my_diff(a, b):
+ return [
+ '*****',
+ a,
+ '*****',
+ b,
+ '*****',
+ ]
+test = TestCmd.TestCmd(diff = my_diff)
+test.diff("a\\nb1\\nc\\n", "a\\nb2\\nc\\n", "STDOUT")
+sys.exit(0)
+""" % self.orig_cwd,
+ stdout = """\
+STDOUT==========================================================================
+*****
+['a', 'b1', 'c']
+*****
+['a', 'b2', 'c']
+*****
+""")
+
+ def test_diff_string(self):
+ self.popen_python("""import sys
+sys.path = ['%s'] + sys.path
+import TestCmd
+test = TestCmd.TestCmd(diff = 'diff_re')
+test.diff("a\\nb1\\nc\\n", "a\\nb2\\nc\\n", 'STDOUT')
+sys.exit(0)
+""" % self.orig_cwd,
+ stdout = """\
+STDOUT==========================================================================
+2c2
+< 'b1'
+---
+> 'b2'
+""")
+
+ def test_error(self):
+ """Test handling a compilation error in TestCmd.diff_re()"""
+ script_input = """import sys
+sys.path = ['%s'] + sys.path
+import TestCmd
+assert TestCmd.diff_re(["a.*(e"], ["abcde"])
+sys.exit(0)
+""" % self.orig_cwd
+ stdout, stderr, status = self.call_python(script_input)
+ assert status == 1, status
+ expect1 = "Regular expression error in '^a.*(e$': missing )\n"
+ expect2 = "Regular expression error in '^a.*(e$': unbalanced parenthesis\n"
+ assert (stderr.find(expect1) != -1 or
+ stderr.find(expect2) != -1), repr(stderr)
+
+ def test_simple_diff_static_method(self):
+ """Test calling the TestCmd.TestCmd.simple_diff() static method"""
+ self.popen_python("""import sys
+sys.path = ['%s'] + sys.path
+import TestCmd
+result = TestCmd.TestCmd.simple_diff(['a', 'b', 'c', 'e', 'f1'],
+ ['a', 'c', 'd', 'e', 'f2'])
+expect = ['2d1', '< b', '3a3', '> d', '5c5', '< f1', '---', '> f2']
+assert result == expect, result
+sys.exit(0)
+""" % self.orig_cwd)
+
+ def test_context_diff_static_method(self):
+ """Test calling the TestCmd.TestCmd.context_diff() static method"""
+ self.popen_python("""import sys
+sys.path = ['%s'] + sys.path
+import TestCmd
+result = TestCmd.TestCmd.context_diff(['a\\n', 'b\\n', 'c\\n', 'e\\n', 'f1\\n'],
+ ['a\\n', 'c\\n', 'd\\n', 'e\\n', 'f2\\n'])
+result = list(result)
+expect = [
+ '*** \\n',
+ '--- \\n',
+ '***************\\n',
+ '*** 1,5 ****\\n',
+ ' a\\n',
+ '- b\\n',
+ ' c\\n',
+ ' e\\n',
+ '! f1\\n',
+ '--- 1,5 ----\\n',
+ ' a\\n',
+ ' c\\n',
+ '+ d\\n',
+ ' e\\n',
+ '! f2\\n',
+]
+assert result == expect, result
+sys.exit(0)
+""" % self.orig_cwd)
+
+ def test_unified_diff_static_method(self):
+ """Test calling the TestCmd.TestCmd.unified_diff() static method"""
+ self.popen_python("""import sys
+sys.path = ['%s'] + sys.path
+import TestCmd
+result = TestCmd.TestCmd.unified_diff(['a\\n', 'b\\n', 'c\\n', 'e\\n', 'f1\\n'],
+ ['a\\n', 'c\\n', 'd\\n', 'e\\n', 'f2\\n'])
+result = list(result)
+expect = [
+ '--- \\n',
+ '+++ \\n',
+ '@@ -1,5 +1,5 @@\\n',
+ ' a\\n',
+ '-b\\n',
+ ' c\\n',
+ '+d\\n',
+ ' e\\n',
+ '-f1\\n',
+ '+f2\\n'
+]
+assert result == expect, result
+sys.exit(0)
+""" % self.orig_cwd)
+
+ def test_diff_re_static_method(self):
+ """Test calling the TestCmd.TestCmd.diff_re() static method"""
+ self.popen_python("""import sys
+sys.path = ['%s'] + sys.path
+import TestCmd
+result = TestCmd.TestCmd.diff_re(['a', 'b', 'c', '.', 'f1'],
+ ['a', 'c', 'd', 'e', 'f2'])
+expect = [
+ '2c2',
+ "< 'b'",
+ '---',
+ "> 'c'",
+ '3c3',
+ "< 'c'",
+ '---',
+ "> 'd'",
+ '5c5',
+ "< 'f1'",
+ '---',
+ "> 'f2'"
+]
+assert result == expect, result
+sys.exit(0)
+""" % self.orig_cwd)
+
+
+
+class diff_stderr_TestCase(TestCmdTestCase):
+ def test_diff_stderr_default(self):
+ """Test diff_stderr() default behavior"""
+ self.popen_python(r"""import sys
+sys.path = ['%s'] + sys.path
+import TestCmd
+test = TestCmd.TestCmd()
+test.diff_stderr('a\nb1\nc\n', 'a\nb2\nc\n')
+sys.exit(0)
+""" % self.orig_cwd,
+ stdout="""\
+2c2
+< b1
+---
+> b2
+""")
+
+ def test_diff_stderr_not_affecting_diff_stdout(self):
+ """Test diff_stderr() not affecting diff_stdout() behavior"""
+ self.popen_python(r"""import sys
+sys.path = ['%s'] + sys.path
+import TestCmd
+test = TestCmd.TestCmd(diff_stderr='diff_re')
+print "diff_stderr:"
+test.diff_stderr('a\nb.\nc\n', 'a\nbb\nc\n')
+print "diff_stdout:"
+test.diff_stdout('a\nb.\nc\n', 'a\nbb\nc\n')
+sys.exit(0)
+""" % self.orig_cwd,
+ stdout="""\
+diff_stderr:
+diff_stdout:
+2c2
+< b.
+---
+> bb
+""")
+
+ def test_diff_stderr_custom_function(self):
+ """Test diff_stderr() using a custom function"""
+ self.popen_python(r"""import sys
+sys.path = ['%s'] + sys.path
+import TestCmd
+def my_diff(a, b):
+ return ["a:"] + a + ["b:"] + b
+test = TestCmd.TestCmd(diff_stderr=my_diff)
+test.diff_stderr('abc', 'def')
+sys.exit(0)
+""" % self.orig_cwd,
+ stdout="""\
+a:
+abc
+b:
+def
+""")
+
+ def test_diff_stderr_TestCmd_function(self):
+ """Test diff_stderr() using a TestCmd function"""
+ self.popen_python(r"""import sys
+sys.path = ['%s'] + sys.path
+import TestCmd
+test = TestCmd.TestCmd(diff_stderr = TestCmd.diff_re)
+test.diff_stderr('a\n.\n', 'b\nc\n')
+sys.exit(0)
+""" % self.orig_cwd,
+ stdout="""\
+1c1
+< 'a'
+---
+> 'b'
+""")
+
+ def test_diff_stderr_static_method(self):
+ """Test diff_stderr() using a static method"""
+ self.popen_python(r"""import sys
+sys.path = ['%s'] + sys.path
+import TestCmd
+test = TestCmd.TestCmd(diff_stderr=TestCmd.TestCmd.diff_re)
+test.diff_stderr('a\n.\n', 'b\nc\n')
+sys.exit(0)
+""" % self.orig_cwd,
+ stdout="""\
+1c1
+< 'a'
+---
+> 'b'
+""")
+
+ def test_diff_stderr_string(self):
+ """Test diff_stderr() using a string to fetch the diff method"""
+ self.popen_python(r"""import sys
+sys.path = ['%s'] + sys.path
+import TestCmd
+test = TestCmd.TestCmd(diff_stderr='diff_re')
+test.diff_stderr('a\n.\n', 'b\nc\n')
+sys.exit(0)
+""" % self.orig_cwd,
+ stdout="""\
+1c1
+< 'a'
+---
+> 'b'
+""")
+
+
+
+class diff_stdout_TestCase(TestCmdTestCase):
+ def test_diff_stdout_default(self):
+ """Test diff_stdout() default behavior"""
+ self.popen_python(r"""import sys
+sys.path = ['%s'] + sys.path
+import TestCmd
+test = TestCmd.TestCmd()
+test.diff_stdout('a\nb1\nc\n', 'a\nb2\nc\n')
+sys.exit(0)
+""" % self.orig_cwd,
+ stdout="""\
+2c2
+< b1
+---
+> b2
+""")
+
+ def test_diff_stdout_not_affecting_diff_stderr(self):
+ """Test diff_stdout() not affecting diff_stderr() behavior"""
+ self.popen_python(r"""import sys
+sys.path = ['%s'] + sys.path
+import TestCmd
+test = TestCmd.TestCmd(diff_stdout='diff_re')
+print "diff_stdout:"
+test.diff_stdout('a\nb.\nc\n', 'a\nbb\nc\n')
+print "diff_stderr:"
+test.diff_stderr('a\nb.\nc\n', 'a\nbb\nc\n')
+sys.exit(0)
+""" % self.orig_cwd,
+ stdout="""\
+diff_stdout:
+diff_stderr:
+2c2
+< b.
+---
+> bb
+""")
+
+ def test_diff_stdout_custom_function(self):
+ """Test diff_stdout() using a custom function"""
+ self.popen_python(r"""import sys
+sys.path = ['%s'] + sys.path
+import TestCmd
+def my_diff(a, b):
+ return ["a:"] + a + ["b:"] + b
+test = TestCmd.TestCmd(diff_stdout=my_diff)
+test.diff_stdout('abc', 'def')
+sys.exit(0)
+""" % self.orig_cwd,
+ stdout="""\
+a:
+abc
+b:
+def
+""")
+
+ def test_diff_stdout_TestCmd_function(self):
+ """Test diff_stdout() using a TestCmd function"""
+ self.popen_python(r"""import sys
+sys.path = ['%s'] + sys.path
+import TestCmd
+test = TestCmd.TestCmd(diff_stdout = TestCmd.diff_re)
+test.diff_stdout('a\n.\n', 'b\nc\n')
+sys.exit(0)
+""" % self.orig_cwd,
+ stdout="""\
+1c1
+< 'a'
+---
+> 'b'
+""")
+
+ def test_diff_stdout_static_method(self):
+ """Test diff_stdout() using a static method"""
+ self.popen_python(r"""import sys
+sys.path = ['%s'] + sys.path
+import TestCmd
+test = TestCmd.TestCmd(diff_stdout=TestCmd.TestCmd.diff_re)
+test.diff_stdout('a\n.\n', 'b\nc\n')
+sys.exit(0)
+""" % self.orig_cwd,
+ stdout="""\
+1c1
+< 'a'
+---
+> 'b'
+""")
+
+ def test_diff_stdout_string(self):
+ """Test diff_stdout() using a string to fetch the diff method"""
+ self.popen_python(r"""import sys
+sys.path = ['%s'] + sys.path
+import TestCmd
+test = TestCmd.TestCmd(diff_stdout='diff_re')
+test.diff_stdout('a\n.\n', 'b\nc\n')
+sys.exit(0)
+""" % self.orig_cwd,
+ stdout="""\
+1c1
+< 'a'
+---
+> 'b'
+""")
+
+
+
+class exit_TestCase(TestCmdTestCase):
+ def test_exit(self):
+ """Test exit()"""
+ def _test_it(cwd, tempdir, condition, preserved):
+ close_true = {'pass_test': 1, 'fail_test': 0, 'no_result': 0}
+ exit_status = {'pass_test': 0, 'fail_test': 1, 'no_result': 2}
+ result_string = {'pass_test': "PASSED\n",
+ 'fail_test': "FAILED test at line 5 of <stdin>\n",
+ 'no_result': "NO RESULT for test at line 5 of <stdin>\n"}
+ global ExitError
+ input = """import sys
+sys.path = ['%s'] + sys.path
+import TestCmd
+test = TestCmd.TestCmd(workdir = '%s')
+test.%s()
+""" % (cwd, tempdir, condition)
+ stdout, stderr, status = self.call_python(input, python="python")
+ if close_true[condition]:
+ unexpected = (status != 0)
+ else:
+ unexpected = (status == 0)
+ if unexpected:
+ msg = "Unexpected exit status from python: %s\n"
+ raise ExitError(msg % status + stdout + stderr)
+ if status != exit_status[condition]:
+ msg = "Expected exit status %d, got %d\n"
+ raise ExitError(msg % (exit_status[condition], status))
+ if stderr != result_string[condition]:
+ msg = "Expected error output:\n%sGot error output:\n%s"
+ raise ExitError(msg % (result_string[condition], stderr))
+ if preserved:
+ if not os.path.exists(tempdir):
+ msg = "Working directory %s was mistakenly removed\n"
+ raise ExitError(msg % tempdir + stdout)
+ else:
+ if os.path.exists(tempdir):
+ msg = "Working directory %s was mistakenly preserved\n"
+ raise ExitError(msg % tempdir + stdout)
+
+ run_env = TestCmd.TestCmd(workdir = '')
+ os.chdir(run_env.workdir)
+ # Everything before this prepared our "source directory."
+ # Now do the real test.
+ try:
+ cwd = self.orig_cwd
+ _clear_dict(os.environ, 'PRESERVE', 'PRESERVE_PASS', 'PRESERVE_FAIL', 'PRESERVE_NO_RESULT')
+ _test_it(cwd, 'dir01', 'pass_test', 0)
+ _test_it(cwd, 'dir02', 'fail_test', 0)
+ _test_it(cwd, 'dir03', 'no_result', 0)
+ os.environ['PRESERVE'] = '1'
+ _test_it(cwd, 'dir04', 'pass_test', 1)
+ _test_it(cwd, 'dir05', 'fail_test', 1)
+ _test_it(cwd, 'dir06', 'no_result', 1)
+ os.environ['PRESERVE'] = '' # del os.environ['PRESERVE']
+ os.environ['PRESERVE_PASS'] = '1'
+ _test_it(cwd, 'dir07', 'pass_test', 1)
+ _test_it(cwd, 'dir08', 'fail_test', 0)
+ _test_it(cwd, 'dir09', 'no_result', 0)
+ os.environ['PRESERVE_PASS'] = '' # del os.environ['PRESERVE_PASS']
+ os.environ['PRESERVE_FAIL'] = '1'
+ _test_it(cwd, 'dir10', 'pass_test', 0)
+ _test_it(cwd, 'dir11', 'fail_test', 1)
+ _test_it(cwd, 'dir12', 'no_result', 0)
+ os.environ['PRESERVE_FAIL'] = '' # del os.environ['PRESERVE_FAIL']
+ os.environ['PRESERVE_NO_RESULT'] = '1'
+ _test_it(cwd, 'dir13', 'pass_test', 0)
+ _test_it(cwd, 'dir14', 'fail_test', 0)
+ _test_it(cwd, 'dir15', 'no_result', 1)
+ os.environ['PRESERVE_NO_RESULT'] = '' # del os.environ['PRESERVE_NO_RESULT']
+ finally:
+ _clear_dict(os.environ, 'PRESERVE', 'PRESERVE_PASS', 'PRESERVE_FAIL', 'PRESERVE_NO_RESULT')
+
+
+
+class fail_test_TestCase(TestCmdTestCase):
+ def test_fail_test(self):
+ """Test fail_test()"""
+ run_env = TestCmd.TestCmd(workdir = '')
+ run_env.write('run', """import sys
+sys.stdout.write("run: STDOUT\\n")
+sys.stderr.write("run: STDERR\\n")
+""")
+ os.chdir(run_env.workdir)
+ # Everything before this prepared our "source directory."
+ # Now do the real test.
+ self.popen_python("""import sys
+sys.path = ['%s'] + sys.path
+import TestCmd
+TestCmd.fail_test(condition = 1)
+""" % self.orig_cwd, status = 1, stderr = "FAILED test at line 4 of <stdin>\n")
+
+ self.popen_python("""import sys
+sys.path = ['%s'] + sys.path
+import TestCmd
+test = TestCmd.TestCmd(program = 'run', interpreter = 'python', workdir = '')
+test.run()
+test.fail_test(condition = (test.status == 0))
+""" % self.orig_cwd, status = 1, stderr = "FAILED test of %s\n\tat line 6 of <stdin>\n" % run_env.workpath('run'))
+
+ self.popen_python("""import sys
+sys.path = ['%s'] + sys.path
+import TestCmd
+test = TestCmd.TestCmd(program = 'run', interpreter = 'python', description = 'xyzzy', workdir = '')
+test.run()
+test.fail_test(condition = (test.status == 0))
+""" % self.orig_cwd, status = 1, stderr = "FAILED test of %s [xyzzy]\n\tat line 6 of <stdin>\n" % run_env.workpath('run'))
+
+ self.popen_python("""import sys
+sys.path = ['%s'] + sys.path
+import TestCmd
+test = TestCmd.TestCmd(program = 'run', interpreter = 'python', workdir = '')
+test.run()
+def xxx():
+ sys.stderr.write("printed on failure\\n")
+test.fail_test(condition = (test.status == 0), function = xxx)
+""" % self.orig_cwd, status = 1, stderr = "printed on failure\nFAILED test of %s\n\tat line 8 of <stdin>\n" % run_env.workpath('run'))
+
+ self.popen_python("""import sys
+sys.path = ['%s'] + sys.path
+import TestCmd
+def test1(self):
+ self.run()
+ self.fail_test(condition = (self.status == 0))
+def test2(self):
+ test1(self)
+test2(TestCmd.TestCmd(program = 'run', interpreter = 'python', workdir = ''))
+""" % self.orig_cwd, status = 1, stderr = "FAILED test of %s\n\tat line 6 of <stdin> (test1)\n\tfrom line 8 of <stdin> (test2)\n\tfrom line 9 of <stdin>\n" % run_env.workpath('run'))
+
+ self.popen_python("""import sys
+sys.path = ['%s'] + sys.path
+import TestCmd
+def test1(self):
+ self.run()
+ self.fail_test(condition = (self.status == 0), skip = 1)
+def test2(self):
+ test1(self)
+test2(TestCmd.TestCmd(program = 'run', interpreter = 'python', workdir = ''))
+""" % self.orig_cwd, status = 1, stderr = "FAILED test of %s\n\tat line 8 of <stdin> (test2)\n\tfrom line 9 of <stdin>\n" % run_env.workpath('run'))
+
+
+
+class interpreter_TestCase(TestCmdTestCase):
+ def test_interpreter(self):
+ """Test interpreter()"""
+ run_env = TestCmd.TestCmd(workdir = '')
+ run_env.write('run', """import sys
+sys.stdout.write("run: STDOUT\\n")
+sys.stderr.write("run: STDERR\\n")
+""")
+ os.chdir(run_env.workdir)
+ # Everything before this prepared our "source directory."
+ # Now do the real test.
+ test = TestCmd.TestCmd(program = 'run', workdir = '')
+ test.interpreter_set('foo')
+ assert test.interpreter == 'foo', 'did not set interpreter'
+ test.interpreter_set('python')
+ assert test.interpreter == 'python', 'did not set interpreter'
+ test.run()
+
+
+
+class match_TestCase(TestCmdTestCase):
+ def test_match_default(self):
+ """Test match() default behavior"""
+ test = TestCmd.TestCmd()
+ assert test.match("abcde\n", "a.*e\n")
+ assert test.match("12345\nabcde\n", "1\\d+5\na.*e\n")
+ lines = ["vwxyz\n", "67890\n"]
+ regexes = ["v[^a-u]*z\n", "6[^ ]+0\n"]
+ assert test.match(lines, regexes)
+
+ def test_match_custom_function(self):
+ """Test match() using a custom function"""
+ def match_length(lines, matches):
+ return len(lines) == len(matches)
+ test = TestCmd.TestCmd(match=match_length)
+ assert not test.match("123\n", "1\n")
+ assert test.match("123\n", "111\n")
+ assert not test.match("123\n123\n", "1\n1\n")
+ assert test.match("123\n123\n", "111\n111\n")
+ lines = ["123\n", "123\n"]
+ regexes = ["1\n", "1\n"]
+ assert test.match(lines, regexes) # due to equal numbers of lines
+
+ def test_match_TestCmd_function(self):
+ """Test match() using a TestCmd function"""
+ test = TestCmd.TestCmd(match = TestCmd.match_exact)
+ assert not test.match("abcde\n", "a.*e\n")
+ assert test.match("abcde\n", "abcde\n")
+ assert not test.match("12345\nabcde\n", "1\d+5\na.*e\n")
+ assert test.match("12345\nabcde\n", "12345\nabcde\n")
+ lines = ["vwxyz\n", "67890\n"]
+ regexes = ["v[^a-u]*z\n", "6[^ ]+0\n"]
+ assert not test.match(lines, regexes)
+ assert test.match(lines, lines)
+
+ def test_match_static_method(self):
+ """Test match() using a static method"""
+ test = TestCmd.TestCmd(match=TestCmd.TestCmd.match_exact)
+ assert not test.match("abcde\n", "a.*e\n")
+ assert test.match("abcde\n", "abcde\n")
+ assert not test.match("12345\nabcde\n", "1\d+5\na.*e\n")
+ assert test.match("12345\nabcde\n", "12345\nabcde\n")
+ lines = ["vwxyz\n", "67890\n"]
+ regexes = ["v[^a-u]*z\n", "6[^ ]+0\n"]
+ assert not test.match(lines, regexes)
+ assert test.match(lines, lines)
+
+ def test_match_string(self):
+ """Test match() using a string to fetch the match method"""
+ test = TestCmd.TestCmd(match='match_exact')
+ assert not test.match("abcde\n", "a.*e\n")
+ assert test.match("abcde\n", "abcde\n")
+ assert not test.match("12345\nabcde\n", "1\d+5\na.*e\n")
+ assert test.match("12345\nabcde\n", "12345\nabcde\n")
+ lines = ["vwxyz\n", "67890\n"]
+ regexes = ["v[^a-u]*z\n", "6[^ ]+0\n"]
+ assert not test.match(lines, regexes)
+ assert test.match(lines, lines)
+
+
+
+class match_exact_TestCase(TestCmdTestCase):
+ def test_match_exact_function(self):
+ """Test calling the TestCmd.match_exact() function"""
+ assert not TestCmd.match_exact("abcde\\n", "a.*e\\n")
+ assert TestCmd.match_exact("abcde\\n", "abcde\\n")
+
+ def test_match_exact_instance_method(self):
+ """Test calling the TestCmd.TestCmd().match_exact() instance method"""
+ test = TestCmd.TestCmd()
+ assert not test.match_exact("abcde\\n", "a.*e\\n")
+ assert test.match_exact("abcde\\n", "abcde\\n")
+
+ def test_match_exact_static_method(self):
+ """Test calling the TestCmd.TestCmd.match_exact() static method"""
+ assert not TestCmd.TestCmd.match_exact("abcde\\n", "a.*e\\n")
+ assert TestCmd.TestCmd.match_exact("abcde\\n", "abcde\\n")
+
+ def test_evaluation(self):
+ """Test match_exact() evaluation"""
+ test = TestCmd.TestCmd()
+ assert not test.match_exact("abcde\n", "a.*e\n")
+ assert test.match_exact("abcde\n", "abcde\n")
+ assert not test.match_exact(["12345\n", "abcde\n"], ["1[0-9]*5\n", "a.*e\n"])
+ assert test.match_exact(["12345\n", "abcde\n"], ["12345\n", "abcde\n"])
+ assert not test.match_exact(UserList.UserList(["12345\n", "abcde\n"]),
+ ["1[0-9]*5\n", "a.*e\n"])
+ assert test.match_exact(UserList.UserList(["12345\n", "abcde\n"]),
+ ["12345\n", "abcde\n"])
+ assert not test.match_exact(["12345\n", "abcde\n"],
+ UserList.UserList(["1[0-9]*5\n", "a.*e\n"]))
+ assert test.match_exact(["12345\n", "abcde\n"],
+ UserList.UserList(["12345\n", "abcde\n"]))
+ assert not test.match_exact("12345\nabcde\n", "1[0-9]*5\na.*e\n")
+ assert test.match_exact("12345\nabcde\n", "12345\nabcde\n")
+ lines = ["vwxyz\n", "67890\n"]
+ regexes = ["v[^a-u]*z\n", "6[^ ]+0\n"]
+ assert not test.match_exact(lines, regexes)
+ assert test.match_exact(lines, lines)
+
+
+
+class match_re_dotall_TestCase(TestCmdTestCase):
+ def test_match_re_dotall_function(self):
+ """Test calling the TestCmd.match_re_dotall() function"""
+ assert TestCmd.match_re_dotall("abcde\nfghij\n", "a.*j\n")
+
+ def test_match_re_dotall_instance_method(self):
+ """Test calling the TestCmd.TestCmd().match_re_dotall() instance method"""
+ test = TestCmd.TestCmd()
+ test.match_re_dotall("abcde\\nfghij\\n", "a.*j\\n")
+
+ def test_match_re_dotall_static_method(self):
+ """Test calling the TestCmd.TestCmd.match_re_dotall() static method"""
+ assert TestCmd.TestCmd.match_re_dotall("abcde\nfghij\n", "a.*j\n")
+
+ def test_error(self):
+ """Test handling a compilation error in TestCmd.match_re_dotall()"""
+ run_env = TestCmd.TestCmd(workdir = '')
+ cwd = os.getcwd()
+ os.chdir(run_env.workdir)
+ # Everything before this prepared our "source directory."
+ # Now do the real test.
+ try:
+ script_input = """import sys
+sys.path = ['%s'] + sys.path
+import TestCmd
+assert TestCmd.match_re_dotall("abcde", "a.*(e")
+sys.exit(0)
+""" % cwd
+ stdout, stderr, status = self.call_python(script_input)
+ assert status == 1, status
+ expect1 = "Regular expression error in '^a.*(e$': missing )\n"
+ expect2 = "Regular expression error in '^a.*(e$': unbalanced parenthesis\n"
+ assert (stderr.find(expect1) != -1 or
+ stderr.find(expect2) != -1), repr(stderr)
+ finally:
+ os.chdir(cwd)
+
+ def test_evaluation(self):
+ """Test match_re_dotall() evaluation"""
+ test = TestCmd.TestCmd()
+ assert test.match_re_dotall("abcde\nfghij\n", "a.*e\nf.*j\n")
+ assert test.match_re_dotall("abcde\nfghij\n", "a[^j]*j\n")
+ assert test.match_re_dotall("abcde\nfghij\n", "abcde\nfghij\n")
+ assert test.match_re_dotall(["12345\n", "abcde\n", "fghij\n"],
+ ["1[0-9]*5\n", "a.*e\n", "f.*j\n"])
+ assert test.match_re_dotall(["12345\n", "abcde\n", "fghij\n"],
+ ["1.*j\n"])
+ assert test.match_re_dotall(["12345\n", "abcde\n", "fghij\n"],
+ ["12345\n", "abcde\n", "fghij\n"])
+ assert test.match_re_dotall(UserList.UserList(["12345\n",
+ "abcde\n",
+ "fghij\n"]),
+ ["1[0-9]*5\n", "a.*e\n", "f.*j\n"])
+ assert test.match_re_dotall(UserList.UserList(["12345\n",
+ "abcde\n",
+ "fghij\n"]),
+ ["1.*j\n"])
+ assert test.match_re_dotall(UserList.UserList(["12345\n",
+ "abcde\n",
+ "fghij\n"]),
+ ["12345\n", "abcde\n", "fghij\n"])
+ assert test.match_re_dotall(["12345\n", "abcde\n", "fghij\n"],
+ UserList.UserList(["1[0-9]*5\n",
+ "a.*e\n",
+ "f.*j\n"]))
+ assert test.match_re_dotall(["12345\n", "abcde\n", "fghij\n"],
+ UserList.UserList(["1.*j\n"]))
+ assert test.match_re_dotall(["12345\n", "abcde\n", "fghij\n"],
+ UserList.UserList(["12345\n",
+ "abcde\n",
+ "fghij\n"]))
+ assert test.match_re_dotall("12345\nabcde\nfghij\n",
+ "1[0-9]*5\na.*e\nf.*j\n")
+ assert test.match_re_dotall("12345\nabcde\nfghij\n", "1.*j\n")
+ assert test.match_re_dotall("12345\nabcde\nfghij\n",
+ "12345\nabcde\nfghij\n")
+ lines = ["vwxyz\n", "67890\n"]
+ regexes = ["v[^a-u]*z\n", "6[^ ]+0\n"]
+ assert test.match_re_dotall(lines, regexes)
+ assert test.match_re_dotall(lines, lines)
+
+
+
+class match_re_TestCase(TestCmdTestCase):
+ def test_match_re_function(self):
+ """Test calling the TestCmd.match_re() function"""
+ assert TestCmd.match_re("abcde\n", "a.*e\n")
+
+ def test_match_re_instance_method(self):
+ """Test calling the TestCmd.TestCmd().match_re() instance method"""
+ test = TestCmd.TestCmd()
+ assert test.match_re("abcde\n", "a.*e\n")
+
+ def test_match_re_static_method(self):
+ """Test calling the TestCmd.TestCmd.match_re() static method"""
+ assert TestCmd.TestCmd.match_re("abcde\n", "a.*e\n")
+
+ def test_error(self):
+ """Test handling a compilation error in TestCmd.match_re()"""
+ run_env = TestCmd.TestCmd(workdir = '')
+ cwd = os.getcwd()
+ os.chdir(run_env.workdir)
+ # Everything before this prepared our "source directory."
+ # Now do the real test.
+ try:
+ script_input = """import sys
+sys.path = ['%s'] + sys.path
+import TestCmd
+assert TestCmd.match_re("abcde\\n", "a.*(e\\n")
+sys.exit(0)
+""" % cwd
+ stdout, stderr, status = self.call_python(script_input)
+ assert status == 1, status
+ expect1 = "Regular expression error in '^a.*(e$': missing )\n"
+ expect2 = "Regular expression error in '^a.*(e$': unbalanced parenthesis\n"
+ assert (stderr.find(expect1) != -1 or
+ stderr.find(expect2) != -1), repr(stderr)
+ finally:
+ os.chdir(cwd)
+
+ def test_evaluation(self):
+ """Test match_re() evaluation"""
+ test = TestCmd.TestCmd()
+ assert test.match_re("abcde\n", "a.*e\n")
+ assert test.match_re("abcde\n", "abcde\n")
+ assert test.match_re(["12345\n", "abcde\n"], ["1[0-9]*5\n", "a.*e\n"])
+ assert test.match_re(["12345\n", "abcde\n"], ["12345\n", "abcde\n"])
+ assert test.match_re(UserList.UserList(["12345\n", "abcde\n"]),
+ ["1[0-9]*5\n", "a.*e\n"])
+ assert test.match_re(UserList.UserList(["12345\n", "abcde\n"]),
+ ["12345\n", "abcde\n"])
+ assert test.match_re(["12345\n", "abcde\n"],
+ UserList.UserList(["1[0-9]*5\n", "a.*e\n"]))
+ assert test.match_re(["12345\n", "abcde\n"],
+ UserList.UserList(["12345\n", "abcde\n"]))
+ assert test.match_re("12345\nabcde\n", "1[0-9]*5\na.*e\n")
+ assert test.match_re("12345\nabcde\n", "12345\nabcde\n")
+ lines = ["vwxyz\n", "67890\n"]
+ regexes = ["v[^a-u]*z\n", "6[^ ]+0\n"]
+ assert test.match_re(lines, regexes)
+ assert test.match_re(lines, lines)
+
+
+
+class match_stderr_TestCase(TestCmdTestCase):
+ def test_match_stderr_default(self):
+ """Test match_stderr() default behavior"""
+ test = TestCmd.TestCmd()
+ assert test.match_stderr("abcde\n", "a.*e\n")
+ assert test.match_stderr("12345\nabcde\n", "1\\d+5\na.*e\n")
+ lines = ["vwxyz\n", "67890\n"]
+ regexes = ["v[^a-u]*z\n", "6[^ ]+0\n"]
+ assert test.match_stderr(lines, regexes)
+
+ def test_match_stderr_not_affecting_match_stdout(self):
+ """Test match_stderr() not affecting match_stdout() behavior"""
+ test = TestCmd.TestCmd(match_stderr=TestCmd.TestCmd.match_exact)
+
+ assert not test.match_stderr("abcde\n", "a.*e\n")
+ assert test.match_stderr("abcde\n", "abcde\n")
+ assert not test.match_stderr("12345\nabcde\n", "1\\d+5\na.*e\n")
+ assert test.match_stderr("12345\nabcde\n", "12345\nabcde\n")
+ lines = ["vwxyz\n", "67890\n"]
+ regexes = ["v[^a-u]*z\n", "6[^ ]+0\n"]
+ assert not test.match_stderr(lines, regexes)
+ assert test.match_stderr(lines, lines)
+
+ assert test.match_stdout("abcde\n", "a.*e\n")
+ assert test.match_stdout("12345\nabcde\n", "1\\d+5\na.*e\n")
+ lines = ["vwxyz\n", "67890\n"]
+ regexes = ["v[^a-u]*z\n", "6[^ ]+0\n"]
+ assert test.match_stdout(lines, regexes)
+
+ def test_match_stderr_custom_function(self):
+ """Test match_stderr() using a custom function"""
+ def match_length(lines, matches):
+ return len(lines) == len(matches)
+ test = TestCmd.TestCmd(match_stderr=match_length)
+ assert not test.match_stderr("123\n", "1\n")
+ assert test.match_stderr("123\n", "111\n")
+ assert not test.match_stderr("123\n123\n", "1\n1\n")
+ assert test.match_stderr("123\n123\n", "111\n111\n")
+ lines = ["123\n", "123\n"]
+ regexes = ["1\n", "1\n"]
+ assert test.match_stderr(lines, regexes) # equal numbers of lines
+
+ def test_match_stderr_TestCmd_function(self):
+ """Test match_stderr() using a TestCmd function"""
+ test = TestCmd.TestCmd(match_stderr = TestCmd.match_exact)
+ assert not test.match_stderr("abcde\n", "a.*e\n")
+ assert test.match_stderr("abcde\n", "abcde\n")
+ assert not test.match_stderr("12345\nabcde\n", "1\d+5\na.*e\n")
+ assert test.match_stderr("12345\nabcde\n", "12345\nabcde\n")
+ lines = ["vwxyz\n", "67890\n"]
+ regexes = ["v[^a-u]*z\n", "6[^ ]+0\n"]
+ assert not test.match_stderr(lines, regexes)
+ assert test.match_stderr(lines, lines)
+
+ def test_match_stderr_static_method(self):
+ """Test match_stderr() using a static method"""
+ test = TestCmd.TestCmd(match_stderr=TestCmd.TestCmd.match_exact)
+ assert not test.match_stderr("abcde\n", "a.*e\n")
+ assert test.match_stderr("abcde\n", "abcde\n")
+ assert not test.match_stderr("12345\nabcde\n", "1\d+5\na.*e\n")
+ assert test.match_stderr("12345\nabcde\n", "12345\nabcde\n")
+ lines = ["vwxyz\n", "67890\n"]
+ regexes = ["v[^a-u]*z\n", "6[^ ]+0\n"]
+ assert not test.match_stderr(lines, regexes)
+ assert test.match_stderr(lines, lines)
+
+ def test_match_stderr_string(self):
+ """Test match_stderr() using a string to fetch the match method"""
+ test = TestCmd.TestCmd(match_stderr='match_exact')
+ assert not test.match_stderr("abcde\n", "a.*e\n")
+ assert test.match_stderr("abcde\n", "abcde\n")
+ assert not test.match_stderr("12345\nabcde\n", "1\d+5\na.*e\n")
+ assert test.match_stderr("12345\nabcde\n", "12345\nabcde\n")
+ lines = ["vwxyz\n", "67890\n"]
+ regexes = ["v[^a-u]*z\n", "6[^ ]+0\n"]
+ assert not test.match_stderr(lines, regexes)
+ assert test.match_stderr(lines, lines)
+
+
+
+class match_stdout_TestCase(TestCmdTestCase):
+ def test_match_stdout_default(self):
+ """Test match_stdout() default behavior"""
+ test = TestCmd.TestCmd()
+ assert test.match_stdout("abcde\n", "a.*e\n")
+ assert test.match_stdout("12345\nabcde\n", "1\\d+5\na.*e\n")
+ lines = ["vwxyz\n", "67890\n"]
+ regexes = ["v[^a-u]*z\n", "6[^ ]+0\n"]
+ assert test.match_stdout(lines, regexes)
+
+ def test_match_stdout_not_affecting_match_stderr(self):
+ """Test match_stdout() not affecting match_stderr() behavior"""
+ test = TestCmd.TestCmd(match_stdout=TestCmd.TestCmd.match_exact)
+
+ assert not test.match_stdout("abcde\n", "a.*e\n")
+ assert test.match_stdout("abcde\n", "abcde\n")
+ assert not test.match_stdout("12345\nabcde\n", "1\\d+5\na.*e\n")
+ assert test.match_stdout("12345\nabcde\n", "12345\nabcde\n")
+ lines = ["vwxyz\n", "67890\n"]
+ regexes = ["v[^a-u]*z\n", "6[^ ]+0\n"]
+ assert not test.match_stdout(lines, regexes)
+ assert test.match_stdout(lines, lines)
+
+ assert test.match_stderr("abcde\n", "a.*e\n")
+ assert test.match_stderr("12345\nabcde\n", "1\\d+5\na.*e\n")
+ lines = ["vwxyz\n", "67890\n"]
+ regexes = ["v[^a-u]*z\n", "6[^ ]+0\n"]
+ assert test.match_stderr(lines, regexes)
+
+ def test_match_stdout_custom_function(self):
+ """Test match_stdout() using a custom function"""
+ def match_length(lines, matches):
+ return len(lines) == len(matches)
+ test = TestCmd.TestCmd(match_stdout=match_length)
+ assert not test.match_stdout("123\n", "1\n")
+ assert test.match_stdout("123\n", "111\n")
+ assert not test.match_stdout("123\n123\n", "1\n1\n")
+ assert test.match_stdout("123\n123\n", "111\n111\n")
+ lines = ["123\n", "123\n"]
+ regexes = ["1\n", "1\n"]
+ assert test.match_stdout(lines, regexes) # equal numbers of lines
+
+ def test_match_stdout_TestCmd_function(self):
+ """Test match_stdout() using a TestCmd function"""
+ test = TestCmd.TestCmd(match_stdout = TestCmd.match_exact)
+ assert not test.match_stdout("abcde\n", "a.*e\n")
+ assert test.match_stdout("abcde\n", "abcde\n")
+ assert not test.match_stdout("12345\nabcde\n", "1\d+5\na.*e\n")
+ assert test.match_stdout("12345\nabcde\n", "12345\nabcde\n")
+ lines = ["vwxyz\n", "67890\n"]
+ regexes = ["v[^a-u]*z\n", "6[^ ]+0\n"]
+ assert not test.match_stdout(lines, regexes)
+ assert test.match_stdout(lines, lines)
+
+ def test_match_stdout_static_method(self):
+ """Test match_stdout() using a static method"""
+ test = TestCmd.TestCmd(match_stdout=TestCmd.TestCmd.match_exact)
+ assert not test.match_stdout("abcde\n", "a.*e\n")
+ assert test.match_stdout("abcde\n", "abcde\n")
+ assert not test.match_stdout("12345\nabcde\n", "1\d+5\na.*e\n")
+ assert test.match_stdout("12345\nabcde\n", "12345\nabcde\n")
+ lines = ["vwxyz\n", "67890\n"]
+ regexes = ["v[^a-u]*z\n", "6[^ ]+0\n"]
+ assert not test.match_stdout(lines, regexes)
+ assert test.match_stdout(lines, lines)
+
+ def test_match_stdout_string(self):
+ """Test match_stdout() using a string to fetch the match method"""
+ test = TestCmd.TestCmd(match_stdout='match_exact')
+ assert not test.match_stdout("abcde\n", "a.*e\n")
+ assert test.match_stdout("abcde\n", "abcde\n")
+ assert not test.match_stdout("12345\nabcde\n", "1\d+5\na.*e\n")
+ assert test.match_stdout("12345\nabcde\n", "12345\nabcde\n")
+ lines = ["vwxyz\n", "67890\n"]
+ regexes = ["v[^a-u]*z\n", "6[^ ]+0\n"]
+ assert not test.match_stdout(lines, regexes)
+ assert test.match_stdout(lines, lines)
+
+
+
+class no_result_TestCase(TestCmdTestCase):
+ def test_no_result(self):
+ """Test no_result()"""
+ run_env = TestCmd.TestCmd(workdir = '')
+ run_env.write('run', """import sys
+sys.stdout.write("run: STDOUT\\n")
+sys.stderr.write("run: STDERR\\n")
+""")
+ os.chdir(run_env.workdir)
+ # Everything before this prepared our "source directory."
+ # Now do the real test.
+ self.popen_python("""import sys
+sys.path = ['%s'] + sys.path
+import TestCmd
+TestCmd.no_result(condition = 1)
+""" % self.orig_cwd, status = 2, stderr = "NO RESULT for test at line 4 of <stdin>\n")
+
+ self.popen_python("""import sys
+sys.path = ['%s'] + sys.path
+import TestCmd
+test = TestCmd.TestCmd(program = 'run', interpreter = 'python', workdir = '')
+test.run()
+test.no_result(condition = (test.status == 0))
+""" % self.orig_cwd, status = 2, stderr = "NO RESULT for test of %s\n\tat line 6 of <stdin>\n" % run_env.workpath('run'))
+
+ self.popen_python("""import sys
+sys.path = ['%s'] + sys.path
+import TestCmd
+test = TestCmd.TestCmd(program = 'run', interpreter = 'python', description = 'xyzzy', workdir = '')
+test.run()
+test.no_result(condition = (test.status == 0))
+""" % self.orig_cwd, status = 2, stderr = "NO RESULT for test of %s [xyzzy]\n\tat line 6 of <stdin>\n" % run_env.workpath('run'))
+
+ self.popen_python("""import sys
+sys.path = ['%s'] + sys.path
+import TestCmd
+test = TestCmd.TestCmd(program = 'run', interpreter = 'python', workdir = '')
+test.run()
+def xxx():
+ sys.stderr.write("printed on no result\\n")
+test.no_result(condition = (test.status == 0), function = xxx)
+""" % self.orig_cwd, status = 2, stderr = "printed on no result\nNO RESULT for test of %s\n\tat line 8 of <stdin>\n" % run_env.workpath('run'))
+
+ self.popen_python("""import sys
+sys.path = ['%s'] + sys.path
+import TestCmd
+def test1(self):
+ self.run()
+ self.no_result(condition = (self.status == 0))
+def test2(self):
+ test1(self)
+test2(TestCmd.TestCmd(program = 'run', interpreter = 'python', workdir = ''))
+""" % self.orig_cwd, status = 2, stderr = "NO RESULT for test of %s\n\tat line 6 of <stdin> (test1)\n\tfrom line 8 of <stdin> (test2)\n\tfrom line 9 of <stdin>\n" % run_env.workpath('run'))
+
+ self.popen_python("""import sys
+sys.path = ['%s'] + sys.path
+import TestCmd
+def test1(self):
+ self.run()
+ self.no_result(condition = (self.status == 0), skip = 1)
+def test2(self):
+ test1(self)
+test2(TestCmd.TestCmd(program = 'run', interpreter = 'python', workdir = ''))
+""" % self.orig_cwd, status = 2, stderr = "NO RESULT for test of %s\n\tat line 8 of <stdin> (test2)\n\tfrom line 9 of <stdin>\n" % run_env.workpath('run'))
+
+
+
+class pass_test_TestCase(TestCmdTestCase):
+ def test_pass_test(self):
+ """Test pass_test()"""
+ run_env = TestCmd.TestCmd(workdir = '')
+ run_env.write('run', """import sys
+sys.stdout.write("run: STDOUT\\n")
+sys.stderr.write("run: STDERR\\n")
+""")
+ os.chdir(run_env.workdir)
+ # Everything before this prepared our "source directory."
+ # Now do the real test.
+ self.popen_python("""import sys
+sys.path = ['%s'] + sys.path
+import TestCmd
+TestCmd.pass_test(condition = 1)
+""" % self.orig_cwd, stderr = "PASSED\n")
+
+ self.popen_python("""import sys
+sys.path = ['%s'] + sys.path
+import TestCmd
+test = TestCmd.TestCmd(program = 'run', interpreter = 'python', workdir = '')
+test.run()
+test.pass_test(condition = (test.status == 0))
+""" % self.orig_cwd, stderr = "PASSED\n")
+
+ self.popen_python("""import sys
+sys.path = ['%s'] + sys.path
+import TestCmd
+test = TestCmd.TestCmd(program = 'run', interpreter = 'python', workdir = '')
+test.run()
+def brag():
+ sys.stderr.write("printed on success\\n")
+test.pass_test(condition = (test.status == 0), function = brag)
+""" % self.orig_cwd, stderr = "printed on success\nPASSED\n")
+
+ # TODO(sgk): SHOULD ALSO TEST FAILURE CONDITIONS
+
+
+
+class preserve_TestCase(TestCmdTestCase):
+ def test_preserve(self):
+ """Test preserve()"""
+ def cleanup_test(test, cond=None, stdout=""):
+ io = StringIO.StringIO()
+ save = sys.stdout
+ sys.stdout = io
+ try:
+ if cond:
+ test.cleanup(cond)
+ else:
+ test.cleanup()
+ o = io.getvalue()
+ assert o == stdout, "o = `%s', stdout = `%s'" % (o, stdout)
+ finally:
+ sys.stdout = save
+
+ test = TestCmd.TestCmd(workdir = '')
+ wdir = test.workdir
+ try:
+ test.write('file1', "Test file #1\n")
+ #test.cleanup()
+ cleanup_test(test, )
+ assert not os.path.exists(wdir)
+ finally:
+ if os.path.exists(wdir):
+ shutil.rmtree(wdir, ignore_errors = 1)
+ test._dirlist.remove(wdir)
+
+ test = TestCmd.TestCmd(workdir = '')
+ wdir = test.workdir
+ try:
+ test.write('file2', "Test file #2\n")
+ test.preserve('pass_test')
+ cleanup_test(test, 'pass_test', "Preserved directory %s\n" % wdir)
+ assert os.path.isdir(wdir)
+ cleanup_test(test, 'fail_test')
+ assert not os.path.exists(wdir)
+ finally:
+ if os.path.exists(wdir):
+ shutil.rmtree(wdir, ignore_errors = 1)
+ test._dirlist.remove(wdir)
+
+ test = TestCmd.TestCmd(workdir = '')
+ wdir = test.workdir
+ try:
+ test.write('file3', "Test file #3\n")
+ test.preserve('fail_test')
+ cleanup_test(test, 'fail_test', "Preserved directory %s\n" % wdir)
+ assert os.path.isdir(wdir)
+ cleanup_test(test, 'pass_test')
+ assert not os.path.exists(wdir)
+ finally:
+ if os.path.exists(wdir):
+ shutil.rmtree(wdir, ignore_errors = 1)
+ test._dirlist.remove(wdir)
+
+ test = TestCmd.TestCmd(workdir = '')
+ wdir = test.workdir
+ try:
+ test.write('file4', "Test file #4\n")
+ test.preserve('fail_test', 'no_result')
+ cleanup_test(test, 'fail_test', "Preserved directory %s\n" % wdir)
+ assert os.path.isdir(wdir)
+ cleanup_test(test, 'no_result', "Preserved directory %s\n" % wdir)
+ assert os.path.isdir(wdir)
+ cleanup_test(test, 'pass_test')
+ assert not os.path.exists(wdir)
+ finally:
+ if os.path.exists(wdir):
+ shutil.rmtree(wdir, ignore_errors = 1)
+ test._dirlist.remove(wdir)
+
+ test = TestCmd.TestCmd(workdir = '')
+ wdir = test.workdir
+ try:
+ test.preserve()
+ cleanup_test(test, 'pass_test', "Preserved directory %s\n" % wdir)
+ assert os.path.isdir(wdir)
+ cleanup_test(test, 'fail_test', "Preserved directory %s\n" % wdir)
+ assert os.path.isdir(wdir)
+ cleanup_test(test, 'no_result', "Preserved directory %s\n" % wdir)
+ assert os.path.isdir(wdir)
+ finally:
+ if os.path.exists(wdir):
+ shutil.rmtree(wdir, ignore_errors = 1)
+ test._dirlist.remove(wdir)
+
+
+
+class program_TestCase(TestCmdTestCase):
+ def test_program(self):
+ """Test program()"""
+ test = TestCmd.TestCmd()
+ assert test.program is None, 'initialized program?'
+ test = TestCmd.TestCmd(program = 'test')
+ assert test.program == os.path.join(os.getcwd(), 'test'), 'uninitialized program'
+ test.program_set('foo')
+ assert test.program == os.path.join(os.getcwd(), 'foo'), 'did not set program'
+
+
+
+class read_TestCase(TestCmdTestCase):
+ def test_read(self):
+ """Test read()"""
+ test = TestCmd.TestCmd(workdir = '', subdir = 'foo')
+ wdir_file1 = os.path.join(test.workdir, 'file1')
+ wdir_file2 = os.path.join(test.workdir, 'file2')
+ wdir_foo_file3 = os.path.join(test.workdir, 'foo', 'file3')
+ wdir_file4 = os.path.join(test.workdir, 'file4')
+ wdir_file5 = os.path.join(test.workdir, 'file5')
+
+ open(wdir_file1, 'wb').write("")
+ open(wdir_file2, 'wb').write("Test\nfile\n#2.\n")
+ open(wdir_foo_file3, 'wb').write("Test\nfile\n#3.\n")
+ open(wdir_file4, 'wb').write("Test\nfile\n#4.\n")
+ open(wdir_file5, 'wb').write("Test\r\nfile\r\n#5.\r\n")
+
+ try:
+ contents = test.read('no_file')
+ except IOError: # expect "No such file or directory"
+ pass
+ except:
+ raise
+
+ try:
+ test.read(test.workpath('file_x'), mode = 'w')
+ except ValueError: # expect "mode must begin with 'r'
+ pass
+ except:
+ raise
+
+ def _file_matches(file, contents, expected):
+ assert contents == expected, \
+ "Expected contents of " + str(file) + "==========\n" + \
+ expected + \
+ "Actual contents of " + str(file) + "============\n" + \
+ contents
+
+ _file_matches(wdir_file1, test.read('file1'), "")
+ _file_matches(wdir_file2, test.read('file2'), "Test\nfile\n#2.\n")
+ _file_matches(wdir_foo_file3, test.read(['foo', 'file3']),
+ "Test\nfile\n#3.\n")
+ _file_matches(wdir_foo_file3,
+ test.read(UserList.UserList(['foo', 'file3'])),
+ "Test\nfile\n#3.\n")
+ _file_matches(wdir_file4, test.read('file4', mode = 'r'),
+ "Test\nfile\n#4.\n")
+ _file_matches(wdir_file5, test.read('file5', mode = 'rb'),
+ "Test\r\nfile\r\n#5.\r\n")
+
+
+
+class rmdir_TestCase(TestCmdTestCase):
+ def test_rmdir(self):
+ """Test rmdir()"""
+ test = TestCmd.TestCmd(workdir = '')
+
+ try:
+ test.rmdir(['no', 'such', 'dir'])
+ except EnvironmentError:
+ pass
+ else:
+ raise Exception("did not catch expected EnvironmentError")
+
+ test.subdir(['sub'],
+ ['sub', 'dir'],
+ ['sub', 'dir', 'one'])
+
+ s = test.workpath('sub')
+ s_d = test.workpath('sub', 'dir')
+ s_d_o = test.workpath('sub', 'dir', 'one')
+
+ try:
+ test.rmdir(['sub'])
+ except EnvironmentError:
+ pass
+ else:
+ raise Exception("did not catch expected EnvironmentError")
+
+ assert os.path.isdir(s_d_o), "%s is gone?" % s_d_o
+
+ try:
+ test.rmdir(['sub'])
+ except EnvironmentError:
+ pass
+ else:
+ raise Exception("did not catch expected EnvironmentError")
+
+ assert os.path.isdir(s_d_o), "%s is gone?" % s_d_o
+
+ test.rmdir(['sub', 'dir', 'one'])
+
+ assert not os.path.exists(s_d_o), "%s exists?" % s_d_o
+ assert os.path.isdir(s_d), "%s is gone?" % s_d
+
+ test.rmdir(['sub', 'dir'])
+
+ assert not os.path.exists(s_d), "%s exists?" % s_d
+ assert os.path.isdir(s), "%s is gone?" % s
+
+ test.rmdir('sub')
+
+ assert not os.path.exists(s), "%s exists?" % s
+
+
+
+class run_TestCase(TestCmdTestCase):
+ def test_run(self):
+ """Test run()"""
+
+ t = self.setup_run_scripts()
+
+ # Everything before this prepared our "source directory."
+ # Now do the real test.
+ try:
+ test = TestCmd.TestCmd(program = t.script,
+ interpreter = 'python',
+ workdir = '',
+ subdir = 'script_subdir')
+
+ test.run()
+ self.run_match(test.stdout(), t.script, "STDOUT", t.workdir,
+ repr([]))
+ self.run_match(test.stderr(), t.script, "STDERR", t.workdir,
+ repr([]))
+
+ test.run(arguments = 'arg1 arg2 arg3')
+ self.run_match(test.stdout(), t.script, "STDOUT", t.workdir,
+ repr(['arg1', 'arg2', 'arg3']))
+ self.run_match(test.stderr(), t.script, "STDERR", t.workdir,
+ repr(['arg1', 'arg2', 'arg3']))
+
+ test.run(program = t.scriptx, arguments = 'foo')
+ self.run_match(test.stdout(), t.scriptx, "STDOUT", t.workdir,
+ repr(['foo']))
+ self.run_match(test.stderr(), t.scriptx, "STDERR", t.workdir,
+ repr(['foo']))
+
+ test.run(chdir = os.curdir, arguments = 'x y z')
+ self.run_match(test.stdout(), t.script, "STDOUT", test.workdir,
+ repr(['x', 'y', 'z']))
+ self.run_match(test.stderr(), t.script, "STDERR", test.workdir,
+ repr(['x', 'y', 'z']))
+
+ test.run(chdir = 'script_subdir')
+ script_subdir = test.workpath('script_subdir')
+ self.run_match(test.stdout(), t.script, "STDOUT", script_subdir,
+ repr([]))
+ self.run_match(test.stderr(), t.script, "STDERR", script_subdir,
+ repr([]))
+
+ test.run(program = t.script1, interpreter = ['python', '-x'])
+ self.run_match(test.stdout(), t.script1, "STDOUT", t.workdir,
+ repr([]))
+ self.run_match(test.stderr(), t.script1, "STDERR", t.workdir,
+ repr([]))
+
+ try:
+ test.run(chdir = 'no_subdir')
+ except OSError:
+ pass
+
+ test.run(program = 'no_script', interpreter = 'python')
+ assert test.status != None, test.status
+
+ try:
+ test.run(program = 'no_script', interpreter = 'no_interpreter')
+ except OSError:
+ # Python versions that use subprocess throw an OSError
+ # exception when they try to execute something that
+ # isn't there.
+ pass
+ else:
+ # Python versions that use os.popen3() or the Popen3
+ # class run things through the shell, which just returns
+ # a non-zero exit status.
+ assert test.status != None, test.status
+
+ testx = TestCmd.TestCmd(program = t.scriptx,
+ workdir = '',
+ subdir = 't.scriptx_subdir')
+
+ testx.run()
+ self.run_match(testx.stdout(), t.scriptx, "STDOUT", t.workdir,
+ repr([]))
+ self.run_match(testx.stderr(), t.scriptx, "STDERR", t.workdir,
+ repr([]))
+
+ testx.run(arguments = 'foo bar')
+ self.run_match(testx.stdout(), t.scriptx, "STDOUT", t.workdir,
+ repr(['foo', 'bar']))
+ self.run_match(testx.stderr(), t.scriptx, "STDERR", t.workdir,
+ repr(['foo', 'bar']))
+
+ testx.run(program = t.script, interpreter = 'python', arguments = 'bar')
+ self.run_match(testx.stdout(), t.script, "STDOUT", t.workdir,
+ repr(['bar']))
+ self.run_match(testx.stderr(), t.script, "STDERR", t.workdir,
+ repr(['bar']))
+
+ testx.run(chdir = os.curdir, arguments = 'baz')
+ self.run_match(testx.stdout(), t.scriptx, "STDOUT", testx.workdir,
+ repr(['baz']))
+ self.run_match(testx.stderr(), t.scriptx, "STDERR", testx.workdir,
+ repr(['baz']))
+
+ testx.run(chdir = 't.scriptx_subdir')
+ t.scriptx_subdir = testx.workpath('t.scriptx_subdir')
+ self.run_match(testx.stdout(), t.scriptx, "STDOUT", t.scriptx_subdir,
+ repr([]))
+ self.run_match(testx.stderr(), t.scriptx, "STDERR", t.scriptx_subdir,
+ repr([]))
+
+ testx.run(program = t.script1, interpreter = ('python', '-x'))
+ self.run_match(testx.stdout(), t.script1, "STDOUT", t.workdir,
+ repr([]))
+ self.run_match(testx.stderr(), t.script1, "STDERR", t.workdir,
+ repr([]))
+
+ s = os.path.join('.', t.scriptx)
+ testx.run(program = [s])
+ self.run_match(testx.stdout(), t.scriptx, "STDOUT", t.workdir,
+ repr([]))
+ self.run_match(testx.stderr(), t.scriptx, "STDERR", t.workdir,
+ repr([]))
+
+ try:
+ testx.run(chdir = 'no_subdir')
+ except OSError:
+ pass
+
+ try:
+ testx.run(program = 'no_program')
+ except OSError:
+ # Python versions that use subprocess throw an OSError
+ # exception when they try to execute something that
+ # isn't there.
+ pass
+ else:
+ # Python versions that use os.popen3() or the Popen3
+ # class run things through the shell, which just returns
+ # a non-zero exit status.
+ assert test.status != None
+
+ test1 = TestCmd.TestCmd(program = t.script1,
+ interpreter = ['python', '-x'],
+ workdir = '')
+
+ test1.run()
+ self.run_match(test1.stdout(), t.script1, "STDOUT", t.workdir,
+ repr([]))
+ self.run_match(test1.stderr(), t.script1, "STDERR", t.workdir,
+ repr([]))
+
+ finally:
+ os.chdir(t.orig_cwd)
+
+ def test_run_subclass(self):
+ """Test run() through a subclass with different signatures"""
+
+ t = self.setup_run_scripts()
+
+ # Everything before this prepared our "source directory."
+ # Now do the real test.
+
+ class MyTestCmdSubclass(TestCmd.TestCmd):
+ def start(self, additional_argument=None, **kw):
+ return TestCmd.TestCmd.start(self, **kw)
+
+ try:
+ test = MyTestCmdSubclass(program = t.script,
+ interpreter = 'python',
+ workdir = '',
+ subdir = 'script_subdir')
+
+ test.run()
+ self.run_match(test.stdout(), t.script, "STDOUT", t.workdir,
+ repr([]))
+ self.run_match(test.stderr(), t.script, "STDERR", t.workdir,
+ repr([]))
+ finally:
+ os.chdir(t.orig_cwd)
+
+
+class run_verbose_TestCase(TestCmdTestCase):
+ def test_run_verbose(self):
+ """Test the run() method's verbose attribute"""
+
+ # Prepare our "source directory."
+ t = self.setup_run_scripts()
+
+ save_stdout = sys.stderr
+ save_stderr = sys.stderr
+
+ try:
+ # Test calling TestCmd() with an explicit verbose = 1.
+
+ test = TestCmd.TestCmd(program = t.script,
+ interpreter = 'python',
+ workdir = '',
+ verbose = 1)
+
+ sys.stdout = StringIO.StringIO()
+ sys.stderr = StringIO.StringIO()
+
+ test.run(arguments = ['arg1 arg2'])
+ o = sys.stdout.getvalue()
+ assert o == '', o
+ e = sys.stderr.getvalue()
+ expect = 'python "%s" "arg1 arg2"\n' % t.script_path
+ assert expect == e, (expect, e)
+
+ testx = TestCmd.TestCmd(program = t.scriptx,
+ workdir = '',
+ verbose = 1)
+
+ sys.stdout = StringIO.StringIO()
+ sys.stderr = StringIO.StringIO()
+
+ testx.run(arguments = ['arg1 arg2'])
+ expect = '"%s" "arg1 arg2"\n' % t.scriptx_path
+ o = sys.stdout.getvalue()
+ assert o == '', o
+ e = sys.stderr.getvalue()
+ assert expect == e, (expect, e)
+
+ # Test calling TestCmd() with an explicit verbose = 2.
+
+ outerr_fmt = """\
+============ STATUS: 0
+============ BEGIN STDOUT (len=%s):
+%s============ END STDOUT
+============ BEGIN STDERR (len=%s)
+%s============ END STDERR
+"""
+
+ out_fmt = """\
+============ STATUS: 0
+============ BEGIN STDOUT (len=%s):
+%s============ END STDOUT
+"""
+
+ err_fmt = """\
+============ STATUS: 0
+============ BEGIN STDERR (len=%s)
+%s============ END STDERR
+"""
+
+ test = TestCmd.TestCmd(program = t.script,
+ interpreter = 'python',
+ workdir = '',
+ verbose = 2)
+
+ sys.stdout = StringIO.StringIO()
+ sys.stderr = StringIO.StringIO()
+
+ test.run(arguments = ['arg1 arg2'])
+
+ line_fmt = "script: %s: %s: ['arg1 arg2']\n"
+ stdout_line = line_fmt % ('STDOUT', t.sub_dir)
+ stderr_line = line_fmt % ('STDERR', t.sub_dir)
+ expect = outerr_fmt % (len(stdout_line), stdout_line,
+ len(stderr_line), stderr_line)
+ o = sys.stdout.getvalue()
+ assert expect == o, (expect, o)
+
+ expect = 'python "%s" "arg1 arg2"\n' % t.script_path
+ e = sys.stderr.getvalue()
+ assert e == expect, (e, expect)
+
+ testx = TestCmd.TestCmd(program = t.scriptx,
+ workdir = '',
+ verbose = 2)
+
+ sys.stdout = StringIO.StringIO()
+ sys.stderr = StringIO.StringIO()
+
+ testx.run(arguments = ['arg1 arg2'])
+
+ line_fmt = "scriptx.bat: %s: %s: ['arg1 arg2']\n"
+ stdout_line = line_fmt % ('STDOUT', t.sub_dir)
+ stderr_line = line_fmt % ('STDERR', t.sub_dir)
+ expect = outerr_fmt % (len(stdout_line), stdout_line,
+ len(stderr_line), stderr_line)
+ o = sys.stdout.getvalue()
+ assert expect == o, (expect, o)
+
+ expect = '"%s" "arg1 arg2"\n' % t.scriptx_path
+ e = sys.stderr.getvalue()
+ assert e == expect, (e, expect)
+
+ # Test calling TestCmd() with an explicit verbose = 3.
+
+ test = TestCmd.TestCmd(program = t.scriptout,
+ interpreter = 'python',
+ workdir = '',
+ verbose = 2)
+
+ sys.stdout = StringIO.StringIO()
+ sys.stderr = StringIO.StringIO()
+
+ test.run(arguments = ['arg1 arg2'])
+
+ line_fmt = "scriptout: %s: %s: ['arg1 arg2']\n"
+ stdout_line = line_fmt % ('STDOUT', t.sub_dir)
+ expect = out_fmt % (len(stdout_line), stdout_line)
+ o = sys.stdout.getvalue()
+ assert expect == o, (expect, o)
+
+ e = sys.stderr.getvalue()
+ expect = 'python "%s" "arg1 arg2"\n' % (t.scriptout_path)
+ assert e == expect, (e, expect)
+
+ test = TestCmd.TestCmd(program = t.scriptout,
+ interpreter = 'python',
+ workdir = '',
+ verbose = 3)
+
+ sys.stdout = StringIO.StringIO()
+ sys.stderr = StringIO.StringIO()
+
+ test.run(arguments = ['arg1 arg2'])
+
+ line_fmt = "scriptout: %s: %s: ['arg1 arg2']\n"
+ stdout_line = line_fmt % ('STDOUT', t.sub_dir)
+ expect = outerr_fmt % (len(stdout_line), stdout_line,
+ '0', '')
+ o = sys.stdout.getvalue()
+ assert expect == o, (expect, o)
+
+ e = sys.stderr.getvalue()
+ expect = 'python "%s" "arg1 arg2"\n' % (t.scriptout_path)
+ assert e == expect, (e, expect)
+
+ # Test letting TestCmd() pick up verbose = 2 from the environment.
+
+ os.environ['TESTCMD_VERBOSE'] = '2'
+
+ test = TestCmd.TestCmd(program = t.script,
+ interpreter = 'python',
+ workdir = '')
+
+ sys.stdout = StringIO.StringIO()
+ sys.stderr = StringIO.StringIO()
+
+ test.run(arguments = ['arg1 arg2'])
+
+ line_fmt = "script: %s: %s: ['arg1 arg2']\n"
+ stdout_line = line_fmt % ('STDOUT', t.sub_dir)
+ stderr_line = line_fmt % ('STDERR', t.sub_dir)
+ expect = outerr_fmt % (len(stdout_line), stdout_line,
+ len(stderr_line), stderr_line)
+ o = sys.stdout.getvalue()
+ assert expect == o, (expect, o)
+
+ expect = 'python "%s" "arg1 arg2"\n' % t.script_path
+ e = sys.stderr.getvalue()
+ assert e == expect, (e, expect)
+
+ testx = TestCmd.TestCmd(program = t.scriptx,
+ workdir = '')
+
+ sys.stdout = StringIO.StringIO()
+ sys.stderr = StringIO.StringIO()
+
+ testx.run(arguments = ['arg1 arg2'])
+
+ line_fmt = "scriptx.bat: %s: %s: ['arg1 arg2']\n"
+ stdout_line = line_fmt % ('STDOUT', t.sub_dir)
+ stderr_line = line_fmt % ('STDERR', t.sub_dir)
+ expect = outerr_fmt % (len(stdout_line), stdout_line,
+ len(stderr_line), stderr_line)
+ o = sys.stdout.getvalue()
+ assert expect == o, (expect, o)
+
+ expect = '"%s" "arg1 arg2"\n' % t.scriptx_path
+ e = sys.stderr.getvalue()
+ assert e == expect, (e, expect)
+
+ # Test letting TestCmd() pick up verbose = 1 from the environment.
+
+ os.environ['TESTCMD_VERBOSE'] = '1'
+
+ test = TestCmd.TestCmd(program = t.script,
+ interpreter = 'python',
+ workdir = '',
+ verbose = 1)
+
+ sys.stdout = StringIO.StringIO()
+ sys.stderr = StringIO.StringIO()
+
+ test.run(arguments = ['arg1 arg2'])
+ o = sys.stdout.getvalue()
+ assert o == '', o
+ e = sys.stderr.getvalue()
+ expect = 'python "%s" "arg1 arg2"\n' % t.script_path
+ assert expect == e, (expect, e)
+
+ testx = TestCmd.TestCmd(program = t.scriptx,
+ workdir = '',
+ verbose = 1)
+
+ sys.stdout = StringIO.StringIO()
+ sys.stderr = StringIO.StringIO()
+
+ testx.run(arguments = ['arg1 arg2'])
+ expect = '"%s" "arg1 arg2"\n' % t.scriptx_path
+ o = sys.stdout.getvalue()
+ assert o == '', o
+ e = sys.stderr.getvalue()
+ assert expect == e, (expect, e)
+
+ finally:
+ sys.stdout = save_stdout
+ sys.stderr = save_stderr
+ os.chdir(t.orig_cwd)
+ os.environ['TESTCMD_VERBOSE'] = ''
+
+
+
+class set_diff_function_TestCase(TestCmdTestCase):
+ def test_set_diff_function(self):
+ """Test set_diff_function()"""
+ self.popen_python(r"""import sys
+sys.path = ['%s'] + sys.path
+import TestCmd
+test = TestCmd.TestCmd()
+test.diff("a\n", "a\n")
+test.set_diff_function('diff_re')
+test.diff(".\n", "a\n")
+sys.exit(0)
+""" % self.orig_cwd)
+
+ def test_set_diff_function_stdout(self):
+ """Test set_diff_function(): stdout"""
+ self.popen_python("""import sys
+sys.path = ['%s'] + sys.path
+import TestCmd
+test = TestCmd.TestCmd()
+print "diff:"
+test.diff("a\\n", "a\\n")
+print "diff_stdout:"
+test.diff_stdout("a\\n", "a\\n")
+test.set_diff_function(stdout='diff_re')
+print "diff:"
+test.diff(".\\n", "a\\n")
+print "diff_stdout:"
+test.diff_stdout(".\\n", "a\\n")
+sys.exit(0)
+""" % self.orig_cwd,
+ stdout="""\
+diff:
+diff_stdout:
+diff:
+1c1
+< .
+---
+> a
+diff_stdout:
+""")
+
+ def test_set_diff_function_stderr(self):
+ """Test set_diff_function(): stderr """
+ self.popen_python("""import sys
+sys.path = ['%s'] + sys.path
+import TestCmd
+test = TestCmd.TestCmd()
+print "diff:"
+test.diff("a\\n", "a\\n")
+print "diff_stderr:"
+test.diff_stderr("a\\n", "a\\n")
+test.set_diff_function(stderr='diff_re')
+print "diff:"
+test.diff(".\\n", "a\\n")
+print "diff_stderr:"
+test.diff_stderr(".\\n", "a\\n")
+sys.exit(0)
+""" % self.orig_cwd,
+ stdout="""\
+diff:
+diff_stderr:
+diff:
+1c1
+< .
+---
+> a
+diff_stderr:
+""")
+
+
+
+class set_match_function_TestCase(TestCmdTestCase):
+ def test_set_match_function(self):
+ """Test set_match_function()"""
+ test = TestCmd.TestCmd()
+ assert test.match("abcde\n", "a.*e\n")
+ assert test.match("abcde\n", "abcde\n")
+
+ test.set_match_function('match_exact')
+
+ assert not test.match("abcde\n", "a.*e\n")
+ assert test.match("abcde\n", "abcde\n")
+
+ def test_set_match_function_stdout(self):
+ """Test set_match_function(): stdout """
+ test = TestCmd.TestCmd()
+ assert test.match("abcde\n", "a.*e\n")
+ assert test.match("abcde\n", "abcde\n")
+ assert test.match_stdout("abcde\n", "a.*e\n")
+ assert test.match_stdout("abcde\n", "abcde\n")
+
+ test.set_match_function(stdout='match_exact')
+
+ assert test.match("abcde\n", "a.*e\n")
+ assert test.match("abcde\n", "abcde\n")
+ assert not test.match_stdout("abcde\n", "a.*e\n")
+ assert test.match_stdout("abcde\n", "abcde\n")
+
+ def test_set_match_function_stderr(self):
+ """Test set_match_function(): stderr """
+ test = TestCmd.TestCmd()
+ assert test.match("abcde\n", "a.*e\n")
+ assert test.match("abcde\n", "abcde\n")
+ assert test.match_stderr("abcde\n", "a.*e\n")
+ assert test.match_stderr("abcde\n", "abcde\n")
+
+ test.set_match_function(stderr='match_exact')
+
+ assert test.match("abcde\n", "a.*e\n")
+ assert test.match("abcde\n", "abcde\n")
+ assert not test.match_stderr("abcde\n", "a.*e\n")
+ assert test.match_stderr("abcde\n", "abcde\n")
+
+
+
+class sleep_TestCase(TestCmdTestCase):
+ def test_sleep(self):
+ """Test sleep()"""
+ test = TestCmd.TestCmd()
+
+ start = time.time()
+ test.sleep()
+ end = time.time()
+ diff = end - start
+ assert diff > 0.9, "only slept %f seconds (start %f, end %f), not default" % (diff, start, end)
+
+ start = time.time()
+ test.sleep(3)
+ end = time.time()
+ diff = end - start
+ assert diff > 2.9, "only slept %f seconds (start %f, end %f), not 3" % (diff, start, end)
+
+
+
+class stderr_TestCase(TestCmdTestCase):
+ def test_stderr(self):
+ """Test stderr()"""
+ run_env = TestCmd.TestCmd(workdir = '')
+ run_env.write('run1', """import sys
+sys.stdout.write("run1 STDOUT %s\\n" % sys.argv[1:])
+sys.stdout.write("run1 STDOUT second line\\n")
+sys.stderr.write("run1 STDERR %s\\n" % sys.argv[1:])
+sys.stderr.write("run1 STDERR second line\\n")
+""")
+ run_env.write('run2', """import sys
+sys.stdout.write("run2 STDOUT %s\\n" % sys.argv[1:])
+sys.stdout.write("run2 STDOUT second line\\n")
+sys.stderr.write("run2 STDERR %s\\n" % sys.argv[1:])
+sys.stderr.write("run2 STDERR second line\\n")
+""")
+ os.chdir(run_env.workdir)
+ # Everything before this prepared our "source directory."
+ # Now do the real test.
+ test = TestCmd.TestCmd(interpreter = 'python', workdir = '')
+ try:
+ output = test.stderr()
+ except IndexError:
+ pass
+ else:
+ raise IndexError("got unexpected output:\n" + output)
+ test.program_set('run1')
+ test.run(arguments = 'foo bar')
+ test.program_set('run2')
+ test.run(arguments = 'snafu')
+ # XXX SHOULD TEST ABSOLUTE NUMBER AS WELL
+ output = test.stderr()
+ assert output == "run2 STDERR ['snafu']\nrun2 STDERR second line\n", output
+ output = test.stderr(run = -1)
+ assert output == "run1 STDERR ['foo', 'bar']\nrun1 STDERR second line\n", output
+
+
+
+class command_args_TestCase(TestCmdTestCase):
+ def test_command_args(self):
+ """Test command_args()"""
+ run_env = TestCmd.TestCmd(workdir = '')
+ os.chdir(run_env.workdir)
+ # Everything before this prepared our "source directory."
+ # Now do the real test.
+ test = TestCmd.TestCmd(workdir = '')
+
+ r = test.command_args('prog')
+ expect = [run_env.workpath('prog')]
+ assert r == expect, (expect, r)
+
+ r = test.command_args(test.workpath('new_prog'))
+ expect = [test.workpath('new_prog')]
+ assert r == expect, (expect, r)
+
+ r = test.command_args('prog', 'python')
+ expect = ['python', run_env.workpath('prog')]
+ assert r == expect, (expect, r)
+
+ r = test.command_args('prog', 'python', 'arg1 arg2')
+ expect = ['python', run_env.workpath('prog'), 'arg1', 'arg2']
+ assert r == expect, (expect, r)
+
+ test.program_set('default_prog')
+ default_prog = run_env.workpath('default_prog')
+
+ r = test.command_args()
+ expect = [default_prog]
+ assert r == expect, (expect, r)
+
+ r = test.command_args(interpreter='PYTHON')
+ expect = ['PYTHON', default_prog]
+ assert r == expect, (expect, r)
+
+ r = test.command_args(interpreter='PYTHON', arguments='arg3 arg4')
+ expect = ['PYTHON', default_prog, 'arg3', 'arg4']
+ assert r == expect, (expect, r)
+
+ test.interpreter_set('default_python')
+
+ r = test.command_args()
+ expect = ['default_python', default_prog]
+ assert r == expect, (expect, r)
+
+ r = test.command_args(arguments='arg5 arg6')
+ expect = ['default_python', default_prog, 'arg5', 'arg6']
+ assert r == expect, (expect, r)
+
+ r = test.command_args('new_prog_1')
+ expect = [run_env.workpath('new_prog_1')]
+ assert r == expect, (expect, r)
+
+ r = test.command_args(program='new_prog_2')
+ expect = [run_env.workpath('new_prog_2')]
+ assert r == expect, (expect, r)
+
+
+
+class start_TestCase(TestCmdTestCase):
+ def setup_run_scripts(self):
+ t = TestCmdTestCase.setup_run_scripts(self)
+ t.recv_script = 'script_recv'
+ t.recv_script_path = t.run_env.workpath(t.sub_dir, t.recv_script)
+ t.recv_out_path = t.run_env.workpath('script_recv.out')
+ text = """\
+import os
+import sys
+
+class Unbuffered:
+ def __init__(self, file):
+ self.file = file
+ def write(self, arg):
+ self.file.write(arg)
+ self.file.flush()
+ def __getattr__(self, attr):
+ return getattr(self.file, attr)
+
+sys.stdout = Unbuffered(sys.stdout)
+sys.stderr = Unbuffered(sys.stderr)
+
+sys.stdout.write('script_recv: STDOUT\\n')
+sys.stderr.write('script_recv: STDERR\\n')
+logfp = open(r'%s', 'wb')
+while 1:
+ line = sys.stdin.readline()
+ if not line:
+ break
+ logfp.write('script_recv: ' + line)
+ sys.stdout.write('script_recv: STDOUT: ' + line)
+ sys.stderr.write('script_recv: STDERR: ' + line)
+logfp.close()
+ """ % t.recv_out_path
+ t.run_env.write(t.recv_script_path, text)
+ os.chmod(t.recv_script_path, 0644) # XXX UNIX-specific
+ return t
+
+ def test_start(self):
+ """Test start()"""
+
+ t = self.setup_run_scripts()
+
+ # Everything before this prepared our "source directory."
+ # Now do the real test.
+ try:
+ test = TestCmd.TestCmd(program = t.script,
+ interpreter = 'python',
+ workdir = '',
+ subdir = 'script_subdir')
+
+ p = test.start()
+ self.run_match(p.stdout.read(), t.script, "STDOUT", t.workdir,
+ repr([]))
+ self.run_match(p.stderr.read(), t.script, "STDERR", t.workdir,
+ repr([]))
+ p.wait()
+
+ p = test.start(arguments='arg1 arg2 arg3')
+ self.run_match(p.stdout.read(), t.script, "STDOUT", t.workdir,
+ repr(['arg1', 'arg2', 'arg3']))
+ self.run_match(p.stderr.read(), t.script, "STDERR", t.workdir,
+ repr(['arg1', 'arg2', 'arg3']))
+ p.wait()
+
+ p = test.start(program=t.scriptx, arguments='foo')
+ self.run_match(p.stdout.read(), t.scriptx, "STDOUT", t.workdir,
+ repr(['foo']))
+ self.run_match(p.stderr.read(), t.scriptx, "STDERR", t.workdir,
+ repr(['foo']))
+ p.wait()
+
+ p = test.start(program=t.script1, interpreter=['python', '-x'])
+ self.run_match(p.stdout.read(), t.script1, "STDOUT", t.workdir,
+ repr([]))
+ self.run_match(p.stderr.read(), t.script1, "STDERR", t.workdir,
+ repr([]))
+ p.wait()
+
+ p = test.start(program='no_script', interpreter='python')
+ status = p.wait()
+ assert status != None, status
+
+ try:
+ p = test.start(program='no_script', interpreter='no_interpreter')
+ except OSError:
+ # Python versions that use subprocess throw an OSError
+ # exception when they try to execute something that
+ # isn't there.
+ pass
+ else:
+ status = p.wait()
+ # Python versions that use os.popen3() or the Popen3
+ # class run things through the shell, which just returns
+ # a non-zero exit status.
+ assert status != None, status
+
+ testx = TestCmd.TestCmd(program = t.scriptx,
+ workdir = '',
+ subdir = 't.scriptx_subdir')
+
+ p = testx.start()
+ self.run_match(p.stdout.read(), t.scriptx, "STDOUT", t.workdir,
+ repr([]))
+ self.run_match(p.stderr.read(), t.scriptx, "STDERR", t.workdir,
+ repr([]))
+ p.wait()
+
+ p = testx.start(arguments='foo bar')
+ self.run_match(p.stdout.read(), t.scriptx, "STDOUT", t.workdir,
+ repr(['foo', 'bar']))
+ self.run_match(p.stderr.read(), t.scriptx, "STDERR", t.workdir,
+ repr(['foo', 'bar']))
+ p.wait()
+
+ p = testx.start(program=t.script, interpreter='python', arguments='bar')
+ self.run_match(p.stdout.read(), t.script, "STDOUT", t.workdir,
+ repr(['bar']))
+ self.run_match(p.stderr.read(), t.script, "STDERR", t.workdir,
+ repr(['bar']))
+ p.wait()
+
+ p = testx.start(program=t.script1, interpreter=('python', '-x'))
+ self.run_match(p.stdout.read(), t.script1, "STDOUT", t.workdir,
+ repr([]))
+ self.run_match(p.stderr.read(), t.script1, "STDERR", t.workdir,
+ repr([]))
+ p.wait()
+
+ s = os.path.join('.', t.scriptx)
+ p = testx.start(program=[s])
+ self.run_match(p.stdout.read(), t.scriptx, "STDOUT", t.workdir,
+ repr([]))
+ self.run_match(p.stderr.read(), t.scriptx, "STDERR", t.workdir,
+ repr([]))
+ p.wait()
+
+ try:
+ testx.start(program='no_program')
+ except OSError:
+ # Python versions that use subprocess throw an OSError
+ # exception when they try to execute something that
+ # isn't there.
+ pass
+ else:
+ # Python versions that use os.popen3() or the Popen3
+ # class run things through the shell, which just dies
+ # trying to execute the non-existent program before
+ # we can wait() for it.
+ try:
+ p = p.wait()
+ except OSError:
+ pass
+
+ test1 = TestCmd.TestCmd(program = t.script1,
+ interpreter = ['python', '-x'],
+ workdir = '')
+
+ p = test1.start()
+ self.run_match(p.stdout.read(), t.script1, "STDOUT", t.workdir,
+ repr([]))
+ self.run_match(p.stderr.read(), t.script1, "STDERR", t.workdir,
+ repr([]))
+ p.wait()
+
+ finally:
+ os.chdir(t.orig_cwd)
+
+ def test_finish(self):
+ """Test finish()"""
+
+ t = self.setup_run_scripts()
+
+ # Everything before this prepared our "source directory."
+ # Now do the real test.
+ try:
+
+ test = TestCmd.TestCmd(program = t.recv_script,
+ interpreter = 'python',
+ workdir = '',
+ subdir = 'script_subdir')
+
+ test.start(stdin=1)
+ test.finish()
+ expect_stdout = """\
+script_recv: STDOUT
+"""
+ expect_stderr = """\
+script_recv: STDERR
+"""
+ stdout = test.stdout()
+ assert stdout == expect_stdout, stdout
+ stderr = test.stderr()
+ assert stderr == expect_stderr, stderr
+
+ p = test.start(stdin=1)
+ p.send('input\n')
+ test.finish(p)
+ expect_stdout = """\
+script_recv: STDOUT
+script_recv: STDOUT: input
+"""
+ expect_stderr = """\
+script_recv: STDERR
+script_recv: STDERR: input
+"""
+ stdout = test.stdout()
+ assert stdout == expect_stdout, stdout
+ stderr = test.stderr()
+ assert stderr == expect_stderr, stderr
+
+ p = test.start(combine=1, stdin=1)
+ p.send('input\n')
+ test.finish(p)
+ expect_stdout = """\
+script_recv: STDOUT
+script_recv: STDERR
+script_recv: STDOUT: input
+script_recv: STDERR: input
+"""
+ expect_stderr = ""
+ stdout = test.stdout()
+ assert stdout == expect_stdout, stdout
+ stderr = test.stderr()
+ assert stderr == expect_stderr, stderr
+
+ finally:
+ os.chdir(t.orig_cwd)
+
+ def test_recv(self):
+ """Test the recv() method of objects returned by start()"""
+
+ t = self.setup_run_scripts()
+
+ # Everything before this prepared our "source directory."
+ # Now do the real test.
+ try:
+ test = TestCmd.TestCmd(program = t.script,
+ interpreter = 'python',
+ workdir = '',
+ subdir = 'script_subdir')
+
+ p = test.start()
+ stdout = p.recv()
+ while stdout == '':
+ import time
+ time.sleep(1)
+ stdout = p.recv()
+ self.run_match(stdout, t.script, "STDOUT", t.workdir,
+ repr([]))
+ p.wait()
+
+ finally:
+ os.chdir(t.orig_cwd)
+
+ def test_recv_err(self):
+ """Test the recv_err() method of objects returned by start()"""
+
+ t = self.setup_run_scripts()
+
+ # Everything before this prepared our "source directory."
+ # Now do the real test.
+ try:
+
+ test = TestCmd.TestCmd(program = t.script,
+ interpreter = 'python',
+ workdir = '',
+ subdir = 'script_subdir')
+
+ p = test.start()
+ stderr = p.recv_err()
+ while stderr == '':
+ import time
+ time.sleep(1)
+ stderr = p.recv_err()
+ self.run_match(stderr, t.script, "STDERR", t.workdir,
+ repr([]))
+ p.wait()
+
+
+ finally:
+ os.chdir(t.orig_cwd)
+
+ def test_send(self):
+ """Test the send() method of objects returned by start()"""
+
+ t = self.setup_run_scripts()
+
+ # Everything before this prepared our "source directory."
+ # Now do the real test.
+ try:
+
+ test = TestCmd.TestCmd(program = t.recv_script,
+ interpreter = 'python',
+ workdir = '',
+ subdir = 'script_subdir')
+
+ p = test.start(stdin=1)
+ input = 'stdin.write() input to the receive script\n'
+ p.stdin.write(input)
+ p.stdin.close()
+ p.wait()
+ result = open(t.recv_out_path, 'rb').read()
+ expect = 'script_recv: ' + input
+ assert result == expect, repr(result)
+
+ p = test.start(stdin=1)
+ input = 'send() input to the receive script\n'
+ p.send(input)
+ p.stdin.close()
+ p.wait()
+ result = open(t.recv_out_path, 'rb').read()
+ expect = 'script_recv: ' + input
+ assert result == expect, repr(result)
+
+ finally:
+ os.chdir(t.orig_cwd)
+
+ # TODO(sgk): figure out how to eliminate the race conditions here.
+ def __FLAKY__test_send_recv(self):
+ """Test the send_recv() method of objects returned by start()"""
+
+ t = self.setup_run_scripts()
+
+ # Everything before this prepared our "source directory."
+ # Now do the real test.
+ try:
+
+ test = TestCmd.TestCmd(program = t.recv_script,
+ interpreter = 'python',
+ workdir = '',
+ subdir = 'script_subdir')
+
+ def do_send_recv(p, input):
+ send, stdout, stderr = p.send_recv(input)
+ stdout = self.translate_newlines(stdout)
+ stderr = self.translate_newlines(stderr)
+ return send, stdout, stderr
+
+ p = test.start(stdin=1)
+ input = 'input to the receive script\n'
+ send, stdout, stderr = do_send_recv(p, input)
+ # Buffering issues and a race condition prevent this from
+ # being completely deterministic, so check for both null
+ # output and the first write() on each stream.
+ assert stdout in ("", "script_recv: STDOUT\n"), stdout
+ assert stderr in ("", "script_recv: STDERR\n"), stderr
+ send, stdout, stderr = do_send_recv(p, input)
+ assert stdout in ("", "script_recv: STDOUT\n"), stdout
+ assert stderr in ("", "script_recv: STDERR\n"), stderr
+ p.stdin.close()
+ stdout = self.translate_newlines(p.recv())
+ stderr = self.translate_newlines(p.recv_err())
+ assert stdout in ("", "script_recv: STDOUT\n"), stdout
+ assert stderr in ("", "script_recv: STDERR\n"), stderr
+ p.wait()
+ stdout = self.translate_newlines(p.recv())
+ stderr = self.translate_newlines(p.recv_err())
+ expect_stdout = """\
+script_recv: STDOUT
+script_recv: STDOUT: input to the receive script
+script_recv: STDOUT: input to the receive script
+"""
+ expect_stderr = """\
+script_recv: STDERR
+script_recv: STDERR: input to the receive script
+script_recv: STDERR: input to the receive script
+"""
+ assert stdout == expect_stdout, stdout
+ assert stderr == expect_stderr, stderr
+ result = open(t.recv_out_path, 'rb').read()
+ expect = ('script_recv: ' + input) * 2
+ assert result == expect, (result, stdout, stderr)
+
+ finally:
+ os.chdir(t.orig_cwd)
+
+
+
+class stdin_TestCase(TestCmdTestCase):
+ def test_stdin(self):
+ """Test stdin()"""
+ run_env = TestCmd.TestCmd(workdir = '')
+ run_env.write('run', """import fileinput
+for line in fileinput.input():
+ print 'Y'.join(line[:-1].split('X'))
+""")
+ run_env.write('input', "X on X this X line X\n")
+ os.chdir(run_env.workdir)
+ # Everything before this prepared our "source directory."
+ # Now do the real test.
+ test = TestCmd.TestCmd(program = 'run', interpreter = 'python', workdir = '')
+ test.run(arguments = 'input')
+ assert test.stdout() == "Y on Y this Y line Y\n"
+ test.run(stdin = "X is X here X tooX\n")
+ assert test.stdout() == "Y is Y here Y tooY\n"
+ test.run(stdin = """X here X
+X there X
+""")
+ assert test.stdout() == "Y here Y\nY there Y\n"
+ test.run(stdin = ["X line X\n", "X another X\n"])
+ assert test.stdout() == "Y line Y\nY another Y\n"
+
+
+
+class stdout_TestCase(TestCmdTestCase):
+ def test_stdout(self):
+ """Test stdout()"""
+ run_env = TestCmd.TestCmd(workdir = '')
+ run_env.write('run1', """import sys
+sys.stdout.write("run1 STDOUT %s\\n" % sys.argv[1:])
+sys.stdout.write("run1 STDOUT second line\\n")
+sys.stderr.write("run1 STDERR %s\\n" % sys.argv[1:])
+sys.stderr.write("run1 STDERR second line\\n")
+""")
+ run_env.write('run2', """import sys
+sys.stdout.write("run2 STDOUT %s\\n" % sys.argv[1:])
+sys.stdout.write("run2 STDOUT second line\\n")
+sys.stderr.write("run2 STDERR %s\\n" % sys.argv[1:])
+sys.stderr.write("run2 STDERR second line\\n")
+""")
+ os.chdir(run_env.workdir)
+ # Everything before this prepared our "source directory."
+ # Now do the real test.
+ test = TestCmd.TestCmd(interpreter = 'python', workdir = '')
+ try:
+ output = test.stdout()
+ except IndexError:
+ pass
+ else:
+ raise IndexError("got unexpected output:\n\t`%s'\n" % output)
+ test.program_set('run1')
+ test.run(arguments = 'foo bar')
+ test.program_set('run2')
+ test.run(arguments = 'snafu')
+ # XXX SHOULD TEST ABSOLUTE NUMBER AS WELL
+ output = test.stdout()
+ assert output == "run2 STDOUT ['snafu']\nrun2 STDOUT second line\n", output
+ output = test.stdout(run = -1)
+ assert output == "run1 STDOUT ['foo', 'bar']\nrun1 STDOUT second line\n", output
+
+
+
+class subdir_TestCase(TestCmdTestCase):
+ def test_subdir(self):
+ """Test subdir()"""
+ test = TestCmd.TestCmd(workdir = '', subdir = ['no', 'such', 'subdir'])
+ assert not os.path.exists(test.workpath('no'))
+
+ test = TestCmd.TestCmd(workdir = '', subdir = 'foo')
+ assert test.subdir('bar') == 1
+ assert test.subdir(['foo', 'succeed']) == 1
+ if os.name != "nt":
+ os.chmod(test.workpath('foo'), 0500)
+ assert test.subdir(['foo', 'fail']) == 0
+ assert test.subdir(['sub', 'dir', 'ectory'], 'sub') == 1
+ assert test.subdir('one',
+ UserList.UserList(['one', 'two']),
+ ['one', 'two', 'three']) == 3
+ assert os.path.isdir(test.workpath('foo'))
+ assert os.path.isdir(test.workpath('bar'))
+ assert os.path.isdir(test.workpath('foo', 'succeed'))
+ if os.name != "nt":
+ assert not os.path.exists(test.workpath('foo', 'fail'))
+ assert os.path.isdir(test.workpath('sub'))
+ assert not os.path.exists(test.workpath('sub', 'dir'))
+ assert not os.path.exists(test.workpath('sub', 'dir', 'ectory'))
+ assert os.path.isdir(test.workpath('one', 'two', 'three'))
+
+
+
+class symlink_TestCase(TestCmdTestCase):
+ def test_symlink(self):
+ """Test symlink()"""
+ try: os.symlink
+ except AttributeError: return
+
+ test = TestCmd.TestCmd(workdir = '', subdir = 'foo')
+ wdir_file1 = os.path.join(test.workdir, 'file1')
+ wdir_target1 = os.path.join(test.workdir, 'target1')
+ wdir_foo_file2 = os.path.join(test.workdir, 'foo', 'file2')
+ wdir_target2 = os.path.join(test.workdir, 'target2')
+ wdir_foo_target2 = os.path.join(test.workdir, 'foo', 'target2')
+
+ test.symlink('target1', 'file1')
+ assert os.path.islink(wdir_file1)
+ assert not os.path.exists(wdir_file1)
+ open(wdir_target1, 'w').write("")
+ assert os.path.exists(wdir_file1)
+
+ test.symlink('target2', ['foo', 'file2'])
+ assert os.path.islink(wdir_foo_file2)
+ assert not os.path.exists(wdir_foo_file2)
+ open(wdir_target2, 'w').write("")
+ assert not os.path.exists(wdir_foo_file2)
+ open(wdir_foo_target2, 'w').write("")
+ assert os.path.exists(wdir_foo_file2)
+
+
+
+class tempdir_TestCase(TestCmdTestCase):
+ def setUp(self):
+ TestCmdTestCase.setUp(self)
+ self._tempdir = tempfile.mktemp()
+ os.mkdir(self._tempdir)
+ os.chdir(self._tempdir)
+
+ def tearDown(self):
+ TestCmdTestCase.tearDown(self)
+ os.rmdir(self._tempdir)
+
+ def test_tempdir(self):
+ """Test tempdir()"""
+ test = TestCmd.TestCmd()
+ tdir1 = test.tempdir()
+ assert os.path.isdir(tdir1)
+ test.workdir_set(None)
+ test.cleanup()
+ assert not os.path.exists(tdir1)
+
+ test = TestCmd.TestCmd()
+ tdir2 = test.tempdir('temp')
+ assert os.path.isdir(tdir2)
+ tdir3 = test.tempdir()
+ assert os.path.isdir(tdir3)
+ test.workdir_set(None)
+ test.cleanup()
+ assert not os.path.exists(tdir2)
+ assert not os.path.exists(tdir3)
+
+
+timeout_script = """\
+import sys
+import time
+seconds = int(sys.argv[1])
+sys.stdout.write('sleeping %s\\n' % seconds)
+sys.stdout.flush()
+time.sleep(seconds)
+sys.stdout.write('slept %s\\n' % seconds)
+sys.stdout.flush()
+sys.exit(0)
+"""
+
+class timeout_TestCase(TestCmdTestCase):
+ def test_initialization(self):
+ """Test initialization timeout"""
+ test = TestCmd.TestCmd(workdir='', timeout=2)
+ test.write('sleep.py', timeout_script)
+
+ test.run([sys.executable, test.workpath('sleep.py'), '4'])
+ assert test.stderr() == '', test.stderr()
+ assert test.stdout() == 'sleeping 4\n', test.stdout()
+
+ test.run([sys.executable, test.workpath('sleep.py'), '4'])
+ assert test.stderr() == '', test.stderr()
+ assert test.stdout() == 'sleeping 4\n', test.stdout()
+
+ def test_cancellation(self):
+ """Test timer cancellation after firing"""
+ test = TestCmd.TestCmd(workdir='', timeout=4)
+ test.write('sleep.py', timeout_script)
+
+ test.run([sys.executable, test.workpath('sleep.py'), '6'])
+ assert test.stderr() == '', test.stderr()
+ assert test.stdout() == 'sleeping 6\n', test.stdout()
+
+ test.run([sys.executable, test.workpath('sleep.py'), '2'])
+ assert test.stderr() == '', test.stderr()
+ assert test.stdout() == 'sleeping 2\nslept 2\n', test.stdout()
+
+ test.run([sys.executable, test.workpath('sleep.py'), '6'])
+ assert test.stderr() == '', test.stderr()
+ assert test.stdout() == 'sleeping 6\n', test.stdout()
+
+ def test_run(self):
+ """Test run() timeout"""
+ test = TestCmd.TestCmd(workdir='', timeout=8)
+ test.write('sleep.py', timeout_script)
+
+ test.run([sys.executable, test.workpath('sleep.py'), '2'],
+ timeout=4)
+ assert test.stderr() == '', test.stderr()
+ assert test.stdout() == 'sleeping 2\nslept 2\n', test.stdout()
+
+ test.run([sys.executable, test.workpath('sleep.py'), '6'],
+ timeout=4)
+ assert test.stderr() == '', test.stderr()
+ assert test.stdout() == 'sleeping 6\n', test.stdout()
+
+ def test_set_timeout(self):
+ """Test set_timeout()"""
+ test = TestCmd.TestCmd(workdir='', timeout=2)
+ test.write('sleep.py', timeout_script)
+
+ test.run([sys.executable, test.workpath('sleep.py'), '4'])
+ assert test.stderr() == '', test.stderr()
+ assert test.stdout() == 'sleeping 4\n', test.stdout()
+
+ test.set_timeout(None)
+
+ test.run([sys.executable, test.workpath('sleep.py'), '4'])
+ assert test.stderr() == '', test.stderr()
+ assert test.stdout() == 'sleeping 4\nslept 4\n', test.stdout()
+
+ test.set_timeout(6)
+
+ test.run([sys.executable, test.workpath('sleep.py'), '4'])
+ assert test.stderr() == '', test.stderr()
+ assert test.stdout() == 'sleeping 4\nslept 4\n', test.stdout()
+
+ test.run([sys.executable, test.workpath('sleep.py'), '8'])
+ assert test.stderr() == '', test.stderr()
+ assert test.stdout() == 'sleeping 8\n', test.stdout()
+
+
+
+class unlink_TestCase(TestCmdTestCase):
+ def test_unlink(self):
+ """Test unlink()"""
+ test = TestCmd.TestCmd(workdir = '', subdir = 'foo')
+ wdir_file1 = os.path.join(test.workdir, 'file1')
+ wdir_file2 = os.path.join(test.workdir, 'file2')
+ wdir_foo_file3a = os.path.join(test.workdir, 'foo', 'file3a')
+ wdir_foo_file3b = os.path.join(test.workdir, 'foo', 'file3b')
+ wdir_foo_file4 = os.path.join(test.workdir, 'foo', 'file4')
+ wdir_file5 = os.path.join(test.workdir, 'file5')
+
+ open(wdir_file1, 'w').write("")
+ open(wdir_file2, 'w').write("")
+ open(wdir_foo_file3a, 'w').write("")
+ open(wdir_foo_file3b, 'w').write("")
+ open(wdir_foo_file4, 'w').write("")
+ open(wdir_file5, 'w').write("")
+
+ try:
+ contents = test.unlink('no_file')
+ except OSError: # expect "No such file or directory"
+ pass
+ except:
+ raise
+
+ test.unlink("file1")
+ assert not os.path.exists(wdir_file1)
+
+ test.unlink(wdir_file2)
+ assert not os.path.exists(wdir_file2)
+
+ test.unlink(['foo', 'file3a'])
+ assert not os.path.exists(wdir_foo_file3a)
+
+ test.unlink(UserList.UserList(['foo', 'file3b']))
+ assert not os.path.exists(wdir_foo_file3b)
+
+ test.unlink([test.workdir, 'foo', 'file4'])
+ assert not os.path.exists(wdir_foo_file4)
+
+ # Make it so we can't unlink file5.
+ # For UNIX, remove write permission from the dir and the file.
+ # For Windows, open the file.
+ os.chmod(test.workdir, 0500)
+ os.chmod(wdir_file5, 0400)
+ f = open(wdir_file5, 'r')
+
+ try:
+ try:
+ test.unlink('file5')
+ except OSError: # expect "Permission denied"
+ pass
+ except:
+ raise
+ finally:
+ os.chmod(test.workdir, 0700)
+ os.chmod(wdir_file5, 0600)
+ f.close()
+
+
+
+class touch_TestCase(TestCmdTestCase):
+ def test_touch(self):
+ """Test touch()"""
+ test = TestCmd.TestCmd(workdir = '', subdir = 'sub')
+
+ wdir_file1 = os.path.join(test.workdir, 'file1')
+ wdir_sub_file2 = os.path.join(test.workdir, 'sub', 'file2')
+
+ open(wdir_file1, 'w').write("")
+ open(wdir_sub_file2, 'w').write("")
+
+ file1_old_time = os.path.getmtime(wdir_file1)
+ file2_old_time = os.path.getmtime(wdir_sub_file2)
+
+ test.sleep()
+
+ test.touch(wdir_file1)
+
+ file1_new_time = os.path.getmtime(wdir_file1)
+ assert file1_new_time > file1_old_time
+
+ test.touch('file1', file1_old_time)
+
+ result = os.path.getmtime(wdir_file1)
+ # Sub-second granularity of file systems may still vary.
+ # On Windows, the two times may be off by a microsecond.
+ assert int(result) == int(file1_old_time), (result, file1_old_time)
+
+ test.touch(['sub', 'file2'])
+
+ file2_new_time = os.path.getmtime(wdir_sub_file2)
+ assert file2_new_time > file2_old_time
+
+
+
+class verbose_TestCase(TestCmdTestCase):
+ def test_verbose(self):
+ """Test verbose()"""
+ test = TestCmd.TestCmd()
+ assert test.verbose == 0, 'verbose already initialized?'
+ test = TestCmd.TestCmd(verbose = 1)
+ assert test.verbose == 1, 'did not initialize verbose'
+ test.verbose = 2
+ assert test.verbose == 2, 'did not set verbose'
+
+
+
+class workdir_TestCase(TestCmdTestCase):
+ def test_workdir(self):
+ """Test workdir()"""
+ run_env = TestCmd.TestCmd(workdir = '')
+ os.chdir(run_env.workdir)
+ # Everything before this prepared our "source directory."
+ # Now do the real test.
+ test = TestCmd.TestCmd()
+ assert test.workdir is None
+
+ test = TestCmd.TestCmd(workdir = None)
+ assert test.workdir is None
+
+ test = TestCmd.TestCmd(workdir = '')
+ assert test.workdir != None
+ assert os.path.isdir(test.workdir)
+
+ test = TestCmd.TestCmd(workdir = 'dir')
+ assert test.workdir != None
+ assert os.path.isdir(test.workdir)
+
+ no_such_subdir = os.path.join('no', 'such', 'subdir')
+ try:
+ test = TestCmd.TestCmd(workdir = no_such_subdir)
+ except OSError: # expect "No such file or directory"
+ pass
+ except:
+ raise
+
+ test = TestCmd.TestCmd(workdir = 'foo')
+ workdir_foo = test.workdir
+ assert workdir_foo != None
+
+ test.workdir_set('bar')
+ workdir_bar = test.workdir
+ assert workdir_bar != None
+
+ try:
+ test.workdir_set(no_such_subdir)
+ except OSError:
+ pass # expect "No such file or directory"
+ except:
+ raise
+ assert workdir_bar == test.workdir
+
+ assert os.path.isdir(workdir_foo)
+ assert os.path.isdir(workdir_bar)
+
+
+
+class workdirs_TestCase(TestCmdTestCase):
+ def test_workdirs(self):
+ """Test workdirs()"""
+ test = TestCmd.TestCmd()
+ assert test.workdir is None
+ test.workdir_set('')
+ wdir1 = test.workdir
+ test.workdir_set('')
+ wdir2 = test.workdir
+ assert os.path.isdir(wdir1)
+ assert os.path.isdir(wdir2)
+ test.cleanup()
+ assert not os.path.exists(wdir1)
+ assert not os.path.exists(wdir2)
+
+
+
+class workpath_TestCase(TestCmdTestCase):
+ def test_workpath(self):
+ """Test workpath()"""
+ test = TestCmd.TestCmd()
+ assert test.workdir is None
+
+ test = TestCmd.TestCmd(workdir = '')
+ wpath = test.workpath('foo', 'bar')
+ assert wpath == os.path.join(test.workdir, 'foo', 'bar')
+
+
+
+class readable_TestCase(TestCmdTestCase):
+ def test_readable(self):
+ """Test readable()"""
+ test = TestCmd.TestCmd(workdir = '', subdir = 'foo')
+ test.write('file1', "Test file #1\n")
+ test.write(['foo', 'file2'], "Test file #2\n")
+
+ try: symlink = os.symlink
+ except AttributeError: pass
+ else: symlink('no_such_file', test.workpath('dangling_symlink'))
+
+ test.readable(test.workdir, 0)
+ # XXX skip these tests if euid == 0?
+ assert not _is_readable(test.workdir)
+ assert not _is_readable(test.workpath('file1'))
+ assert not _is_readable(test.workpath('foo'))
+ assert not _is_readable(test.workpath('foo', 'file2'))
+
+ test.readable(test.workdir, 1)
+ assert _is_readable(test.workdir)
+ assert _is_readable(test.workpath('file1'))
+ assert _is_readable(test.workpath('foo'))
+ assert _is_readable(test.workpath('foo', 'file2'))
+
+ test.readable(test.workdir, 0)
+ # XXX skip these tests if euid == 0?
+ assert not _is_readable(test.workdir)
+ assert not _is_readable(test.workpath('file1'))
+ assert not _is_readable(test.workpath('foo'))
+ assert not _is_readable(test.workpath('foo', 'file2'))
+
+ test.readable(test.workpath('file1'), 1)
+ assert _is_readable(test.workpath('file1'))
+
+ test.readable(test.workpath('file1'), 0)
+ assert not _is_readable(test.workpath('file1'))
+
+ test.readable(test.workdir, 1)
+
+
+
+class writable_TestCase(TestCmdTestCase):
+ def test_writable(self):
+ """Test writable()"""
+ test = TestCmd.TestCmd(workdir = '', subdir = 'foo')
+ test.write('file1', "Test file #1\n")
+ test.write(['foo', 'file2'], "Test file #2\n")
+
+ try: symlink = os.symlink
+ except AttributeError: pass
+ else: symlink('no_such_file', test.workpath('dangling_symlink'))
+
+ test.writable(test.workdir, 0)
+ # XXX skip these tests if euid == 0?
+ assert not _is_writable(test.workdir)
+ assert not _is_writable(test.workpath('file1'))
+ assert not _is_writable(test.workpath('foo'))
+ assert not _is_writable(test.workpath('foo', 'file2'))
+
+ test.writable(test.workdir, 1)
+ assert _is_writable(test.workdir)
+ assert _is_writable(test.workpath('file1'))
+ assert _is_writable(test.workpath('foo'))
+ assert _is_writable(test.workpath('foo', 'file2'))
+
+ test.writable(test.workdir, 0)
+ # XXX skip these tests if euid == 0?
+ assert not _is_writable(test.workdir)
+ assert not _is_writable(test.workpath('file1'))
+ assert not _is_writable(test.workpath('foo'))
+ assert not _is_writable(test.workpath('foo', 'file2'))
+
+ test.writable(test.workpath('file1'), 1)
+ assert _is_writable(test.workpath('file1'))
+
+ test.writable(test.workpath('file1'), 0)
+ assert not _is_writable(test.workpath('file1'))
+
+
+
+class executable_TestCase(TestCmdTestCase):
+ def test_executable(self):
+ """Test executable()"""
+ test = TestCmd.TestCmd(workdir = '', subdir = 'foo')
+ test.write('file1', "Test file #1\n")
+ test.write(['foo', 'file2'], "Test file #2\n")
+
+ try: symlink = os.symlink
+ except AttributeError: pass
+ else: symlink('no_such_file', test.workpath('dangling_symlink'))
+
+ def make_executable(fname):
+ st = os.stat(fname)
+ os.chmod(fname, stat.S_IMODE(st[stat.ST_MODE]|0100))
+
+ def make_non_executable(fname):
+ st = os.stat(fname)
+ os.chmod(fname, stat.S_IMODE(st[stat.ST_MODE]&~0100))
+
+ test.executable(test.workdir, 0)
+ # XXX skip these tests if euid == 0?
+ assert not _is_executable(test.workdir)
+ make_executable(test.workdir)
+ assert not _is_executable(test.workpath('file1'))
+ assert not _is_executable(test.workpath('foo'))
+ make_executable(test.workpath('foo'))
+ assert not _is_executable(test.workpath('foo', 'file2'))
+ make_non_executable(test.workpath('foo'))
+ make_non_executable(test.workdir)
+
+ test.executable(test.workdir, 1)
+ assert _is_executable(test.workdir)
+ assert _is_executable(test.workpath('file1'))
+ assert _is_executable(test.workpath('foo'))
+ assert _is_executable(test.workpath('foo', 'file2'))
+
+ test.executable(test.workdir, 0)
+ # XXX skip these tests if euid == 0?
+ assert not _is_executable(test.workdir)
+ make_executable(test.workdir)
+ assert not _is_executable(test.workpath('file1'))
+ assert not _is_executable(test.workpath('foo'))
+ make_executable(test.workpath('foo'))
+ assert not _is_executable(test.workpath('foo', 'file2'))
+
+ test.executable(test.workpath('file1'), 1)
+ assert _is_executable(test.workpath('file1'))
+
+ test.executable(test.workpath('file1'), 0)
+ assert not _is_executable(test.workpath('file1'))
+
+ test.executable(test.workdir, 1)
+
+
+
+class write_TestCase(TestCmdTestCase):
+ def test_write(self):
+ """Test write()"""
+ test = TestCmd.TestCmd(workdir = '', subdir = 'foo')
+ test.write('file1', "Test file #1\n")
+ test.write(['foo', 'file2'], "Test file #2\n")
+ try:
+ test.write(['bar', 'file3'], "Test file #3 (should not get created)\n")
+ except IOError: # expect "No such file or directory"
+ pass
+ except:
+ raise
+ test.write(test.workpath('file4'), "Test file #4.\n")
+ test.write(test.workpath('foo', 'file5'), "Test file #5.\n")
+ try:
+ test.write(test.workpath('bar', 'file6'), "Test file #6 (should not get created)\n")
+ except IOError: # expect "No such file or directory"
+ pass
+ except:
+ raise
+
+ try:
+ test.write('file7', "Test file #8.\n", mode = 'r')
+ except ValueError: # expect "mode must begin with 'w'
+ pass
+ except:
+ raise
+
+ test.write('file8', "Test file #8.\n", mode = 'w')
+ test.write('file9', "Test file #9.\r\n", mode = 'wb')
+
+ if os.name != "nt":
+ os.chmod(test.workdir, 0500)
+ try:
+ test.write('file10', "Test file #10 (should not get created).\n")
+ except IOError: # expect "Permission denied"
+ pass
+ except:
+ raise
+
+ assert os.path.isdir(test.workpath('foo'))
+ assert not os.path.exists(test.workpath('bar'))
+ assert os.path.isfile(test.workpath('file1'))
+ assert os.path.isfile(test.workpath('foo', 'file2'))
+ assert not os.path.exists(test.workpath('bar', 'file3'))
+ assert os.path.isfile(test.workpath('file4'))
+ assert os.path.isfile(test.workpath('foo', 'file5'))
+ assert not os.path.exists(test.workpath('bar', 'file6'))
+ assert not os.path.exists(test.workpath('file7'))
+ assert os.path.isfile(test.workpath('file8'))
+ assert os.path.isfile(test.workpath('file9'))
+ if os.name != "nt":
+ assert not os.path.exists(test.workpath('file10'))
+
+ assert open(test.workpath('file8'), 'r').read() == "Test file #8.\n"
+ assert open(test.workpath('file9'), 'rb').read() == "Test file #9.\r\n"
+
+
+
+class variables_TestCase(TestCmdTestCase):
+ def test_variables(self):
+ """Test global variables"""
+ run_env = TestCmd.TestCmd(workdir = '')
+
+ variables = [
+ 'fail_test',
+ 'no_result',
+ 'pass_test',
+ 'match_exact',
+ 'match_re',
+ 'match_re_dotall',
+ 'python',
+ '_python_',
+ 'TestCmd',
+ ]
+
+ script = "import TestCmd\n" + \
+ '\n'.join([ "print TestCmd.%s\n" % v for v in variables ])
+ run_env.run(program=sys.executable, stdin=script)
+ stderr = run_env.stderr()
+ assert stderr == "", stderr
+
+ script = "from TestCmd import *\n" + \
+ '\n'.join([ "print %s" % v for v in variables ])
+ run_env.run(program=sys.executable, stdin=script)
+ stderr = run_env.stderr()
+ assert stderr == "", stderr
+
+
+
+if __name__ == "__main__":
+ tclasses = [
+ __init__TestCase,
+ basename_TestCase,
+ cleanup_TestCase,
+ chmod_TestCase,
+ combine_TestCase,
+ command_args_TestCase,
+ description_TestCase,
+ diff_TestCase,
+ diff_stderr_TestCase,
+ diff_stdout_TestCase,
+ exit_TestCase,
+ fail_test_TestCase,
+ interpreter_TestCase,
+ match_TestCase,
+ match_exact_TestCase,
+ match_re_dotall_TestCase,
+ match_re_TestCase,
+ match_stderr_TestCase,
+ match_stdout_TestCase,
+ no_result_TestCase,
+ pass_test_TestCase,
+ preserve_TestCase,
+ program_TestCase,
+ read_TestCase,
+ rmdir_TestCase,
+ run_TestCase,
+ run_verbose_TestCase,
+ set_diff_function_TestCase,
+ set_match_function_TestCase,
+ sleep_TestCase,
+ start_TestCase,
+ stderr_TestCase,
+ stdin_TestCase,
+ stdout_TestCase,
+ subdir_TestCase,
+ symlink_TestCase,
+ tempdir_TestCase,
+ timeout_TestCase,
+ unlink_TestCase,
+ touch_TestCase,
+ verbose_TestCase,
+ workdir_TestCase,
+ workdirs_TestCase,
+ workpath_TestCase,
+ writable_TestCase,
+ write_TestCase,
+ variables_TestCase,
+ ]
+ if sys.platform != 'win32':
+ tclasses.extend([
+ executable_TestCase,
+ readable_TestCase,
+ ])
+ suite = unittest.TestSuite()
+ for tclass in tclasses:
+ names = unittest.getTestCaseNames(tclass, 'test_')
+ suite.addTests([ tclass(n) for n in names ])
+ if not unittest.TextTestRunner().run(suite).wasSuccessful():
+ sys.exit(1)
+
+# Local Variables:
+# tab-width:4
+# indent-tabs-mode:nil
+# End:
+# vim: set expandtab tabstop=4 shiftwidth=4:
diff --git a/QMTest/TestCommon.py b/QMTest/TestCommon.py
index dac9556..37d3f9c 100644
--- a/QMTest/TestCommon.py
+++ b/QMTest/TestCommon.py
@@ -92,8 +92,8 @@ The TestCommon module also provides the following variables
# SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
__author__ = "Steven Knight <knight at baldmt dot com>"
-__revision__ = "TestCommon.py 1.1.D001 2010/05/27 14:16:37 knight"
-__version__ = "1.1"
+__revision__ = "TestCommon.py 1.3.D001 2010/06/03 12:58:27 knight"
+__version__ = "1.3"
import copy
import os
diff --git a/QMTest/TestCommonTests.py b/QMTest/TestCommonTests.py
new file mode 100644
index 0000000..8bf64fc
--- /dev/null
+++ b/QMTest/TestCommonTests.py
@@ -0,0 +1,2094 @@
+#!/usr/bin/env python
+"""
+TestCommonTests.py: Unit tests for the TestCommon.py module.
+
+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.
+
+IN NO EVENT SHALL THE AUTHOR BE LIABLE TO ANY PARTY FOR DIRECT, INDIRECT,
+SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OF
+THIS CODE, EVEN IF THE AUTHOR HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
+DAMAGE.
+
+THE AUTHOR SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, BUT NOT
+LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
+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.
+"""
+
+__author__ = "Steven Knight <knight at baldmt dot com>"
+__revision__ = "TestCommonTests.py 1.3.D001 2010/06/03 12:58:27 knight"
+
+import difflib
+import os
+import re
+import signal
+import stat
+import sys
+import unittest
+
+# Strip the current directory so we get the right TestCommon.py module.
+sys.path = sys.path[1:]
+
+import TestCmd
+import TestCommon
+
+def lstrip(s):
+ lines = [ _.expandtabs() for _ in s.split('\n') ]
+ if lines[0] == '':
+ lines = lines[1:]
+ spaces = len(re.match('^( *).*', lines[0]).group(1))
+ if spaces:
+ lines = [ l[spaces:] for l in lines ]
+ return '\n'.join(lines)
+
+if sys.version[:3] == '1.5':
+ expected_newline = '\\012'
+else:
+ expected_newline = '\\n'
+
+def assert_display(expect, result, error=None):
+ try:
+ expect = expect.pattern
+ except AttributeError:
+ pass
+ result = [
+ '\n',
+ ('*'*80) + '\n',
+ expect,
+ ('*'*80) + '\n',
+ result,
+ ('*'*80) + '\n',
+ ]
+ if error:
+ result.append(error)
+ return ''.join(result)
+
+
+class TestCommonTestCase(unittest.TestCase):
+ """Base class for TestCommon test cases, fixture and utility methods."""
+ create_run_env = True
+
+ def setUp(self):
+ self.orig_cwd = os.getcwd()
+ if self.create_run_env:
+ self.run_env = TestCmd.TestCmd(workdir = '')
+
+ def tearDown(self):
+ os.chdir(self.orig_cwd)
+
+ def set_up_execution_scripts(self):
+ run_env = self.run_env
+
+ run_env.subdir('sub dir')
+
+ self.python = sys.executable
+
+ self.pass_script = run_env.workpath('sub dir', 'pass')
+ self.fail_script = run_env.workpath('sub dir', 'fail')
+ self.stdout_script = run_env.workpath('sub dir', 'stdout')
+ self.stderr_script = run_env.workpath('sub dir', 'stderr')
+ self.signal_script = run_env.workpath('sub dir', 'signal')
+ self.stdin_script = run_env.workpath('sub dir', 'stdin')
+
+ preamble = "import sys"
+ stdout = "; sys.stdout.write(r'%s: STDOUT: ' + repr(sys.argv[1:]) + '\\n')"
+ stderr = "; sys.stderr.write(r'%s: STDERR: ' + repr(sys.argv[1:]) + '\\n')"
+ exit0 = "; sys.exit(0)"
+ exit1 = "; sys.exit(1)"
+ if sys.platform == 'win32':
+ wrapper = '@python -c "%s" %%1 %%2 %%3 %%4 %%5 %%6 %%7 %%8 %%9\n'
+ else:
+ wrapper = '#! /usr/bin/env python\n%s\n'
+ wrapper = '#! /usr/bin/env python\n%s\n'
+
+ pass_body = preamble + stdout % self.pass_script + exit0
+ fail_body = preamble + stdout % self.fail_script + exit1
+ stderr_body = preamble + stderr % self.stderr_script + exit0
+
+ run_env.write(self.pass_script, wrapper % pass_body)
+ run_env.write(self.fail_script, wrapper % fail_body)
+ run_env.write(self.stderr_script, wrapper % stderr_body)
+
+ signal_body = lstrip("""\
+ import os
+ import signal
+ os.kill(os.getpid(), signal.SIGTERM)
+ """)
+
+ run_env.write(self.signal_script, wrapper % signal_body)
+
+ stdin_body = lstrip("""\
+ import sys
+ input = sys.stdin.read()[:-1]
+ sys.stdout.write(r'%s: STDOUT: ' + repr(input) + '\\n')
+ sys.stderr.write(r'%s: STDERR: ' + repr(input) + '\\n')
+ """ % (self.stdin_script, self.stdin_script))
+
+ run_env.write(self.stdin_script, wrapper % stdin_body)
+
+ def run_execution_test(self, script, expect_stdout, expect_stderr):
+ self.set_up_execution_scripts()
+
+ run_env = self.run_env
+
+ os.chdir(run_env.workpath('sub dir'))
+
+ # Everything before this prepared our "source directory."
+ # Now do the real test.
+ script = script % self.__dict__
+ run_env.run(program=sys.executable, stdin=script)
+
+ stdout = run_env.stdout()
+ stderr = run_env.stderr()
+
+ expect_stdout = expect_stdout % self.__dict__
+ assert stdout == expect_stdout, assert_display(expect_stdout,
+ stdout,
+ stderr)
+
+ try:
+ match = expect_stderr.match
+ except AttributeError:
+ expect_stderr = expect_stderr % self.__dict__
+ assert stderr == expect_stderr, assert_display(expect_stderr,
+ stderr)
+ else:
+ assert expect_stderr.match(stderr), assert_display(expect_stderr,
+ stderr)
+
+
+class __init__TestCase(TestCommonTestCase):
+ def test___init__(self):
+ """Test initialization"""
+ run_env = self.run_env
+
+ os.chdir(run_env.workdir)
+ script = lstrip("""\
+ from TestCommon import TestCommon
+ tc = TestCommon(workdir='')
+ import os
+ print os.getcwd()
+ """)
+ run_env.run(program=sys.executable, stdin=script)
+ stdout = run_env.stdout()[:-1]
+ assert stdout != run_env.workdir, stdout
+ stderr = run_env.stderr()
+ assert stderr == "", stderr
+
+
+class banner_TestCase(TestCommonTestCase):
+ create_run_env = False
+ def test_banner(self):
+ """Test banner()"""
+ tc = TestCommon.TestCommon(workdir='')
+
+ b = tc.banner('xyzzy ')
+ assert b == "xyzzy ==========================================================================", b
+
+ tc.banner_width = 10
+
+ b = tc.banner('xyzzy ')
+ assert b == "xyzzy ====", b
+
+ b = tc.banner('xyzzy ', 20)
+ assert b == "xyzzy ==============", b
+
+ tc.banner_char = '-'
+
+ b = tc.banner('xyzzy ')
+ assert b == "xyzzy ----", b
+
+class must_be_writable_TestCase(TestCommonTestCase):
+ def test_file_does_not_exists(self):
+ """Test must_be_writable(): file does not exist"""
+ run_env = self.run_env
+
+ script = lstrip("""\
+ from TestCommon import TestCommon
+ tc = TestCommon(workdir='')
+ tc.must_be_writable('file1')
+ tc.pass_test()
+ """)
+ run_env.run(program=sys.executable, stdin=script)
+ stdout = run_env.stdout()
+ assert stdout == "Missing files: `file1'\n", stdout
+ stderr = run_env.stderr()
+ assert stderr.find("FAILED") != -1, stderr
+
+ def test_writable_file_exists(self):
+ """Test must_be_writable(): writable file exists"""
+ run_env = self.run_env
+
+ script = lstrip("""\
+ import os
+ import stat
+ from TestCommon import TestCommon
+ tc = TestCommon(workdir='')
+ tc.write('file1', "file1\\n")
+ f1 = tc.workpath('file1')
+ mode = os.stat(f1)[stat.ST_MODE]
+ os.chmod(f1, mode | stat.S_IWUSR)
+ tc.must_be_writable('file1')
+ tc.pass_test()
+ """)
+ run_env.run(program=sys.executable, stdin=script)
+ stdout = run_env.stdout()
+ assert stdout == "", stdout
+ stderr = run_env.stderr()
+ assert stderr == "PASSED\n", stderr
+
+ def test_non_writable_file_exists(self):
+ """Test must_be_writable(): non-writable file exists"""
+ run_env = self.run_env
+
+ script = lstrip("""\
+ import os
+ import stat
+ from TestCommon import TestCommon
+ tc = TestCommon(workdir='')
+ tc.write('file1', "file1\\n")
+ f1 = tc.workpath('file1')
+ mode = os.stat(f1)[stat.ST_MODE]
+ os.chmod(f1, mode & ~stat.S_IWUSR)
+ tc.must_be_writable('file1')
+ tc.pass_test()
+ """)
+ run_env.run(program=sys.executable, stdin=script)
+ stdout = run_env.stdout()
+ assert stdout == "Unwritable files: `file1'\n", stdout
+ stderr = run_env.stderr()
+ assert stderr.find("FAILED") != -1, stderr
+
+ def test_file_specified_as_list(self):
+ """Test must_be_writable(): file specified as list"""
+ run_env = self.run_env
+
+ script = lstrip("""\
+ import os
+ import stat
+ from TestCommon import TestCommon
+ tc = TestCommon(workdir='')
+ tc.subdir('sub')
+ tc.write(['sub', 'file1'], "sub/file1\\n")
+ f1 = tc.workpath('sub', 'file1')
+ mode = os.stat(f1)[stat.ST_MODE]
+ os.chmod(f1, mode | stat.S_IWUSR)
+ tc.must_be_writable(['sub', 'file1'])
+ tc.pass_test()
+ """)
+ run_env.run(program=sys.executable, stdin=script)
+ stdout = run_env.stdout()
+ assert stdout == "", stdout
+ stderr = run_env.stderr()
+ assert stderr == "PASSED\n", stderr
+
+
+class must_contain_TestCase(TestCommonTestCase):
+ def test_success(self):
+ """Test must_contain(): success"""
+ run_env = self.run_env
+
+ script = lstrip("""\
+ from TestCommon import TestCommon
+ tc = TestCommon(workdir='')
+ tc.write('file1', "file1 contents\\n")
+ tc.must_contain('file1', "1 c")
+ tc.pass_test()
+ """)
+ run_env.run(program=sys.executable, stdin=script)
+ stdout = run_env.stdout()
+ assert stdout == "", stdout
+ stderr = run_env.stderr()
+ assert stderr == "PASSED\n", stderr
+
+ def test_file_missing(self):
+ """Test must_contain(): file missing"""
+ run_env = self.run_env
+
+ script = lstrip("""\
+ from TestCommon import TestCommon
+ tc = TestCommon(workdir='')
+ tc.must_contain('file1', "1 c\\n")
+ tc.pass_test()
+ """)
+ run_env.run(program=sys.executable, stdin=script)
+ stdout = run_env.stdout()
+ assert stdout == "", stdout
+ stderr = run_env.stderr()
+ assert stderr.find("No such file or directory:") != -1, stderr
+
+ def test_failure(self):
+ """Test must_contain(): failure"""
+ run_env = self.run_env
+
+ script = lstrip("""\
+ from TestCommon import TestCommon
+ tc = TestCommon(workdir='')
+ tc.write('file1', "file1 does not match\\n")
+ tc.must_contain('file1', "1 c")
+ tc.run()
+ """)
+ expect = lstrip("""\
+ File `file1' does not contain required string.
+ Required string ================================================================
+ 1 c
+ file1 contents =================================================================
+ file1 does not match
+
+ """)
+ run_env.run(program=sys.executable, stdin=script)
+ stdout = run_env.stdout()
+ assert stdout == expect, repr(stdout)
+ stderr = run_env.stderr()
+ assert stderr.find("FAILED") != -1, stderr
+
+ def test_mode(self):
+ """Test must_contain(): mode"""
+ run_env = self.run_env
+
+ script = lstrip("""\
+ from TestCommon import TestCommon
+ tc = TestCommon(workdir='')
+ tc.write('file1', "file1 contents\\n", mode='w')
+ tc.must_contain('file1', "1 c", mode='r')
+ tc.write('file2', "file2 contents\\n", mode='wb')
+ tc.must_contain('file2', "2 c", mode='rb')
+ tc.pass_test()
+ """)
+ run_env.run(program=sys.executable, stdin=script)
+ stdout = run_env.stdout()
+ assert stdout == "", stdout
+ stderr = run_env.stderr()
+ assert stderr == "PASSED\n", stderr
+
+
+
+class must_contain_all_lines_TestCase(TestCommonTestCase):
+ def test_success(self):
+ """Test must_contain_all_lines(): success"""
+ run_env = self.run_env
+
+ script = lstrip("""
+ import TestCommon
+ test = TestCommon.TestCommon(workdir='')
+
+ lines = [
+ 'xxx\\n',
+ 'yyy\\n',
+ ]
+
+ output = '''\\
+ www
+ xxx
+ yyy
+ zzz
+ '''
+
+ test.must_contain_all_lines(output, lines)
+
+ test.must_contain_all_lines(output, ['www\\n'])
+
+ test.pass_test()
+ """)
+
+ run_env.run(program=sys.executable, stdin=script)
+ stdout = run_env.stdout()
+ assert stdout == "", stdout
+ stderr = run_env.stderr()
+ assert stderr == "PASSED\n", stderr
+
+ def test_failure(self):
+ """Test must_contain_all_lines(): failure"""
+ run_env = self.run_env
+
+ script = lstrip("""
+ import TestCommon
+ test = TestCommon.TestCommon(workdir='')
+
+ lines = [
+ 'xxx\\n',
+ 'yyy\\n',
+ ]
+
+ output = '''\\
+ www
+ zzz
+ '''
+
+ test.must_contain_all_lines(output, lines)
+
+ test.pass_test()
+ """)
+
+ expect = lstrip("""\
+ Missing expected lines from output:
+ 'xxx%(expected_newline)s'
+ 'yyy%(expected_newline)s'
+ output =========================================================================
+ www
+ zzz
+ """ % globals())
+
+ run_env.run(program=sys.executable, stdin=script)
+ stdout = run_env.stdout()
+ stderr = run_env.stderr()
+ assert stdout == expect, assert_display(expect, stdout, stderr)
+ assert stderr.find("FAILED") != -1, stderr
+
+ def test_find(self):
+ """Test must_contain_all_lines(): find"""
+ run_env = self.run_env
+
+ script = lstrip("""
+ import re
+ import TestCommon
+ test = TestCommon.TestCommon(workdir='')
+
+ lines = [
+ 'x.*',
+ '.*y',
+ ]
+
+ output = '''\\
+ www
+ xxx
+ yyy
+ zzz
+ '''
+
+ def re_search(output, line):
+ return re.compile(line, re.S).search(output)
+ test.must_contain_all_lines(output, lines, find=re_search)
+
+ test.pass_test()
+ """)
+
+ run_env.run(program=sys.executable, stdin=script)
+ stdout = run_env.stdout()
+ assert stdout == "", stdout
+ stderr = run_env.stderr()
+ assert stderr == "PASSED\n", stderr
+
+ def test_title(self):
+ """Test must_contain_all_lines(): title"""
+ run_env = self.run_env
+
+ script = lstrip("""
+ import TestCommon
+ test = TestCommon.TestCommon(workdir='')
+
+ lines = [
+ 'xxx\\n',
+ 'yyy\\n',
+ ]
+
+ output = '''\\
+ www
+ zzz
+ '''
+
+ test.must_contain_all_lines(output, lines, title='STDERR')
+
+ test.pass_test()
+ """)
+
+ expect = lstrip("""\
+ Missing expected lines from STDERR:
+ 'xxx%(expected_newline)s'
+ 'yyy%(expected_newline)s'
+ STDERR =========================================================================
+ www
+ zzz
+ """ % globals())
+
+ run_env.run(program=sys.executable, stdin=script)
+ stdout = run_env.stdout()
+ stderr = run_env.stderr()
+ assert stdout == expect, assert_display(expect, stdout, stderr)
+ assert stderr.find("FAILED") != -1, stderr
+
+
+
+class must_contain_any_line_TestCase(TestCommonTestCase):
+ def test_success(self):
+ """Test must_contain_any_line(): success"""
+ run_env = self.run_env
+
+ script = lstrip("""
+ import TestCommon
+ test = TestCommon.TestCommon(workdir='')
+
+ lines = [
+ 'aaa\\n',
+ 'yyy\\n',
+ ]
+
+ output = '''\\
+ www
+ xxx
+ yyy
+ zzz
+ '''
+
+ test.must_contain_any_line(output, lines)
+
+ test.must_contain_any_line(output, ['www\\n'])
+
+ test.pass_test()
+ """)
+
+ run_env.run(program=sys.executable, stdin=script)
+ stdout = run_env.stdout()
+ assert stdout == "", stdout
+ stderr = run_env.stderr()
+ assert stderr == "PASSED\n", stderr
+
+ def test_failure(self):
+ """Test must_contain_any_line(): failure"""
+ run_env = self.run_env
+
+ script = lstrip("""
+ import TestCommon
+ test = TestCommon.TestCommon(workdir='')
+
+ lines = [
+ 'xxx\\n',
+ 'yyy\\n',
+ ]
+
+ output = '''\\
+ www
+ zzz
+ '''
+
+ test.must_contain_any_line(output, lines)
+
+ test.pass_test()
+ """)
+
+ expect = lstrip("""\
+ Missing any expected line from output:
+ 'xxx%(expected_newline)s'
+ 'yyy%(expected_newline)s'
+ output =========================================================================
+ www
+ zzz
+ """ % globals())
+
+ run_env.run(program=sys.executable, stdin=script)
+ stdout = run_env.stdout()
+ stderr = run_env.stderr()
+ assert stdout == expect, assert_display(expect, stdout, stderr)
+ assert stderr.find("FAILED") != -1, stderr
+
+ def test_find(self):
+ """Test must_contain_any_line(): find"""
+ run_env = self.run_env
+
+ script = lstrip("""
+ import re
+ import TestCommon
+ test = TestCommon.TestCommon(workdir='')
+
+ lines = [
+ 'aaa',
+ '.*y',
+ ]
+
+ output = '''\\
+ www
+ xxx
+ yyy
+ zzz
+ '''
+
+ def re_search(output, line):
+ return re.compile(line, re.S).search(output)
+ test.must_contain_any_line(output, lines, find=re_search)
+
+ test.pass_test()
+ """)
+
+ run_env.run(program=sys.executable, stdin=script)
+ stdout = run_env.stdout()
+ assert stdout == "", stdout
+ stderr = run_env.stderr()
+ assert stderr == "PASSED\n", stderr
+
+ def test_title(self):
+ """Test must_contain_any_line(): title"""
+ run_env = self.run_env
+
+ script = lstrip("""
+ import TestCommon
+ test = TestCommon.TestCommon(workdir='')
+
+ lines = [
+ 'xxx\\n',
+ 'yyy\\n',
+ ]
+
+ output = '''\\
+ www
+ zzz
+ '''
+
+ test.must_contain_any_line(output, lines, title='STDOUT')
+
+ test.pass_test()
+ """)
+
+ expect = lstrip("""\
+ Missing any expected line from STDOUT:
+ 'xxx%(expected_newline)s'
+ 'yyy%(expected_newline)s'
+ STDOUT =========================================================================
+ www
+ zzz
+ """ % globals())
+
+ run_env.run(program=sys.executable, stdin=script)
+ stdout = run_env.stdout()
+ stderr = run_env.stderr()
+ assert stdout == expect, assert_display(expect, stdout, stderr)
+ assert stderr.find("FAILED") != -1, stderr
+
+
+
+class must_contain_exactly_lines_TestCase(TestCommonTestCase):
+ def test_success_list(self):
+ """Test must_contain_exactly_lines(): success (input list)"""
+ run_env = self.run_env
+
+ script = lstrip("""
+ import TestCommon
+ test = TestCommon.TestCommon(workdir='')
+
+ lines = [
+ 'yyy\\n',
+ 'xxx\\n',
+ 'zzz',
+ 'www\\n',
+ ]
+
+ output = '''\\
+ www
+ xxx
+ yyy
+ zzz
+ '''
+
+ test.must_contain_exactly_lines(output, lines)
+
+ test.pass_test()
+ """)
+
+ run_env.run(program=sys.executable, stdin=script)
+ stdout = run_env.stdout()
+ assert stdout == "", stdout
+ stderr = run_env.stderr()
+ assert stderr == "PASSED\n", stderr
+
+ def test_success_string(self):
+ """Test must_contain_exactly_lines(): success (input string)"""
+ run_env = self.run_env
+
+ script = lstrip("""
+ import TestCommon
+ test = TestCommon.TestCommon(workdir='')
+
+ lines = '''\\
+ yyy
+ xxx
+ zzz
+ www
+ '''
+
+ output = '''\\
+ www
+ xxx
+ yyy
+ zzz
+ '''
+
+ test.must_contain_exactly_lines(output, lines)
+
+ test.pass_test()
+ """)
+
+ run_env.run(program=sys.executable, stdin=script)
+ stdout = run_env.stdout()
+ assert stdout == "", stdout
+ stderr = run_env.stderr()
+ assert stderr == "PASSED\n", stderr
+
+ def test_failure(self):
+ """Test must_contain_exactly_lines(): failure"""
+ run_env = self.run_env
+
+ script = lstrip("""
+ import TestCommon
+ test = TestCommon.TestCommon(workdir='')
+
+ lines = [
+ 'xxx\\n',
+ 'yyy\\n',
+ ]
+
+ output = '''\\
+ www
+ zzz
+ '''
+
+ test.must_contain_exactly_lines(output, lines)
+
+ test.pass_test()
+ """)
+
+ expect = lstrip("""\
+ Missing expected lines from output:
+ 'xxx'
+ 'yyy'
+ Missing output =================================================================
+ Extra unexpected lines from output:
+ 'www'
+ 'zzz'
+ Extra output ===================================================================
+ """ % globals())
+
+ run_env.run(program=sys.executable, stdin=script)
+ stdout = run_env.stdout()
+ stderr = run_env.stderr()
+ assert stdout == expect, assert_display(expect, stdout, stderr)
+ assert stderr.find("FAILED") != -1, stderr
+
+ def test_find(self):
+ """Test must_contain_exactly_lines(): find"""
+ run_env = self.run_env
+
+ script = lstrip("""
+ import re
+ import TestCommon
+ test = TestCommon.TestCommon(workdir='')
+
+ lines = [
+ 'zzz',
+ '.*y',
+ 'xxx',
+ 'www',
+ ]
+
+ output = '''\\\
+ www
+ xxx
+ yyy
+ zzz
+ '''
+
+ def re_search(output, line):
+ pattern = re.compile(line, re.S)
+ index = 0
+ for o in output:
+ if pattern.search(o):
+ return index
+ index +=1
+ return None
+ test.must_contain_exactly_lines(output, lines, find=re_search)
+
+ test.pass_test()
+ """)
+
+ run_env.run(program=sys.executable, stdin=script)
+ stdout = run_env.stdout()
+ assert stdout == "", stdout
+ stderr = run_env.stderr()
+ assert stderr == "PASSED\n", stderr
+
+ def test_title(self):
+ """Test must_contain_exactly_lines(): title"""
+ run_env = self.run_env
+
+ script = lstrip("""
+ import TestCommon
+ test = TestCommon.TestCommon(workdir='')
+
+ lines = [
+ 'xxx\\n',
+ 'yyy\\n',
+ ]
+
+ output = '''\\
+ www
+ zzz
+ '''
+
+ test.must_contain_exactly_lines(output, lines, title='STDOUT')
+
+ test.pass_test()
+ """)
+
+ expect = lstrip("""\
+ Missing expected lines from STDOUT:
+ 'xxx'
+ 'yyy'
+ Missing STDOUT =================================================================
+ Extra unexpected lines from STDOUT:
+ 'www'
+ 'zzz'
+ Extra STDOUT ===================================================================
+ """ % globals())
+
+ run_env.run(program=sys.executable, stdin=script)
+ stdout = run_env.stdout()
+ stderr = run_env.stderr()
+ assert stdout == expect, assert_display(expect, stdout, stderr)
+ assert stderr.find("FAILED") != -1, stderr
+
+
+
+class must_contain_lines_TestCase(TestCommonTestCase):
+ def test_success(self):
+ """Test must_contain_lines(): success"""
+ run_env = self.run_env
+
+ script = lstrip("""
+ import TestCommon
+ test = TestCommon.TestCommon(workdir='')
+
+ lines = [
+ 'xxx\\n',
+ 'yyy\\n',
+ ]
+
+ output = '''\\
+ www
+ xxx
+ yyy
+ zzz
+ '''
+
+ test.must_contain_lines(lines, output)
+
+ test.pass_test()
+ """)
+
+ run_env.run(program=sys.executable, stdin=script)
+ stdout = run_env.stdout()
+ assert stdout == "", stdout
+ stderr = run_env.stderr()
+ assert stderr == "PASSED\n", stderr
+
+ def test_failure(self):
+ """Test must_contain_lines(): failure"""
+ run_env = self.run_env
+
+ script = lstrip("""
+ import TestCommon
+ test = TestCommon.TestCommon(workdir='')
+
+ lines = [
+ 'xxx\\n',
+ 'yyy\\n',
+ ]
+
+ output = '''\\
+ www
+ zzz
+ '''
+
+ test.must_contain_lines(lines, output)
+
+ test.pass_test()
+ """)
+
+ expect = lstrip("""\
+ Missing expected lines from output:
+ 'xxx%(expected_newline)s'
+ 'yyy%(expected_newline)s'
+ output =========================================================================
+ www
+ zzz
+ """ % globals())
+
+ run_env.run(program=sys.executable, stdin=script)
+ stdout = run_env.stdout()
+ stderr = run_env.stderr()
+ assert stdout == expect, assert_display(expect, stdout, stderr)
+ assert stderr.find("FAILED") != -1, stderr
+
+
+
+class must_exist_TestCase(TestCommonTestCase):
+ def test_success(self):
+ """Test must_exist(): success"""
+ run_env = self.run_env
+
+ script = lstrip("""\
+ from TestCommon import TestCommon
+ tc = TestCommon(workdir='')
+ tc.write('file1', "file1\\n")
+ tc.must_exist('file1')
+ tc.pass_test()
+ """)
+ run_env.run(program=sys.executable, stdin=script)
+ stdout = run_env.stdout()
+ assert stdout == "", stdout
+ stderr = run_env.stderr()
+ assert stderr == "PASSED\n", stderr
+
+ def test_failure(self):
+ """Test must_exist(): failure"""
+ run_env = self.run_env
+
+ script = lstrip("""\
+ from TestCommon import TestCommon
+ tc = TestCommon(workdir='')
+ tc.must_exist('file1')
+ tc.pass_test()
+ """)
+ run_env.run(program=sys.executable, stdin=script)
+ stdout = run_env.stdout()
+ assert stdout == "Missing files: `file1'\n", stdout
+ stderr = run_env.stderr()
+ assert stderr.find("FAILED") != -1, stderr
+
+ def test_file_specified_as_list(self):
+ """Test must_exist(): file specified as list"""
+ run_env = self.run_env
+
+ script = lstrip("""\
+ from TestCommon import TestCommon
+ tc = TestCommon(workdir='')
+ tc.subdir('sub')
+ tc.write(['sub', 'file1'], "sub/file1\\n")
+ tc.must_exist(['sub', 'file1'])
+ tc.pass_test()
+ """)
+ run_env.run(program=sys.executable, stdin=script)
+ stdout = run_env.stdout()
+ assert stdout == "", stdout
+ stderr = run_env.stderr()
+ assert stderr == "PASSED\n", stderr
+
+
+
+class must_match_TestCase(TestCommonTestCase):
+ def test_success(self):
+ """Test must_match(): success"""
+ run_env = self.run_env
+
+ script = lstrip("""\
+ from TestCommon import TestCommon
+ tc = TestCommon(workdir='')
+ tc.write('file1', "file1\\n")
+ tc.must_match('file1', "file1\\n")
+ tc.pass_test()
+ """)
+ run_env.run(program=sys.executable, stdin=script)
+ stdout = run_env.stdout()
+ assert stdout == "", stdout
+ stderr = run_env.stderr()
+ assert stderr == "PASSED\n", stderr
+
+ def test_file_does_not_exists(self):
+ """Test must_match(): file does not exist"""
+ run_env = self.run_env
+
+ script = lstrip("""\
+ from TestCommon import TestCommon
+ tc = TestCommon(workdir='')
+ tc.must_match('file1', "file1\\n")
+ tc.pass_test()
+ """)
+ run_env.run(program=sys.executable, stdin=script)
+ stdout = run_env.stdout()
+ assert stdout == "", stdout
+ stderr = run_env.stderr()
+ assert stderr.find("No such file or directory:") != -1, stderr
+
+ def test_failure(self):
+ """Test must_match(): failure"""
+ run_env = self.run_env
+
+ script = lstrip("""\
+ from TestCommon import TestCommon
+ tc = TestCommon(workdir='')
+ tc.write('file1', "file1 does not match\\n")
+ tc.must_match('file1', "file1\\n")
+ tc.run()
+ """)
+
+ expect = lstrip("""\
+ Unexpected contents of `file1'
+ contents =======================================================================
+ 1c1
+ < file1
+ ---
+ > file1 does not match
+ """)
+ run_env.run(program=sys.executable, stdin=script)
+ stdout = run_env.stdout()
+ assert stdout == expect, stdout
+ stderr = run_env.stderr()
+ assert stderr.find("FAILED") != -1, stderr
+
+ def test_mode(self):
+ """Test must_match(): mode"""
+ run_env = self.run_env
+
+ script = lstrip("""\
+ from TestCommon import TestCommon
+ tc = TestCommon(workdir='')
+ tc.write('file1', "file1\\n", mode='w')
+ tc.must_match('file1', "file1\\n", mode='r')
+ tc.write('file2', "file2\\n", mode='wb')
+ tc.must_match('file2', "file2\\n", mode='rb')
+ tc.pass_test()
+ """)
+ run_env.run(program=sys.executable, stdin=script)
+ stdout = run_env.stdout()
+ assert stdout == "", stdout
+ stderr = run_env.stderr()
+ assert stderr == "PASSED\n", stderr
+
+
+
+class must_not_be_writable_TestCase(TestCommonTestCase):
+ def test_file_does_not_exists(self):
+ """Test must_not_be_writable(): file does not exist"""
+ run_env = self.run_env
+
+ script = lstrip("""\
+ from TestCommon import TestCommon
+ tc = TestCommon(workdir='')
+ tc.must_not_be_writable('file1')
+ tc.pass_test()
+ """)
+ run_env.run(program=sys.executable, stdin=script)
+ stdout = run_env.stdout()
+ assert stdout == "Missing files: `file1'\n", stdout
+ stderr = run_env.stderr()
+ assert stderr.find("FAILED") != -1, stderr
+
+ def test_writable_file_exists(self):
+ """Test must_not_be_writable(): writable file exists"""
+ run_env = self.run_env
+
+ script = lstrip("""\
+ import os
+ import stat
+ from TestCommon import TestCommon
+ tc = TestCommon(workdir='')
+ tc.write('file1', "file1\\n")
+ f1 = tc.workpath('file1')
+ mode = os.stat(f1)[stat.ST_MODE]
+ os.chmod(f1, mode | stat.S_IWUSR)
+ tc.must_not_be_writable('file1')
+ tc.pass_test()
+ """)
+ run_env.run(program=sys.executable, stdin=script)
+ stdout = run_env.stdout()
+ assert stdout == "Writable files: `file1'\n", stdout
+ stderr = run_env.stderr()
+ assert stderr.find("FAILED") != -1, stderr
+
+ def test_non_writable_file_exists(self):
+ """Test must_not_be_writable(): non-writable file exists"""
+ run_env = self.run_env
+
+ script = lstrip("""\
+ import os
+ import stat
+ from TestCommon import TestCommon
+ tc = TestCommon(workdir='')
+ tc.write('file1', "file1\\n")
+ f1 = tc.workpath('file1')
+ mode = os.stat(f1)[stat.ST_MODE]
+ os.chmod(f1, mode & ~stat.S_IWUSR)
+ tc.must_not_be_writable('file1')
+ tc.pass_test()
+ """)
+ run_env.run(program=sys.executable, stdin=script)
+ stdout = run_env.stdout()
+ assert stdout == "", stdout
+ stderr = run_env.stderr()
+ assert stderr == "PASSED\n", stderr
+
+ def test_file_specified_as_list(self):
+ """Test must_not_be_writable(): file specified as list"""
+ run_env = self.run_env
+
+ script = lstrip("""\
+ import os
+ import stat
+ from TestCommon import TestCommon
+ tc = TestCommon(workdir='')
+ tc.subdir('sub')
+ tc.write(['sub', 'file1'], "sub/file1\\n")
+ f1 = tc.workpath('sub', 'file1')
+ mode = os.stat(f1)[stat.ST_MODE]
+ os.chmod(f1, mode & ~stat.S_IWUSR)
+ tc.must_not_be_writable(['sub', 'file1'])
+ tc.pass_test()
+ """)
+ run_env.run(program=sys.executable, stdin=script)
+ stdout = run_env.stdout()
+ assert stdout == "", stdout
+ stderr = run_env.stderr()
+ assert stderr == "PASSED\n", stderr
+
+
+
+class must_not_contain_TestCase(TestCommonTestCase):
+ def test_success(self):
+ """Test must_not_contain(): success"""
+ run_env = self.run_env
+
+ script = lstrip("""\
+ from TestCommon import TestCommon
+ tc = TestCommon(workdir='')
+ tc.write('file1', "file1 contents\\n")
+ tc.must_not_contain('file1', "1 does not contain c")
+ tc.pass_test()
+ """)
+ run_env.run(program=sys.executable, stdin=script)
+ stdout = run_env.stdout()
+ assert stdout == "", stdout
+ stderr = run_env.stderr()
+ assert stderr == "PASSED\n", stderr
+
+ def test_file_does_not_exist(self):
+ """Test must_not_contain(): file does not exist"""
+ run_env = self.run_env
+
+ script = lstrip("""\
+ from TestCommon import TestCommon
+ tc = TestCommon(workdir='')
+ tc.must_not_contain('file1', "1 c\\n")
+ tc.pass_test()
+ """)
+ run_env.run(program=sys.executable, stdin=script)
+ stdout = run_env.stdout()
+ assert stdout == "", stdout
+ stderr = run_env.stderr()
+ assert stderr.find("No such file or directory:") != -1, stderr
+
+ def test_failure(self):
+ """Test must_not_contain(): failure"""
+ run_env = self.run_env
+
+ script = lstrip("""\
+ from TestCommon import TestCommon
+ tc = TestCommon(workdir='')
+ tc.write('file1', "file1 does contain contents\\n")
+ tc.must_not_contain('file1', "1 does contain c")
+ tc.run()
+ """)
+ expect = lstrip("""\
+ File `file1' contains banned string.
+ Banned string ==================================================================
+ 1 does contain c
+ file1 contents =================================================================
+ file1 does contain contents
+
+ """)
+ run_env.run(program=sys.executable, stdin=script)
+ stdout = run_env.stdout()
+ assert stdout == expect, repr(stdout)
+ stderr = run_env.stderr()
+ assert stderr.find("FAILED") != -1, stderr
+
+ def test_mode(self):
+ """Test must_not_contain(): mode"""
+ run_env = self.run_env
+
+ script = lstrip("""\
+ from TestCommon import TestCommon
+ tc = TestCommon(workdir='')
+ tc.write('file1', "file1 contents\\n", mode='w')
+ tc.must_not_contain('file1', "1 does not contain c", mode='r')
+ tc.write('file2', "file2 contents\\n", mode='wb')
+ tc.must_not_contain('file2', "2 does not contain c", mode='rb')
+ tc.pass_test()
+ """)
+ run_env.run(program=sys.executable, stdin=script)
+ stdout = run_env.stdout()
+ assert stdout == "", stdout
+ stderr = run_env.stderr()
+ assert stderr == "PASSED\n", stderr
+
+
+
+class must_not_contain_any_line_TestCase(TestCommonTestCase):
+ def test_failure(self):
+ """Test must_not_contain_any_line(): failure"""
+ run_env = self.run_env
+
+ script = lstrip("""
+ import TestCommon
+ test = TestCommon.TestCommon(workdir='')
+
+ lines = [
+ 'xxx\\n',
+ 'yyy\\n',
+ 'www\\n',
+ ]
+
+ output = '''\\
+ www
+ xxx
+ yyy
+ zzz
+ '''
+
+ test.must_not_contain_any_line(output, lines)
+
+ test.pass_test()
+ """)
+
+ expect = lstrip("""\
+ Unexpected lines in output:
+ 'xxx%(expected_newline)s'
+ 'yyy%(expected_newline)s'
+ 'www%(expected_newline)s'
+ output =========================================================================
+ www
+ xxx
+ yyy
+ zzz
+ """ % globals())
+
+ run_env.run(program=sys.executable, stdin=script)
+ stdout = run_env.stdout()
+ stderr = run_env.stderr()
+ assert stdout == expect, assert_display(expect, stdout, stderr)
+ assert stderr.find("FAILED") != -1, stderr
+
+ def test_find(self):
+ """Test must_not_contain_any_line(): find"""
+ run_env = self.run_env
+
+ script = lstrip("""
+ import re
+ import TestCommon
+ test = TestCommon.TestCommon(workdir='')
+
+ lines = [
+ 'x.*'
+ '.*y'
+ ]
+
+ output = '''\\
+ www
+ zzz
+ '''
+
+ def re_search(output, line):
+ return re.compile(line, re.S).search(output)
+ test.must_not_contain_any_line(output, lines, find=re_search)
+
+ test.pass_test()
+ """)
+
+ run_env.run(program=sys.executable, stdin=script)
+ stdout = run_env.stdout()
+ assert stdout == "", stdout
+ stderr = run_env.stderr()
+ assert stderr == "PASSED\n", stderr
+
+ def test_success(self):
+ """Test must_not_contain_any_line(): success"""
+ run_env = self.run_env
+
+ script = lstrip("""
+ import TestCommon
+ test = TestCommon.TestCommon(workdir='')
+
+ lines = [
+ 'xxx\\n'
+ 'yyy\\n'
+ ]
+
+ output = '''\\
+ www
+ zzz
+ '''
+
+ test.must_not_contain_any_line(output, lines)
+
+ test.pass_test()
+ """)
+
+ run_env.run(program=sys.executable, stdin=script)
+ stdout = run_env.stdout()
+ assert stdout == "", stdout
+ stderr = run_env.stderr()
+ assert stderr == "PASSED\n", stderr
+
+ def test_title(self):
+ """Test must_not_contain_any_line(): title"""
+ run_env = self.run_env
+
+ script = lstrip("""
+ import TestCommon
+ test = TestCommon.TestCommon(workdir='')
+
+ lines = [
+ 'xxx\\n',
+ 'yyy\\n',
+ ]
+
+ output = '''\\
+ www
+ xxx
+ yyy
+ zzz
+ '''
+
+ test.must_not_contain_any_line(output, lines, title='XYZZY')
+
+ test.pass_test()
+ """)
+
+ expect = lstrip("""\
+ Unexpected lines in XYZZY:
+ 'xxx%(expected_newline)s'
+ 'yyy%(expected_newline)s'
+ XYZZY ==========================================================================
+ www
+ xxx
+ yyy
+ zzz
+ """ % globals())
+
+ run_env.run(program=sys.executable, stdin=script)
+ stdout = run_env.stdout()
+ stderr = run_env.stderr()
+ assert stdout == expect, assert_display(expect, stdout, stderr)
+ assert stderr.find("FAILED") != -1, stderr
+
+
+
+class must_not_contain_lines_TestCase(TestCommonTestCase):
+ def test_failure(self):
+ """Test must_not_contain_lines(): failure"""
+ run_env = self.run_env
+
+ script = lstrip("""
+ import TestCommon
+ test = TestCommon.TestCommon(workdir='')
+
+ lines = [
+ 'xxx\\n',
+ 'yyy\\n',
+ ]
+
+ output = '''\\
+ www
+ xxx
+ yyy
+ zzz
+ '''
+
+ test.must_not_contain_lines(lines, output)
+
+ test.pass_test()
+ """)
+
+ expect = lstrip("""\
+ Unexpected lines in output:
+ 'xxx%(expected_newline)s'
+ 'yyy%(expected_newline)s'
+ output =========================================================================
+ www
+ xxx
+ yyy
+ zzz
+ """ % globals())
+
+ run_env.run(program=sys.executable, stdin=script)
+ stdout = run_env.stdout()
+ stderr = run_env.stderr()
+ assert stdout == expect, assert_display(expect, stdout, stderr)
+ assert stderr.find("FAILED") != -1, stderr
+
+ def test_success(self):
+ """Test must_not_contain_lines(): success"""
+ run_env = self.run_env
+
+ script = lstrip("""
+ import TestCommon
+ test = TestCommon.TestCommon(workdir='')
+
+ lines = [
+ 'xxx\\n'
+ 'yyy\\n'
+ ]
+
+ output = '''\\
+ www
+ zzz
+ '''
+
+ test.must_not_contain_lines(lines, output)
+
+ test.pass_test()
+ """)
+
+ run_env.run(program=sys.executable, stdin=script)
+ stdout = run_env.stdout()
+ assert stdout == "", stdout
+ stderr = run_env.stderr()
+ assert stderr == "PASSED\n", stderr
+
+
+
+class must_not_exist_TestCase(TestCommonTestCase):
+ def test_failure(self):
+ """Test must_not_exist(): failure"""
+ run_env = self.run_env
+
+ script = lstrip("""\
+ from TestCommon import TestCommon
+ tc = TestCommon(workdir='')
+ tc.write('file1', "file1\\n")
+ tc.must_not_exist('file1')
+ tc.pass_test()
+ """)
+ run_env.run(program=sys.executable, stdin=script)
+ stdout = run_env.stdout()
+ assert stdout == "Unexpected files exist: `file1'\n", stdout
+ stderr = run_env.stderr()
+ assert stderr.find("FAILED") != -1, stderr
+
+ def test_success(self):
+ """Test must_not_exist(): success"""
+ run_env = self.run_env
+
+ script = lstrip("""\
+ from TestCommon import TestCommon
+ tc = TestCommon(workdir='')
+ tc.must_not_exist('file1')
+ tc.pass_test()
+ """)
+ run_env.run(program=sys.executable, stdin=script)
+ stdout = run_env.stdout()
+ assert stdout == "", stdout
+ stderr = run_env.stderr()
+ assert stderr == "PASSED\n", stderr
+
+ def test_file_specified_as_list(self):
+ """Test must_not_exist(): file specified as list"""
+ run_env = self.run_env
+
+ script = lstrip("""\
+ from TestCommon import TestCommon
+ tc = TestCommon(workdir='')
+ tc.subdir('sub')
+ tc.must_not_exist(['sub', 'file1'])
+ tc.pass_test()
+ """)
+ run_env.run(program=sys.executable, stdin=script)
+ stdout = run_env.stdout()
+ assert stdout == "", stdout
+ stderr = run_env.stderr()
+ assert stderr == "PASSED\n", stderr
+
+
+
+class run_TestCase(TestCommonTestCase):
+ def test_argument_handling(self):
+ """Test run(): argument handling"""
+
+ script = lstrip("""\
+ from TestCommon import TestCommon, match_exact
+ tc = TestCommon(program=r'%(pass_script)s',
+ interpreter='%(python)s',
+ workdir="",
+ match=match_exact)
+ tc.run(arguments = "arg1 arg2 arg3",
+ stdout = r"%(pass_script)s: STDOUT: ['arg1', 'arg2', 'arg3']" + "\\n")
+ """)
+
+ self.run_execution_test(script, "", "")
+
+ def test_default_pass(self):
+ """Test run(): default arguments, script passes"""
+
+ script = lstrip("""\
+ from TestCommon import TestCommon
+ tc = TestCommon(program=r'%(pass_script)s',
+ interpreter=r'%(python)s',
+ workdir='')
+ tc.run()
+ """)
+
+ self.run_execution_test(script, "", "")
+
+ def test_default_fail(self):
+ """Test run(): default arguments, script fails"""
+
+ script = lstrip("""\
+ from TestCommon import TestCommon
+ tc = TestCommon(program=r'%(fail_script)s',
+ interpreter='%(python)s',
+ workdir='')
+ tc.run()
+ """)
+
+ expect_stdout = lstrip("""\
+ %(fail_script)s returned 1
+ STDOUT =========================================================================
+ %(fail_script)s: STDOUT: []
+
+ STDERR =========================================================================
+
+ """)
+
+ expect_stderr = lstrip("""\
+ FAILED test of .*fail
+ \\tat line \\d+ of .*TestCommon\\.py \\(_complete\\)
+ \\tfrom line \\d+ of .*TestCommon\\.py \\(run\\)
+ \\tfrom line \\d+ of <stdin>( \(<module>\))?
+ """)
+ expect_stderr = re.compile(expect_stderr, re.M)
+
+ self.run_execution_test(script, expect_stdout, expect_stderr)
+
+ def test_default_stderr(self):
+ """Test run(): default arguments, error output"""
+ script = lstrip("""\
+ from TestCommon import TestCommon
+ tc = TestCommon(program=r'%(stderr_script)s',
+ interpreter='%(python)s',
+ workdir='')
+ tc.run()
+ """)
+
+ expect_stdout = lstrip("""\
+ STDOUT =========================================================================
+
+ STDERR =========================================================================
+ 0a1
+ > %(stderr_script)s: STDERR: []
+ """)
+
+ expect_stderr = lstrip("""\
+ FAILED test of .*stderr
+ \\tat line \\d+ of .*TestCommon\\.py \\(_complete\\)
+ \\tfrom line \\d+ of .*TestCommon\\.py \\(run\\)
+ \\tfrom line \\d+ of <stdin>
+ """)
+ expect_stderr = re.compile(expect_stderr, re.M)
+
+ self.run_execution_test(script, expect_stdout, expect_stderr)
+
+ def test_exception_handling(self):
+ """Test run(): exception handling"""
+ script = lstrip("""\
+ import TestCmd
+ from TestCommon import TestCommon
+ def raise_exception(*args, **kw):
+ raise TypeError("forced TypeError")
+ TestCmd.TestCmd.start = raise_exception
+ tc = TestCommon(program='%(pass_script)s',
+ interpreter='%(python)s',
+ workdir='')
+ tc.run()
+ """)
+
+ expect_stdout = lstrip("""\
+ STDOUT =========================================================================
+ STDERR =========================================================================
+ """)
+
+ expect_stderr = lstrip("""\
+ Exception trying to execute: \\[%s, '[^']*pass'\\]
+ Traceback \\((innermost|most recent call) last\\):
+ File "<stdin>", line \\d+, in (\\?|<module>)
+ File "[^"]+TestCommon.py", line \\d+, in run
+ TestCmd.run\\(self, \\*\\*kw\\)
+ File "[^"]+TestCmd.py", line \\d+, in run
+ .*
+ File "[^"]+TestCommon.py", line \\d+, in start
+ raise e
+ TypeError: forced TypeError
+ """ % re.escape(repr(sys.executable)))
+ expect_stderr = re.compile(expect_stderr, re.M)
+
+ self.run_execution_test(script, expect_stdout, expect_stderr)
+
+ def test_ignore_stderr(self):
+ """Test run(): ignore stderr"""
+
+ script = lstrip("""\
+ from TestCommon import TestCommon
+ tc = TestCommon(program=r'%(stderr_script)s',
+ interpreter='%(python)s',
+ workdir='')
+ tc.run(stderr = None)
+ """)
+
+ self.run_execution_test(script, "", "")
+
+ def test_match_function_stdout(self):
+ """Test run(): explicit match function, stdout"""
+
+ script = lstrip("""\
+ def my_match_exact(actual, expect): return actual == expect
+ from TestCommon import TestCommon, match_re_dotall
+ tc = TestCommon(program=r'%(pass_script)s',
+ interpreter='%(python)s',
+ workdir="",
+ match=match_re_dotall)
+ tc.run(arguments = "arg1 arg2 arg3",
+ stdout = r"%(pass_script)s: STDOUT: ['arg1', 'arg2', 'arg3']" + "\\n",
+ match = my_match_exact)
+ """)
+
+ self.run_execution_test(script, "", "")
+
+ def test_match_function_stderr(self):
+ """Test run(): explicit match function, stderr"""
+
+ script = lstrip("""\
+ def my_match_exact(actual, expect): return actual == expect
+ from TestCommon import TestCommon, match_re_dotall
+ tc = TestCommon(program=r'%(stderr_script)s',
+ interpreter='%(python)s',
+ workdir="",
+ match=match_re_dotall)
+ tc.run(arguments = "arg1 arg2 arg3",
+ stderr = r"%(stderr_script)s: STDERR: ['arg1', 'arg2', 'arg3']" + "\\n",
+ match = my_match_exact)
+ """)
+
+ self.run_execution_test(script, "", "")
+
+ def test_matched_status_fails(self):
+ """Test run(): matched status, script fails"""
+
+ script = lstrip("""\
+ from TestCommon import TestCommon
+ tc = TestCommon(program=r'%(fail_script)s',
+ interpreter='%(python)s',
+ workdir='')
+ tc.run(status = 1)
+ """)
+
+ self.run_execution_test(script, "", "")
+
+ def test_matched_stdout(self):
+ """Test run(): matched stdout"""
+
+ script = lstrip("""\
+ from TestCommon import TestCommon, match_exact
+ tc = TestCommon(program=r'%(pass_script)s',
+ interpreter='%(python)s',
+ workdir="",
+ match=match_exact)
+ tc.run(stdout = r"%(pass_script)s: STDOUT: []" + "\\n")
+ """)
+
+ self.run_execution_test(script, "", "")
+
+ def test_matched_stderr(self):
+ """Test run(): matched stderr"""
+
+ script = lstrip("""\
+ from TestCommon import TestCommon, match_exact
+ tc = TestCommon(program=r'%(stderr_script)s',
+ interpreter='%(python)s',
+ workdir="",
+ match=match_exact)
+ tc.run(stderr = r"%(stderr_script)s: STDERR: []" + "\\n")
+ """)
+
+ self.run_execution_test(script, "", "")
+
+ def test_mismatched_status_pass(self):
+ """Test run(): mismatched status, script passes"""
+
+ script = lstrip("""\
+ from TestCommon import TestCommon
+ tc = TestCommon(program=r'%(pass_script)s',
+ interpreter='%(python)s',
+ workdir='')
+ tc.run(status = 1)
+ """)
+
+ expect_stdout = lstrip("""\
+ %(pass_script)s returned 0 (expected 1)
+ STDOUT =========================================================================
+ %(pass_script)s: STDOUT: []
+
+ STDERR =========================================================================
+
+ """)
+
+ expect_stderr = lstrip("""\
+ FAILED test of .*pass
+ \\tat line \\d+ of .*TestCommon\\.py \\(_complete\\)
+ \\tfrom line \\d+ of .*TestCommon\\.py \\(run\\)
+ \\tfrom line \\d+ of <stdin>( \(<module>\))?
+ """)
+ expect_stderr = re.compile(expect_stderr, re.M)
+
+ self.run_execution_test(script, expect_stdout, expect_stderr)
+
+ def test_mismatched_status_fail(self):
+ """Test run(): mismatched status, script fails"""
+
+ script = lstrip("""\
+ from TestCommon import TestCommon
+ tc = TestCommon(program=r'%(fail_script)s',
+ interpreter='%(python)s',
+ workdir='')
+ tc.run(status = 2)
+ """)
+
+ expect_stdout = lstrip("""\
+ %(fail_script)s returned 1 (expected 2)
+ STDOUT =========================================================================
+ %(fail_script)s: STDOUT: []
+
+ STDERR =========================================================================
+
+ """)
+
+ expect_stderr = lstrip("""\
+ FAILED test of .*fail
+ \\tat line \\d+ of .*TestCommon\\.py \\(_complete\\)
+ \\tfrom line \\d+ of .*TestCommon\\.py \\(run\\)
+ \\tfrom line \\d+ of <stdin>( \(<module>\))?
+ """)
+ expect_stderr = re.compile(expect_stderr, re.M)
+
+ self.run_execution_test(script, expect_stdout, expect_stderr)
+
+ def test_mismatched_stdout(self):
+ """Test run(): mismatched stdout"""
+
+ script = lstrip("""\
+ from TestCommon import TestCommon
+ tc = TestCommon(program=r'%(pass_script)s',
+ interpreter='%(python)s',
+ workdir='')
+ tc.run(stdout = "Not found\\n")
+ """)
+
+ expect_stdout = lstrip("""\
+ STDOUT =========================================================================
+ 1c1
+ < Not found
+ ---
+ > %(pass_script)s: STDOUT: []
+ """)
+
+ expect_stderr = lstrip("""\
+ FAILED test of .*pass
+ \\tat line \\d+ of .*TestCommon\\.py \\(_complete\\)
+ \\tfrom line \\d+ of .*TestCommon\\.py \\(run\\)
+ \\tfrom line \\d+ of <stdin>( \(<module>\))?
+ """)
+ expect_stderr = re.compile(expect_stderr, re.M)
+
+ self.run_execution_test(script, expect_stdout, expect_stderr)
+
+ def test_mismatched_stderr(self):
+ """Test run(): mismatched stderr"""
+
+ script = lstrip("""\
+ from TestCommon import TestCommon
+ tc = TestCommon(program=r'%(stderr_script)s',
+ interpreter='%(python)s',
+ workdir='')
+ tc.run(stderr = "Not found\\n")
+ """)
+
+ expect_stdout = lstrip("""\
+ STDOUT =========================================================================
+
+ STDERR =========================================================================
+ 1c1
+ < Not found
+ ---
+ > %(stderr_script)s: STDERR: []
+ """)
+
+ expect_stderr = lstrip("""\
+ FAILED test of .*stderr
+ \\tat line \\d+ of .*TestCommon\\.py \\(_complete\\)
+ \\tfrom line \\d+ of .*TestCommon\\.py \\(run\\)
+ \\tfrom line \\d+ of <stdin>( \(<module>\))?
+ """)
+ expect_stderr = re.compile(expect_stderr, re.M)
+
+ self.run_execution_test(script, expect_stdout, expect_stderr)
+
+ def test_option_handling(self):
+ """Test run(): option handling"""
+
+ script = lstrip("""\
+ from TestCommon import TestCommon, match_exact
+ tc = TestCommon(program=r'%(pass_script)s',
+ interpreter='%(python)s',
+ workdir="",
+ match=match_exact)
+ tc.run(options = "opt1 opt2 opt3",
+ stdout = r"%(pass_script)s: STDOUT: ['opt1', 'opt2', 'opt3']" + "\\n")
+ """)
+
+ self.run_execution_test(script, "", "")
+
+ def test_options_plus_arguments(self):
+ """Test run(): option handling with arguments"""
+
+ script = lstrip("""\
+ from TestCommon import TestCommon, match_exact
+ tc = TestCommon(program=r'%(pass_script)s',
+ interpreter='%(python)s',
+ workdir="",
+ match=match_exact)
+ tc.run(options = "opt1 opt2 opt3",
+ arguments = "arg1 arg2 arg3",
+ stdout = r"%(pass_script)s: STDOUT: ['opt1', 'opt2', 'opt3', 'arg1', 'arg2', 'arg3']" + "\\n")
+ """)
+
+ self.run_execution_test(script, "", "")
+
+ def test_signal_handling(self):
+ """Test run(): signal handling"""
+
+ try:
+ os.kill
+ except AttributeError:
+ sys.stderr.write('can not test, no os.kill ... ')
+ return
+
+ script = lstrip("""\
+ from TestCommon import TestCommon
+ tc = TestCommon(program=r'%(signal_script)s',
+ interpreter='%(python)s',
+ workdir='')
+ tc.run()
+ """)
+
+ self.SIGTERM = signal.SIGTERM
+
+ # Script returns the signal value as a negative number.
+ expect_stdout = lstrip("""\
+ %(signal_script)s returned -%(SIGTERM)s
+ STDOUT =========================================================================
+
+ STDERR =========================================================================
+
+ """)
+
+ expect_stderr = lstrip("""\
+ FAILED test of .*signal
+ \\tat line \\d+ of .*TestCommon\\.py \\(_complete\\)
+ \\tfrom line \\d+ of .*TestCommon\\.py \\(run\\)
+ \\tfrom line \\d+ of <stdin>
+ """)
+ expect_stderr = re.compile(expect_stderr, re.M)
+
+ self.run_execution_test(script, expect_stdout, expect_stderr)
+
+ def test_stdin(self):
+ """Test run(): stdin handling"""
+
+ script = lstrip("""\
+ from TestCommon import TestCommon, match_exact
+ tc = TestCommon(program=r'%(stdin_script)s',
+ interpreter='%(python)s',
+ workdir='',
+ match=match_exact)
+ expect_stdout = r"%(stdin_script)s: STDOUT: 'input'" + "\\n"
+ expect_stderr = r"%(stdin_script)s: STDERR: 'input'" + "\\n"
+ tc.run(stdin="input\\n", stdout = expect_stdout, stderr = expect_stderr)
+ """)
+
+ expect_stdout = lstrip("""\
+ %(pass_script)s returned 0 (expected 1)
+ STDOUT =========================================================================
+ %(pass_script)s: STDOUT: []
+
+ STDERR =========================================================================
+
+ """)
+
+ self.run_execution_test(script, "", "")
+
+
+
+class start_TestCase(TestCommonTestCase):
+ def test_option_handling(self):
+ """Test start(): option handling"""
+
+ script = lstrip("""\
+ from TestCommon import TestCommon, match_exact
+ tc = TestCommon(program=r'%(pass_script)s',
+ interpreter='%(python)s',
+ workdir="",
+ match=match_exact)
+ p = tc.start(options = "opt1 opt2 opt3")
+ expect = r"%(pass_script)s: STDOUT: ['opt1', 'opt2', 'opt3']" + "\\n"
+ tc.finish(p, stdout = expect)
+ """)
+
+ self.run_execution_test(script, "", "")
+
+ def test_options_plus_arguments(self):
+ """Test start(): option handling with arguments"""
+
+ script = lstrip("""\
+ from TestCommon import TestCommon, match_exact
+ tc = TestCommon(program=r'%(pass_script)s',
+ interpreter='%(python)s',
+ workdir="",
+ match=match_exact)
+ p = tc.start(options = "opt1 opt2 opt3",
+ arguments = "arg1 arg2 arg3")
+ expect = r"%(pass_script)s: STDOUT: ['opt1', 'opt2', 'opt3', 'arg1', 'arg2', 'arg3']" + "\\n"
+ tc.finish(p, stdout = expect)
+ """)
+
+ self.run_execution_test(script, "", "")
+
+
+
+class skip_test_TestCase(TestCommonTestCase):
+ def test_skip_test(self):
+ """Test skip_test()"""
+ run_env = self.run_env
+
+ script = lstrip("""\
+ import TestCommon
+ test = TestCommon.TestCommon(workdir='')
+ test.skip_test()
+ """)
+ run_env.run(program=sys.executable, stdin=script)
+ stdout = run_env.stdout()
+ assert stdout == "Skipping test.\n", stdout
+ stderr = run_env.stderr()
+ expect = [
+ "NO RESULT for test at line 3 of <stdin>\n",
+ "NO RESULT for test at line 3 of <stdin> (<module>)\n",
+ ]
+ assert stderr in expect, repr(stderr)
+
+ script = lstrip("""\
+ import TestCommon
+ test = TestCommon.TestCommon(workdir='')
+ test.skip_test("skipping test because I said so\\n")
+ """)
+ run_env.run(program=sys.executable, stdin=script)
+ stdout = run_env.stdout()
+ assert stdout == "skipping test because I said so\n", stdout
+ stderr = run_env.stderr()
+ expect = [
+ "NO RESULT for test at line 3 of <stdin>\n",
+ "NO RESULT for test at line 3 of <stdin> (<module>)\n",
+ ]
+ assert stderr in expect, repr(stderr)
+
+ import os
+ os.environ['TESTCOMMON_PASS_SKIPS'] = '1'
+
+ try:
+ script = lstrip("""\
+ import TestCommon
+ test = TestCommon.TestCommon(workdir='')
+ test.skip_test()
+ """)
+ run_env.run(program=sys.executable, stdin=script)
+ stdout = run_env.stdout()
+ assert stdout == "Skipping test.\n", stdout
+ stderr = run_env.stderr()
+ assert stderr == "PASSED\n", stderr
+
+ finally:
+ del os.environ['TESTCOMMON_PASS_SKIPS']
+
+
+
+class variables_TestCase(TestCommonTestCase):
+ def test_variables(self):
+ """Test global variables"""
+ run_env = self.run_env
+
+ variables = [
+ 'fail_test',
+ 'no_result',
+ 'pass_test',
+ 'match_exact',
+ 'match_re',
+ 'match_re_dotall',
+ 'python',
+ '_python_',
+ 'TestCmd',
+
+ 'TestCommon',
+ 'exe_suffix',
+ 'obj_suffix',
+ 'shobj_prefix',
+ 'shobj_suffix',
+ 'lib_prefix',
+ 'lib_suffix',
+ 'dll_prefix',
+ 'dll_suffix',
+ ]
+
+ script = "import TestCommon\n" + \
+ '\n'.join([ "print TestCommon.%s\n" % v for v in variables ])
+ run_env.run(program=sys.executable, stdin=script)
+ stderr = run_env.stderr()
+ assert stderr == "", stderr
+
+ script = "from TestCommon import *\n" + \
+ '\n'.join([ "print %s" % v for v in variables ])
+ run_env.run(program=sys.executable, stdin=script)
+ stderr = run_env.stderr()
+ assert stderr == "", stderr
+
+
+
+if __name__ == "__main__":
+ tclasses = [
+ __init__TestCase,
+ banner_TestCase,
+ must_be_writable_TestCase,
+ must_contain_TestCase,
+ must_contain_all_lines_TestCase,
+ must_contain_any_line_TestCase,
+ must_contain_exactly_lines_TestCase,
+ must_contain_lines_TestCase,
+ must_exist_TestCase,
+ must_match_TestCase,
+ must_not_be_writable_TestCase,
+ must_not_contain_TestCase,
+ must_not_contain_any_line_TestCase,
+ must_not_contain_lines_TestCase,
+ must_not_exist_TestCase,
+ run_TestCase,
+ start_TestCase,
+ skip_test_TestCase,
+ variables_TestCase,
+ ]
+ suite = unittest.TestSuite()
+ for tclass in tclasses:
+ names = unittest.getTestCaseNames(tclass, 'test_')
+ suite.addTests([ tclass(n) for n in names ])
+ if not unittest.TextTestRunner().run(suite).wasSuccessful():
+ sys.exit(1)
+
+# Local Variables:
+# tab-width:4
+# indent-tabs-mode:nil
+# End:
+# vim: set expandtab tabstop=4 shiftwidth=4:
diff --git a/src/engine/SCons/Scanner/LaTeX.py b/src/engine/SCons/Scanner/LaTeX.py
index d3c5c9a..b8d48b1 100644
--- a/src/engine/SCons/Scanner/LaTeX.py
+++ b/src/engine/SCons/Scanner/LaTeX.py
@@ -168,8 +168,11 @@ class LaTeX(SCons.Scanner.Base):
# Without the \n, the ^ could match the beginning of a *previous*
# line followed by one or more newline characters (i.e. blank
# lines), interfering with a match on the next line.
- regex = r'^[^%\n]*\\(include|includegraphics(?:\[[^\]]+\])?|lstinputlisting(?:\[[^\]]+\])?|input|bibliography|usepackage){([^}]*)}'
+ # add option for whitespace before the '[options]' or the '{filename}'
+ regex = r'^[^%\n]*\\(include|includegraphics(?:\s*\[[^\]]+\])?|lstinputlisting(?:\[[^\]]+\])?|input|bibliography|usepackage)\s*{([^}]*)}'
self.cre = re.compile(regex, re.M)
+ self.comment_re = re.compile(r'^((?:(?:\\%)|[^%\n])*)(.*)$', re.M)
+
self.graphics_extensions = graphics_extensions
def _scan(node, env, path=(), self=self):
@@ -274,6 +277,23 @@ class LaTeX(SCons.Scanner.Base):
return i, include
return i, include
+ def canonical_text(self, text):
+ """Standardize an input TeX-file contents.
+
+ Currently:
+ * removes comments, unwrapping comment-wrapped lines.
+ """
+ out = []
+ line_continues_a_comment = False
+ for line in text.splitlines():
+ line,comment = self.comment_re.findall(line)[0]
+ if line_continues_a_comment == True:
+ out[-1] = out[-1] + line.lstrip()
+ else:
+ out.append(line)
+ line_continues_a_comment = len(comment) > 0
+ return '\n'.join(out).rstrip()+'\n'
+
def scan(self, node):
# Modify the default scan function to allow for the regular
# expression to return a comma separated list of file names
@@ -281,11 +301,13 @@ class LaTeX(SCons.Scanner.Base):
# Cache the includes list in node so we only scan it once:
# path_dict = dict(list(path))
- noopt_cre = re.compile('\[.*$')
+ # add option for whitespace (\s) before the '['
+ noopt_cre = re.compile('\s*\[.*$')
if node.includes != None:
includes = node.includes
else:
- includes = self.cre.findall(node.get_text_contents())
+ text = self.canonical_text(node.get_text_contents())
+ includes = self.cre.findall(text)
# 1. Split comma-separated lines, e.g.
# ('bibliography', 'phys,comp')
# should become two entries
diff --git a/src/engine/SCons/Tool/tex.py b/src/engine/SCons/Tool/tex.py
index a2870b5..37881bb 100644
--- a/src/engine/SCons/Tool/tex.py
+++ b/src/engine/SCons/Tool/tex.py
@@ -38,6 +38,7 @@ import os.path
import re
import shutil
import sys
+import platform
import SCons.Action
import SCons.Node
@@ -757,45 +758,50 @@ def generate_common(env):
if MakeAcronymsAction is None:
MakeAcronymsAction = SCons.Action.Action("$MAKEACRONYMSCOM", "$MAKEACRONYMSCOMSTR")
+ CDCOM = 'cd '
+ if platform.system() == 'Windows':
+ # allow cd command to change drives on Windows
+ CDCOM = 'cd /D '
+
env['TEX'] = 'tex'
env['TEXFLAGS'] = SCons.Util.CLVar('-interaction=nonstopmode -recorder')
- env['TEXCOM'] = 'cd ${TARGET.dir} && $TEX $TEXFLAGS ${SOURCE.file}'
+ env['TEXCOM'] = CDCOM + '${TARGET.dir} && $TEX $TEXFLAGS ${SOURCE.file}'
env['PDFTEX'] = 'pdftex'
env['PDFTEXFLAGS'] = SCons.Util.CLVar('-interaction=nonstopmode -recorder')
- env['PDFTEXCOM'] = 'cd ${TARGET.dir} && $PDFTEX $PDFTEXFLAGS ${SOURCE.file}'
+ env['PDFTEXCOM'] = CDCOM + '${TARGET.dir} && $PDFTEX $PDFTEXFLAGS ${SOURCE.file}'
env['LATEX'] = 'latex'
env['LATEXFLAGS'] = SCons.Util.CLVar('-interaction=nonstopmode -recorder')
- env['LATEXCOM'] = 'cd ${TARGET.dir} && $LATEX $LATEXFLAGS ${SOURCE.file}'
+ env['LATEXCOM'] = CDCOM + '${TARGET.dir} && $LATEX $LATEXFLAGS ${SOURCE.file}'
env['LATEXRETRIES'] = 3
env['PDFLATEX'] = 'pdflatex'
env['PDFLATEXFLAGS'] = SCons.Util.CLVar('-interaction=nonstopmode -recorder')
- env['PDFLATEXCOM'] = 'cd ${TARGET.dir} && $PDFLATEX $PDFLATEXFLAGS ${SOURCE.file}'
+ env['PDFLATEXCOM'] = CDCOM + '${TARGET.dir} && $PDFLATEX $PDFLATEXFLAGS ${SOURCE.file}'
env['BIBTEX'] = 'bibtex'
env['BIBTEXFLAGS'] = SCons.Util.CLVar('')
- env['BIBTEXCOM'] = 'cd ${TARGET.dir} && $BIBTEX $BIBTEXFLAGS ${SOURCE.filebase}'
+ env['BIBTEXCOM'] = CDCOM + '${TARGET.dir} && $BIBTEX $BIBTEXFLAGS ${SOURCE.filebase}'
env['MAKEINDEX'] = 'makeindex'
env['MAKEINDEXFLAGS'] = SCons.Util.CLVar('')
- env['MAKEINDEXCOM'] = 'cd ${TARGET.dir} && $MAKEINDEX $MAKEINDEXFLAGS ${SOURCE.file}'
+ env['MAKEINDEXCOM'] = CDCOM + '${TARGET.dir} && $MAKEINDEX $MAKEINDEXFLAGS ${SOURCE.file}'
env['MAKEGLOSSARY'] = 'makeindex'
env['MAKEGLOSSARYSTYLE'] = '${SOURCE.filebase}.ist'
env['MAKEGLOSSARYFLAGS'] = SCons.Util.CLVar('-s ${MAKEGLOSSARYSTYLE} -t ${SOURCE.filebase}.glg')
- env['MAKEGLOSSARYCOM'] = 'cd ${TARGET.dir} && $MAKEGLOSSARY ${SOURCE.filebase}.glo $MAKEGLOSSARYFLAGS -o ${SOURCE.filebase}.gls'
+ env['MAKEGLOSSARYCOM'] = CDCOM + '${TARGET.dir} && $MAKEGLOSSARY ${SOURCE.filebase}.glo $MAKEGLOSSARYFLAGS -o ${SOURCE.filebase}.gls'
env['MAKEACRONYMS'] = 'makeindex'
env['MAKEACRONYMSSTYLE'] = '${SOURCE.filebase}.ist'
env['MAKEACRONYMSFLAGS'] = SCons.Util.CLVar('-s ${MAKEACRONYMSSTYLE} -t ${SOURCE.filebase}.alg')
- env['MAKEACRONYMSCOM'] = 'cd ${TARGET.dir} && $MAKEACRONYMS ${SOURCE.filebase}.acn $MAKEACRONYMSFLAGS -o ${SOURCE.filebase}.acr'
+ env['MAKEACRONYMSCOM'] = CDCOM + '${TARGET.dir} && $MAKEACRONYMS ${SOURCE.filebase}.acn $MAKEACRONYMSFLAGS -o ${SOURCE.filebase}.acr'
env['MAKENCL'] = 'makeindex'
env['MAKENCLSTYLE'] = 'nomencl.ist'
env['MAKENCLFLAGS'] = '-s ${MAKENCLSTYLE} -t ${SOURCE.filebase}.nlg'
- env['MAKENCLCOM'] = 'cd ${TARGET.dir} && $MAKENCL ${SOURCE.filebase}.nlo $MAKENCLFLAGS -o ${SOURCE.filebase}.nls'
+ env['MAKENCLCOM'] = CDCOM + '${TARGET.dir} && $MAKENCL ${SOURCE.filebase}.nlo $MAKENCLFLAGS -o ${SOURCE.filebase}.nls'
def exists(env):
return env.Detect('tex')
diff --git a/src/test_strings.py b/src/test_strings.py
index 0b39592..26cd2ad 100644
--- a/src/test_strings.py
+++ b/src/test_strings.py
@@ -211,7 +211,9 @@ check_list = [
'QMTest/classes.qmc',
'QMTest/configuration',
'QMTest/TestCmd.py',
+ 'QMTest/TestCmdTests.py',
'QMTest/TestCommon.py',
+ 'QMTest/TestCommonTests.py',
'src/os_spawnv_fix.diff',
'src/MANIFEST.in',
'src/setup.cfg',
diff --git a/test/SConstruct.py b/test/SConstruct.py
index f061728..15e1c1b 100644
--- a/test/SConstruct.py
+++ b/test/SConstruct.py
@@ -27,16 +27,15 @@ __revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__"
import TestCmd
import TestSCons
-test = TestSCons.TestSCons(match = TestCmd.match_re)
+test = TestSCons.TestSCons()
test.run(arguments = ".",
status = 2,
stdout = "",
stderr = r"""
scons: \*\*\* No SConstruct file found.
-""" + TestSCons.file_expr)
-
-test.match_function = TestCmd.match_exact
+""" + TestSCons.file_expr,
+ match = TestCmd.match_re)
wpath = test.workpath()
diff --git a/test/TEX/eps_graphics2.py b/test/TEX/eps_graphics2.py
index d291b0b..d388b69 100644
--- a/test/TEX/eps_graphics2.py
+++ b/test/TEX/eps_graphics2.py
@@ -158,7 +158,9 @@ To get a hard copy of this report call me.
\begin{figure}[htbp]
\begin{center}
-\includegraphics{Fig1}
+\includegraphics
+ [width=.5\textwidth]
+ {Fig1}
\caption{Zone and Node indexing}
\label{fig1}
\end{center}
@@ -170,7 +172,7 @@ All done now.
""")
# makeindex will write status messages to stderr (grrr...), so ignore it.
-test.run(arguments = '.', stderr=None)
+test.run(arguments = 'docs/test.pdf', stderr=None)
# All (?) the files we expect will get created in the docs directory
diff --git a/test/TEX/multi-line_include_options.py b/test/TEX/multi-line_include_options.py
new file mode 100644
index 0000000..7d536dc
--- /dev/null
+++ b/test/TEX/multi-line_include_options.py
@@ -0,0 +1,90 @@
+#!/usr/bin/env python
+#
+# __COPYRIGHT__
+#
+# Permission is hereby granted, free of charge, to any person obtaining
+# a copy of this software and associated documentation files (the
+# "Software"), to deal in the Software without restriction, including
+# without limitation the rights to use, copy, modify, merge, publish,
+# distribute, sublicense, and/or sell copies of the Software, and to
+# permit persons to whom the Software is furnished to do so, subject to
+# the following conditions:
+#
+# The above copyright notice and this permission notice shall be included
+# in all copies or substantial portions of the Software.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY
+# KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
+# WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+#
+
+__revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__"
+
+"""
+When an inclusion's optional argument (enclosed in square brackets:
+[]) spans multiple lines (via comment wrapping), ensure that the LaTeX
+Scanner doesn't throw an IndexError.
+
+An example of this in the wild is in Thomas Heim's epsdice LaTeX package:
+ \includegraphics[height=1.75ex,viewport= 3 4 38 39,%
+ clip=true]{\dicefile}%
+In epsdice 2007/02/15, v. 2.1.
+"""
+
+import TestSCons
+
+_exe = TestSCons._exe
+
+test = TestSCons.TestSCons()
+
+latex = test.where_is('latex')
+
+if not latex:
+ test.skip_test("Could not find latex; skipping test(s).\n")
+
+test.write('SConstruct', """\
+import os
+env = Environment(ENV = { 'PATH' : os.environ['PATH'] })
+env.DVI('root.tex')
+""")
+
+test.write('root.tex',
+r"""\documentclass{article}
+\usepackage{graphicx}
+\begin{document}
+ \includegraphics[height=1.75ex,%
+ clip=true]{square}
+\end{document}
+""")
+
+# Dummy EPS file drawing a square
+test.write('square.eps',
+r"""%!PS-Adobe-2.0 EPSF-1.2
+%%BoundingBox: 0 0 20 20
+ newpath
+ 5 5 moveto
+ 15 5 lineto
+ 15 15 lineto
+ 5 15 lineto
+ 5 5 lineto
+ stroke
+%%EOF
+""")
+
+test.run(arguments = '.')
+
+test.must_exist(test.workpath('root.dvi'))
+test.must_exist(test.workpath('root.log'))
+
+test.pass_test()
+
+# Local Variables:
+# tab-width:4
+# indent-tabs-mode:nil
+# End:
+# vim: set expandtab tabstop=4 shiftwidth=4:
+
diff --git a/test/option-n.py b/test/option-n.py
index b8dde0f..a32dfb7 100644
--- a/test/option-n.py
+++ b/test/option-n.py
@@ -168,8 +168,8 @@ test.fail_test(os.path.exists(test.workpath('build', 'f4.in')))
# test Configure-calls in conjunction with -n
test.subdir('configure')
-test.match_function = TestSCons.match_re_dotall
-test.diff_function = TestSCons.diff_re
+test.set_match_function(TestSCons.match_re_dotall)
+test.set_diff_function(TestSCons.diff_re)
test.write('configure/SConstruct',
"""def CustomTest(context):
def userAction(target,source,env):