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