1735d57d5d1c055db9e0ef28857e8dc7b3d7d6b9bDavid 'Digit' Turner#!/usr/bin/env python 2735d57d5d1c055db9e0ef28857e8dc7b3d7d6b9bDavid 'Digit' Turner# 3735d57d5d1c055db9e0ef28857e8dc7b3d7d6b9bDavid 'Digit' Turner# Copyright 2006, Google Inc. 4735d57d5d1c055db9e0ef28857e8dc7b3d7d6b9bDavid 'Digit' Turner# All rights reserved. 5735d57d5d1c055db9e0ef28857e8dc7b3d7d6b9bDavid 'Digit' Turner# 6735d57d5d1c055db9e0ef28857e8dc7b3d7d6b9bDavid 'Digit' Turner# Redistribution and use in source and binary forms, with or without 7735d57d5d1c055db9e0ef28857e8dc7b3d7d6b9bDavid 'Digit' Turner# modification, are permitted provided that the following conditions are 8735d57d5d1c055db9e0ef28857e8dc7b3d7d6b9bDavid 'Digit' Turner# met: 9735d57d5d1c055db9e0ef28857e8dc7b3d7d6b9bDavid 'Digit' Turner# 10735d57d5d1c055db9e0ef28857e8dc7b3d7d6b9bDavid 'Digit' Turner# * Redistributions of source code must retain the above copyright 11735d57d5d1c055db9e0ef28857e8dc7b3d7d6b9bDavid 'Digit' Turner# notice, this list of conditions and the following disclaimer. 12735d57d5d1c055db9e0ef28857e8dc7b3d7d6b9bDavid 'Digit' Turner# * Redistributions in binary form must reproduce the above 13735d57d5d1c055db9e0ef28857e8dc7b3d7d6b9bDavid 'Digit' Turner# copyright notice, this list of conditions and the following disclaimer 14735d57d5d1c055db9e0ef28857e8dc7b3d7d6b9bDavid 'Digit' Turner# in the documentation and/or other materials provided with the 15735d57d5d1c055db9e0ef28857e8dc7b3d7d6b9bDavid 'Digit' Turner# distribution. 16735d57d5d1c055db9e0ef28857e8dc7b3d7d6b9bDavid 'Digit' Turner# * Neither the name of Google Inc. nor the names of its 17735d57d5d1c055db9e0ef28857e8dc7b3d7d6b9bDavid 'Digit' Turner# contributors may be used to endorse or promote products derived from 18735d57d5d1c055db9e0ef28857e8dc7b3d7d6b9bDavid 'Digit' Turner# this software without specific prior written permission. 19735d57d5d1c055db9e0ef28857e8dc7b3d7d6b9bDavid 'Digit' Turner# 20735d57d5d1c055db9e0ef28857e8dc7b3d7d6b9bDavid 'Digit' Turner# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 21735d57d5d1c055db9e0ef28857e8dc7b3d7d6b9bDavid 'Digit' Turner# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 22735d57d5d1c055db9e0ef28857e8dc7b3d7d6b9bDavid 'Digit' Turner# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 23735d57d5d1c055db9e0ef28857e8dc7b3d7d6b9bDavid 'Digit' Turner# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 24735d57d5d1c055db9e0ef28857e8dc7b3d7d6b9bDavid 'Digit' Turner# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 25735d57d5d1c055db9e0ef28857e8dc7b3d7d6b9bDavid 'Digit' Turner# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 26735d57d5d1c055db9e0ef28857e8dc7b3d7d6b9bDavid 'Digit' Turner# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 27735d57d5d1c055db9e0ef28857e8dc7b3d7d6b9bDavid 'Digit' Turner# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 28735d57d5d1c055db9e0ef28857e8dc7b3d7d6b9bDavid 'Digit' Turner# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 29735d57d5d1c055db9e0ef28857e8dc7b3d7d6b9bDavid 'Digit' Turner# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 30735d57d5d1c055db9e0ef28857e8dc7b3d7d6b9bDavid 'Digit' Turner# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 31735d57d5d1c055db9e0ef28857e8dc7b3d7d6b9bDavid 'Digit' Turner 32735d57d5d1c055db9e0ef28857e8dc7b3d7d6b9bDavid 'Digit' Turner"""Unit test utilities for Google C++ Testing Framework.""" 33735d57d5d1c055db9e0ef28857e8dc7b3d7d6b9bDavid 'Digit' Turner 34735d57d5d1c055db9e0ef28857e8dc7b3d7d6b9bDavid 'Digit' Turner__author__ = 'wan@google.com (Zhanyong Wan)' 35735d57d5d1c055db9e0ef28857e8dc7b3d7d6b9bDavid 'Digit' Turner 36735d57d5d1c055db9e0ef28857e8dc7b3d7d6b9bDavid 'Digit' Turnerimport atexit 37735d57d5d1c055db9e0ef28857e8dc7b3d7d6b9bDavid 'Digit' Turnerimport os 38735d57d5d1c055db9e0ef28857e8dc7b3d7d6b9bDavid 'Digit' Turnerimport shutil 39735d57d5d1c055db9e0ef28857e8dc7b3d7d6b9bDavid 'Digit' Turnerimport sys 40735d57d5d1c055db9e0ef28857e8dc7b3d7d6b9bDavid 'Digit' Turnerimport tempfile 41735d57d5d1c055db9e0ef28857e8dc7b3d7d6b9bDavid 'Digit' Turnerimport unittest 42735d57d5d1c055db9e0ef28857e8dc7b3d7d6b9bDavid 'Digit' Turner_test_module = unittest 43735d57d5d1c055db9e0ef28857e8dc7b3d7d6b9bDavid 'Digit' Turner 44735d57d5d1c055db9e0ef28857e8dc7b3d7d6b9bDavid 'Digit' Turner# Suppresses the 'Import not at the top of the file' lint complaint. 45735d57d5d1c055db9e0ef28857e8dc7b3d7d6b9bDavid 'Digit' Turner# pylint: disable-msg=C6204 46735d57d5d1c055db9e0ef28857e8dc7b3d7d6b9bDavid 'Digit' Turnertry: 47735d57d5d1c055db9e0ef28857e8dc7b3d7d6b9bDavid 'Digit' Turner import subprocess 48735d57d5d1c055db9e0ef28857e8dc7b3d7d6b9bDavid 'Digit' Turner _SUBPROCESS_MODULE_AVAILABLE = True 49735d57d5d1c055db9e0ef28857e8dc7b3d7d6b9bDavid 'Digit' Turnerexcept: 50735d57d5d1c055db9e0ef28857e8dc7b3d7d6b9bDavid 'Digit' Turner import popen2 51735d57d5d1c055db9e0ef28857e8dc7b3d7d6b9bDavid 'Digit' Turner _SUBPROCESS_MODULE_AVAILABLE = False 52735d57d5d1c055db9e0ef28857e8dc7b3d7d6b9bDavid 'Digit' Turner# pylint: enable-msg=C6204 53735d57d5d1c055db9e0ef28857e8dc7b3d7d6b9bDavid 'Digit' Turner 54735d57d5d1c055db9e0ef28857e8dc7b3d7d6b9bDavid 'Digit' TurnerGTEST_OUTPUT_VAR_NAME = 'GTEST_OUTPUT' 55735d57d5d1c055db9e0ef28857e8dc7b3d7d6b9bDavid 'Digit' Turner 56735d57d5d1c055db9e0ef28857e8dc7b3d7d6b9bDavid 'Digit' TurnerIS_WINDOWS = os.name == 'nt' 57735d57d5d1c055db9e0ef28857e8dc7b3d7d6b9bDavid 'Digit' TurnerIS_CYGWIN = os.name == 'posix' and 'CYGWIN' in os.uname()[0] 58735d57d5d1c055db9e0ef28857e8dc7b3d7d6b9bDavid 'Digit' Turner 59735d57d5d1c055db9e0ef28857e8dc7b3d7d6b9bDavid 'Digit' Turner# Here we expose a class from a particular module, depending on the 60735d57d5d1c055db9e0ef28857e8dc7b3d7d6b9bDavid 'Digit' Turner# environment. The comment suppresses the 'Invalid variable name' lint 61735d57d5d1c055db9e0ef28857e8dc7b3d7d6b9bDavid 'Digit' Turner# complaint. 62735d57d5d1c055db9e0ef28857e8dc7b3d7d6b9bDavid 'Digit' TurnerTestCase = _test_module.TestCase # pylint: disable-msg=C6409 63735d57d5d1c055db9e0ef28857e8dc7b3d7d6b9bDavid 'Digit' Turner 64735d57d5d1c055db9e0ef28857e8dc7b3d7d6b9bDavid 'Digit' Turner# Initially maps a flag to its default value. After 65735d57d5d1c055db9e0ef28857e8dc7b3d7d6b9bDavid 'Digit' Turner# _ParseAndStripGTestFlags() is called, maps a flag to its actual value. 66735d57d5d1c055db9e0ef28857e8dc7b3d7d6b9bDavid 'Digit' Turner_flag_map = {'source_dir': os.path.dirname(sys.argv[0]), 67735d57d5d1c055db9e0ef28857e8dc7b3d7d6b9bDavid 'Digit' Turner 'build_dir': os.path.dirname(sys.argv[0])} 68735d57d5d1c055db9e0ef28857e8dc7b3d7d6b9bDavid 'Digit' Turner_gtest_flags_are_parsed = False 69735d57d5d1c055db9e0ef28857e8dc7b3d7d6b9bDavid 'Digit' Turner 70735d57d5d1c055db9e0ef28857e8dc7b3d7d6b9bDavid 'Digit' Turner 71735d57d5d1c055db9e0ef28857e8dc7b3d7d6b9bDavid 'Digit' Turnerdef _ParseAndStripGTestFlags(argv): 72735d57d5d1c055db9e0ef28857e8dc7b3d7d6b9bDavid 'Digit' Turner """Parses and strips Google Test flags from argv. This is idempotent.""" 73735d57d5d1c055db9e0ef28857e8dc7b3d7d6b9bDavid 'Digit' Turner 74735d57d5d1c055db9e0ef28857e8dc7b3d7d6b9bDavid 'Digit' Turner # Suppresses the lint complaint about a global variable since we need it 75735d57d5d1c055db9e0ef28857e8dc7b3d7d6b9bDavid 'Digit' Turner # here to maintain module-wide state. 76735d57d5d1c055db9e0ef28857e8dc7b3d7d6b9bDavid 'Digit' Turner global _gtest_flags_are_parsed # pylint: disable-msg=W0603 77735d57d5d1c055db9e0ef28857e8dc7b3d7d6b9bDavid 'Digit' Turner if _gtest_flags_are_parsed: 78735d57d5d1c055db9e0ef28857e8dc7b3d7d6b9bDavid 'Digit' Turner return 79735d57d5d1c055db9e0ef28857e8dc7b3d7d6b9bDavid 'Digit' Turner 80735d57d5d1c055db9e0ef28857e8dc7b3d7d6b9bDavid 'Digit' Turner _gtest_flags_are_parsed = True 81735d57d5d1c055db9e0ef28857e8dc7b3d7d6b9bDavid 'Digit' Turner for flag in _flag_map: 82735d57d5d1c055db9e0ef28857e8dc7b3d7d6b9bDavid 'Digit' Turner # The environment variable overrides the default value. 83735d57d5d1c055db9e0ef28857e8dc7b3d7d6b9bDavid 'Digit' Turner if flag.upper() in os.environ: 84735d57d5d1c055db9e0ef28857e8dc7b3d7d6b9bDavid 'Digit' Turner _flag_map[flag] = os.environ[flag.upper()] 85735d57d5d1c055db9e0ef28857e8dc7b3d7d6b9bDavid 'Digit' Turner 86735d57d5d1c055db9e0ef28857e8dc7b3d7d6b9bDavid 'Digit' Turner # The command line flag overrides the environment variable. 87735d57d5d1c055db9e0ef28857e8dc7b3d7d6b9bDavid 'Digit' Turner i = 1 # Skips the program name. 88735d57d5d1c055db9e0ef28857e8dc7b3d7d6b9bDavid 'Digit' Turner while i < len(argv): 89735d57d5d1c055db9e0ef28857e8dc7b3d7d6b9bDavid 'Digit' Turner prefix = '--' + flag + '=' 90735d57d5d1c055db9e0ef28857e8dc7b3d7d6b9bDavid 'Digit' Turner if argv[i].startswith(prefix): 91735d57d5d1c055db9e0ef28857e8dc7b3d7d6b9bDavid 'Digit' Turner _flag_map[flag] = argv[i][len(prefix):] 92735d57d5d1c055db9e0ef28857e8dc7b3d7d6b9bDavid 'Digit' Turner del argv[i] 93735d57d5d1c055db9e0ef28857e8dc7b3d7d6b9bDavid 'Digit' Turner break 94735d57d5d1c055db9e0ef28857e8dc7b3d7d6b9bDavid 'Digit' Turner else: 95735d57d5d1c055db9e0ef28857e8dc7b3d7d6b9bDavid 'Digit' Turner # We don't increment i in case we just found a --gtest_* flag 96735d57d5d1c055db9e0ef28857e8dc7b3d7d6b9bDavid 'Digit' Turner # and removed it from argv. 97735d57d5d1c055db9e0ef28857e8dc7b3d7d6b9bDavid 'Digit' Turner i += 1 98735d57d5d1c055db9e0ef28857e8dc7b3d7d6b9bDavid 'Digit' Turner 99735d57d5d1c055db9e0ef28857e8dc7b3d7d6b9bDavid 'Digit' Turner 100735d57d5d1c055db9e0ef28857e8dc7b3d7d6b9bDavid 'Digit' Turnerdef GetFlag(flag): 101735d57d5d1c055db9e0ef28857e8dc7b3d7d6b9bDavid 'Digit' Turner """Returns the value of the given flag.""" 102735d57d5d1c055db9e0ef28857e8dc7b3d7d6b9bDavid 'Digit' Turner 103735d57d5d1c055db9e0ef28857e8dc7b3d7d6b9bDavid 'Digit' Turner # In case GetFlag() is called before Main(), we always call 104735d57d5d1c055db9e0ef28857e8dc7b3d7d6b9bDavid 'Digit' Turner # _ParseAndStripGTestFlags() here to make sure the --gtest_* flags 105735d57d5d1c055db9e0ef28857e8dc7b3d7d6b9bDavid 'Digit' Turner # are parsed. 106735d57d5d1c055db9e0ef28857e8dc7b3d7d6b9bDavid 'Digit' Turner _ParseAndStripGTestFlags(sys.argv) 107735d57d5d1c055db9e0ef28857e8dc7b3d7d6b9bDavid 'Digit' Turner 108735d57d5d1c055db9e0ef28857e8dc7b3d7d6b9bDavid 'Digit' Turner return _flag_map[flag] 109735d57d5d1c055db9e0ef28857e8dc7b3d7d6b9bDavid 'Digit' Turner 110735d57d5d1c055db9e0ef28857e8dc7b3d7d6b9bDavid 'Digit' Turner 111735d57d5d1c055db9e0ef28857e8dc7b3d7d6b9bDavid 'Digit' Turnerdef GetSourceDir(): 112735d57d5d1c055db9e0ef28857e8dc7b3d7d6b9bDavid 'Digit' Turner """Returns the absolute path of the directory where the .py files are.""" 113735d57d5d1c055db9e0ef28857e8dc7b3d7d6b9bDavid 'Digit' Turner 114735d57d5d1c055db9e0ef28857e8dc7b3d7d6b9bDavid 'Digit' Turner return os.path.abspath(GetFlag('source_dir')) 115735d57d5d1c055db9e0ef28857e8dc7b3d7d6b9bDavid 'Digit' Turner 116735d57d5d1c055db9e0ef28857e8dc7b3d7d6b9bDavid 'Digit' Turner 117735d57d5d1c055db9e0ef28857e8dc7b3d7d6b9bDavid 'Digit' Turnerdef GetBuildDir(): 118735d57d5d1c055db9e0ef28857e8dc7b3d7d6b9bDavid 'Digit' Turner """Returns the absolute path of the directory where the test binaries are.""" 119735d57d5d1c055db9e0ef28857e8dc7b3d7d6b9bDavid 'Digit' Turner 120735d57d5d1c055db9e0ef28857e8dc7b3d7d6b9bDavid 'Digit' Turner return os.path.abspath(GetFlag('build_dir')) 121735d57d5d1c055db9e0ef28857e8dc7b3d7d6b9bDavid 'Digit' Turner 122735d57d5d1c055db9e0ef28857e8dc7b3d7d6b9bDavid 'Digit' Turner 123735d57d5d1c055db9e0ef28857e8dc7b3d7d6b9bDavid 'Digit' Turner_temp_dir = None 124735d57d5d1c055db9e0ef28857e8dc7b3d7d6b9bDavid 'Digit' Turner 125735d57d5d1c055db9e0ef28857e8dc7b3d7d6b9bDavid 'Digit' Turnerdef _RemoveTempDir(): 126735d57d5d1c055db9e0ef28857e8dc7b3d7d6b9bDavid 'Digit' Turner if _temp_dir: 127735d57d5d1c055db9e0ef28857e8dc7b3d7d6b9bDavid 'Digit' Turner shutil.rmtree(_temp_dir, ignore_errors=True) 128735d57d5d1c055db9e0ef28857e8dc7b3d7d6b9bDavid 'Digit' Turner 129735d57d5d1c055db9e0ef28857e8dc7b3d7d6b9bDavid 'Digit' Turneratexit.register(_RemoveTempDir) 130735d57d5d1c055db9e0ef28857e8dc7b3d7d6b9bDavid 'Digit' Turner 131735d57d5d1c055db9e0ef28857e8dc7b3d7d6b9bDavid 'Digit' Turner 132735d57d5d1c055db9e0ef28857e8dc7b3d7d6b9bDavid 'Digit' Turnerdef GetTempDir(): 133735d57d5d1c055db9e0ef28857e8dc7b3d7d6b9bDavid 'Digit' Turner """Returns a directory for temporary files.""" 134735d57d5d1c055db9e0ef28857e8dc7b3d7d6b9bDavid 'Digit' Turner 135735d57d5d1c055db9e0ef28857e8dc7b3d7d6b9bDavid 'Digit' Turner global _temp_dir 136735d57d5d1c055db9e0ef28857e8dc7b3d7d6b9bDavid 'Digit' Turner if not _temp_dir: 137735d57d5d1c055db9e0ef28857e8dc7b3d7d6b9bDavid 'Digit' Turner _temp_dir = tempfile.mkdtemp() 138735d57d5d1c055db9e0ef28857e8dc7b3d7d6b9bDavid 'Digit' Turner return _temp_dir 139735d57d5d1c055db9e0ef28857e8dc7b3d7d6b9bDavid 'Digit' Turner 140735d57d5d1c055db9e0ef28857e8dc7b3d7d6b9bDavid 'Digit' Turner 141735d57d5d1c055db9e0ef28857e8dc7b3d7d6b9bDavid 'Digit' Turnerdef GetTestExecutablePath(executable_name, build_dir=None): 142735d57d5d1c055db9e0ef28857e8dc7b3d7d6b9bDavid 'Digit' Turner """Returns the absolute path of the test binary given its name. 143735d57d5d1c055db9e0ef28857e8dc7b3d7d6b9bDavid 'Digit' Turner 144735d57d5d1c055db9e0ef28857e8dc7b3d7d6b9bDavid 'Digit' Turner The function will print a message and abort the program if the resulting file 145735d57d5d1c055db9e0ef28857e8dc7b3d7d6b9bDavid 'Digit' Turner doesn't exist. 146735d57d5d1c055db9e0ef28857e8dc7b3d7d6b9bDavid 'Digit' Turner 147735d57d5d1c055db9e0ef28857e8dc7b3d7d6b9bDavid 'Digit' Turner Args: 148735d57d5d1c055db9e0ef28857e8dc7b3d7d6b9bDavid 'Digit' Turner executable_name: name of the test binary that the test script runs. 149735d57d5d1c055db9e0ef28857e8dc7b3d7d6b9bDavid 'Digit' Turner build_dir: directory where to look for executables, by default 150735d57d5d1c055db9e0ef28857e8dc7b3d7d6b9bDavid 'Digit' Turner the result of GetBuildDir(). 151735d57d5d1c055db9e0ef28857e8dc7b3d7d6b9bDavid 'Digit' Turner 152735d57d5d1c055db9e0ef28857e8dc7b3d7d6b9bDavid 'Digit' Turner Returns: 153735d57d5d1c055db9e0ef28857e8dc7b3d7d6b9bDavid 'Digit' Turner The absolute path of the test binary. 154735d57d5d1c055db9e0ef28857e8dc7b3d7d6b9bDavid 'Digit' Turner """ 155735d57d5d1c055db9e0ef28857e8dc7b3d7d6b9bDavid 'Digit' Turner 156735d57d5d1c055db9e0ef28857e8dc7b3d7d6b9bDavid 'Digit' Turner path = os.path.abspath(os.path.join(build_dir or GetBuildDir(), 157735d57d5d1c055db9e0ef28857e8dc7b3d7d6b9bDavid 'Digit' Turner executable_name)) 158735d57d5d1c055db9e0ef28857e8dc7b3d7d6b9bDavid 'Digit' Turner if (IS_WINDOWS or IS_CYGWIN) and not path.endswith('.exe'): 159735d57d5d1c055db9e0ef28857e8dc7b3d7d6b9bDavid 'Digit' Turner path += '.exe' 160735d57d5d1c055db9e0ef28857e8dc7b3d7d6b9bDavid 'Digit' Turner 161735d57d5d1c055db9e0ef28857e8dc7b3d7d6b9bDavid 'Digit' Turner if not os.path.exists(path): 162735d57d5d1c055db9e0ef28857e8dc7b3d7d6b9bDavid 'Digit' Turner message = ( 163735d57d5d1c055db9e0ef28857e8dc7b3d7d6b9bDavid 'Digit' Turner 'Unable to find the test binary. Please make sure to provide path\n' 164735d57d5d1c055db9e0ef28857e8dc7b3d7d6b9bDavid 'Digit' Turner 'to the binary via the --build_dir flag or the BUILD_DIR\n' 165735d57d5d1c055db9e0ef28857e8dc7b3d7d6b9bDavid 'Digit' Turner 'environment variable.') 166735d57d5d1c055db9e0ef28857e8dc7b3d7d6b9bDavid 'Digit' Turner print >> sys.stderr, message 167735d57d5d1c055db9e0ef28857e8dc7b3d7d6b9bDavid 'Digit' Turner sys.exit(1) 168735d57d5d1c055db9e0ef28857e8dc7b3d7d6b9bDavid 'Digit' Turner 169735d57d5d1c055db9e0ef28857e8dc7b3d7d6b9bDavid 'Digit' Turner return path 170735d57d5d1c055db9e0ef28857e8dc7b3d7d6b9bDavid 'Digit' Turner 171735d57d5d1c055db9e0ef28857e8dc7b3d7d6b9bDavid 'Digit' Turner 172735d57d5d1c055db9e0ef28857e8dc7b3d7d6b9bDavid 'Digit' Turnerdef GetExitStatus(exit_code): 173735d57d5d1c055db9e0ef28857e8dc7b3d7d6b9bDavid 'Digit' Turner """Returns the argument to exit(), or -1 if exit() wasn't called. 174735d57d5d1c055db9e0ef28857e8dc7b3d7d6b9bDavid 'Digit' Turner 175735d57d5d1c055db9e0ef28857e8dc7b3d7d6b9bDavid 'Digit' Turner Args: 176735d57d5d1c055db9e0ef28857e8dc7b3d7d6b9bDavid 'Digit' Turner exit_code: the result value of os.system(command). 177735d57d5d1c055db9e0ef28857e8dc7b3d7d6b9bDavid 'Digit' Turner """ 178735d57d5d1c055db9e0ef28857e8dc7b3d7d6b9bDavid 'Digit' Turner 179735d57d5d1c055db9e0ef28857e8dc7b3d7d6b9bDavid 'Digit' Turner if os.name == 'nt': 180735d57d5d1c055db9e0ef28857e8dc7b3d7d6b9bDavid 'Digit' Turner # On Windows, os.WEXITSTATUS() doesn't work and os.system() returns 181735d57d5d1c055db9e0ef28857e8dc7b3d7d6b9bDavid 'Digit' Turner # the argument to exit() directly. 182735d57d5d1c055db9e0ef28857e8dc7b3d7d6b9bDavid 'Digit' Turner return exit_code 183735d57d5d1c055db9e0ef28857e8dc7b3d7d6b9bDavid 'Digit' Turner else: 184735d57d5d1c055db9e0ef28857e8dc7b3d7d6b9bDavid 'Digit' Turner # On Unix, os.WEXITSTATUS() must be used to extract the exit status 185735d57d5d1c055db9e0ef28857e8dc7b3d7d6b9bDavid 'Digit' Turner # from the result of os.system(). 186735d57d5d1c055db9e0ef28857e8dc7b3d7d6b9bDavid 'Digit' Turner if os.WIFEXITED(exit_code): 187735d57d5d1c055db9e0ef28857e8dc7b3d7d6b9bDavid 'Digit' Turner return os.WEXITSTATUS(exit_code) 188735d57d5d1c055db9e0ef28857e8dc7b3d7d6b9bDavid 'Digit' Turner else: 189735d57d5d1c055db9e0ef28857e8dc7b3d7d6b9bDavid 'Digit' Turner return -1 190735d57d5d1c055db9e0ef28857e8dc7b3d7d6b9bDavid 'Digit' Turner 191735d57d5d1c055db9e0ef28857e8dc7b3d7d6b9bDavid 'Digit' Turner 192735d57d5d1c055db9e0ef28857e8dc7b3d7d6b9bDavid 'Digit' Turnerclass Subprocess: 193735d57d5d1c055db9e0ef28857e8dc7b3d7d6b9bDavid 'Digit' Turner def __init__(self, command, working_dir=None, capture_stderr=True, env=None): 194735d57d5d1c055db9e0ef28857e8dc7b3d7d6b9bDavid 'Digit' Turner """Changes into a specified directory, if provided, and executes a command. 195735d57d5d1c055db9e0ef28857e8dc7b3d7d6b9bDavid 'Digit' Turner 196735d57d5d1c055db9e0ef28857e8dc7b3d7d6b9bDavid 'Digit' Turner Restores the old directory afterwards. 197735d57d5d1c055db9e0ef28857e8dc7b3d7d6b9bDavid 'Digit' Turner 198735d57d5d1c055db9e0ef28857e8dc7b3d7d6b9bDavid 'Digit' Turner Args: 199735d57d5d1c055db9e0ef28857e8dc7b3d7d6b9bDavid 'Digit' Turner command: The command to run, in the form of sys.argv. 200735d57d5d1c055db9e0ef28857e8dc7b3d7d6b9bDavid 'Digit' Turner working_dir: The directory to change into. 201735d57d5d1c055db9e0ef28857e8dc7b3d7d6b9bDavid 'Digit' Turner capture_stderr: Determines whether to capture stderr in the output member 202735d57d5d1c055db9e0ef28857e8dc7b3d7d6b9bDavid 'Digit' Turner or to discard it. 203735d57d5d1c055db9e0ef28857e8dc7b3d7d6b9bDavid 'Digit' Turner env: Dictionary with environment to pass to the subprocess. 204735d57d5d1c055db9e0ef28857e8dc7b3d7d6b9bDavid 'Digit' Turner 205735d57d5d1c055db9e0ef28857e8dc7b3d7d6b9bDavid 'Digit' Turner Returns: 206735d57d5d1c055db9e0ef28857e8dc7b3d7d6b9bDavid 'Digit' Turner An object that represents outcome of the executed process. It has the 207735d57d5d1c055db9e0ef28857e8dc7b3d7d6b9bDavid 'Digit' Turner following attributes: 208735d57d5d1c055db9e0ef28857e8dc7b3d7d6b9bDavid 'Digit' Turner terminated_by_signal True iff the child process has been terminated 209735d57d5d1c055db9e0ef28857e8dc7b3d7d6b9bDavid 'Digit' Turner by a signal. 210735d57d5d1c055db9e0ef28857e8dc7b3d7d6b9bDavid 'Digit' Turner signal Sygnal that terminated the child process. 211735d57d5d1c055db9e0ef28857e8dc7b3d7d6b9bDavid 'Digit' Turner exited True iff the child process exited normally. 212735d57d5d1c055db9e0ef28857e8dc7b3d7d6b9bDavid 'Digit' Turner exit_code The code with which the child process exited. 213735d57d5d1c055db9e0ef28857e8dc7b3d7d6b9bDavid 'Digit' Turner output Child process's stdout and stderr output 214735d57d5d1c055db9e0ef28857e8dc7b3d7d6b9bDavid 'Digit' Turner combined in a string. 215735d57d5d1c055db9e0ef28857e8dc7b3d7d6b9bDavid 'Digit' Turner """ 216735d57d5d1c055db9e0ef28857e8dc7b3d7d6b9bDavid 'Digit' Turner 217735d57d5d1c055db9e0ef28857e8dc7b3d7d6b9bDavid 'Digit' Turner # The subprocess module is the preferrable way of running programs 218735d57d5d1c055db9e0ef28857e8dc7b3d7d6b9bDavid 'Digit' Turner # since it is available and behaves consistently on all platforms, 219735d57d5d1c055db9e0ef28857e8dc7b3d7d6b9bDavid 'Digit' Turner # including Windows. But it is only available starting in python 2.4. 220735d57d5d1c055db9e0ef28857e8dc7b3d7d6b9bDavid 'Digit' Turner # In earlier python versions, we revert to the popen2 module, which is 221735d57d5d1c055db9e0ef28857e8dc7b3d7d6b9bDavid 'Digit' Turner # available in python 2.0 and later but doesn't provide required 222735d57d5d1c055db9e0ef28857e8dc7b3d7d6b9bDavid 'Digit' Turner # functionality (Popen4) under Windows. This allows us to support Mac 223735d57d5d1c055db9e0ef28857e8dc7b3d7d6b9bDavid 'Digit' Turner # OS X 10.4 Tiger, which has python 2.3 installed. 224735d57d5d1c055db9e0ef28857e8dc7b3d7d6b9bDavid 'Digit' Turner if _SUBPROCESS_MODULE_AVAILABLE: 225735d57d5d1c055db9e0ef28857e8dc7b3d7d6b9bDavid 'Digit' Turner if capture_stderr: 226735d57d5d1c055db9e0ef28857e8dc7b3d7d6b9bDavid 'Digit' Turner stderr = subprocess.STDOUT 227735d57d5d1c055db9e0ef28857e8dc7b3d7d6b9bDavid 'Digit' Turner else: 228735d57d5d1c055db9e0ef28857e8dc7b3d7d6b9bDavid 'Digit' Turner stderr = subprocess.PIPE 229735d57d5d1c055db9e0ef28857e8dc7b3d7d6b9bDavid 'Digit' Turner 230735d57d5d1c055db9e0ef28857e8dc7b3d7d6b9bDavid 'Digit' Turner p = subprocess.Popen(command, 231735d57d5d1c055db9e0ef28857e8dc7b3d7d6b9bDavid 'Digit' Turner stdout=subprocess.PIPE, stderr=stderr, 232735d57d5d1c055db9e0ef28857e8dc7b3d7d6b9bDavid 'Digit' Turner cwd=working_dir, universal_newlines=True, env=env) 233735d57d5d1c055db9e0ef28857e8dc7b3d7d6b9bDavid 'Digit' Turner # communicate returns a tuple with the file obect for the child's 234735d57d5d1c055db9e0ef28857e8dc7b3d7d6b9bDavid 'Digit' Turner # output. 235735d57d5d1c055db9e0ef28857e8dc7b3d7d6b9bDavid 'Digit' Turner self.output = p.communicate()[0] 236735d57d5d1c055db9e0ef28857e8dc7b3d7d6b9bDavid 'Digit' Turner self._return_code = p.returncode 237735d57d5d1c055db9e0ef28857e8dc7b3d7d6b9bDavid 'Digit' Turner else: 238735d57d5d1c055db9e0ef28857e8dc7b3d7d6b9bDavid 'Digit' Turner old_dir = os.getcwd() 239735d57d5d1c055db9e0ef28857e8dc7b3d7d6b9bDavid 'Digit' Turner 240735d57d5d1c055db9e0ef28857e8dc7b3d7d6b9bDavid 'Digit' Turner def _ReplaceEnvDict(dest, src): 241735d57d5d1c055db9e0ef28857e8dc7b3d7d6b9bDavid 'Digit' Turner # Changes made by os.environ.clear are not inheritable by child 242735d57d5d1c055db9e0ef28857e8dc7b3d7d6b9bDavid 'Digit' Turner # processes until Python 2.6. To produce inheritable changes we have 243735d57d5d1c055db9e0ef28857e8dc7b3d7d6b9bDavid 'Digit' Turner # to delete environment items with the del statement. 244735d57d5d1c055db9e0ef28857e8dc7b3d7d6b9bDavid 'Digit' Turner for key in dest.keys(): 245735d57d5d1c055db9e0ef28857e8dc7b3d7d6b9bDavid 'Digit' Turner del dest[key] 246735d57d5d1c055db9e0ef28857e8dc7b3d7d6b9bDavid 'Digit' Turner dest.update(src) 247735d57d5d1c055db9e0ef28857e8dc7b3d7d6b9bDavid 'Digit' Turner 248735d57d5d1c055db9e0ef28857e8dc7b3d7d6b9bDavid 'Digit' Turner # When 'env' is not None, backup the environment variables and replace 249735d57d5d1c055db9e0ef28857e8dc7b3d7d6b9bDavid 'Digit' Turner # them with the passed 'env'. When 'env' is None, we simply use the 250735d57d5d1c055db9e0ef28857e8dc7b3d7d6b9bDavid 'Digit' Turner # current 'os.environ' for compatibility with the subprocess.Popen 251735d57d5d1c055db9e0ef28857e8dc7b3d7d6b9bDavid 'Digit' Turner # semantics used above. 252735d57d5d1c055db9e0ef28857e8dc7b3d7d6b9bDavid 'Digit' Turner if env is not None: 253735d57d5d1c055db9e0ef28857e8dc7b3d7d6b9bDavid 'Digit' Turner old_environ = os.environ.copy() 254735d57d5d1c055db9e0ef28857e8dc7b3d7d6b9bDavid 'Digit' Turner _ReplaceEnvDict(os.environ, env) 255735d57d5d1c055db9e0ef28857e8dc7b3d7d6b9bDavid 'Digit' Turner 256735d57d5d1c055db9e0ef28857e8dc7b3d7d6b9bDavid 'Digit' Turner try: 257735d57d5d1c055db9e0ef28857e8dc7b3d7d6b9bDavid 'Digit' Turner if working_dir is not None: 258735d57d5d1c055db9e0ef28857e8dc7b3d7d6b9bDavid 'Digit' Turner os.chdir(working_dir) 259735d57d5d1c055db9e0ef28857e8dc7b3d7d6b9bDavid 'Digit' Turner if capture_stderr: 260735d57d5d1c055db9e0ef28857e8dc7b3d7d6b9bDavid 'Digit' Turner p = popen2.Popen4(command) 261735d57d5d1c055db9e0ef28857e8dc7b3d7d6b9bDavid 'Digit' Turner else: 262735d57d5d1c055db9e0ef28857e8dc7b3d7d6b9bDavid 'Digit' Turner p = popen2.Popen3(command) 263735d57d5d1c055db9e0ef28857e8dc7b3d7d6b9bDavid 'Digit' Turner p.tochild.close() 264735d57d5d1c055db9e0ef28857e8dc7b3d7d6b9bDavid 'Digit' Turner self.output = p.fromchild.read() 265735d57d5d1c055db9e0ef28857e8dc7b3d7d6b9bDavid 'Digit' Turner ret_code = p.wait() 266735d57d5d1c055db9e0ef28857e8dc7b3d7d6b9bDavid 'Digit' Turner finally: 267735d57d5d1c055db9e0ef28857e8dc7b3d7d6b9bDavid 'Digit' Turner os.chdir(old_dir) 268735d57d5d1c055db9e0ef28857e8dc7b3d7d6b9bDavid 'Digit' Turner 269735d57d5d1c055db9e0ef28857e8dc7b3d7d6b9bDavid 'Digit' Turner # Restore the old environment variables 270735d57d5d1c055db9e0ef28857e8dc7b3d7d6b9bDavid 'Digit' Turner # if they were replaced. 271735d57d5d1c055db9e0ef28857e8dc7b3d7d6b9bDavid 'Digit' Turner if env is not None: 272735d57d5d1c055db9e0ef28857e8dc7b3d7d6b9bDavid 'Digit' Turner _ReplaceEnvDict(os.environ, old_environ) 273735d57d5d1c055db9e0ef28857e8dc7b3d7d6b9bDavid 'Digit' Turner 274735d57d5d1c055db9e0ef28857e8dc7b3d7d6b9bDavid 'Digit' Turner # Converts ret_code to match the semantics of 275735d57d5d1c055db9e0ef28857e8dc7b3d7d6b9bDavid 'Digit' Turner # subprocess.Popen.returncode. 276735d57d5d1c055db9e0ef28857e8dc7b3d7d6b9bDavid 'Digit' Turner if os.WIFSIGNALED(ret_code): 277735d57d5d1c055db9e0ef28857e8dc7b3d7d6b9bDavid 'Digit' Turner self._return_code = -os.WTERMSIG(ret_code) 278735d57d5d1c055db9e0ef28857e8dc7b3d7d6b9bDavid 'Digit' Turner else: # os.WIFEXITED(ret_code) should return True here. 279735d57d5d1c055db9e0ef28857e8dc7b3d7d6b9bDavid 'Digit' Turner self._return_code = os.WEXITSTATUS(ret_code) 280735d57d5d1c055db9e0ef28857e8dc7b3d7d6b9bDavid 'Digit' Turner 281735d57d5d1c055db9e0ef28857e8dc7b3d7d6b9bDavid 'Digit' Turner if self._return_code < 0: 282735d57d5d1c055db9e0ef28857e8dc7b3d7d6b9bDavid 'Digit' Turner self.terminated_by_signal = True 283735d57d5d1c055db9e0ef28857e8dc7b3d7d6b9bDavid 'Digit' Turner self.exited = False 284735d57d5d1c055db9e0ef28857e8dc7b3d7d6b9bDavid 'Digit' Turner self.signal = -self._return_code 285735d57d5d1c055db9e0ef28857e8dc7b3d7d6b9bDavid 'Digit' Turner else: 286735d57d5d1c055db9e0ef28857e8dc7b3d7d6b9bDavid 'Digit' Turner self.terminated_by_signal = False 287735d57d5d1c055db9e0ef28857e8dc7b3d7d6b9bDavid 'Digit' Turner self.exited = True 288735d57d5d1c055db9e0ef28857e8dc7b3d7d6b9bDavid 'Digit' Turner self.exit_code = self._return_code 289735d57d5d1c055db9e0ef28857e8dc7b3d7d6b9bDavid 'Digit' Turner 290735d57d5d1c055db9e0ef28857e8dc7b3d7d6b9bDavid 'Digit' Turner 291735d57d5d1c055db9e0ef28857e8dc7b3d7d6b9bDavid 'Digit' Turnerdef Main(): 292735d57d5d1c055db9e0ef28857e8dc7b3d7d6b9bDavid 'Digit' Turner """Runs the unit test.""" 293735d57d5d1c055db9e0ef28857e8dc7b3d7d6b9bDavid 'Digit' Turner 294735d57d5d1c055db9e0ef28857e8dc7b3d7d6b9bDavid 'Digit' Turner # We must call _ParseAndStripGTestFlags() before calling 295735d57d5d1c055db9e0ef28857e8dc7b3d7d6b9bDavid 'Digit' Turner # unittest.main(). Otherwise the latter will be confused by the 296735d57d5d1c055db9e0ef28857e8dc7b3d7d6b9bDavid 'Digit' Turner # --gtest_* flags. 297735d57d5d1c055db9e0ef28857e8dc7b3d7d6b9bDavid 'Digit' Turner _ParseAndStripGTestFlags(sys.argv) 298735d57d5d1c055db9e0ef28857e8dc7b3d7d6b9bDavid 'Digit' Turner # The tested binaries should not be writing XML output files unless the 299735d57d5d1c055db9e0ef28857e8dc7b3d7d6b9bDavid 'Digit' Turner # script explicitly instructs them to. 300735d57d5d1c055db9e0ef28857e8dc7b3d7d6b9bDavid 'Digit' Turner # TODO(vladl@google.com): Move this into Subprocess when we implement 301735d57d5d1c055db9e0ef28857e8dc7b3d7d6b9bDavid 'Digit' Turner # passing environment into it as a parameter. 302735d57d5d1c055db9e0ef28857e8dc7b3d7d6b9bDavid 'Digit' Turner if GTEST_OUTPUT_VAR_NAME in os.environ: 303735d57d5d1c055db9e0ef28857e8dc7b3d7d6b9bDavid 'Digit' Turner del os.environ[GTEST_OUTPUT_VAR_NAME] 304735d57d5d1c055db9e0ef28857e8dc7b3d7d6b9bDavid 'Digit' Turner 305735d57d5d1c055db9e0ef28857e8dc7b3d7d6b9bDavid 'Digit' Turner _test_module.main() 306