From 19eb9e9e3d4d5a4f0eee786d7664ca0e45137390 Mon Sep 17 00:00:00 2001 From: "zhanyong.wan" Date: Tue, 24 Nov 2009 20:23:18 +0000 Subject: Pulls in gtest r344; improves implicit_cast (by Zhanyong Wan); makes the Python tests work on Windows (by Vlad Losev); adds run_tests.py (by Vlad Losev). --- include/gmock/internal/gmock-port.h | 40 ++++++------------ run_tests.py | 82 +++++++++++++++++++++++++++++++++++++ scripts/gmock_doctor.py | 6 +-- test/gmock-actions_test.cc | 4 -- test/gmock-port_test.cc | 10 ----- test/gmock_leak_test.py | 50 ++++++++++++---------- test/gmock_output_test.py | 67 ++++-------------------------- test/gmock_test_utils.py | 40 ++++++++++++++++-- 8 files changed, 171 insertions(+), 128 deletions(-) create mode 100755 run_tests.py diff --git a/include/gmock/internal/gmock-port.h b/include/gmock/internal/gmock-port.h index 1bd455b2..0cff73fe 100644 --- a/include/gmock/internal/gmock-port.h +++ b/include/gmock/internal/gmock-port.h @@ -81,39 +81,22 @@ namespace internal { #error "At least Visual C++ 2003 (7.1) is required to compile Google Mock." #endif -// Use implicit_cast as a safe version of static_cast or const_cast -// for upcasting in the type hierarchy (i.e. casting a pointer to Foo -// to a pointer to SuperclassOfFoo or casting a pointer to Foo to -// a const pointer to Foo). -// When you use implicit_cast, the compiler checks that the cast is safe. -// Such explicit implicit_casts are necessary in surprisingly many -// situations where C++ demands an exact type match instead of an -// argument type convertable to a target type. -// -// The From type can be inferred, so the preferred syntax for using -// implicit_cast is the same as for static_cast etc.: +// Use implicit_cast as a safe version of static_cast for upcasting in +// the type hierarchy (e.g. casting a Foo* to a SuperclassOfFoo* or a +// const Foo*). When you use implicit_cast, the compiler checks that +// the cast is safe. Such explicit implicit_casts are necessary in +// surprisingly many situations where C++ demands an exact type match +// instead of an argument type convertable to a target type. +// +// The syntax for using implicit_cast is the same as for static_cast: // // implicit_cast(expr) // // implicit_cast would have been part of the C++ standard library, // but the proposal was submitted too late. It will probably make // its way into the language in the future. -template -inline To implicit_cast(const From& f) { - return f; -} -// Nokia's compiler can't tell which version of implicit_cast to use when -// the source is a const, causing the compilation to fail with the error -// "ambiguous access to overloaded function". So we only support the const -// version of implicit_cast on Symbian. -#if !GTEST_OS_SYMBIAN -// This overload is needed in case the From type has a non-const type -// conversion operator to type To. -template -inline To implicit_cast(From& f) { - return f; -} -#endif +template +inline To implicit_cast(To x) { return x; } // When you upcast (that is, cast a pointer from type Foo to type // SuperclassOfFoo), it's fine to use implicit_cast<>, since upcasts @@ -139,7 +122,8 @@ inline To down_cast(From* f) { // so we only accept pointers // optimized build at run-time, as it will be optimized away // completely. if (false) { - implicit_cast(0); + const To to = NULL; + implicit_cast(to); } #if GTEST_HAS_RTTI diff --git a/run_tests.py b/run_tests.py new file mode 100755 index 00000000..42dc14bf --- /dev/null +++ b/run_tests.py @@ -0,0 +1,82 @@ +#!/usr/bin/env python +# +# Copyright 2008, Google Inc. All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are +# met: +# +# * Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# * Redistributions in binary form must reproduce the above +# copyright notice, this list of conditions and the following disclaimer +# in the documentation and/or other materials provided with the +# distribution. +# * Neither the name of Google Inc. nor the names of its +# contributors may be used to endorse or promote products derived from +# this software without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +"""Runs the specified tests for Google Mock. + +This script requires Python 2.3 or higher. To learn the usage, run it +with -h. +""" + +__author__ = 'vladl@google.com (Vlad Losev)' + + +import os +import sys + +SCRIPT_DIR = os.path.dirname(__file__) or '.' + +# Path to the Google Test code this Google Mock will use. We assume the +# gtest/ directory is either a subdirectory (possibly via a symbolic link) +# of gmock/ or a sibling. +# +# isdir resolves symbolic links. +if os.path.isdir(os.path.join(SCRIPT_DIR, 'gtest/test')): + RUN_TESTS_UTIL_DIR = os.path.join(SCRIPT_DIR, 'gtest/test') +else: + RUN_TESTS_UTIL_DIR = os.path.join(SCRIPT_DIR, '../gtest/test') + +sys.path.append(RUN_TESTS_UTIL_DIR) +import run_tests_util + +def GetGmockBuildDir(injected_os, script_dir, config): + return injected_os.path.normpath(injected_os.path.join(script_dir, + 'scons/build', + config, + 'gmock/scons')) + + +def _Main(): + """Runs all tests for Google Mock.""" + + options, args = run_tests_util.ParseArgs('gtest') + test_runner = run_tests_util.TestRunner( + script_dir=SCRIPT_DIR, + build_dir_var_name='GMOCK_BUILD_DIR', + injected_build_dir_finder=GetGmockBuildDir) + tests = test_runner.GetTestsToRun(args, + options.configurations, + options.built_configurations) + if not tests: + sys.exit(1) # Incorrect parameters given, abort execution. + + sys.exit(test_runner.RunTests(tests[0], tests[1])) + +if __name__ == '__main__': + _Main() diff --git a/scripts/gmock_doctor.py b/scripts/gmock_doctor.py index d21b9ee7..74af1083 100755 --- a/scripts/gmock_doctor.py +++ b/scripts/gmock_doctor.py @@ -340,11 +340,11 @@ def _NeedToUseReturnNullDiagnoser(msg): regex = ('instantiated from \'testing::internal::ReturnAction' '::operator testing::Action\(\) const.*\n' + _FILE_LINE_RE + r'instantiated from here\n' - r'.*gmock-port\.h.*error: invalid conversion from ' - r'\'long int\' to \'(?P.+\*)') + r'.*error: no matching function for call to \'implicit_cast\(' + r'long int&\)') diagnosis = """ You are probably calling Return(NULL) and the compiler isn't sure how to turn -NULL into a %(type)s*. Use ReturnNull() instead. +NULL into the right type. Use ReturnNull() instead. Note: the line number may be off; please fix all instances of Return(NULL).""" return _GenericDiagnoser('NRNULL', 'Need to use ReturnNull', regex, diagnosis, msg) diff --git a/test/gmock-actions_test.cc b/test/gmock-actions_test.cc index e2b1d052..1be4a16c 100644 --- a/test/gmock-actions_test.cc +++ b/test/gmock-actions_test.cc @@ -545,9 +545,6 @@ TEST(ReturnTest, ConvertsArgumentWhenConverted) { << "when performed." ; } -// We do not support non-const type conversions on Symbian. See -// definition of implicit_cast in gmock-port.h for more information. -#if !GTEST_OS_SYMBIAN class DestinationType {}; class SourceType { @@ -560,7 +557,6 @@ TEST(ReturnTest, CanConvertArgumentUsingNonConstTypeCastOperator) { SourceType s; Action action(Return(s)); } -#endif // !GTEST_OS_SYMBIAN // Tests that ReturnNull() returns NULL in a pointer-returning function. TEST(ReturnNullTest, WorksInPointerReturningFunction) { diff --git a/test/gmock-port_test.cc b/test/gmock-port_test.cc index 3d983d52..b2afb932 100644 --- a/test/gmock-port_test.cc +++ b/test/gmock-port_test.cc @@ -76,10 +76,6 @@ TEST(ImplicitCastTest, CanUseInheritance) { EXPECT_EQ(derived.member(), base.member()); } -// The non-const version is not enabled for Symbian since the Nokia compiler -// cannot decide which version of the overloaded implicit_cast method to use -// when the source is a const. -#if !GTEST_OS_SYMBIAN class Castable { public: Castable(bool* converted) : converted_(converted) {} @@ -98,7 +94,6 @@ TEST(ImplicitCastTest, CanUseNonConstCastOperator) { Base base = ::testing::internal::implicit_cast(castable); EXPECT_TRUE(converted); } -#endif // !GTEST_OS_SYMBIAN class ConstCastable { public: @@ -119,10 +114,6 @@ TEST(ImplicitCastTest, CanUseConstCastOperatorOnConstValues) { EXPECT_TRUE(converted); } -// The non-const version is not enabled for Symbian since the Nokia compiler -// cannot decide which version of the overloaded implicit_cast method to use -// when the source is a const. -#if !GTEST_OS_SYMBIAN class ConstAndNonConstCastable { public: ConstAndNonConstCastable(bool* converted, bool* const_converted) @@ -156,7 +147,6 @@ TEST(ImplicitCastTest, CanSelectBetweenConstAndNonConstCasrAppropriately) { EXPECT_FALSE(converted); EXPECT_TRUE(const_converted); } -#endif // !GTEST_OS_SYMBIAN class To { public: diff --git a/test/gmock_leak_test.py b/test/gmock_leak_test.py index 1337e0b0..429cc6ad 100755 --- a/test/gmock_leak_test.py +++ b/test/gmock_leak_test.py @@ -33,51 +33,59 @@ __author__ = 'wan@google.com (Zhanyong Wan)' -import gmock_test_utils import os import unittest -IS_WINDOWS = os.name == 'nt' +import gmock_test_utils -if IS_WINDOWS: - # TODO(wan@google.com): test the opt build too. We should do it - # when Vlad Losev's work on Google Test's Python test driver is - # done, such that we can reuse the work. - PROGRAM = r'..\build.dbg\gmock_leak_test_.exe' -else: - PROGRAM = 'gmock_leak_test_' -PROGRAM_PATH = os.path.join(gmock_test_utils.GetBuildDir(), PROGRAM) -TEST_WITH_EXPECT_CALL = PROGRAM_PATH + ' --gtest_filter=*ExpectCall*' -TEST_WITH_ON_CALL = PROGRAM_PATH + ' --gtest_filter=*OnCall*' -TEST_MULTIPLE_LEAKS = PROGRAM_PATH + ' --gtest_filter=*MultipleLeaked*' +PROGRAM_PATH = gmock_test_utils.GetTestExecutablePath('gmock_leak_test_') +TEST_WITH_EXPECT_CALL = [PROGRAM_PATH, '--gtest_filter=*ExpectCall*'] +TEST_WITH_ON_CALL = [PROGRAM_PATH, '--gtest_filter=*OnCall*'] +TEST_MULTIPLE_LEAKS = [PROGRAM_PATH, '--gtest_filter=*MultipleLeaked*'] class GMockLeakTest(unittest.TestCase): def testCatchesLeakedMockByDefault(self): - self.assertNotEqual(os.system(TEST_WITH_EXPECT_CALL), 0) - self.assertNotEqual(os.system(TEST_WITH_ON_CALL), 0) + self.assertNotEqual( + 0, + gmock_test_utils.Subprocess(TEST_WITH_EXPECT_CALL).exit_code) + self.assertNotEqual( + 0, + gmock_test_utils.Subprocess(TEST_WITH_ON_CALL).exit_code) def testDoesNotCatchLeakedMockWhenDisabled(self): self.assertEquals( - 0, os.system(TEST_WITH_EXPECT_CALL + ' --gmock_catch_leaked_mocks=0')) + 0, + gmock_test_utils.Subprocess(TEST_WITH_EXPECT_CALL + + ['--gmock_catch_leaked_mocks=0']).exit_code) self.assertEquals( - 0, os.system(TEST_WITH_ON_CALL + ' --gmock_catch_leaked_mocks=0')) + 0, + gmock_test_utils.Subprocess(TEST_WITH_ON_CALL + + ['--gmock_catch_leaked_mocks=0']).exit_code) def testCatchesLeakedMockWhenEnabled(self): self.assertNotEqual( - os.system(TEST_WITH_EXPECT_CALL + ' --gmock_catch_leaked_mocks'), 0) + 0, + gmock_test_utils.Subprocess(TEST_WITH_EXPECT_CALL + + ['--gmock_catch_leaked_mocks']).exit_code) self.assertNotEqual( - os.system(TEST_WITH_ON_CALL + ' --gmock_catch_leaked_mocks'), 0) + 0, + gmock_test_utils.Subprocess(TEST_WITH_ON_CALL + + ['--gmock_catch_leaked_mocks']).exit_code) def testCatchesLeakedMockWhenEnabledWithExplictFlagValue(self): self.assertNotEqual( - os.system(TEST_WITH_EXPECT_CALL + ' --gmock_catch_leaked_mocks=1'), 0) + 0, + gmock_test_utils.Subprocess(TEST_WITH_EXPECT_CALL + + ['--gmock_catch_leaked_mocks=1']).exit_code) def testCatchesMultipleLeakedMocks(self): self.assertNotEqual( - os.system(TEST_MULTIPLE_LEAKS + ' --gmock_catch_leaked_mocks'), 0) + 0, + gmock_test_utils.Subprocess(TEST_MULTIPLE_LEAKS + + ['--gmock_catch_leaked_mocks']).exit_code) if __name__ == '__main__': diff --git a/test/gmock_output_test.py b/test/gmock_output_test.py index f43f7074..c5f05b34 100755 --- a/test/gmock_output_test.py +++ b/test/gmock_output_test.py @@ -40,29 +40,21 @@ SYNOPSIS __author__ = 'wan@google.com (Zhanyong Wan)' -import gmock_test_utils import os import re -import string import sys import unittest +import gmock_test_utils + # The flag for generating the golden file GENGOLDEN_FLAG = '--gengolden' -IS_WINDOWS = os.name == 'nt' - -if IS_WINDOWS: - PROGRAM = r'..\build.dbg\gmock_output_test_.exe' -else: - PROGRAM = 'gmock_output_test_' - -PROGRAM_PATH = os.path.join(gmock_test_utils.GetBuildDir(), PROGRAM) -COMMAND = PROGRAM_PATH + ' --gtest_stack_trace_depth=0 --gtest_print_time=0' +PROGRAM_PATH = gmock_test_utils.GetTestExecutablePath('gmock_output_test_') +COMMAND = [PROGRAM_PATH, '--gtest_stack_trace_depth=0', '--gtest_print_time=0'] GOLDEN_NAME = 'gmock_output_test_golden.txt' -GOLDEN_PATH = os.path.join(gmock_test_utils.GetSourceDir(), - GOLDEN_NAME) +GOLDEN_PATH = os.path.join(gmock_test_utils.GetSourceDir(), GOLDEN_NAME) def ToUnixLineEnding(s): @@ -144,51 +136,10 @@ def GetNormalizedOutputAndLeakyTests(output): return (RemoveTestNamesOfLeakedMocks(output), GetLeakyTests(output)) -def IterShellCommandOutput(cmd, stdin_string=None): - """Runs a command in a sub-process, and iterates the lines in its STDOUT. - - Args: - - cmd: The shell command. - stdin_string: The string to be fed to the STDIN of the sub-process; - If None, the sub-process will inherit the STDIN - from the parent process. - """ - - # Spawns cmd in a sub-process, and gets its standard I/O file objects. - stdin_file, stdout_file = os.popen2(cmd, 'b') - - # If the caller didn't specify a string for STDIN, gets it from the - # parent process. - if stdin_string is None: - stdin_string = sys.stdin.read() - - # Feeds the STDIN string to the sub-process. - stdin_file.write(stdin_string) - stdin_file.close() - - while True: - line = stdout_file.readline() - if not line: # EOF - stdout_file.close() - break - - yield line - - -def GetShellCommandOutput(cmd, stdin_string=None): - """Runs a command in a sub-process, and returns its STDOUT in a string. - - Args: - - cmd: The shell command. - stdin_string: The string to be fed to the STDIN of the sub-process; - If None, the sub-process will inherit the STDIN - from the parent process. - """ +def GetShellCommandOutput(cmd): + """Runs a command in a sub-process, and returns its STDOUT in a string.""" - lines = list(IterShellCommandOutput(cmd, stdin_string)) - return string.join(lines, '') + return gmock_test_utils.Subprocess(cmd, capture_stderr=False).output def GetNormalizedCommandOutputAndLeakyTests(cmd): @@ -200,7 +151,7 @@ def GetNormalizedCommandOutputAndLeakyTests(cmd): # Disables exception pop-ups on Windows. os.environ['GTEST_CATCH_EXCEPTIONS'] = '1' - return GetNormalizedOutputAndLeakyTests(GetShellCommandOutput(cmd, '')) + return GetNormalizedOutputAndLeakyTests(GetShellCommandOutput(cmd)) class GMockOutputTest(unittest.TestCase): diff --git a/test/gmock_test_utils.py b/test/gmock_test_utils.py index 2fda138d..ae15a108 100755 --- a/test/gmock_test_utils.py +++ b/test/gmock_test_utils.py @@ -35,7 +35,19 @@ __author__ = 'wan@google.com (Zhanyong Wan)' import os import sys -import unittest + +# Determines path to gtest_test_utils and imports it. +SCRIPT_DIR = os.path.dirname(__file__) or '.' + +# isdir resolves symbolic links. +gtest_tests_util_dir = os.path.join(SCRIPT_DIR, '../gtest/test') +if os.path.isdir(gtest_tests_util_dir): + GTEST_TESTS_UTIL_DIR = gtest_tests_util_dir +else: + GTEST_TESTS_UTIL_DIR = os.path.join(SCRIPT_DIR, '../../gtest/test') + +sys.path.append(GTEST_TESTS_UTIL_DIR) +import gtest_test_utils # pylint: disable-msg=C6204 # Initially maps a flag to its default value. After @@ -96,6 +108,22 @@ def GetBuildDir(): return os.path.abspath(GetFlag('gmock_build_dir')) +def GetTestExecutablePath(executable_name): + """Returns the absolute path of the test binary given its name. + + The function will print a message and abort the program if the resulting file + doesn't exist. + + Args: + executable_name: name of the test binary that the test script runs. + + Returns: + The absolute path of the test binary. + """ + + return gtest_test_utils.GetTestExecutablePath(executable_name, GetBuildDir()) + + def GetExitStatus(exit_code): """Returns the argument to exit(), or -1 if exit() wasn't called. @@ -116,11 +144,15 @@ def GetExitStatus(exit_code): return -1 +# Exposes Subprocess from gtest_test_utils. +Subprocess = gtest_test_utils.Subprocess # pylint: disable-msg=C6409 + + def Main(): """Runs the unit test.""" # We must call _ParseAndStripGMockFlags() before calling - # unittest.main(). Otherwise the latter will be confused by the - # --gmock_* flags. + # gtest_test_utils.Main(). Otherwise unittest.main it calls will be + # confused by the --gmock_* flags. _ParseAndStripGMockFlags(sys.argv) - unittest.main() + gtest_test_utils.Main() -- cgit v1.2.3