?login_element?

Subversion Repositories NedoOS

Rev

Blame | Last modification | View Log | Download | RSS feed

  1. # Copyright 2006, Google Inc.
  2. # All rights reserved.
  3. #
  4. # Redistribution and use in source and binary forms, with or without
  5. # modification, are permitted provided that the following conditions are
  6. # met:
  7. #
  8. #     * Redistributions of source code must retain the above copyright
  9. # notice, this list of conditions and the following disclaimer.
  10. #     * Redistributions in binary form must reproduce the above
  11. # copyright notice, this list of conditions and the following disclaimer
  12. # in the documentation and/or other materials provided with the
  13. # distribution.
  14. #     * Neither the name of Google Inc. nor the names of its
  15. # contributors may be used to endorse or promote products derived from
  16. # this software without specific prior written permission.
  17. #
  18. # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
  19. # "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
  20. # LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
  21. # A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
  22. # OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
  23. # SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
  24. # LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
  25. # DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
  26. # THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
  27. # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
  28. # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  29.  
  30. """Unit test utilities for Google C++ Testing and Mocking Framework."""
  31. # Suppresses the 'Import not at the top of the file' lint complaint.
  32. # pylint: disable-msg=C6204
  33.  
  34. import os
  35. import sys
  36.  
  37. IS_WINDOWS = os.name == 'nt'
  38. IS_CYGWIN = os.name == 'posix' and 'CYGWIN' in os.uname()[0]
  39.  
  40. import atexit
  41. import shutil
  42. import tempfile
  43. import unittest as _test_module
  44.  
  45. try:
  46.   import subprocess
  47.   _SUBPROCESS_MODULE_AVAILABLE = True
  48. except:
  49.   import popen2
  50.   _SUBPROCESS_MODULE_AVAILABLE = False
  51. # pylint: enable-msg=C6204
  52.  
  53. GTEST_OUTPUT_VAR_NAME = 'GTEST_OUTPUT'
  54.  
  55. # The environment variable for specifying the path to the premature-exit file.
  56. PREMATURE_EXIT_FILE_ENV_VAR = 'TEST_PREMATURE_EXIT_FILE'
  57.  
  58. environ = os.environ.copy()
  59.  
  60.  
  61. def SetEnvVar(env_var, value):
  62.   """Sets/unsets an environment variable to a given value."""
  63.  
  64.   if value is not None:
  65.     environ[env_var] = value
  66.   elif env_var in environ:
  67.     del environ[env_var]
  68.  
  69.  
  70. # Here we expose a class from a particular module, depending on the
  71. # environment. The comment suppresses the 'Invalid variable name' lint
  72. # complaint.
  73. TestCase = _test_module.TestCase  # pylint: disable=C6409
  74.  
  75. # Initially maps a flag to its default value. After
  76. # _ParseAndStripGTestFlags() is called, maps a flag to its actual value.
  77. _flag_map = {'source_dir': os.path.dirname(sys.argv[0]),
  78.              'build_dir': os.path.dirname(sys.argv[0])}
  79. _gtest_flags_are_parsed = False
  80.  
  81.  
  82. def _ParseAndStripGTestFlags(argv):
  83.   """Parses and strips Google Test flags from argv.  This is idempotent."""
  84.  
  85.   # Suppresses the lint complaint about a global variable since we need it
  86.   # here to maintain module-wide state.
  87.   global _gtest_flags_are_parsed  # pylint: disable=W0603
  88.   if _gtest_flags_are_parsed:
  89.     return
  90.  
  91.   _gtest_flags_are_parsed = True
  92.   for flag in _flag_map:
  93.     # The environment variable overrides the default value.
  94.     if flag.upper() in os.environ:
  95.       _flag_map[flag] = os.environ[flag.upper()]
  96.  
  97.     # The command line flag overrides the environment variable.
  98.     i = 1  # Skips the program name.
  99.     while i < len(argv):
  100.       prefix = '--' + flag + '='
  101.       if argv[i].startswith(prefix):
  102.         _flag_map[flag] = argv[i][len(prefix):]
  103.         del argv[i]
  104.         break
  105.       else:
  106.         # We don't increment i in case we just found a --gtest_* flag
  107.         # and removed it from argv.
  108.         i += 1
  109.  
  110.  
  111. def GetFlag(flag):
  112.   """Returns the value of the given flag."""
  113.  
  114.   # In case GetFlag() is called before Main(), we always call
  115.   # _ParseAndStripGTestFlags() here to make sure the --gtest_* flags
  116.   # are parsed.
  117.   _ParseAndStripGTestFlags(sys.argv)
  118.  
  119.   return _flag_map[flag]
  120.  
  121.  
  122. def GetSourceDir():
  123.   """Returns the absolute path of the directory where the .py files are."""
  124.  
  125.   return os.path.abspath(GetFlag('source_dir'))
  126.  
  127.  
  128. def GetBuildDir():
  129.   """Returns the absolute path of the directory where the test binaries are."""
  130.  
  131.   return os.path.abspath(GetFlag('build_dir'))
  132.  
  133.  
  134. _temp_dir = None
  135.  
  136. def _RemoveTempDir():
  137.   if _temp_dir:
  138.     shutil.rmtree(_temp_dir, ignore_errors=True)
  139.  
  140. atexit.register(_RemoveTempDir)
  141.  
  142.  
  143. def GetTempDir():
  144.   global _temp_dir
  145.   if not _temp_dir:
  146.     _temp_dir = tempfile.mkdtemp()
  147.   return _temp_dir
  148.  
  149.  
  150. def GetTestExecutablePath(executable_name, build_dir=None):
  151.   """Returns the absolute path of the test binary given its name.
  152.  
  153.  The function will print a message and abort the program if the resulting file
  154.  doesn't exist.
  155.  
  156.  Args:
  157.    executable_name: name of the test binary that the test script runs.
  158.    build_dir:       directory where to look for executables, by default
  159.                     the result of GetBuildDir().
  160.  
  161.  Returns:
  162.    The absolute path of the test binary.
  163.  """
  164.  
  165.   path = os.path.abspath(os.path.join(build_dir or GetBuildDir(),
  166.                                       executable_name))
  167.   if (IS_WINDOWS or IS_CYGWIN) and not path.endswith('.exe'):
  168.     path += '.exe'
  169.  
  170.   if not os.path.exists(path):
  171.     message = (
  172.         'Unable to find the test binary "%s". Please make sure to provide\n'
  173.         'a path to the binary via the --build_dir flag or the BUILD_DIR\n'
  174.         'environment variable.' % path)
  175.     print >> sys.stderr, message
  176.     sys.exit(1)
  177.  
  178.   return path
  179.  
  180.  
  181. def GetExitStatus(exit_code):
  182.   """Returns the argument to exit(), or -1 if exit() wasn't called.
  183.  
  184.  Args:
  185.    exit_code: the result value of os.system(command).
  186.  """
  187.  
  188.   if os.name == 'nt':
  189.     # On Windows, os.WEXITSTATUS() doesn't work and os.system() returns
  190.     # the argument to exit() directly.
  191.     return exit_code
  192.   else:
  193.     # On Unix, os.WEXITSTATUS() must be used to extract the exit status
  194.     # from the result of os.system().
  195.     if os.WIFEXITED(exit_code):
  196.       return os.WEXITSTATUS(exit_code)
  197.     else:
  198.       return -1
  199.  
  200.  
  201. class Subprocess:
  202.   def __init__(self, command, working_dir=None, capture_stderr=True, env=None):
  203.     """Changes into a specified directory, if provided, and executes a command.
  204.  
  205.    Restores the old directory afterwards.
  206.  
  207.    Args:
  208.      command:        The command to run, in the form of sys.argv.
  209.      working_dir:    The directory to change into.
  210.      capture_stderr: Determines whether to capture stderr in the output member
  211.                      or to discard it.
  212.      env:            Dictionary with environment to pass to the subprocess.
  213.  
  214.    Returns:
  215.      An object that represents outcome of the executed process. It has the
  216.      following attributes:
  217.        terminated_by_signal   True iff the child process has been terminated
  218.                               by a signal.
  219.        signal                 Sygnal that terminated the child process.
  220.        exited                 True iff the child process exited normally.
  221.        exit_code              The code with which the child process exited.
  222.        output                 Child process's stdout and stderr output
  223.                               combined in a string.
  224.    """
  225.  
  226.     # The subprocess module is the preferrable way of running programs
  227.     # since it is available and behaves consistently on all platforms,
  228.     # including Windows. But it is only available starting in python 2.4.
  229.     # In earlier python versions, we revert to the popen2 module, which is
  230.     # available in python 2.0 and later but doesn't provide required
  231.     # functionality (Popen4) under Windows. This allows us to support Mac
  232.     # OS X 10.4 Tiger, which has python 2.3 installed.
  233.     if _SUBPROCESS_MODULE_AVAILABLE:
  234.       if capture_stderr:
  235.         stderr = subprocess.STDOUT
  236.       else:
  237.         stderr = subprocess.PIPE
  238.  
  239.       p = subprocess.Popen(command,
  240.                            stdout=subprocess.PIPE, stderr=stderr,
  241.                            cwd=working_dir, universal_newlines=True, env=env)
  242.       # communicate returns a tuple with the file object for the child's
  243.       # output.
  244.       self.output = p.communicate()[0]
  245.       self._return_code = p.returncode
  246.     else:
  247.       old_dir = os.getcwd()
  248.  
  249.       def _ReplaceEnvDict(dest, src):
  250.         # Changes made by os.environ.clear are not inheritable by child
  251.         # processes until Python 2.6. To produce inheritable changes we have
  252.         # to delete environment items with the del statement.
  253.         for key in dest.keys():
  254.           del dest[key]
  255.         dest.update(src)
  256.  
  257.       # When 'env' is not None, backup the environment variables and replace
  258.       # them with the passed 'env'. When 'env' is None, we simply use the
  259.       # current 'os.environ' for compatibility with the subprocess.Popen
  260.       # semantics used above.
  261.       if env is not None:
  262.         old_environ = os.environ.copy()
  263.         _ReplaceEnvDict(os.environ, env)
  264.  
  265.       try:
  266.         if working_dir is not None:
  267.           os.chdir(working_dir)
  268.         if capture_stderr:
  269.           p = popen2.Popen4(command)
  270.         else:
  271.           p = popen2.Popen3(command)
  272.         p.tochild.close()
  273.         self.output = p.fromchild.read()
  274.         ret_code = p.wait()
  275.       finally:
  276.         os.chdir(old_dir)
  277.  
  278.         # Restore the old environment variables
  279.         # if they were replaced.
  280.         if env is not None:
  281.           _ReplaceEnvDict(os.environ, old_environ)
  282.  
  283.       # Converts ret_code to match the semantics of
  284.       # subprocess.Popen.returncode.
  285.       if os.WIFSIGNALED(ret_code):
  286.         self._return_code = -os.WTERMSIG(ret_code)
  287.       else:  # os.WIFEXITED(ret_code) should return True here.
  288.         self._return_code = os.WEXITSTATUS(ret_code)
  289.  
  290.     if self._return_code < 0:
  291.       self.terminated_by_signal = True
  292.       self.exited = False
  293.       self.signal = -self._return_code
  294.     else:
  295.       self.terminated_by_signal = False
  296.       self.exited = True
  297.       self.exit_code = self._return_code
  298.  
  299.  
  300. def Main():
  301.   """Runs the unit test."""
  302.  
  303.   # We must call _ParseAndStripGTestFlags() before calling
  304.   # unittest.main().  Otherwise the latter will be confused by the
  305.   # --gtest_* flags.
  306.   _ParseAndStripGTestFlags(sys.argv)
  307.   # The tested binaries should not be writing XML output files unless the
  308.   # script explicitly instructs them to.
  309.   # FIXME: Move this into Subprocess when we implement
  310.   # passing environment into it as a parameter.
  311.   if GTEST_OUTPUT_VAR_NAME in os.environ:
  312.     del os.environ[GTEST_OUTPUT_VAR_NAME]
  313.  
  314.   _test_module.main()
  315.