Refactors run_tests.py s.t. it can be shared by gmock (by Vlad Losev); Fixes a warning in gtest-tuple_test.cc on Cygwin (by Vlad Losev).
This commit is contained in:
parent
b6fe6899be
commit
2e075a7f60
|
@ -11,6 +11,7 @@ EXTRA_DIST = \
|
||||||
include/gtest/internal/gtest-type-util.h.pump \
|
include/gtest/internal/gtest-type-util.h.pump \
|
||||||
include/gtest/internal/gtest-param-util-generated.h.pump \
|
include/gtest/internal/gtest-param-util-generated.h.pump \
|
||||||
make/Makefile \
|
make/Makefile \
|
||||||
|
run_tests.py \
|
||||||
scons/SConscript \
|
scons/SConscript \
|
||||||
scons/SConstruct \
|
scons/SConstruct \
|
||||||
scons/SConstruct.common \
|
scons/SConstruct.common \
|
||||||
|
@ -432,6 +433,10 @@ test_gtest_xml_output_unittest__LDADD = lib/libgtest.la
|
||||||
check_SCRIPTS += test/gtest_xml_output_unittest.py
|
check_SCRIPTS += test/gtest_xml_output_unittest.py
|
||||||
TESTS += test/gtest_xml_output_unittest.py
|
TESTS += test/gtest_xml_output_unittest.py
|
||||||
|
|
||||||
|
check_SCRIPTS += test/run_tests_util.py \
|
||||||
|
test/run_tests_util_test.py
|
||||||
|
TESTS += test/run_tests_util_test.py
|
||||||
|
|
||||||
# TODO(wan@google.com): make the build script compile and run the
|
# TODO(wan@google.com): make the build script compile and run the
|
||||||
# negative-compilation tests. (The test/gtest_nc* files are unfinished
|
# negative-compilation tests. (The test/gtest_nc* files are unfinished
|
||||||
# implementation of tests for verifying that certain kinds of misuse
|
# implementation of tests for verifying that certain kinds of misuse
|
||||||
|
|
405
run_tests.py
405
run_tests.py
|
@ -28,415 +28,26 @@
|
||||||
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||||
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
|
||||||
"""Runs specified tests for Google Test.
|
"""Runs the specified tests for Google Test.
|
||||||
|
|
||||||
SYNOPSIS
|
This script requires Python 2.3 or higher. To learn the usage, run it
|
||||||
run_tests.py [OPTION]... [BUILD_DIR]... [TEST]...
|
with -h.
|
||||||
|
|
||||||
DESCRIPTION
|
|
||||||
Runs the specified tests (either binary or Python), and prints a
|
|
||||||
summary of the results. BUILD_DIRS will be used to search for the
|
|
||||||
binaries. If no TESTs are specified, all binary tests found in
|
|
||||||
BUILD_DIRs and all Python tests found in the directory test/ (in the
|
|
||||||
gtest root) are run.
|
|
||||||
|
|
||||||
TEST is a name of either a binary or a Python test. A binary test is
|
|
||||||
an executable file named *_test or *_unittest (with the .exe
|
|
||||||
extension on Windows) A Python test is a script named *_test.py or
|
|
||||||
*_unittest.py.
|
|
||||||
|
|
||||||
OPTIONS
|
|
||||||
-c CONFIGURATIONS
|
|
||||||
Specify build directories via build configurations.
|
|
||||||
CONFIGURATIONS is either a comma-separated list of build
|
|
||||||
configurations or 'all'. Each configuration is equivalent to
|
|
||||||
adding 'scons/build/<configuration>/gtest/scons' to BUILD_DIRs.
|
|
||||||
Specifying -c=all is equivalent to providing all directories
|
|
||||||
listed in KNOWN BUILD DIRECTORIES section below.
|
|
||||||
|
|
||||||
-a
|
|
||||||
Equivalent to -c=all
|
|
||||||
|
|
||||||
-b
|
|
||||||
Equivalent to -c=all with the exception that the script will not
|
|
||||||
fail if some of the KNOWN BUILD DIRECTORIES do not exists; the
|
|
||||||
script will simply not run the tests there. 'b' stands for
|
|
||||||
'built directories'.
|
|
||||||
|
|
||||||
RETURN VALUE
|
|
||||||
Returns 0 if all tests are successful; otherwise returns 1.
|
|
||||||
|
|
||||||
EXAMPLES
|
|
||||||
run_tests.py
|
|
||||||
Runs all tests for the default build configuration.
|
|
||||||
|
|
||||||
run_tests.py -a
|
|
||||||
Runs all tests with binaries in KNOWN BUILD DIRECTORIES.
|
|
||||||
|
|
||||||
run_tests.py -b
|
|
||||||
Runs all tests in KNOWN BUILD DIRECTORIES that have been
|
|
||||||
built.
|
|
||||||
|
|
||||||
run_tests.py foo/
|
|
||||||
Runs all tests in the foo/ directory and all Python tests in
|
|
||||||
the directory test. The Python tests are instructed to look
|
|
||||||
for binaries in foo/.
|
|
||||||
|
|
||||||
run_tests.py bar_test.exe test/baz_test.exe foo/ bar/
|
|
||||||
Runs foo/bar_test.exe, bar/bar_test.exe, foo/baz_test.exe, and
|
|
||||||
bar/baz_test.exe.
|
|
||||||
|
|
||||||
run_tests.py foo bar test/foo_test.py
|
|
||||||
Runs test/foo_test.py twice instructing it to look for its
|
|
||||||
test binaries in the directories foo and bar,
|
|
||||||
correspondingly.
|
|
||||||
|
|
||||||
KNOWN BUILD DIRECTORIES
|
|
||||||
run_tests.py knows about directories where the SCons build script
|
|
||||||
deposits its products. These are the directories where run_tests.py
|
|
||||||
will be looking for its binaries. Currently, gtest's SConstruct file
|
|
||||||
defines them as follows (the default build directory is the first one
|
|
||||||
listed in each group):
|
|
||||||
On Windows:
|
|
||||||
<gtest root>/scons/build/win-dbg8/gtest/scons/
|
|
||||||
<gtest root>/scons/build/win-opt8/gtest/scons/
|
|
||||||
<gtest root>/scons/build/win-dbg/gtest/scons/
|
|
||||||
<gtest root>/scons/build/win-opt/gtest/scons/
|
|
||||||
On Mac:
|
|
||||||
<gtest root>/scons/build/mac-dbg/gtest/scons/
|
|
||||||
<gtest root>/scons/build/mac-opt/gtest/scons/
|
|
||||||
On other platforms:
|
|
||||||
<gtest root>/scons/build/dbg/gtest/scons/
|
|
||||||
<gtest root>/scons/build/opt/gtest/scons/
|
|
||||||
|
|
||||||
AUTHOR
|
|
||||||
Written by Zhanyong Wan (wan@google.com)
|
|
||||||
and Vlad Losev(vladl@google.com).
|
|
||||||
|
|
||||||
REQUIREMENTS
|
|
||||||
This script requires Python 2.3 or higher.
|
|
||||||
"""
|
"""
|
||||||
|
|
||||||
import optparse
|
|
||||||
import os
|
import os
|
||||||
import re
|
|
||||||
import sets
|
|
||||||
import sys
|
import sys
|
||||||
|
|
||||||
try:
|
SCRIPT_DIR = os.path.dirname(__file__) or '.'
|
||||||
# subrocess module is a preferable way to invoke subprocesses but it may
|
|
||||||
# not be available on MacOS X 10.4.
|
|
||||||
import subprocess
|
|
||||||
except ImportError:
|
|
||||||
subprocess = None
|
|
||||||
|
|
||||||
IS_WINDOWS = os.name == 'nt'
|
sys.path.append(os.path.join(SCRIPT_DIR, 'test'))
|
||||||
IS_MAC = os.name == 'posix' and os.uname()[0] == 'Darwin'
|
import run_tests_util
|
||||||
IS_CYGWIN = os.name == 'posix' and 'CYGWIN' in os.uname()[0]
|
|
||||||
|
|
||||||
# Definition of CONFIGS must match that of the build directory names in the
|
|
||||||
# SConstruct script. The first list item is the default build configuration.
|
|
||||||
if IS_WINDOWS:
|
|
||||||
CONFIGS = ('win-dbg8', 'win-opt8', 'win-dbg', 'win-opt')
|
|
||||||
elif IS_MAC:
|
|
||||||
CONFIGS = ('mac-dbg', 'mac-opt')
|
|
||||||
else:
|
|
||||||
CONFIGS = ('dbg', 'opt')
|
|
||||||
|
|
||||||
if IS_WINDOWS or IS_CYGWIN:
|
|
||||||
PYTHON_TEST_REGEX = re.compile(r'_(unit)?test\.py$', re.IGNORECASE)
|
|
||||||
BINARY_TEST_REGEX = re.compile(r'_(unit)?test(\.exe)?$', re.IGNORECASE)
|
|
||||||
BINARY_TEST_SEARCH_REGEX = re.compile(r'_(unit)?test\.exe$', re.IGNORECASE)
|
|
||||||
else:
|
|
||||||
PYTHON_TEST_REGEX = re.compile(r'_(unit)?test\.py$')
|
|
||||||
BINARY_TEST_REGEX = re.compile(r'_(unit)?test$')
|
|
||||||
BINARY_TEST_SEARCH_REGEX = BINARY_TEST_REGEX
|
|
||||||
|
|
||||||
|
|
||||||
def _GetGtestBuildDir(os, script_dir, config):
|
|
||||||
"""Calculates path to the Google Test SCons build directory."""
|
|
||||||
|
|
||||||
return os.path.normpath(os.path.join(script_dir,
|
|
||||||
'scons/build',
|
|
||||||
config,
|
|
||||||
'gtest/scons'))
|
|
||||||
|
|
||||||
|
|
||||||
# All paths in this script are either absolute or relative to the current
|
|
||||||
# working directory, unless otherwise specified.
|
|
||||||
class TestRunner(object):
|
|
||||||
"""Provides facilities for running Python and binary tests for Google Test."""
|
|
||||||
|
|
||||||
def __init__(self,
|
|
||||||
build_dir_var_name='GTEST_BUILD_DIR',
|
|
||||||
injected_os=os,
|
|
||||||
injected_subprocess=subprocess,
|
|
||||||
injected_script_dir=os.path.dirname(__file__),
|
|
||||||
injected_build_dir_finder=_GetGtestBuildDir):
|
|
||||||
self.os = injected_os
|
|
||||||
self.subprocess = injected_subprocess
|
|
||||||
self.build_dir_finder = injected_build_dir_finder
|
|
||||||
self.build_dir_var_name = build_dir_var_name
|
|
||||||
# If a program using this file is invoked via a relative path, the
|
|
||||||
# script directory will be relative to the path of the main program
|
|
||||||
# file. It may be '.' when this script is invoked directly or '..' when
|
|
||||||
# it is imported for testing. To simplify testing we inject the script
|
|
||||||
# directory into TestRunner.
|
|
||||||
self.script_dir = injected_script_dir
|
|
||||||
|
|
||||||
def _GetBuildDirForConfig(self, config):
|
|
||||||
"""Returns the build directory for a given configuration."""
|
|
||||||
|
|
||||||
return self.build_dir_finder(self.os, self.script_dir, config)
|
|
||||||
|
|
||||||
def _Run(self, args):
|
|
||||||
"""Runs the executable with given args (args[0] is the executable name).
|
|
||||||
|
|
||||||
Args:
|
|
||||||
args: Command line arguments for the process.
|
|
||||||
|
|
||||||
Returns:
|
|
||||||
Process's exit code if it exits normally, or -signal if the process is
|
|
||||||
killed by a signal.
|
|
||||||
"""
|
|
||||||
|
|
||||||
if self.subprocess:
|
|
||||||
return self.subprocess.Popen(args).wait()
|
|
||||||
else:
|
|
||||||
return self.os.spawnv(self.os.P_WAIT, args[0], args)
|
|
||||||
|
|
||||||
def _RunBinaryTest(self, test):
|
|
||||||
"""Runs the binary test given its path.
|
|
||||||
|
|
||||||
Args:
|
|
||||||
test: Path to the test binary.
|
|
||||||
|
|
||||||
Returns:
|
|
||||||
Process's exit code if it exits normally, or -signal if the process is
|
|
||||||
killed by a signal.
|
|
||||||
"""
|
|
||||||
|
|
||||||
return self._Run([test])
|
|
||||||
|
|
||||||
def _RunPythonTest(self, test, build_dir):
|
|
||||||
"""Runs the Python test script with the specified build directory.
|
|
||||||
|
|
||||||
Args:
|
|
||||||
test: Path to the test's Python script.
|
|
||||||
build_dir: Path to the directory where the test binary is to be found.
|
|
||||||
|
|
||||||
Returns:
|
|
||||||
Process's exit code if it exits normally, or -signal if the process is
|
|
||||||
killed by a signal.
|
|
||||||
"""
|
|
||||||
|
|
||||||
old_build_dir = self.os.environ.get(self.build_dir_var_name)
|
|
||||||
|
|
||||||
try:
|
|
||||||
self.os.environ[self.build_dir_var_name] = build_dir
|
|
||||||
|
|
||||||
# If this script is run on a Windows machine that has no association
|
|
||||||
# between the .py extension and a python interpreter, simply passing
|
|
||||||
# the script name into subprocess.Popen/os.spawn will not work.
|
|
||||||
print 'Running %s . . .' % (test,)
|
|
||||||
return self._Run([sys.executable, test])
|
|
||||||
|
|
||||||
finally:
|
|
||||||
if old_build_dir is None:
|
|
||||||
del self.os.environ[self.build_dir_var_name]
|
|
||||||
else:
|
|
||||||
self.os.environ[self.build_dir_var_name] = old_build_dir
|
|
||||||
|
|
||||||
def _FindFilesByRegex(self, directory, regex):
|
|
||||||
"""Returns files in a directory whose names match a regular expression.
|
|
||||||
|
|
||||||
Args:
|
|
||||||
directory: Path to the directory to search for files.
|
|
||||||
regex: Regular expression to filter file names.
|
|
||||||
|
|
||||||
Returns:
|
|
||||||
The list of the paths to the files in the directory.
|
|
||||||
"""
|
|
||||||
|
|
||||||
return [self.os.path.join(directory, file_name)
|
|
||||||
for file_name in self.os.listdir(directory)
|
|
||||||
if re.search(regex, file_name)]
|
|
||||||
|
|
||||||
# TODO(vladl@google.com): Implement parsing of scons/SConscript to run all
|
|
||||||
# tests defined there when no tests are specified.
|
|
||||||
# TODO(vladl@google.com): Update the docstring after the code is changed to
|
|
||||||
# try to test all builds defined in scons/SConscript.
|
|
||||||
def GetTestsToRun(self,
|
|
||||||
args,
|
|
||||||
named_configurations,
|
|
||||||
built_configurations,
|
|
||||||
available_configurations=CONFIGS):
|
|
||||||
"""Determines what tests should be run.
|
|
||||||
|
|
||||||
Args:
|
|
||||||
args: The list of non-option arguments from the command line.
|
|
||||||
named_configurations: The list of configurations specified via -c or -a.
|
|
||||||
built_configurations: True if -b has been specified.
|
|
||||||
available_configurations: a list of configurations available on the
|
|
||||||
current platform, injectable for testing.
|
|
||||||
|
|
||||||
Returns:
|
|
||||||
A tuple with 2 elements: the list of Python tests to run and the list of
|
|
||||||
binary tests to run.
|
|
||||||
"""
|
|
||||||
|
|
||||||
if named_configurations == 'all':
|
|
||||||
named_configurations = ','.join(available_configurations)
|
|
||||||
|
|
||||||
normalized_args = [self.os.path.normpath(arg) for arg in args]
|
|
||||||
|
|
||||||
# A final list of build directories which will be searched for the test
|
|
||||||
# binaries. First, add directories specified directly on the command
|
|
||||||
# line.
|
|
||||||
build_dirs = filter(self.os.path.isdir, normalized_args)
|
|
||||||
|
|
||||||
# Adds build directories specified via their build configurations using
|
|
||||||
# the -c or -a options.
|
|
||||||
if named_configurations:
|
|
||||||
build_dirs += [self._GetBuildDirForConfig(config)
|
|
||||||
for config in named_configurations.split(',')]
|
|
||||||
|
|
||||||
# Adds KNOWN BUILD DIRECTORIES if -b is specified.
|
|
||||||
if built_configurations:
|
|
||||||
build_dirs += [self._GetBuildDirForConfig(config)
|
|
||||||
for config in available_configurations
|
|
||||||
if self.os.path.isdir(self._GetBuildDirForConfig(config))]
|
|
||||||
|
|
||||||
# If no directories were specified either via -a, -b, -c, or directly, use
|
|
||||||
# the default configuration.
|
|
||||||
elif not build_dirs:
|
|
||||||
build_dirs = [self._GetBuildDirForConfig(available_configurations[0])]
|
|
||||||
|
|
||||||
# Makes sure there are no duplications.
|
|
||||||
build_dirs = sets.Set(build_dirs)
|
|
||||||
|
|
||||||
errors_found = False
|
|
||||||
listed_python_tests = [] # All Python tests listed on the command line.
|
|
||||||
listed_binary_tests = [] # All binary tests listed on the command line.
|
|
||||||
|
|
||||||
test_dir = self.os.path.normpath(self.os.path.join(self.script_dir, 'test'))
|
|
||||||
|
|
||||||
# Sifts through non-directory arguments fishing for any Python or binary
|
|
||||||
# tests and detecting errors.
|
|
||||||
for argument in sets.Set(normalized_args) - build_dirs:
|
|
||||||
if re.search(PYTHON_TEST_REGEX, argument):
|
|
||||||
python_path = self.os.path.join(test_dir,
|
|
||||||
self.os.path.basename(argument))
|
|
||||||
if self.os.path.isfile(python_path):
|
|
||||||
listed_python_tests.append(python_path)
|
|
||||||
else:
|
|
||||||
sys.stderr.write('Unable to find Python test %s' % argument)
|
|
||||||
errors_found = True
|
|
||||||
elif re.search(BINARY_TEST_REGEX, argument):
|
|
||||||
# This script also accepts binary test names prefixed with test/ for
|
|
||||||
# the convenience of typing them (can use path completions in the
|
|
||||||
# shell). Strips test/ prefix from the binary test names.
|
|
||||||
listed_binary_tests.append(self.os.path.basename(argument))
|
|
||||||
else:
|
|
||||||
sys.stderr.write('%s is neither test nor build directory' % argument)
|
|
||||||
errors_found = True
|
|
||||||
|
|
||||||
if errors_found:
|
|
||||||
return None
|
|
||||||
|
|
||||||
user_has_listed_tests = listed_python_tests or listed_binary_tests
|
|
||||||
|
|
||||||
if user_has_listed_tests:
|
|
||||||
selected_python_tests = listed_python_tests
|
|
||||||
else:
|
|
||||||
selected_python_tests = self._FindFilesByRegex(test_dir,
|
|
||||||
PYTHON_TEST_REGEX)
|
|
||||||
|
|
||||||
# TODO(vladl@google.com): skip unbuilt Python tests when -b is specified.
|
|
||||||
python_test_pairs = []
|
|
||||||
for directory in build_dirs:
|
|
||||||
for test in selected_python_tests:
|
|
||||||
python_test_pairs.append((directory, test))
|
|
||||||
|
|
||||||
binary_test_pairs = []
|
|
||||||
for directory in build_dirs:
|
|
||||||
if user_has_listed_tests:
|
|
||||||
binary_test_pairs.extend(
|
|
||||||
[(directory, self.os.path.join(directory, test))
|
|
||||||
for test in listed_binary_tests])
|
|
||||||
else:
|
|
||||||
tests = self._FindFilesByRegex(directory, BINARY_TEST_SEARCH_REGEX)
|
|
||||||
binary_test_pairs.extend([(directory, test) for test in tests])
|
|
||||||
|
|
||||||
return (python_test_pairs, binary_test_pairs)
|
|
||||||
|
|
||||||
def RunTests(self, python_tests, binary_tests):
|
|
||||||
"""Runs Python and binary tests and reports results to the standard output.
|
|
||||||
|
|
||||||
Args:
|
|
||||||
python_tests: List of Python tests to run in the form of tuples
|
|
||||||
(build directory, Python test script).
|
|
||||||
binary_tests: List of binary tests to run in the form of tuples
|
|
||||||
(build directory, binary file).
|
|
||||||
|
|
||||||
Returns:
|
|
||||||
The exit code the program should pass into sys.exit().
|
|
||||||
"""
|
|
||||||
|
|
||||||
if python_tests or binary_tests:
|
|
||||||
results = []
|
|
||||||
for directory, test in python_tests:
|
|
||||||
results.append((directory,
|
|
||||||
test,
|
|
||||||
self._RunPythonTest(test, directory) == 0))
|
|
||||||
for directory, test in binary_tests:
|
|
||||||
results.append((directory,
|
|
||||||
self.os.path.basename(test),
|
|
||||||
self._RunBinaryTest(test) == 0))
|
|
||||||
|
|
||||||
failed = [(directory, test)
|
|
||||||
for (directory, test, success) in results
|
|
||||||
if not success]
|
|
||||||
print
|
|
||||||
print '%d tests run.' % len(results)
|
|
||||||
if failed:
|
|
||||||
print 'The following %d tests failed:' % len(failed)
|
|
||||||
for (directory, test) in failed:
|
|
||||||
print '%s in %s' % (test, directory)
|
|
||||||
return 1
|
|
||||||
else:
|
|
||||||
print 'All tests passed!'
|
|
||||||
else: # No tests defined
|
|
||||||
print 'Nothing to test - no tests specified!'
|
|
||||||
|
|
||||||
return 0
|
|
||||||
|
|
||||||
|
|
||||||
def _Main():
|
def _Main():
|
||||||
"""Runs all tests for Google Test."""
|
"""Runs all tests for Google Test."""
|
||||||
|
|
||||||
parser = optparse.OptionParser()
|
options, args = run_tests_util.ParseArgs('gtest')
|
||||||
parser.add_option('-c',
|
test_runner = run_tests_util.TestRunner(script_dir=SCRIPT_DIR)
|
||||||
action='store',
|
|
||||||
dest='configurations',
|
|
||||||
default=None,
|
|
||||||
help='Test in the specified build directories')
|
|
||||||
parser.add_option('-a',
|
|
||||||
action='store_const',
|
|
||||||
dest='configurations',
|
|
||||||
default=None,
|
|
||||||
const='all',
|
|
||||||
help='Test in all default build directories')
|
|
||||||
parser.add_option('-b',
|
|
||||||
action='store_const',
|
|
||||||
dest='built_configurations',
|
|
||||||
default=False,
|
|
||||||
const=True,
|
|
||||||
help=('Test in all default build directories, do not fail'
|
|
||||||
'if some of them do not exist'))
|
|
||||||
(options, args) = parser.parse_args()
|
|
||||||
|
|
||||||
test_runner = TestRunner()
|
|
||||||
tests = test_runner.GetTestsToRun(args,
|
tests = test_runner.GetTestsToRun(args,
|
||||||
options.configurations,
|
options.configurations,
|
||||||
options.built_configurations)
|
options.built_configurations)
|
||||||
|
|
|
@ -159,7 +159,7 @@ TEST(TupleConstructorTest, DefaultConstructorDefaultInitializesEachField) {
|
||||||
b3 = a3;
|
b3 = a3;
|
||||||
EXPECT_EQ(0.0, get<0>(b3));
|
EXPECT_EQ(0.0, get<0>(b3));
|
||||||
EXPECT_EQ('\0', get<1>(b3));
|
EXPECT_EQ('\0', get<1>(b3));
|
||||||
EXPECT_EQ(NULL, get<2>(b3));
|
EXPECT_TRUE(get<2>(b3) == NULL);
|
||||||
|
|
||||||
tuple<int, int, int, int, int, int, int, int, int, int> a10, b10;
|
tuple<int, int, int, int, int, int, int, int, int, int> a10, b10;
|
||||||
b10 = a10;
|
b10 = a10;
|
||||||
|
|
|
@ -138,7 +138,7 @@ def GetTempDir():
|
||||||
return _temp_dir
|
return _temp_dir
|
||||||
|
|
||||||
|
|
||||||
def GetTestExecutablePath(executable_name):
|
def GetTestExecutablePath(executable_name, build_dir=None):
|
||||||
"""Returns the absolute path of the test binary given its name.
|
"""Returns the absolute path of the test binary given its name.
|
||||||
|
|
||||||
The function will print a message and abort the program if the resulting file
|
The function will print a message and abort the program if the resulting file
|
||||||
|
@ -146,12 +146,15 @@ def GetTestExecutablePath(executable_name):
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
executable_name: name of the test binary that the test script runs.
|
executable_name: name of the test binary that the test script runs.
|
||||||
|
build_dir: directory where to look for executables, by default
|
||||||
|
the result of GetBuildDir().
|
||||||
|
|
||||||
Returns:
|
Returns:
|
||||||
The absolute path of the test binary.
|
The absolute path of the test binary.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
path = os.path.abspath(os.path.join(GetBuildDir(), executable_name))
|
path = os.path.abspath(os.path.join(build_dir or GetBuildDir(),
|
||||||
|
executable_name))
|
||||||
if (IS_WINDOWS or IS_CYGWIN) and not path.endswith('.exe'):
|
if (IS_WINDOWS or IS_CYGWIN) and not path.endswith('.exe'):
|
||||||
path += '.exe'
|
path += '.exe'
|
||||||
|
|
||||||
|
|
445
test/run_tests_util.py
Executable file
445
test/run_tests_util.py
Executable file
|
@ -0,0 +1,445 @@
|
||||||
|
# Copyright 2008 Google Inc. All Rights Reserved.
|
||||||
|
#
|
||||||
|
# Redistribution and use in source and binary forms, with or without
|
||||||
|
# modification, are permitted provided that the following conditions are
|
||||||
|
# met:
|
||||||
|
#
|
||||||
|
# * Redistributions of source code must retain the above copyright
|
||||||
|
# notice, this list of conditions and the following disclaimer.
|
||||||
|
# * Redistributions in binary form must reproduce the above
|
||||||
|
# copyright notice, this list of conditions and the following disclaimer
|
||||||
|
# in the documentation and/or other materials provided with the
|
||||||
|
# distribution.
|
||||||
|
# * Neither the name of Google Inc. nor the names of its
|
||||||
|
# contributors may be used to endorse or promote products derived from
|
||||||
|
# this software without specific prior written permission.
|
||||||
|
#
|
||||||
|
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||||
|
# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||||
|
# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||||
|
# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||||
|
# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||||
|
# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||||
|
# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||||
|
# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||||
|
# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||||
|
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||||
|
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
|
||||||
|
"""Provides facilities for running SCons-built Google Test/Mock tests."""
|
||||||
|
|
||||||
|
|
||||||
|
import optparse
|
||||||
|
import os
|
||||||
|
import re
|
||||||
|
import sets
|
||||||
|
import sys
|
||||||
|
|
||||||
|
try:
|
||||||
|
# subrocess module is a preferable way to invoke subprocesses but it may
|
||||||
|
# not be available on MacOS X 10.4.
|
||||||
|
# Suppresses the 'Import not at the top of the file' lint complaint.
|
||||||
|
# pylint: disable-msg=C6204
|
||||||
|
import subprocess
|
||||||
|
except ImportError:
|
||||||
|
subprocess = None
|
||||||
|
|
||||||
|
HELP_MSG = """Runs the specified tests for %(proj)s.
|
||||||
|
|
||||||
|
SYNOPSIS
|
||||||
|
run_tests.py [OPTION]... [BUILD_DIR]... [TEST]...
|
||||||
|
|
||||||
|
DESCRIPTION
|
||||||
|
Runs the specified tests (either binary or Python), and prints a
|
||||||
|
summary of the results. BUILD_DIRS will be used to search for the
|
||||||
|
binaries. If no TESTs are specified, all binary tests found in
|
||||||
|
BUILD_DIRs and all Python tests found in the directory test/ (in the
|
||||||
|
%(proj)s root) are run.
|
||||||
|
|
||||||
|
TEST is a name of either a binary or a Python test. A binary test is
|
||||||
|
an executable file named *_test or *_unittest (with the .exe
|
||||||
|
extension on Windows) A Python test is a script named *_test.py or
|
||||||
|
*_unittest.py.
|
||||||
|
|
||||||
|
OPTIONS
|
||||||
|
-h, --help
|
||||||
|
Print this help message.
|
||||||
|
-c CONFIGURATIONS
|
||||||
|
Specify build directories via build configurations.
|
||||||
|
CONFIGURATIONS is either a comma-separated list of build
|
||||||
|
configurations or 'all'. Each configuration is equivalent to
|
||||||
|
adding 'scons/build/<configuration>/%(proj)s/scons' to BUILD_DIRs.
|
||||||
|
Specifying -c=all is equivalent to providing all directories
|
||||||
|
listed in KNOWN BUILD DIRECTORIES section below.
|
||||||
|
-a
|
||||||
|
Equivalent to -c=all
|
||||||
|
-b
|
||||||
|
Equivalent to -c=all with the exception that the script will not
|
||||||
|
fail if some of the KNOWN BUILD DIRECTORIES do not exists; the
|
||||||
|
script will simply not run the tests there. 'b' stands for
|
||||||
|
'built directories'.
|
||||||
|
|
||||||
|
RETURN VALUE
|
||||||
|
Returns 0 if all tests are successful; otherwise returns 1.
|
||||||
|
|
||||||
|
EXAMPLES
|
||||||
|
run_tests.py
|
||||||
|
Runs all tests for the default build configuration.
|
||||||
|
run_tests.py -a
|
||||||
|
Runs all tests with binaries in KNOWN BUILD DIRECTORIES.
|
||||||
|
run_tests.py -b
|
||||||
|
Runs all tests in KNOWN BUILD DIRECTORIES that have been
|
||||||
|
built.
|
||||||
|
run_tests.py foo/
|
||||||
|
Runs all tests in the foo/ directory and all Python tests in
|
||||||
|
the directory test. The Python tests are instructed to look
|
||||||
|
for binaries in foo/.
|
||||||
|
run_tests.py bar_test.exe test/baz_test.exe foo/ bar/
|
||||||
|
Runs foo/bar_test.exe, bar/bar_test.exe, foo/baz_test.exe, and
|
||||||
|
bar/baz_test.exe.
|
||||||
|
run_tests.py foo bar test/foo_test.py
|
||||||
|
Runs test/foo_test.py twice instructing it to look for its
|
||||||
|
test binaries in the directories foo and bar,
|
||||||
|
correspondingly.
|
||||||
|
|
||||||
|
KNOWN BUILD DIRECTORIES
|
||||||
|
run_tests.py knows about directories where the SCons build script
|
||||||
|
deposits its products. These are the directories where run_tests.py
|
||||||
|
will be looking for its binaries. Currently, %(proj)s's SConstruct file
|
||||||
|
defines them as follows (the default build directory is the first one
|
||||||
|
listed in each group):
|
||||||
|
On Windows:
|
||||||
|
<%(proj)s root>/scons/build/win-dbg8/%(proj)s/scons/
|
||||||
|
<%(proj)s root>/scons/build/win-opt8/%(proj)s/scons/
|
||||||
|
<%(proj)s root>/scons/build/win-dbg/%(proj)s/scons/
|
||||||
|
<%(proj)s root>/scons/build/win-opt/%(proj)s/scons/
|
||||||
|
On Mac:
|
||||||
|
<%(proj)s root>/scons/build/mac-dbg/%(proj)s/scons/
|
||||||
|
<%(proj)s root>/scons/build/mac-opt/%(proj)s/scons/
|
||||||
|
On other platforms:
|
||||||
|
<%(proj)s root>/scons/build/dbg/%(proj)s/scons/
|
||||||
|
<%(proj)s root>/scons/build/opt/%(proj)s/scons/"""
|
||||||
|
|
||||||
|
IS_WINDOWS = os.name == 'nt'
|
||||||
|
IS_MAC = os.name == 'posix' and os.uname()[0] == 'Darwin'
|
||||||
|
IS_CYGWIN = os.name == 'posix' and 'CYGWIN' in os.uname()[0]
|
||||||
|
|
||||||
|
# Definition of CONFIGS must match that of the build directory names in the
|
||||||
|
# SConstruct script. The first list item is the default build configuration.
|
||||||
|
if IS_WINDOWS:
|
||||||
|
CONFIGS = ('win-dbg8', 'win-opt8', 'win-dbg', 'win-opt')
|
||||||
|
elif IS_MAC:
|
||||||
|
CONFIGS = ('mac-dbg', 'mac-opt')
|
||||||
|
else:
|
||||||
|
CONFIGS = ('dbg', 'opt')
|
||||||
|
|
||||||
|
if IS_WINDOWS or IS_CYGWIN:
|
||||||
|
PYTHON_TEST_REGEX = re.compile(r'_(unit)?test\.py$', re.IGNORECASE)
|
||||||
|
BINARY_TEST_REGEX = re.compile(r'_(unit)?test(\.exe)?$', re.IGNORECASE)
|
||||||
|
BINARY_TEST_SEARCH_REGEX = re.compile(r'_(unit)?test\.exe$', re.IGNORECASE)
|
||||||
|
else:
|
||||||
|
PYTHON_TEST_REGEX = re.compile(r'_(unit)?test\.py$')
|
||||||
|
BINARY_TEST_REGEX = re.compile(r'_(unit)?test$')
|
||||||
|
BINARY_TEST_SEARCH_REGEX = BINARY_TEST_REGEX
|
||||||
|
|
||||||
|
|
||||||
|
def _GetGtestBuildDir(injected_os, script_dir, config):
|
||||||
|
"""Calculates path to the Google Test SCons build directory."""
|
||||||
|
|
||||||
|
return injected_os.path.normpath(injected_os.path.join(script_dir,
|
||||||
|
'scons/build',
|
||||||
|
config,
|
||||||
|
'gtest/scons'))
|
||||||
|
|
||||||
|
|
||||||
|
# All paths in this script are either absolute or relative to the current
|
||||||
|
# working directory, unless otherwise specified.
|
||||||
|
class TestRunner(object):
|
||||||
|
"""Provides facilities for running Python and binary tests for Google Test."""
|
||||||
|
|
||||||
|
def __init__(self,
|
||||||
|
script_dir,
|
||||||
|
build_dir_var_name='GTEST_BUILD_DIR',
|
||||||
|
injected_os=os,
|
||||||
|
injected_subprocess=subprocess,
|
||||||
|
injected_build_dir_finder=_GetGtestBuildDir):
|
||||||
|
"""Initializes a TestRunner instance.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
script_dir: File path to the calling script.
|
||||||
|
build_dir_var_name: Name of the env variable used to pass the
|
||||||
|
the build directory path to the invoked
|
||||||
|
tests.
|
||||||
|
injected_os: standard os module or a mock/stub for
|
||||||
|
testing.
|
||||||
|
injected_subprocess: standard subprocess module or a mock/stub
|
||||||
|
for testing
|
||||||
|
injected_build_dir_finder: function that determines the path to
|
||||||
|
the build directory.
|
||||||
|
"""
|
||||||
|
|
||||||
|
self.os = injected_os
|
||||||
|
self.subprocess = injected_subprocess
|
||||||
|
self.build_dir_finder = injected_build_dir_finder
|
||||||
|
self.build_dir_var_name = build_dir_var_name
|
||||||
|
self.script_dir = script_dir
|
||||||
|
|
||||||
|
def _GetBuildDirForConfig(self, config):
|
||||||
|
"""Returns the build directory for a given configuration."""
|
||||||
|
|
||||||
|
return self.build_dir_finder(self.os, self.script_dir, config)
|
||||||
|
|
||||||
|
def _Run(self, args):
|
||||||
|
"""Runs the executable with given args (args[0] is the executable name).
|
||||||
|
|
||||||
|
Args:
|
||||||
|
args: Command line arguments for the process.
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
Process's exit code if it exits normally, or -signal if the process is
|
||||||
|
killed by a signal.
|
||||||
|
"""
|
||||||
|
|
||||||
|
if self.subprocess:
|
||||||
|
return self.subprocess.Popen(args).wait()
|
||||||
|
else:
|
||||||
|
return self.os.spawnv(self.os.P_WAIT, args[0], args)
|
||||||
|
|
||||||
|
def _RunBinaryTest(self, test):
|
||||||
|
"""Runs the binary test given its path.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
test: Path to the test binary.
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
Process's exit code if it exits normally, or -signal if the process is
|
||||||
|
killed by a signal.
|
||||||
|
"""
|
||||||
|
|
||||||
|
return self._Run([test])
|
||||||
|
|
||||||
|
def _RunPythonTest(self, test, build_dir):
|
||||||
|
"""Runs the Python test script with the specified build directory.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
test: Path to the test's Python script.
|
||||||
|
build_dir: Path to the directory where the test binary is to be found.
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
Process's exit code if it exits normally, or -signal if the process is
|
||||||
|
killed by a signal.
|
||||||
|
"""
|
||||||
|
|
||||||
|
old_build_dir = self.os.environ.get(self.build_dir_var_name)
|
||||||
|
|
||||||
|
try:
|
||||||
|
self.os.environ[self.build_dir_var_name] = build_dir
|
||||||
|
|
||||||
|
# If this script is run on a Windows machine that has no association
|
||||||
|
# between the .py extension and a python interpreter, simply passing
|
||||||
|
# the script name into subprocess.Popen/os.spawn will not work.
|
||||||
|
print 'Running %s . . .' % (test,)
|
||||||
|
return self._Run([sys.executable, test])
|
||||||
|
|
||||||
|
finally:
|
||||||
|
if old_build_dir is None:
|
||||||
|
del self.os.environ[self.build_dir_var_name]
|
||||||
|
else:
|
||||||
|
self.os.environ[self.build_dir_var_name] = old_build_dir
|
||||||
|
|
||||||
|
def _FindFilesByRegex(self, directory, regex):
|
||||||
|
"""Returns files in a directory whose names match a regular expression.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
directory: Path to the directory to search for files.
|
||||||
|
regex: Regular expression to filter file names.
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
The list of the paths to the files in the directory.
|
||||||
|
"""
|
||||||
|
|
||||||
|
return [self.os.path.join(directory, file_name)
|
||||||
|
for file_name in self.os.listdir(directory)
|
||||||
|
if re.search(regex, file_name)]
|
||||||
|
|
||||||
|
# TODO(vladl@google.com): Implement parsing of scons/SConscript to run all
|
||||||
|
# tests defined there when no tests are specified.
|
||||||
|
# TODO(vladl@google.com): Update the docstring after the code is changed to
|
||||||
|
# try to test all builds defined in scons/SConscript.
|
||||||
|
def GetTestsToRun(self,
|
||||||
|
args,
|
||||||
|
named_configurations,
|
||||||
|
built_configurations,
|
||||||
|
available_configurations=CONFIGS):
|
||||||
|
"""Determines what tests should be run.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
args: The list of non-option arguments from the command line.
|
||||||
|
named_configurations: The list of configurations specified via -c or -a.
|
||||||
|
built_configurations: True if -b has been specified.
|
||||||
|
available_configurations: a list of configurations available on the
|
||||||
|
current platform, injectable for testing.
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
A tuple with 2 elements: the list of Python tests to run and the list of
|
||||||
|
binary tests to run.
|
||||||
|
"""
|
||||||
|
|
||||||
|
if named_configurations == 'all':
|
||||||
|
named_configurations = ','.join(available_configurations)
|
||||||
|
|
||||||
|
normalized_args = [self.os.path.normpath(arg) for arg in args]
|
||||||
|
|
||||||
|
# A final list of build directories which will be searched for the test
|
||||||
|
# binaries. First, add directories specified directly on the command
|
||||||
|
# line.
|
||||||
|
build_dirs = filter(self.os.path.isdir, normalized_args)
|
||||||
|
|
||||||
|
# Adds build directories specified via their build configurations using
|
||||||
|
# the -c or -a options.
|
||||||
|
if named_configurations:
|
||||||
|
build_dirs += [self._GetBuildDirForConfig(config)
|
||||||
|
for config in named_configurations.split(',')]
|
||||||
|
|
||||||
|
# Adds KNOWN BUILD DIRECTORIES if -b is specified.
|
||||||
|
if built_configurations:
|
||||||
|
build_dirs += [self._GetBuildDirForConfig(config)
|
||||||
|
for config in available_configurations
|
||||||
|
if self.os.path.isdir(self._GetBuildDirForConfig(config))]
|
||||||
|
|
||||||
|
# If no directories were specified either via -a, -b, -c, or directly, use
|
||||||
|
# the default configuration.
|
||||||
|
elif not build_dirs:
|
||||||
|
build_dirs = [self._GetBuildDirForConfig(available_configurations[0])]
|
||||||
|
|
||||||
|
# Makes sure there are no duplications.
|
||||||
|
build_dirs = sets.Set(build_dirs)
|
||||||
|
|
||||||
|
errors_found = False
|
||||||
|
listed_python_tests = [] # All Python tests listed on the command line.
|
||||||
|
listed_binary_tests = [] # All binary tests listed on the command line.
|
||||||
|
|
||||||
|
test_dir = self.os.path.normpath(self.os.path.join(self.script_dir, 'test'))
|
||||||
|
|
||||||
|
# Sifts through non-directory arguments fishing for any Python or binary
|
||||||
|
# tests and detecting errors.
|
||||||
|
for argument in sets.Set(normalized_args) - build_dirs:
|
||||||
|
if re.search(PYTHON_TEST_REGEX, argument):
|
||||||
|
python_path = self.os.path.join(test_dir,
|
||||||
|
self.os.path.basename(argument))
|
||||||
|
if self.os.path.isfile(python_path):
|
||||||
|
listed_python_tests.append(python_path)
|
||||||
|
else:
|
||||||
|
sys.stderr.write('Unable to find Python test %s' % argument)
|
||||||
|
errors_found = True
|
||||||
|
elif re.search(BINARY_TEST_REGEX, argument):
|
||||||
|
# This script also accepts binary test names prefixed with test/ for
|
||||||
|
# the convenience of typing them (can use path completions in the
|
||||||
|
# shell). Strips test/ prefix from the binary test names.
|
||||||
|
listed_binary_tests.append(self.os.path.basename(argument))
|
||||||
|
else:
|
||||||
|
sys.stderr.write('%s is neither test nor build directory' % argument)
|
||||||
|
errors_found = True
|
||||||
|
|
||||||
|
if errors_found:
|
||||||
|
return None
|
||||||
|
|
||||||
|
user_has_listed_tests = listed_python_tests or listed_binary_tests
|
||||||
|
|
||||||
|
if user_has_listed_tests:
|
||||||
|
selected_python_tests = listed_python_tests
|
||||||
|
else:
|
||||||
|
selected_python_tests = self._FindFilesByRegex(test_dir,
|
||||||
|
PYTHON_TEST_REGEX)
|
||||||
|
|
||||||
|
# TODO(vladl@google.com): skip unbuilt Python tests when -b is specified.
|
||||||
|
python_test_pairs = []
|
||||||
|
for directory in build_dirs:
|
||||||
|
for test in selected_python_tests:
|
||||||
|
python_test_pairs.append((directory, test))
|
||||||
|
|
||||||
|
binary_test_pairs = []
|
||||||
|
for directory in build_dirs:
|
||||||
|
if user_has_listed_tests:
|
||||||
|
binary_test_pairs.extend(
|
||||||
|
[(directory, self.os.path.join(directory, test))
|
||||||
|
for test in listed_binary_tests])
|
||||||
|
else:
|
||||||
|
tests = self._FindFilesByRegex(directory, BINARY_TEST_SEARCH_REGEX)
|
||||||
|
binary_test_pairs.extend([(directory, test) for test in tests])
|
||||||
|
|
||||||
|
return (python_test_pairs, binary_test_pairs)
|
||||||
|
|
||||||
|
def RunTests(self, python_tests, binary_tests):
|
||||||
|
"""Runs Python and binary tests and reports results to the standard output.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
python_tests: List of Python tests to run in the form of tuples
|
||||||
|
(build directory, Python test script).
|
||||||
|
binary_tests: List of binary tests to run in the form of tuples
|
||||||
|
(build directory, binary file).
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
The exit code the program should pass into sys.exit().
|
||||||
|
"""
|
||||||
|
|
||||||
|
if python_tests or binary_tests:
|
||||||
|
results = []
|
||||||
|
for directory, test in python_tests:
|
||||||
|
results.append((directory,
|
||||||
|
test,
|
||||||
|
self._RunPythonTest(test, directory) == 0))
|
||||||
|
for directory, test in binary_tests:
|
||||||
|
results.append((directory,
|
||||||
|
self.os.path.basename(test),
|
||||||
|
self._RunBinaryTest(test) == 0))
|
||||||
|
|
||||||
|
failed = [(directory, test)
|
||||||
|
for (directory, test, success) in results
|
||||||
|
if not success]
|
||||||
|
print
|
||||||
|
print '%d tests run.' % len(results)
|
||||||
|
if failed:
|
||||||
|
print 'The following %d tests failed:' % len(failed)
|
||||||
|
for (directory, test) in failed:
|
||||||
|
print '%s in %s' % (test, directory)
|
||||||
|
return 1
|
||||||
|
else:
|
||||||
|
print 'All tests passed!'
|
||||||
|
else: # No tests defined
|
||||||
|
print 'Nothing to test - no tests specified!'
|
||||||
|
|
||||||
|
return 0
|
||||||
|
|
||||||
|
|
||||||
|
def ParseArgs(project_name, argv=None, help_callback=None):
|
||||||
|
"""Parses the options run_tests.py uses."""
|
||||||
|
|
||||||
|
# Suppresses lint warning on unused arguments. These arguments are
|
||||||
|
# required by optparse, even though they are unused.
|
||||||
|
# pylint: disable-msg=W0613
|
||||||
|
def PrintHelp(option, opt, value, parser):
|
||||||
|
print HELP_MSG % {'proj': project_name}
|
||||||
|
sys.exit(1)
|
||||||
|
|
||||||
|
parser = optparse.OptionParser()
|
||||||
|
parser.add_option('-c',
|
||||||
|
action='store',
|
||||||
|
dest='configurations',
|
||||||
|
default=None)
|
||||||
|
parser.add_option('-a',
|
||||||
|
action='store_const',
|
||||||
|
dest='configurations',
|
||||||
|
default=None,
|
||||||
|
const='all')
|
||||||
|
parser.add_option('-b',
|
||||||
|
action='store_const',
|
||||||
|
dest='built_configurations',
|
||||||
|
default=False,
|
||||||
|
const=True)
|
||||||
|
# Replaces the built-in help with ours.
|
||||||
|
parser.remove_option('-h')
|
||||||
|
parser.add_option('-h', '--help',
|
||||||
|
action='callback',
|
||||||
|
callback=help_callback or PrintHelp)
|
||||||
|
return parser.parse_args(argv)
|
|
@ -28,18 +28,16 @@
|
||||||
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||||
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
|
||||||
"""Tests for run_tests.py test runner script."""
|
"""Tests for run_tests_util.py test runner script."""
|
||||||
|
|
||||||
__author__ = 'vladl@google.com (Vlad Losev)'
|
__author__ = 'vladl@google.com (Vlad Losev)'
|
||||||
|
|
||||||
import os
|
import os
|
||||||
import re
|
import re
|
||||||
import sets
|
import sets
|
||||||
import sys
|
|
||||||
import unittest
|
import unittest
|
||||||
|
|
||||||
sys.path.append(os.path.join(os.path.dirname(sys.argv[0]), os.pardir))
|
import run_tests_util
|
||||||
import run_tests
|
|
||||||
|
|
||||||
|
|
||||||
GTEST_DBG_DIR = 'scons/build/dbg/gtest/scons'
|
GTEST_DBG_DIR = 'scons/build/dbg/gtest/scons'
|
||||||
|
@ -50,7 +48,7 @@ GTEST_OTHER_DIR = 'scons/build/other/gtest/scons'
|
||||||
def AddExeExtension(path):
|
def AddExeExtension(path):
|
||||||
"""Appends .exe to the path on Windows or Cygwin."""
|
"""Appends .exe to the path on Windows or Cygwin."""
|
||||||
|
|
||||||
if run_tests.IS_WINDOWS or run_tests.IS_CYGWIN:
|
if run_tests_util.IS_WINDOWS or run_tests_util.IS_CYGWIN:
|
||||||
return path + '.exe'
|
return path + '.exe'
|
||||||
else:
|
else:
|
||||||
return path
|
return path
|
||||||
|
@ -109,6 +107,8 @@ class FakePath(object):
|
||||||
|
|
||||||
return tree
|
return tree
|
||||||
|
|
||||||
|
# Silences pylint warning about using standard names.
|
||||||
|
# pylint: disable-msg=C6409
|
||||||
def normpath(self, path):
|
def normpath(self, path):
|
||||||
return os.path.normpath(path)
|
return os.path.normpath(path)
|
||||||
|
|
||||||
|
@ -141,6 +141,7 @@ class FakeOs(object):
|
||||||
# Some methods/attributes are delegated to the real os module.
|
# Some methods/attributes are delegated to the real os module.
|
||||||
self.environ = os.environ
|
self.environ = os.environ
|
||||||
|
|
||||||
|
# pylint: disable-msg=C6409
|
||||||
def listdir(self, path):
|
def listdir(self, path):
|
||||||
assert self.path.isdir(path)
|
assert self.path.isdir(path)
|
||||||
return self.path.PathElement(path).iterkeys()
|
return self.path.PathElement(path).iterkeys()
|
||||||
|
@ -169,7 +170,7 @@ class GetTestsToRunTest(unittest.TestCase):
|
||||||
# On Windows and Cygwin, the test file names have the .exe extension, but
|
# On Windows and Cygwin, the test file names have the .exe extension, but
|
||||||
# they can be invoked either by name or by name+extension. Our test must
|
# they can be invoked either by name or by name+extension. Our test must
|
||||||
# accommodate both situations.
|
# accommodate both situations.
|
||||||
if run_tests.IS_WINDOWS or run_tests.IS_CYGWIN:
|
if run_tests_util.IS_WINDOWS or run_tests_util.IS_CYGWIN:
|
||||||
executable = re.sub(r'\.exe$', '', executable)
|
executable = re.sub(r'\.exe$', '', executable)
|
||||||
return (directory, executable)
|
return (directory, executable)
|
||||||
|
|
||||||
|
@ -187,14 +188,14 @@ class GetTestsToRunTest(unittest.TestCase):
|
||||||
|
|
||||||
def setUp(self):
|
def setUp(self):
|
||||||
self.fake_os = FakeOs(FakePath(
|
self.fake_os = FakeOs(FakePath(
|
||||||
current_dir=os.path.abspath(os.path.dirname(run_tests.__file__)),
|
current_dir=os.path.abspath(os.path.dirname(run_tests_util.__file__)),
|
||||||
known_paths=[AddExeExtension(GTEST_DBG_DIR + '/gtest_unittest'),
|
known_paths=[AddExeExtension(GTEST_DBG_DIR + '/gtest_unittest'),
|
||||||
AddExeExtension(GTEST_OPT_DIR + '/gtest_unittest'),
|
AddExeExtension(GTEST_OPT_DIR + '/gtest_unittest'),
|
||||||
'test/gtest_color_test.py']))
|
'test/gtest_color_test.py']))
|
||||||
self.fake_configurations = ['dbg', 'opt']
|
self.fake_configurations = ['dbg', 'opt']
|
||||||
self.test_runner = run_tests.TestRunner(injected_os=self.fake_os,
|
self.test_runner = run_tests_util.TestRunner(script_dir='.',
|
||||||
injected_subprocess=None,
|
injected_os=self.fake_os,
|
||||||
injected_script_dir='.')
|
injected_subprocess=None)
|
||||||
|
|
||||||
def testBinaryTestsOnly(self):
|
def testBinaryTestsOnly(self):
|
||||||
"""Exercises GetTestsToRun with parameters designating binary tests only."""
|
"""Exercises GetTestsToRun with parameters designating binary tests only."""
|
||||||
|
@ -419,12 +420,12 @@ class GetTestsToRunTest(unittest.TestCase):
|
||||||
"""Verifies that GetTestsToRun ignores non-test files in the filesystem."""
|
"""Verifies that GetTestsToRun ignores non-test files in the filesystem."""
|
||||||
|
|
||||||
self.fake_os = FakeOs(FakePath(
|
self.fake_os = FakeOs(FakePath(
|
||||||
current_dir=os.path.abspath(os.path.dirname(run_tests.__file__)),
|
current_dir=os.path.abspath(os.path.dirname(run_tests_util.__file__)),
|
||||||
known_paths=[AddExeExtension(GTEST_DBG_DIR + '/gtest_nontest'),
|
known_paths=[AddExeExtension(GTEST_DBG_DIR + '/gtest_nontest'),
|
||||||
'test/']))
|
'test/']))
|
||||||
self.test_runner = run_tests.TestRunner(injected_os=self.fake_os,
|
self.test_runner = run_tests_util.TestRunner(script_dir='.',
|
||||||
injected_subprocess=None,
|
injected_os=self.fake_os,
|
||||||
injected_script_dir='.')
|
injected_subprocess=None)
|
||||||
self.AssertResultsEqual(
|
self.AssertResultsEqual(
|
||||||
self.test_runner.GetTestsToRun(
|
self.test_runner.GetTestsToRun(
|
||||||
[],
|
[],
|
||||||
|
@ -446,9 +447,9 @@ class GetTestsToRunTest(unittest.TestCase):
|
||||||
AddExeExtension('/d/' + GTEST_OPT_DIR + '/gtest_unittest'),
|
AddExeExtension('/d/' + GTEST_OPT_DIR + '/gtest_unittest'),
|
||||||
'/d/test/gtest_color_test.py']))
|
'/d/test/gtest_color_test.py']))
|
||||||
self.fake_configurations = ['dbg', 'opt']
|
self.fake_configurations = ['dbg', 'opt']
|
||||||
self.test_runner = run_tests.TestRunner(injected_os=self.fake_os,
|
self.test_runner = run_tests_util.TestRunner(script_dir='/d/',
|
||||||
injected_subprocess=None,
|
injected_os=self.fake_os,
|
||||||
injected_script_dir='/d/')
|
injected_subprocess=None)
|
||||||
# A binary test.
|
# A binary test.
|
||||||
self.AssertResultsEqual(
|
self.AssertResultsEqual(
|
||||||
self.test_runner.GetTestsToRun(
|
self.test_runner.GetTestsToRun(
|
||||||
|
@ -468,7 +469,6 @@ class GetTestsToRunTest(unittest.TestCase):
|
||||||
available_configurations=self.fake_configurations),
|
available_configurations=self.fake_configurations),
|
||||||
([('/d/' + GTEST_DBG_DIR, '/d/test/gtest_color_test.py')], []))
|
([('/d/' + GTEST_DBG_DIR, '/d/test/gtest_color_test.py')], []))
|
||||||
|
|
||||||
|
|
||||||
def testNonTestBinary(self):
|
def testNonTestBinary(self):
|
||||||
"""Exercises GetTestsToRun with a non-test parameter."""
|
"""Exercises GetTestsToRun with a non-test parameter."""
|
||||||
|
|
||||||
|
@ -489,16 +489,17 @@ class GetTestsToRunTest(unittest.TestCase):
|
||||||
False,
|
False,
|
||||||
available_configurations=self.fake_configurations))
|
available_configurations=self.fake_configurations))
|
||||||
|
|
||||||
if run_tests.IS_WINDOWS or run_tests.IS_CYGWIN:
|
if run_tests_util.IS_WINDOWS or run_tests_util.IS_CYGWIN:
|
||||||
|
|
||||||
def testDoesNotPickNonExeFilesOnWindows(self):
|
def testDoesNotPickNonExeFilesOnWindows(self):
|
||||||
"""Verifies that GetTestsToRun does not find _test files on Windows."""
|
"""Verifies that GetTestsToRun does not find _test files on Windows."""
|
||||||
|
|
||||||
self.fake_os = FakeOs(FakePath(
|
self.fake_os = FakeOs(FakePath(
|
||||||
current_dir=os.path.abspath(os.path.dirname(run_tests.__file__)),
|
current_dir=os.path.abspath(os.path.dirname(run_tests_util.__file__)),
|
||||||
known_paths=['/d/' + GTEST_DBG_DIR + '/gtest_test', 'test/']))
|
known_paths=['/d/' + GTEST_DBG_DIR + '/gtest_test', 'test/']))
|
||||||
self.test_runner = run_tests.TestRunner(injected_os=self.fake_os,
|
self.test_runner = run_tests_util.TestRunner(script_dir='.',
|
||||||
injected_subprocess=None,
|
injected_os=self.fake_os,
|
||||||
injected_script_dir='.')
|
injected_subprocess=None)
|
||||||
self.AssertResultsEqual(
|
self.AssertResultsEqual(
|
||||||
self.test_runner.GetTestsToRun(
|
self.test_runner.GetTestsToRun(
|
||||||
[],
|
[],
|
||||||
|
@ -525,14 +526,16 @@ class RunTestsTest(unittest.TestCase):
|
||||||
|
|
||||||
def setUp(self):
|
def setUp(self):
|
||||||
self.fake_os = FakeOs(FakePath(
|
self.fake_os = FakeOs(FakePath(
|
||||||
current_dir=os.path.abspath(os.path.dirname(run_tests.__file__)),
|
current_dir=os.path.abspath(os.path.dirname(run_tests_util.__file__)),
|
||||||
known_paths=[
|
known_paths=[
|
||||||
AddExeExtension(GTEST_DBG_DIR + '/gtest_unittest'),
|
AddExeExtension(GTEST_DBG_DIR + '/gtest_unittest'),
|
||||||
AddExeExtension(GTEST_OPT_DIR + '/gtest_unittest'),
|
AddExeExtension(GTEST_OPT_DIR + '/gtest_unittest'),
|
||||||
'test/gtest_color_test.py']))
|
'test/gtest_color_test.py']))
|
||||||
self.fake_configurations = ['dbg', 'opt']
|
self.fake_configurations = ['dbg', 'opt']
|
||||||
self.test_runner = run_tests.TestRunner(injected_os=self.fake_os,
|
self.test_runner = run_tests_util.TestRunner(
|
||||||
injected_subprocess=None)
|
script_dir=os.path.dirname(__file__) or '.',
|
||||||
|
injected_os=self.fake_os,
|
||||||
|
injected_subprocess=None)
|
||||||
self.num_spawn_calls = 0 # A number of calls to spawn.
|
self.num_spawn_calls = 0 # A number of calls to spawn.
|
||||||
|
|
||||||
def testRunPythonTestSuccess(self):
|
def testRunPythonTestSuccess(self):
|
||||||
|
@ -610,5 +613,64 @@ class RunTestsTest(unittest.TestCase):
|
||||||
self.assertEqual(self.num_spawn_calls, 2)
|
self.assertEqual(self.num_spawn_calls, 2)
|
||||||
|
|
||||||
|
|
||||||
|
class ParseArgsTest(unittest.TestCase):
|
||||||
|
"""Exercises ParseArgs."""
|
||||||
|
|
||||||
|
def testNoOptions(self):
|
||||||
|
options, args = run_tests_util.ParseArgs('gtest', argv=['script.py'])
|
||||||
|
self.assertEqual(args, ['script.py'])
|
||||||
|
self.assert_(options.configurations is None)
|
||||||
|
self.assertFalse(options.built_configurations)
|
||||||
|
|
||||||
|
def testOptionC(self):
|
||||||
|
options, args = run_tests_util.ParseArgs(
|
||||||
|
'gtest', argv=['script.py', '-c', 'dbg'])
|
||||||
|
self.assertEqual(args, ['script.py'])
|
||||||
|
self.assertEqual(options.configurations, 'dbg')
|
||||||
|
self.assertFalse(options.built_configurations)
|
||||||
|
|
||||||
|
def testOptionA(self):
|
||||||
|
options, args = run_tests_util.ParseArgs('gtest', argv=['script.py', '-a'])
|
||||||
|
self.assertEqual(args, ['script.py'])
|
||||||
|
self.assertEqual(options.configurations, 'all')
|
||||||
|
self.assertFalse(options.built_configurations)
|
||||||
|
|
||||||
|
def testOptionB(self):
|
||||||
|
options, args = run_tests_util.ParseArgs('gtest', argv=['script.py', '-b'])
|
||||||
|
self.assertEqual(args, ['script.py'])
|
||||||
|
self.assert_(options.configurations is None)
|
||||||
|
self.assertTrue(options.built_configurations)
|
||||||
|
|
||||||
|
def testOptionCAndOptionB(self):
|
||||||
|
options, args = run_tests_util.ParseArgs(
|
||||||
|
'gtest', argv=['script.py', '-c', 'dbg', '-b'])
|
||||||
|
self.assertEqual(args, ['script.py'])
|
||||||
|
self.assertEqual(options.configurations, 'dbg')
|
||||||
|
self.assertTrue(options.built_configurations)
|
||||||
|
|
||||||
|
def testOptionH(self):
|
||||||
|
help_called = [False]
|
||||||
|
|
||||||
|
# Suppresses lint warning on unused arguments. These arguments are
|
||||||
|
# required by optparse, even though they are unused.
|
||||||
|
# pylint: disable-msg=W0613
|
||||||
|
def VerifyHelp(option, opt, value, parser):
|
||||||
|
help_called[0] = True
|
||||||
|
|
||||||
|
# Verifies that -h causes the help callback to be called.
|
||||||
|
help_called[0] = False
|
||||||
|
_, args = run_tests_util.ParseArgs(
|
||||||
|
'gtest', argv=['script.py', '-h'], help_callback=VerifyHelp)
|
||||||
|
self.assertEqual(args, ['script.py'])
|
||||||
|
self.assertTrue(help_called[0])
|
||||||
|
|
||||||
|
# Verifies that --help causes the help callback to be called.
|
||||||
|
help_called[0] = False
|
||||||
|
_, args = run_tests_util.ParseArgs(
|
||||||
|
'gtest', argv=['script.py', '--help'], help_callback=VerifyHelp)
|
||||||
|
self.assertEqual(args, ['script.py'])
|
||||||
|
self.assertTrue(help_called[0])
|
||||||
|
|
||||||
|
|
||||||
if __name__ == '__main__':
|
if __name__ == '__main__':
|
||||||
unittest.main()
|
unittest.main()
|
Loading…
Reference in New Issue
Block a user