Go to the documentation of this file.00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032 """Unit test utilities for Google C++ Testing Framework."""
00033
00034 __author__ = 'wan@google.com (Zhanyong Wan)'
00035
00036 import atexit
00037 import os
00038 import shutil
00039 import sys
00040 import tempfile
00041 import unittest
00042 _test_module = unittest
00043
00044
00045
00046 try:
00047 import subprocess
00048 _SUBPROCESS_MODULE_AVAILABLE = True
00049 except:
00050 import popen2
00051 _SUBPROCESS_MODULE_AVAILABLE = False
00052
00053
00054 GTEST_OUTPUT_VAR_NAME = 'GTEST_OUTPUT'
00055
00056 IS_WINDOWS = os.name == 'nt'
00057 IS_CYGWIN = os.name == 'posix' and 'CYGWIN' in os.uname()[0]
00058
00059
00060 PREMATURE_EXIT_FILE_ENV_VAR = 'TEST_PREMATURE_EXIT_FILE'
00061
00062 environ = os.environ.copy()
00063
00064
00065 def SetEnvVar(env_var, value):
00066 """Sets/unsets an environment variable to a given value."""
00067
00068 if value is not None:
00069 environ[env_var] = value
00070 elif env_var in environ:
00071 del environ[env_var]
00072
00073
00074
00075
00076
00077 TestCase = _test_module.TestCase
00078
00079
00080
00081 _flag_map = {'source_dir': os.path.dirname(sys.argv[0]),
00082 'build_dir': os.path.dirname(sys.argv[0])}
00083 _gtest_flags_are_parsed = False
00084
00085
00086 def _ParseAndStripGTestFlags(argv):
00087 """Parses and strips Google Test flags from argv. This is idempotent."""
00088
00089
00090
00091 global _gtest_flags_are_parsed
00092 if _gtest_flags_are_parsed:
00093 return
00094
00095 _gtest_flags_are_parsed = True
00096 for flag in _flag_map:
00097
00098 if flag.upper() in os.environ:
00099 _flag_map[flag] = os.environ[flag.upper()]
00100
00101
00102 i = 1
00103 while i < len(argv):
00104 prefix = '--' + flag + '='
00105 if argv[i].startswith(prefix):
00106 _flag_map[flag] = argv[i][len(prefix):]
00107 del argv[i]
00108 break
00109 else:
00110
00111
00112 i += 1
00113
00114
00115 def GetFlag(flag):
00116 """Returns the value of the given flag."""
00117
00118
00119
00120
00121 _ParseAndStripGTestFlags(sys.argv)
00122
00123 return _flag_map[flag]
00124
00125
00126 def GetSourceDir():
00127 """Returns the absolute path of the directory where the .py files are."""
00128
00129 return os.path.abspath(GetFlag('source_dir'))
00130
00131
00132 def GetBuildDir():
00133 """Returns the absolute path of the directory where the test binaries are."""
00134
00135 return os.path.abspath(GetFlag('build_dir'))
00136
00137
00138 _temp_dir = None
00139
00140 def _RemoveTempDir():
00141 if _temp_dir:
00142 shutil.rmtree(_temp_dir, ignore_errors=True)
00143
00144 atexit.register(_RemoveTempDir)
00145
00146
00147 def GetTempDir():
00148 """Returns a directory for temporary files."""
00149
00150 global _temp_dir
00151 if not _temp_dir:
00152 _temp_dir = tempfile.mkdtemp()
00153 return _temp_dir
00154
00155
00156 def GetTestExecutablePath(executable_name, build_dir=None):
00157 """Returns the absolute path of the test binary given its name.
00158
00159 The function will print a message and abort the program if the resulting file
00160 doesn't exist.
00161
00162 Args:
00163 executable_name: name of the test binary that the test script runs.
00164 build_dir: directory where to look for executables, by default
00165 the result of GetBuildDir().
00166
00167 Returns:
00168 The absolute path of the test binary.
00169 """
00170
00171 path = os.path.abspath(os.path.join(build_dir or GetBuildDir(),
00172 executable_name))
00173 if (IS_WINDOWS or IS_CYGWIN) and not path.endswith('.exe'):
00174 path += '.exe'
00175
00176 if not os.path.exists(path):
00177 message = (
00178 'Unable to find the test binary "%s". Please make sure to provide\n'
00179 'a path to the binary via the --build_dir flag or the BUILD_DIR\n'
00180 'environment variable.' % path)
00181 print >> sys.stderr, message
00182 sys.exit(1)
00183
00184 return path
00185
00186
00187 def GetExitStatus(exit_code):
00188 """Returns the argument to exit(), or -1 if exit() wasn't called.
00189
00190 Args:
00191 exit_code: the result value of os.system(command).
00192 """
00193
00194 if os.name == 'nt':
00195
00196
00197 return exit_code
00198 else:
00199
00200
00201 if os.WIFEXITED(exit_code):
00202 return os.WEXITSTATUS(exit_code)
00203 else:
00204 return -1
00205
00206
00207 class Subprocess:
00208 def __init__(self, command, working_dir=None, capture_stderr=True, env=None):
00209 """Changes into a specified directory, if provided, and executes a command.
00210
00211 Restores the old directory afterwards.
00212
00213 Args:
00214 command: The command to run, in the form of sys.argv.
00215 working_dir: The directory to change into.
00216 capture_stderr: Determines whether to capture stderr in the output member
00217 or to discard it.
00218 env: Dictionary with environment to pass to the subprocess.
00219
00220 Returns:
00221 An object that represents outcome of the executed process. It has the
00222 following attributes:
00223 terminated_by_signal True iff the child process has been terminated
00224 by a signal.
00225 signal Sygnal that terminated the child process.
00226 exited True iff the child process exited normally.
00227 exit_code The code with which the child process exited.
00228 output Child process's stdout and stderr output
00229 combined in a string.
00230 """
00231
00232
00233
00234
00235
00236
00237
00238
00239 if _SUBPROCESS_MODULE_AVAILABLE:
00240 if capture_stderr:
00241 stderr = subprocess.STDOUT
00242 else:
00243 stderr = subprocess.PIPE
00244
00245 p = subprocess.Popen(command,
00246 stdout=subprocess.PIPE, stderr=stderr,
00247 cwd=working_dir, universal_newlines=True, env=env)
00248
00249
00250 self.output = p.communicate()[0]
00251 self._return_code = p.returncode
00252 else:
00253 old_dir = os.getcwd()
00254
00255 def _ReplaceEnvDict(dest, src):
00256
00257
00258
00259 for key in dest.keys():
00260 del dest[key]
00261 dest.update(src)
00262
00263
00264
00265
00266
00267 if env is not None:
00268 old_environ = os.environ.copy()
00269 _ReplaceEnvDict(os.environ, env)
00270
00271 try:
00272 if working_dir is not None:
00273 os.chdir(working_dir)
00274 if capture_stderr:
00275 p = popen2.Popen4(command)
00276 else:
00277 p = popen2.Popen3(command)
00278 p.tochild.close()
00279 self.output = p.fromchild.read()
00280 ret_code = p.wait()
00281 finally:
00282 os.chdir(old_dir)
00283
00284
00285
00286 if env is not None:
00287 _ReplaceEnvDict(os.environ, old_environ)
00288
00289
00290
00291 if os.WIFSIGNALED(ret_code):
00292 self._return_code = -os.WTERMSIG(ret_code)
00293 else:
00294 self._return_code = os.WEXITSTATUS(ret_code)
00295
00296 if self._return_code < 0:
00297 self.terminated_by_signal = True
00298 self.exited = False
00299 self.signal = -self._return_code
00300 else:
00301 self.terminated_by_signal = False
00302 self.exited = True
00303 self.exit_code = self._return_code
00304
00305
00306 def Main():
00307 """Runs the unit test."""
00308
00309
00310
00311
00312 _ParseAndStripGTestFlags(sys.argv)
00313
00314
00315
00316
00317 if GTEST_OUTPUT_VAR_NAME in os.environ:
00318 del os.environ[GTEST_OUTPUT_VAR_NAME]
00319
00320 _test_module.main()