diff options
Diffstat (limited to 'test')
-rwxr-xr-x | test/gtest_filter_unittest.py | 162 | ||||
-rw-r--r-- | test/gtest_filter_unittest_.cc | 19 | ||||
-rwxr-xr-x | test/gtest_output_test.py | 68 | ||||
-rw-r--r-- | test/gtest_output_test_.cc | 6 | ||||
-rw-r--r-- | test/gtest_output_test_golden_lin.txt | 24 | ||||
-rw-r--r-- | test/gtest_output_test_golden_win.txt | 24 | ||||
-rw-r--r-- | test/gtest_unittest.cc | 158 |
7 files changed, 420 insertions, 41 deletions
diff --git a/test/gtest_filter_unittest.py b/test/gtest_filter_unittest.py index 35307a26..c3a016cf 100755 --- a/test/gtest_filter_unittest.py +++ b/test/gtest_filter_unittest.py @@ -36,6 +36,9 @@ the GTEST_FILTER environment variable or the --gtest_filter flag. This script tests such functionality by invoking gtest_filter_unittest_ (a program written with Google Test) with different environments and command line flags. + +Note that test sharding may also influence which tests are filtered. Therefore, +we test that here also. """ __author__ = 'wan@google.com (Zhanyong Wan)' @@ -43,6 +46,7 @@ __author__ = 'wan@google.com (Zhanyong Wan)' import os import re import sets +import tempfile import unittest import gtest_test_utils @@ -51,6 +55,11 @@ import gtest_test_utils # The environment variable for specifying the test filters. FILTER_ENV_VAR = 'GTEST_FILTER' +# The environment variables for test sharding. +TOTAL_SHARDS_ENV_VAR = 'GTEST_TOTAL_SHARDS' +SHARD_INDEX_ENV_VAR = 'GTEST_SHARD_INDEX' +SHARD_STATUS_FILE_ENV_VAR = 'GTEST_SHARD_STATUS_FILE' + # The command line flag for specifying the test filters. FILTER_FLAG = 'gtest_filter' @@ -103,6 +112,9 @@ ACTIVE_TESTS = [ 'BazTest.TestOne', 'BazTest.TestA', 'BazTest.TestB', + + 'HasDeathTest.Test1', + 'HasDeathTest.Test2', ] + PARAM_TESTS param_tests_present = None @@ -121,7 +133,7 @@ def SetEnvVar(env_var, value): def Run(command): """Runs a Google Test program and returns a list of full names of the - tests that were run. + tests that were run along with the test exit code. """ stdout_file = os.popen(command, 'r') @@ -137,9 +149,32 @@ def Run(command): if match is not None: test = match.group(1) tests_run += [test_case + '.' + test] - stdout_file.close() - return tests_run + exit_code = stdout_file.close() + return (tests_run, exit_code) + + +def InvokeWithModifiedEnv(extra_env, function, *args, **kwargs): + """Runs the given function and arguments in a modified environment.""" + try: + original_env = os.environ.copy() + os.environ.update(extra_env) + return function(*args, **kwargs) + finally: + for key in extra_env.iterkeys(): + if key in original_env: + os.environ[key] = original_env[key] + else: + del os.environ[key] + + +def RunWithSharding(total_shards, shard_index, command): + """Runs the Google Test program shard and returns a list of full names of the + tests that were run along with the exit code. + """ + extra_env = {SHARD_INDEX_ENV_VAR: str(shard_index), + TOTAL_SHARDS_ENV_VAR: str(total_shards)} + return InvokeWithModifiedEnv(extra_env, Run, command) # The unit test. @@ -160,6 +195,15 @@ class GTestFilterUnitTest(unittest.TestCase): for elem in rhs: self.assert_(elem in lhs, '%s in %s' % (elem, lhs)) + def AssertPartitionIsValid(self, set_var, list_of_sets): + """Asserts that list_of_sets is a valid partition of set_var.""" + + full_partition = [] + for slice_var in list_of_sets: + full_partition.extend(slice_var) + self.assertEqual(len(set_var), len(full_partition)) + self.assertEqual(sorted(set_var), sorted(full_partition)) + def RunAndVerify(self, gtest_filter, tests_to_run): """Runs gtest_flag_unittest_ with the given filter, and verifies that the right set of tests were run. @@ -173,7 +217,7 @@ class GTestFilterUnitTest(unittest.TestCase): # First, tests using GTEST_FILTER. SetEnvVar(FILTER_ENV_VAR, gtest_filter) - tests_run = Run(COMMAND) + tests_run = Run(COMMAND)[0] SetEnvVar(FILTER_ENV_VAR, None) self.AssertSetEqual(tests_run, tests_to_run) @@ -185,9 +229,27 @@ class GTestFilterUnitTest(unittest.TestCase): else: command = '%s --%s=%s' % (COMMAND, FILTER_FLAG, gtest_filter) - tests_run = Run(command) + tests_run = Run(command)[0] self.AssertSetEqual(tests_run, tests_to_run) + def RunAndVerifyWithSharding(self, gtest_filter, total_shards, tests_to_run, + command=COMMAND, check_exit_0=False): + """Runs all shards of gtest_flag_unittest_ with the given filter, and + verifies that the right set of tests were run. The union of tests run + on each shard should be identical to tests_to_run, without duplicates. + If check_exit_0, make sure that all shards returned 0. + """ + SetEnvVar(FILTER_ENV_VAR, gtest_filter) + partition = [] + for i in range(0, total_shards): + (tests_run, exit_code) = RunWithSharding(total_shards, i, command) + if check_exit_0: + self.assert_(exit_code is None) + partition.append(tests_run) + + self.AssertPartitionIsValid(tests_to_run, partition) + SetEnvVar(FILTER_ENV_VAR, None) + def RunAndVerifyAllowingDisabled(self, gtest_filter, tests_to_run): """Runs gtest_flag_unittest_ with the given filter, and enables disabled tests. Verifies that the right set of tests were run. @@ -197,7 +259,7 @@ class GTestFilterUnitTest(unittest.TestCase): if gtest_filter is not None: command = '%s --%s=%s' % (command, FILTER_FLAG, gtest_filter) - tests_run = Run(command) + tests_run = Run(command)[0] self.AssertSetEqual(tests_run, tests_to_run) def setUp(self): @@ -214,10 +276,22 @@ class GTestFilterUnitTest(unittest.TestCase): self.RunAndVerify(None, ACTIVE_TESTS) + def testDefaultBehaviorWithShards(self): + """Tests the behavior of not specifying the filter, with sharding + enabled. + """ + self.RunAndVerifyWithSharding(None, 1, ACTIVE_TESTS) + self.RunAndVerifyWithSharding(None, 2, ACTIVE_TESTS) + self.RunAndVerifyWithSharding(None, len(ACTIVE_TESTS) - 1, ACTIVE_TESTS) + self.RunAndVerifyWithSharding(None, len(ACTIVE_TESTS), ACTIVE_TESTS) + self.RunAndVerifyWithSharding(None, len(ACTIVE_TESTS) + 1, ACTIVE_TESTS) + def testEmptyFilter(self): """Tests an empty filter.""" self.RunAndVerify('', []) + self.RunAndVerifyWithSharding('', 1, []) + self.RunAndVerifyWithSharding('', 2, []) def testBadFilter(self): """Tests a filter that matches nothing.""" @@ -230,12 +304,14 @@ class GTestFilterUnitTest(unittest.TestCase): self.RunAndVerify('FooTest.Xyz', ['FooTest.Xyz']) self.RunAndVerifyAllowingDisabled('FooTest.Xyz', ['FooTest.Xyz']) + self.RunAndVerifyWithSharding('FooTest.Xyz', 5, ['FooTest.Xyz']) def testUniversalFilters(self): """Tests filters that match everything.""" self.RunAndVerify('*', ACTIVE_TESTS) self.RunAndVerify('*.*', ACTIVE_TESTS) + self.RunAndVerifyWithSharding('*.*', len(ACTIVE_TESTS) - 3, ACTIVE_TESTS) self.RunAndVerifyAllowingDisabled('*', ACTIVE_TESTS + DISABLED_TESTS) self.RunAndVerifyAllowingDisabled('*.*', ACTIVE_TESTS + DISABLED_TESTS) @@ -289,7 +365,10 @@ class GTestFilterUnitTest(unittest.TestCase): 'BazTest.TestOne', 'BazTest.TestA', - 'BazTest.TestB' ] + PARAM_TESTS) + 'BazTest.TestB', + + 'HasDeathTest.Test1', + 'HasDeathTest.Test2', ] + PARAM_TESTS) def testWildcardInTestName(self): """Tests using wildcard in the test name.""" @@ -350,7 +429,8 @@ class GTestFilterUnitTest(unittest.TestCase): ]) def testNegativeFilters(self): - self.RunAndVerify('*-FooTest.Abc', [ + self.RunAndVerify('*-HasDeathTest.Test1', [ + 'FooTest.Abc', 'FooTest.Xyz', 'BarTest.TestOne', @@ -360,14 +440,20 @@ class GTestFilterUnitTest(unittest.TestCase): 'BazTest.TestOne', 'BazTest.TestA', 'BazTest.TestB', + + 'HasDeathTest.Test2', ] + PARAM_TESTS) - self.RunAndVerify('*-FooTest.Abc:BazTest.*', [ + self.RunAndVerify('*-FooTest.Abc:HasDeathTest.*', [ 'FooTest.Xyz', 'BarTest.TestOne', 'BarTest.TestTwo', 'BarTest.TestThree', + + 'BazTest.TestOne', + 'BazTest.TestA', + 'BazTest.TestB', ] + PARAM_TESTS) self.RunAndVerify('BarTest.*-BarTest.TestOne', [ @@ -376,7 +462,7 @@ class GTestFilterUnitTest(unittest.TestCase): ]) # Tests without leading '*'. - self.RunAndVerify('-FooTest.Abc:FooTest.Xyz', [ + self.RunAndVerify('-FooTest.Abc:FooTest.Xyz:HasDeathTest.*', [ 'BarTest.TestOne', 'BarTest.TestTwo', 'BarTest.TestThree', @@ -412,11 +498,65 @@ class GTestFilterUnitTest(unittest.TestCase): SetEnvVar(FILTER_ENV_VAR, 'Foo*') command = '%s --%s=%s' % (COMMAND, FILTER_FLAG, '*One') - tests_run = Run(command) + tests_run = Run(command)[0] SetEnvVar(FILTER_ENV_VAR, None) self.AssertSetEqual(tests_run, ['BarTest.TestOne', 'BazTest.TestOne']) + def testShardStatusFileIsCreated(self): + """Tests that the shard file is created if specified in the environment.""" + + test_tmpdir = tempfile.mkdtemp() + shard_status_file = os.path.join(test_tmpdir, 'shard_status_file') + self.assert_(not os.path.exists(shard_status_file)) + + extra_env = {SHARD_STATUS_FILE_ENV_VAR: shard_status_file} + stdout_file = InvokeWithModifiedEnv(extra_env, os.popen, COMMAND, 'r') + try: + stdout_file.readlines() + finally: + stdout_file.close() + self.assert_(os.path.exists(shard_status_file)) + os.remove(shard_status_file) + os.removedirs(test_tmpdir) + + def testShardStatusFileIsCreatedWithListTests(self): + """Tests that the shard file is created with --gtest_list_tests.""" + + test_tmpdir = tempfile.mkdtemp() + shard_status_file = os.path.join(test_tmpdir, 'shard_status_file2') + self.assert_(not os.path.exists(shard_status_file)) + + extra_env = {SHARD_STATUS_FILE_ENV_VAR: shard_status_file} + stdout_file = InvokeWithModifiedEnv(extra_env, os.popen, + '%s --gtest_list_tests' % COMMAND, 'r') + try: + stdout_file.readlines() + finally: + stdout_file.close() + self.assert_(os.path.exists(shard_status_file)) + os.remove(shard_status_file) + os.removedirs(test_tmpdir) + + def testShardingWorksWithDeathTests(self): + """Tests integration with death tests and sharding.""" + gtest_filter = 'HasDeathTest.*:SeqP/*' + expected_tests = [ + 'HasDeathTest.Test1', + 'HasDeathTest.Test2', + + 'SeqP/ParamTest.TestX/0', + 'SeqP/ParamTest.TestX/1', + 'SeqP/ParamTest.TestY/0', + 'SeqP/ParamTest.TestY/1', + ] + + for command in (COMMAND + ' --gtest_death_test_style=threadsafe', + COMMAND + ' --gtest_death_test_style=fast'): + self.RunAndVerifyWithSharding(gtest_filter, 3, expected_tests, + check_exit_0=True, command=command) + self.RunAndVerifyWithSharding(gtest_filter, 5, expected_tests, + check_exit_0=True, command=command) if __name__ == '__main__': gtest_test_utils.Main() diff --git a/test/gtest_filter_unittest_.cc b/test/gtest_filter_unittest_.cc index 99610796..22638e0d 100644 --- a/test/gtest_filter_unittest_.cc +++ b/test/gtest_filter_unittest_.cc @@ -91,6 +91,25 @@ TEST(BazTest, DISABLED_TestC) { FAIL() << "Expected failure."; } +// Test case HasDeathTest + +TEST(HasDeathTest, Test1) { +#ifdef GTEST_HAS_DEATH_TEST + EXPECT_DEATH({exit(1);}, + ".*"); +#endif // GTEST_HAS_DEATH_TEST +} + +// We need at least two death tests to make sure that the all death tests +// aren't on the first shard. +TEST(HasDeathTest, Test2) { +#ifdef GTEST_HAS_DEATH_TEST + EXPECT_DEATH({exit(1);}, + ".*"); +#endif // GTEST_HAS_DEATH_TEST +} + + // Test case FoobarTest TEST(DISABLED_FoobarTest, Test1) { diff --git a/test/gtest_output_test.py b/test/gtest_output_test.py index 9aaade2e..f35e0024 100755 --- a/test/gtest_output_test.py +++ b/test/gtest_output_test.py @@ -64,13 +64,17 @@ PROGRAM_PATH = os.path.join(gtest_test_utils.GetBuildDir(), PROGRAM) # At least one command we exercise must not have the # --gtest_internal_skip_environment_and_ad_hoc_tests flag. -COMMAND_WITH_COLOR = PROGRAM_PATH + ' --gtest_color=yes' -COMMAND_WITH_TIME = (PROGRAM_PATH + ' --gtest_print_time ' +COMMAND_WITH_COLOR = ({}, PROGRAM_PATH + ' --gtest_color=yes') +COMMAND_WITH_TIME = ({}, PROGRAM_PATH + ' --gtest_print_time ' '--gtest_internal_skip_environment_and_ad_hoc_tests ' '--gtest_filter="FatalFailureTest.*:LoggingTest.*"') -COMMAND_WITH_DISABLED = (PROGRAM_PATH + ' --gtest_also_run_disabled_tests ' +COMMAND_WITH_DISABLED = ({}, PROGRAM_PATH + ' --gtest_also_run_disabled_tests ' '--gtest_internal_skip_environment_and_ad_hoc_tests ' '--gtest_filter="*DISABLED_*"') +COMMAND_WITH_SHARDING = ({'GTEST_SHARD_INDEX': '1', 'GTEST_TOTAL_SHARDS': '2'}, + PROGRAM_PATH + + ' --gtest_internal_skip_environment_and_ad_hoc_tests ' + ' --gtest_filter="PassingTest.*"') GOLDEN_PATH = os.path.join(gtest_test_utils.GetSourceDir(), GOLDEN_NAME) @@ -136,19 +140,26 @@ def NormalizeOutput(output): return output -def IterShellCommandOutput(cmd, stdin_string=None): +def IterShellCommandOutput(env_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. + env_cmd: The shell command. A 2-tuple where element 0 is a dict + of extra environment variables to set, and element 1 + is a string with the command and any flags. + 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') + # Set and save the environment properly. + old_env_vars = dict(os.environ) + os.environ.update(env_cmd[0]) + stdin_file, stdout_file = os.popen2(env_cmd[1], 'b') + os.environ.clear() + os.environ.update(old_env_vars) # If the caller didn't specify a string for STDIN, gets it from the # parent process. @@ -168,39 +179,50 @@ def IterShellCommandOutput(cmd, stdin_string=None): yield line -def GetShellCommandOutput(cmd, stdin_string=None): +def GetShellCommandOutput(env_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. + env_cmd: The shell command. A 2-tuple where element 0 is a dict + of extra environment variables to set, and element 1 + is a string with the command and any flags. + 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. """ - lines = list(IterShellCommandOutput(cmd, stdin_string)) + lines = list(IterShellCommandOutput(env_cmd, stdin_string)) return string.join(lines, '') -def GetCommandOutput(cmd): +def GetCommandOutput(env_cmd): """Runs a command and returns its output with all file location info stripped off. Args: - cmd: the shell command. + env_cmd: The shell command. A 2-tuple where element 0 is a dict of extra + environment variables to set, and element 1 is a string with + the command and any flags. """ # Disables exception pop-ups on Windows. os.environ['GTEST_CATCH_EXCEPTIONS'] = '1' - return NormalizeOutput(GetShellCommandOutput(cmd, '')) + return NormalizeOutput(GetShellCommandOutput(env_cmd, '')) + + +def GetOutputOfAllCommands(): + """Returns concatenated output from several representative commands.""" + + return (GetCommandOutput(COMMAND_WITH_COLOR) + + GetCommandOutput(COMMAND_WITH_TIME) + + GetCommandOutput(COMMAND_WITH_DISABLED) + + GetCommandOutput(COMMAND_WITH_SHARDING)) class GTestOutputTest(unittest.TestCase): def testOutput(self): - output = (GetCommandOutput(COMMAND_WITH_COLOR) + - GetCommandOutput(COMMAND_WITH_TIME) + - GetCommandOutput(COMMAND_WITH_DISABLED)) + output = GetOutputOfAllCommands() golden_file = open(GOLDEN_PATH, 'rb') golden = golden_file.read() golden_file.close() @@ -214,9 +236,7 @@ class GTestOutputTest(unittest.TestCase): if __name__ == '__main__': if sys.argv[1:] == [GENGOLDEN_FLAG]: - output = (GetCommandOutput(COMMAND_WITH_COLOR) + - GetCommandOutput(COMMAND_WITH_TIME) + - GetCommandOutput(COMMAND_WITH_DISABLED)) + output = GetOutputOfAllCommands() golden_file = open(GOLDEN_PATH, 'wb') golden_file.write(output) golden_file.close() diff --git a/test/gtest_output_test_.cc b/test/gtest_output_test_.cc index 5c76609f..f5748d17 100644 --- a/test/gtest_output_test_.cc +++ b/test/gtest_output_test_.cc @@ -85,6 +85,12 @@ void TryTestSubroutine() { FAIL() << "This should never be reached."; } +TEST(PassingTest, PassingTest1) { +} + +TEST(PassingTest, PassingTest2) { +} + // Tests catching a fatal failure in a subroutine. TEST(FatalFailureTest, FatalFailureInSubroutine) { printf("(expecting a failure that x should be 1)\n"); diff --git a/test/gtest_output_test_golden_lin.txt b/test/gtest_output_test_golden_lin.txt index 74ed7371..46a90fb5 100644 --- a/test/gtest_output_test_golden_lin.txt +++ b/test/gtest_output_test_golden_lin.txt @@ -7,7 +7,7 @@ Expected: true gtest_output_test_.cc:#: Failure Value of: 3 Expected: 2 -[0;32m[==========] [mRunning 54 tests from 22 test cases. +[0;32m[==========] [mRunning 56 tests from 23 test cases. [0;32m[----------] [mGlobal test environment set-up. FooEnvironment::SetUp() called. BarEnvironment::SetUp() called. @@ -26,6 +26,11 @@ BarEnvironment::SetUp() called. [0;32m[----------] [m1 test from My/ATypeParamDeathTest/1, where TypeParam = double [0;32m[ RUN ] [mMy/ATypeParamDeathTest/1.ShouldRunFirst [0;32m[ OK ] [mMy/ATypeParamDeathTest/1.ShouldRunFirst +[0;32m[----------] [m2 tests from PassingTest +[0;32m[ RUN ] [mPassingTest.PassingTest1 +[0;32m[ OK ] [mPassingTest.PassingTest1 +[0;32m[ RUN ] [mPassingTest.PassingTest2 +[0;32m[ OK ] [mPassingTest.PassingTest2 [0;32m[----------] [m3 tests from FatalFailureTest [0;32m[ RUN ] [mFatalFailureTest.FatalFailureInSubroutine (expecting a failure that x should be 1) @@ -508,8 +513,8 @@ FooEnvironment::TearDown() called. gtest_output_test_.cc:#: Failure Failed Expected fatal failure. -[0;32m[==========] [m54 tests from 22 test cases ran. -[0;32m[ PASSED ] [m19 tests. +[0;32m[==========] [m56 tests from 23 test cases ran. +[0;32m[ PASSED ] [m21 tests. [0;31m[ FAILED ] [m35 tests, listed below: [0;31m[ FAILED ] [mFatalFailureTest.FatalFailureInSubroutine [0;31m[ FAILED ] [mFatalFailureTest.FatalFailureInNestedSubroutine @@ -612,3 +617,16 @@ Note: Google Test filter = *DISABLED_* [----------] Global test environment tear-down [==========] 1 test from 1 test case ran. [ PASSED ] 1 test. +Note: Google Test filter = PassingTest.* +Note: This is test shard 1 of 2. +[==========] Running 1 test from 1 test case. +[----------] Global test environment set-up. +[----------] 1 test from PassingTest +[ RUN ] PassingTest.PassingTest2 +[ OK ] PassingTest.PassingTest2 +[----------] Global test environment tear-down +[==========] 1 test from 1 test case ran. +[ PASSED ] 1 test. + + YOU HAVE 1 DISABLED TEST + diff --git a/test/gtest_output_test_golden_win.txt b/test/gtest_output_test_golden_win.txt index 17be5c04..77903ba1 100644 --- a/test/gtest_output_test_golden_win.txt +++ b/test/gtest_output_test_golden_win.txt @@ -5,10 +5,15 @@ gtest_output_test_.cc:#: error: Value of: false Expected: true gtest_output_test_.cc:#: error: Value of: 3 Expected: 2 -[==========] Running 50 tests from 20 test cases. +[==========] Running 52 tests from 21 test cases. [----------] Global test environment set-up. FooEnvironment::SetUp() called. BarEnvironment::SetUp() called. +[----------] 2 tests from PassingTest +[ RUN ] PassingTest.PassingTest1 +[ OK ] PassingTest.PassingTest1 +[ RUN ] PassingTest.PassingTest2 +[ OK ] PassingTest.PassingTest2 [----------] 3 tests from FatalFailureTest [ RUN ] FatalFailureTest.FatalFailureInSubroutine (expecting a failure that x should be 1) @@ -440,8 +445,8 @@ Expected non-fatal failure. FooEnvironment::TearDown() called. gtest_output_test_.cc:#: error: Failed Expected fatal failure. -[==========] 50 tests from 20 test cases ran. -[ PASSED ] 14 tests. +[==========] 52 tests from 21 test cases ran. +[ PASSED ] 16 tests. [ FAILED ] 36 tests, listed below: [ FAILED ] FatalFailureTest.FatalFailureInSubroutine [ FAILED ] FatalFailureTest.FatalFailureInNestedSubroutine @@ -540,3 +545,16 @@ Note: Google Test filter = *DISABLED_* [----------] Global test environment tear-down [==========] 1 test from 1 test case ran. [ PASSED ] 1 test. +Note: Google Test filter = PassingTest.* +Note: This is test shard 1 of 2. +[==========] Running 1 test from 1 test case. +[----------] Global test environment set-up. +[----------] 1 test from PassingTest +[ RUN ] PassingTest.PassingTest2 +[ OK ] PassingTest.PassingTest2 +[----------] Global test environment tear-down +[==========] 1 test from 1 test case ran. +[ PASSED ] 1 test. + + YOU HAVE 1 DISABLED TEST + diff --git a/test/gtest_unittest.cc b/test/gtest_unittest.cc index 4bac8a69..335b9e06 100644 --- a/test/gtest_unittest.cc +++ b/test/gtest_unittest.cc @@ -138,7 +138,10 @@ using testing::internal::GetTestTypeId; using testing::internal::GetTypeId; using testing::internal::GTestFlagSaver; using testing::internal::Int32; +using testing::internal::Int32FromEnvOrDie; using testing::internal::List; +using testing::internal::ShouldRunTestOnShard; +using testing::internal::ShouldShard; using testing::internal::ShouldUseColor; using testing::internal::StreamableToString; using testing::internal::String; @@ -1375,6 +1378,161 @@ TEST(ParseInt32FlagTest, ParsesAndReturnsValidValue) { EXPECT_EQ(-789, value); } +// Tests that Int32FromEnvOrDie() parses the value of the var or +// returns the correct default. +TEST(Int32FromEnvOrDieTest, ParsesAndReturnsValidValue) { + EXPECT_EQ(333, Int32FromEnvOrDie(GTEST_FLAG_PREFIX_UPPER "UnsetVar", 333)); + SetEnv(GTEST_FLAG_PREFIX_UPPER "UnsetVar", "123"); + EXPECT_EQ(123, Int32FromEnvOrDie(GTEST_FLAG_PREFIX_UPPER "UnsetVar", 333)); + SetEnv(GTEST_FLAG_PREFIX_UPPER "UnsetVar", "-123"); + EXPECT_EQ(-123, Int32FromEnvOrDie(GTEST_FLAG_PREFIX_UPPER "UnsetVar", 333)); +} + +#ifdef GTEST_HAS_DEATH_TEST + +// Tests that Int32FromEnvOrDie() aborts with an error message +// if the variable is not an Int32. +TEST(Int32FromEnvOrDieDeathTest, AbortsOnFailure) { + SetEnv(GTEST_FLAG_PREFIX_UPPER "VAR", "xxx"); + EXPECT_DEATH({Int32FromEnvOrDie(GTEST_FLAG_PREFIX_UPPER "VAR", 123);}, + ".*"); +} + +// Tests that Int32FromEnvOrDie() aborts with an error message +// if the variable cannot be represnted by an Int32. +TEST(Int32FromEnvOrDieDeathTest, AbortsOnInt32Overflow) { + SetEnv(GTEST_FLAG_PREFIX_UPPER "VAR", "1234567891234567891234"); + EXPECT_DEATH({Int32FromEnvOrDie(GTEST_FLAG_PREFIX_UPPER "VAR", 123);}, + ".*"); +} + +#endif // GTEST_HAS_DEATH_TEST + + +// Tests that ShouldRunTestOnShard() selects all tests +// where there is 1 shard. +TEST(ShouldRunTestOnShardTest, IsPartitionWhenThereIsOneShard) { + EXPECT_TRUE(ShouldRunTestOnShard(1, 0, 0)); + EXPECT_TRUE(ShouldRunTestOnShard(1, 0, 1)); + EXPECT_TRUE(ShouldRunTestOnShard(1, 0, 2)); + EXPECT_TRUE(ShouldRunTestOnShard(1, 0, 3)); + EXPECT_TRUE(ShouldRunTestOnShard(1, 0, 4)); +} + +class ShouldShardTest : public testing::Test { + protected: + virtual void SetUp() { + index_var_ = GTEST_FLAG_PREFIX_UPPER "INDEX"; + total_var_ = GTEST_FLAG_PREFIX_UPPER "TOTAL"; + } + + virtual void TearDown() { + SetEnv(index_var_, ""); + SetEnv(total_var_, ""); + } + + const char* index_var_; + const char* total_var_; +}; + +// Tests that sharding is disabled if neither of the environment variables +// are set. +TEST_F(ShouldShardTest, ReturnsFalseWhenNeitherEnvVarIsSet) { + SetEnv(index_var_, ""); + SetEnv(total_var_, ""); + + EXPECT_FALSE(ShouldShard(total_var_, index_var_, false)); + EXPECT_FALSE(ShouldShard(total_var_, index_var_, true)); +} + +// Tests that sharding is not enabled if total_shards == 1. +TEST_F(ShouldShardTest, ReturnsFalseWhenTotalShardIsOne) { + SetEnv(index_var_, "0"); + SetEnv(total_var_, "1"); + EXPECT_FALSE(ShouldShard(total_var_, index_var_, false)); + EXPECT_FALSE(ShouldShard(total_var_, index_var_, true)); +} + +// Tests that sharding is enabled if total_shards > 1 and +// we are not in a death test subprocess. +TEST_F(ShouldShardTest, WorksWhenShardEnvVarsAreValid) { + SetEnv(index_var_, "4"); + SetEnv(total_var_, "22"); + EXPECT_TRUE(ShouldShard(total_var_, index_var_, false)); + EXPECT_FALSE(ShouldShard(total_var_, index_var_, true)); + + SetEnv(index_var_, "8"); + SetEnv(total_var_, "9"); + EXPECT_TRUE(ShouldShard(total_var_, index_var_, false)); + EXPECT_FALSE(ShouldShard(total_var_, index_var_, true)); + + SetEnv(index_var_, "0"); + SetEnv(total_var_, "9"); + EXPECT_TRUE(ShouldShard(total_var_, index_var_, false)); + EXPECT_FALSE(ShouldShard(total_var_, index_var_, true)); +} + +#ifdef GTEST_HAS_DEATH_TEST + +// Tests that we exit in error if the sharding values are not valid. +TEST_F(ShouldShardTest, AbortsWhenShardingEnvVarsAreInvalid) { + SetEnv(index_var_, "4"); + SetEnv(total_var_, "4"); + EXPECT_DEATH({ShouldShard(total_var_, index_var_, false);}, + ".*"); + + SetEnv(index_var_, "4"); + SetEnv(total_var_, "-2"); + EXPECT_DEATH({ShouldShard(total_var_, index_var_, false);}, + ".*"); + + SetEnv(index_var_, "5"); + SetEnv(total_var_, ""); + EXPECT_DEATH({ShouldShard(total_var_, index_var_, false);}, + ".*"); + + SetEnv(index_var_, ""); + SetEnv(total_var_, "5"); + EXPECT_DEATH({ShouldShard(total_var_, index_var_, false);}, + ".*"); +} + +#endif // GTEST_HAS_DEATH_TEST + +// Tests that ShouldRunTestOnShard is a partition when 5 +// shards are used. +TEST(ShouldRunTestOnShardTest, IsPartitionWhenThereAreFiveShards) { + // Choose an arbitrary number of tests and shards. + const int num_tests = 17; + const int num_shards = 5; + + // Check partitioning: each test should be on exactly 1 shard. + for (int test_id = 0; test_id < num_tests; test_id++) { + int prev_selected_shard_index = -1; + for (int shard_index = 0; shard_index < num_shards; shard_index++) { + if (ShouldRunTestOnShard(num_shards, shard_index, test_id)) { + if (prev_selected_shard_index < 0) { + prev_selected_shard_index = shard_index; + } else { + ADD_FAILURE() << "Shard " << prev_selected_shard_index << " and " + << shard_index << " are both selected to run test " << test_id; + } + } + } + } + + // Check balance: This is not required by the sharding protocol, but is a + // desirable property for performance. + for (int shard_index = 0; shard_index < num_shards; shard_index++) { + int num_tests_on_shard = 0; + for (int test_id = 0; test_id < num_tests; test_id++) { + num_tests_on_shard += + ShouldRunTestOnShard(num_shards, shard_index, test_id); + } + EXPECT_GE(num_tests_on_shard, num_tests / num_shards); + } +} + // For the same reason we are not explicitly testing everything in the // Test class, there are no separate tests for the following classes // (except for some trivial cases): |