1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/media/webrtc/trunk/testing/gtest/test/gtest_test_utils.py Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,305 @@ 1.4 +#!/usr/bin/env python 1.5 +# 1.6 +# Copyright 2006, Google Inc. 1.7 +# All rights reserved. 1.8 +# 1.9 +# Redistribution and use in source and binary forms, with or without 1.10 +# modification, are permitted provided that the following conditions are 1.11 +# met: 1.12 +# 1.13 +# * Redistributions of source code must retain the above copyright 1.14 +# notice, this list of conditions and the following disclaimer. 1.15 +# * Redistributions in binary form must reproduce the above 1.16 +# copyright notice, this list of conditions and the following disclaimer 1.17 +# in the documentation and/or other materials provided with the 1.18 +# distribution. 1.19 +# * Neither the name of Google Inc. nor the names of its 1.20 +# contributors may be used to endorse or promote products derived from 1.21 +# this software without specific prior written permission. 1.22 +# 1.23 +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 1.24 +# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 1.25 +# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 1.26 +# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 1.27 +# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 1.28 +# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 1.29 +# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 1.30 +# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 1.31 +# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 1.32 +# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 1.33 +# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 1.34 + 1.35 +"""Unit test utilities for Google C++ Testing Framework.""" 1.36 + 1.37 +__author__ = 'wan@google.com (Zhanyong Wan)' 1.38 + 1.39 +import atexit 1.40 +import os 1.41 +import shutil 1.42 +import sys 1.43 +import tempfile 1.44 +import unittest 1.45 +_test_module = unittest 1.46 + 1.47 +# Suppresses the 'Import not at the top of the file' lint complaint. 1.48 +# pylint: disable-msg=C6204 1.49 +try: 1.50 + import subprocess 1.51 + _SUBPROCESS_MODULE_AVAILABLE = True 1.52 +except: 1.53 + import popen2 1.54 + _SUBPROCESS_MODULE_AVAILABLE = False 1.55 +# pylint: enable-msg=C6204 1.56 + 1.57 +GTEST_OUTPUT_VAR_NAME = 'GTEST_OUTPUT' 1.58 + 1.59 +IS_WINDOWS = os.name == 'nt' 1.60 +IS_CYGWIN = os.name == 'posix' and 'CYGWIN' in os.uname()[0] 1.61 + 1.62 +# Here we expose a class from a particular module, depending on the 1.63 +# environment. The comment suppresses the 'Invalid variable name' lint 1.64 +# complaint. 1.65 +TestCase = _test_module.TestCase # pylint: disable-msg=C6409 1.66 + 1.67 +# Initially maps a flag to its default value. After 1.68 +# _ParseAndStripGTestFlags() is called, maps a flag to its actual value. 1.69 +_flag_map = {'source_dir': os.path.dirname(sys.argv[0]), 1.70 + 'build_dir': os.path.dirname(sys.argv[0])} 1.71 +_gtest_flags_are_parsed = False 1.72 + 1.73 + 1.74 +def _ParseAndStripGTestFlags(argv): 1.75 + """Parses and strips Google Test flags from argv. This is idempotent.""" 1.76 + 1.77 + # Suppresses the lint complaint about a global variable since we need it 1.78 + # here to maintain module-wide state. 1.79 + global _gtest_flags_are_parsed # pylint: disable-msg=W0603 1.80 + if _gtest_flags_are_parsed: 1.81 + return 1.82 + 1.83 + _gtest_flags_are_parsed = True 1.84 + for flag in _flag_map: 1.85 + # The environment variable overrides the default value. 1.86 + if flag.upper() in os.environ: 1.87 + _flag_map[flag] = os.environ[flag.upper()] 1.88 + 1.89 + # The command line flag overrides the environment variable. 1.90 + i = 1 # Skips the program name. 1.91 + while i < len(argv): 1.92 + prefix = '--' + flag + '=' 1.93 + if argv[i].startswith(prefix): 1.94 + _flag_map[flag] = argv[i][len(prefix):] 1.95 + del argv[i] 1.96 + break 1.97 + else: 1.98 + # We don't increment i in case we just found a --gtest_* flag 1.99 + # and removed it from argv. 1.100 + i += 1 1.101 + 1.102 + 1.103 +def GetFlag(flag): 1.104 + """Returns the value of the given flag.""" 1.105 + 1.106 + # In case GetFlag() is called before Main(), we always call 1.107 + # _ParseAndStripGTestFlags() here to make sure the --gtest_* flags 1.108 + # are parsed. 1.109 + _ParseAndStripGTestFlags(sys.argv) 1.110 + 1.111 + return _flag_map[flag] 1.112 + 1.113 + 1.114 +def GetSourceDir(): 1.115 + """Returns the absolute path of the directory where the .py files are.""" 1.116 + 1.117 + return os.path.abspath(GetFlag('source_dir')) 1.118 + 1.119 + 1.120 +def GetBuildDir(): 1.121 + """Returns the absolute path of the directory where the test binaries are.""" 1.122 + 1.123 + return os.path.abspath(GetFlag('build_dir')) 1.124 + 1.125 + 1.126 +_temp_dir = None 1.127 + 1.128 +def _RemoveTempDir(): 1.129 + if _temp_dir: 1.130 + shutil.rmtree(_temp_dir, ignore_errors=True) 1.131 + 1.132 +atexit.register(_RemoveTempDir) 1.133 + 1.134 + 1.135 +def GetTempDir(): 1.136 + """Returns a directory for temporary files.""" 1.137 + 1.138 + global _temp_dir 1.139 + if not _temp_dir: 1.140 + _temp_dir = tempfile.mkdtemp() 1.141 + return _temp_dir 1.142 + 1.143 + 1.144 +def GetTestExecutablePath(executable_name, build_dir=None): 1.145 + """Returns the absolute path of the test binary given its name. 1.146 + 1.147 + The function will print a message and abort the program if the resulting file 1.148 + doesn't exist. 1.149 + 1.150 + Args: 1.151 + executable_name: name of the test binary that the test script runs. 1.152 + build_dir: directory where to look for executables, by default 1.153 + the result of GetBuildDir(). 1.154 + 1.155 + Returns: 1.156 + The absolute path of the test binary. 1.157 + """ 1.158 + 1.159 + path = os.path.abspath(os.path.join(build_dir or GetBuildDir(), 1.160 + executable_name)) 1.161 + if (IS_WINDOWS or IS_CYGWIN) and not path.endswith('.exe'): 1.162 + path += '.exe' 1.163 + 1.164 + if not os.path.exists(path): 1.165 + message = ( 1.166 + 'Unable to find the test binary. Please make sure to provide path\n' 1.167 + 'to the binary via the --build_dir flag or the BUILD_DIR\n' 1.168 + 'environment variable.') 1.169 + print >> sys.stderr, message 1.170 + sys.exit(1) 1.171 + 1.172 + return path 1.173 + 1.174 + 1.175 +def GetExitStatus(exit_code): 1.176 + """Returns the argument to exit(), or -1 if exit() wasn't called. 1.177 + 1.178 + Args: 1.179 + exit_code: the result value of os.system(command). 1.180 + """ 1.181 + 1.182 + if os.name == 'nt': 1.183 + # On Windows, os.WEXITSTATUS() doesn't work and os.system() returns 1.184 + # the argument to exit() directly. 1.185 + return exit_code 1.186 + else: 1.187 + # On Unix, os.WEXITSTATUS() must be used to extract the exit status 1.188 + # from the result of os.system(). 1.189 + if os.WIFEXITED(exit_code): 1.190 + return os.WEXITSTATUS(exit_code) 1.191 + else: 1.192 + return -1 1.193 + 1.194 + 1.195 +class Subprocess: 1.196 + def __init__(self, command, working_dir=None, capture_stderr=True, env=None): 1.197 + """Changes into a specified directory, if provided, and executes a command. 1.198 + 1.199 + Restores the old directory afterwards. 1.200 + 1.201 + Args: 1.202 + command: The command to run, in the form of sys.argv. 1.203 + working_dir: The directory to change into. 1.204 + capture_stderr: Determines whether to capture stderr in the output member 1.205 + or to discard it. 1.206 + env: Dictionary with environment to pass to the subprocess. 1.207 + 1.208 + Returns: 1.209 + An object that represents outcome of the executed process. It has the 1.210 + following attributes: 1.211 + terminated_by_signal True iff the child process has been terminated 1.212 + by a signal. 1.213 + signal Sygnal that terminated the child process. 1.214 + exited True iff the child process exited normally. 1.215 + exit_code The code with which the child process exited. 1.216 + output Child process's stdout and stderr output 1.217 + combined in a string. 1.218 + """ 1.219 + 1.220 + # The subprocess module is the preferrable way of running programs 1.221 + # since it is available and behaves consistently on all platforms, 1.222 + # including Windows. But it is only available starting in python 2.4. 1.223 + # In earlier python versions, we revert to the popen2 module, which is 1.224 + # available in python 2.0 and later but doesn't provide required 1.225 + # functionality (Popen4) under Windows. This allows us to support Mac 1.226 + # OS X 10.4 Tiger, which has python 2.3 installed. 1.227 + if _SUBPROCESS_MODULE_AVAILABLE: 1.228 + if capture_stderr: 1.229 + stderr = subprocess.STDOUT 1.230 + else: 1.231 + stderr = subprocess.PIPE 1.232 + 1.233 + p = subprocess.Popen(command, 1.234 + stdout=subprocess.PIPE, stderr=stderr, 1.235 + cwd=working_dir, universal_newlines=True, env=env) 1.236 + # communicate returns a tuple with the file obect for the child's 1.237 + # output. 1.238 + self.output = p.communicate()[0] 1.239 + self._return_code = p.returncode 1.240 + else: 1.241 + old_dir = os.getcwd() 1.242 + 1.243 + def _ReplaceEnvDict(dest, src): 1.244 + # Changes made by os.environ.clear are not inheritable by child 1.245 + # processes until Python 2.6. To produce inheritable changes we have 1.246 + # to delete environment items with the del statement. 1.247 + for key in dest.keys(): 1.248 + del dest[key] 1.249 + dest.update(src) 1.250 + 1.251 + # When 'env' is not None, backup the environment variables and replace 1.252 + # them with the passed 'env'. When 'env' is None, we simply use the 1.253 + # current 'os.environ' for compatibility with the subprocess.Popen 1.254 + # semantics used above. 1.255 + if env is not None: 1.256 + old_environ = os.environ.copy() 1.257 + _ReplaceEnvDict(os.environ, env) 1.258 + 1.259 + try: 1.260 + if working_dir is not None: 1.261 + os.chdir(working_dir) 1.262 + if capture_stderr: 1.263 + p = popen2.Popen4(command) 1.264 + else: 1.265 + p = popen2.Popen3(command) 1.266 + p.tochild.close() 1.267 + self.output = p.fromchild.read() 1.268 + ret_code = p.wait() 1.269 + finally: 1.270 + os.chdir(old_dir) 1.271 + 1.272 + # Restore the old environment variables 1.273 + # if they were replaced. 1.274 + if env is not None: 1.275 + _ReplaceEnvDict(os.environ, old_environ) 1.276 + 1.277 + # Converts ret_code to match the semantics of 1.278 + # subprocess.Popen.returncode. 1.279 + if os.WIFSIGNALED(ret_code): 1.280 + self._return_code = -os.WTERMSIG(ret_code) 1.281 + else: # os.WIFEXITED(ret_code) should return True here. 1.282 + self._return_code = os.WEXITSTATUS(ret_code) 1.283 + 1.284 + if self._return_code < 0: 1.285 + self.terminated_by_signal = True 1.286 + self.exited = False 1.287 + self.signal = -self._return_code 1.288 + else: 1.289 + self.terminated_by_signal = False 1.290 + self.exited = True 1.291 + self.exit_code = self._return_code 1.292 + 1.293 + 1.294 +def Main(): 1.295 + """Runs the unit test.""" 1.296 + 1.297 + # We must call _ParseAndStripGTestFlags() before calling 1.298 + # unittest.main(). Otherwise the latter will be confused by the 1.299 + # --gtest_* flags. 1.300 + _ParseAndStripGTestFlags(sys.argv) 1.301 + # The tested binaries should not be writing XML output files unless the 1.302 + # script explicitly instructs them to. 1.303 + # TODO(vladl@google.com): Move this into Subprocess when we implement 1.304 + # passing environment into it as a parameter. 1.305 + if GTEST_OUTPUT_VAR_NAME in os.environ: 1.306 + del os.environ[GTEST_OUTPUT_VAR_NAME] 1.307 + 1.308 + _test_module.main()