media/webrtc/trunk/testing/gtest/test/gtest_test_utils.py

changeset 0
6474c204b198
     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()

mercurial