From 53e0dc4041f660b6517b15b08b496e164be614f1 Mon Sep 17 00:00:00 2001 From: shiqian Date: Thu, 8 Jan 2009 01:10:31 +0000 Subject: [PATCH] Implements the --gtest_death_test_use_fork flag and StaticAssertTypeEq. --- include/gtest/gtest.h | 46 +++++++++++++++ .../internal/gtest-death-test-internal.h | 1 + include/gtest/internal/gtest-filepath.h | 2 +- include/gtest/internal/gtest-string.h | 2 +- src/gtest-death-test.cc | 25 +++++++- src/gtest-internal-inl.h | 4 ++ src/gtest.cc | 2 + test/gtest-death-test_test.cc | 23 ++++++-- test/gtest_env_var_test.py | 1 + test/gtest_env_var_test_.cc | 5 ++ test/gtest_nc.cc | 41 +++++++++++++ test/gtest_nc_test.py | 12 ++++ test/gtest_unittest.cc | 59 +++++++++++++++++++ 13 files changed, 213 insertions(+), 10 deletions(-) diff --git a/include/gtest/gtest.h b/include/gtest/gtest.h index ebd3123b..dfa338b2 100644 --- a/include/gtest/gtest.h +++ b/include/gtest/gtest.h @@ -1242,6 +1242,52 @@ AssertionResult DoubleLE(const char* expr1, const char* expr2, ::testing::internal::ScopedTrace GTEST_CONCAT_TOKEN_(gtest_trace_, __LINE__)(\ __FILE__, __LINE__, ::testing::Message() << (message)) +namespace internal { + +// This template is declared, but intentionally undefined. +template +struct StaticAssertTypeEqHelper; + +template +struct StaticAssertTypeEqHelper {}; + +} // namespace internal + +// Compile-time assertion for type equality. +// StaticAssertTypeEq() compiles iff type1 and type2 are +// the same type. The value it returns is not interesting. +// +// Instead of making StaticAssertTypeEq a class template, we make it a +// function template that invokes a helper class template. This +// prevents a user from misusing StaticAssertTypeEq by +// defining objects of that type. +// +// CAVEAT: +// +// When used inside a method of a class template, +// StaticAssertTypeEq() is effective ONLY IF the method is +// instantiated. For example, given: +// +// template class Foo { +// public: +// void Bar() { testing::StaticAssertTypeEq(); } +// }; +// +// the code: +// +// void Test1() { Foo foo; } +// +// will NOT generate a compiler error, as Foo::Bar() is never +// actually instantiated. Instead, you need: +// +// void Test2() { Foo foo; foo.Bar(); } +// +// to cause a compiler error. +template +bool StaticAssertTypeEq() { + internal::StaticAssertTypeEqHelper(); + return true; +} // Defines a test. // diff --git a/include/gtest/internal/gtest-death-test-internal.h b/include/gtest/internal/gtest-death-test-internal.h index 0769fcaa..3b90c495 100644 --- a/include/gtest/internal/gtest-death-test-internal.h +++ b/include/gtest/internal/gtest-death-test-internal.h @@ -46,6 +46,7 @@ GTEST_DECLARE_string_(internal_run_death_test); // Names of the flags (needed for parsing Google Test flags). const char kDeathTestStyleFlag[] = "death_test_style"; +const char kDeathTestUseFork[] = "death_test_use_fork"; const char kInternalRunDeathTestFlag[] = "internal_run_death_test"; #ifdef GTEST_HAS_DEATH_TEST diff --git a/include/gtest/internal/gtest-filepath.h b/include/gtest/internal/gtest-filepath.h index 9a0682af..07fb86ae 100644 --- a/include/gtest/internal/gtest-filepath.h +++ b/include/gtest/internal/gtest-filepath.h @@ -34,7 +34,7 @@ // This header file declares classes and functions used internally by // Google Test. They are subject to change without notice. // -// This file is #included in testing/base/internal/gtest-internal.h +// This file is #included in . // Do not include this header file separately! #ifndef GTEST_INCLUDE_GTEST_INTERNAL_GTEST_FILEPATH_H_ diff --git a/include/gtest/internal/gtest-string.h b/include/gtest/internal/gtest-string.h index 178f14e1..566a6b57 100644 --- a/include/gtest/internal/gtest-string.h +++ b/include/gtest/internal/gtest-string.h @@ -35,7 +35,7 @@ // Google Test. They are subject to change without notice. They should not used // by code external to Google Test. // -// This header file is #included by testing/base/internal/gtest-internal.h. +// This header file is #included by . // It should not be #included by other files. #ifndef GTEST_INCLUDE_GTEST_INTERNAL_GTEST_STRING_H_ diff --git a/src/gtest-death-test.cc b/src/gtest-death-test.cc index b667682f..6499842c 100644 --- a/src/gtest-death-test.cc +++ b/src/gtest-death-test.cc @@ -68,6 +68,17 @@ GTEST_DEFINE_string_( "\"fast\" (child process runs the death test immediately " "after forking)."); +GTEST_DEFINE_bool_( + death_test_use_fork, + internal::BoolFromGTestEnv("death_test_use_fork", false), + "Instructs to use fork()/_exit() instead of clone() in death tests. " + "Useful when running under valgrind or similar tools if those " + "do not support clone(). Valgrind 3.3.1 will just fail if " + "it sees an unsupported combination of clone() flags. " + "It is not recommended to use this flag w/o valgrind though it will " + "work in 99% of the cases. Once valgrind is fixed, this flag will " + "most likely be removed."); + namespace internal { GTEST_DEFINE_string_( internal_run_death_test, "", @@ -603,8 +614,18 @@ static pid_t ExecDeathTestFork(char* const* argv, int close_fd) { void* const stack_top = static_cast(stack) + (stack_grows_down ? stack_size : 0); ExecDeathTestArgs args = { argv, close_fd }; - const pid_t child_pid = clone(&ExecDeathTestChildMain, stack_top, - SIGCHLD, &args); + pid_t child_pid; + if (GTEST_FLAG(death_test_use_fork)) { + // Valgrind-friendly version. As of valgrind 3.3.1 the clone() call below + // is not supported (valgrind will fail with an error message). + if ((child_pid = fork()) == 0) { + ExecDeathTestChildMain(&args); + _exit(0); + } + } else { + child_pid = clone(&ExecDeathTestChildMain, stack_top, + SIGCHLD, &args); + } GTEST_DEATH_TEST_CHECK_(child_pid != -1); GTEST_DEATH_TEST_CHECK_(munmap(stack, stack_size) != -1); return child_pid; diff --git a/src/gtest-internal-inl.h b/src/gtest-internal-inl.h index b8f67c18..353c40a6 100644 --- a/src/gtest-internal-inl.h +++ b/src/gtest-internal-inl.h @@ -66,6 +66,7 @@ namespace testing { GTEST_DECLARE_bool_(break_on_failure); GTEST_DECLARE_bool_(catch_exceptions); GTEST_DECLARE_string_(color); +GTEST_DECLARE_bool_(death_test_use_fork); GTEST_DECLARE_string_(filter); GTEST_DECLARE_bool_(list_tests); GTEST_DECLARE_string_(output); @@ -100,6 +101,7 @@ class GTestFlagSaver { catch_exceptions_ = GTEST_FLAG(catch_exceptions); color_ = GTEST_FLAG(color); death_test_style_ = GTEST_FLAG(death_test_style); + death_test_use_fork_ = GTEST_FLAG(death_test_use_fork); filter_ = GTEST_FLAG(filter); internal_run_death_test_ = GTEST_FLAG(internal_run_death_test); list_tests_ = GTEST_FLAG(list_tests); @@ -114,6 +116,7 @@ class GTestFlagSaver { GTEST_FLAG(catch_exceptions) = catch_exceptions_; GTEST_FLAG(color) = color_; GTEST_FLAG(death_test_style) = death_test_style_; + GTEST_FLAG(death_test_use_fork) = death_test_use_fork_; GTEST_FLAG(filter) = filter_; GTEST_FLAG(internal_run_death_test) = internal_run_death_test_; GTEST_FLAG(list_tests) = list_tests_; @@ -127,6 +130,7 @@ class GTestFlagSaver { bool catch_exceptions_; String color_; String death_test_style_; + bool death_test_use_fork_; String filter_; String internal_run_death_test_; bool list_tests_; diff --git a/src/gtest.cc b/src/gtest.cc index a9ca334a..ae20d874 100644 --- a/src/gtest.cc +++ b/src/gtest.cc @@ -3867,6 +3867,8 @@ void ParseGoogleTestFlagsOnlyImpl(int* argc, CharType** argv) { ParseStringFlag(arg, kColorFlag, >EST_FLAG(color)) || ParseStringFlag(arg, kDeathTestStyleFlag, >EST_FLAG(death_test_style)) || + ParseBoolFlag(arg, kDeathTestUseFork, + >EST_FLAG(death_test_use_fork)) || ParseStringFlag(arg, kFilterFlag, >EST_FLAG(filter)) || ParseStringFlag(arg, kInternalRunDeathTestFlag, >EST_FLAG(internal_run_death_test)) || diff --git a/test/gtest-death-test_test.cc b/test/gtest-death-test_test.cc index 07268d00..204ec413 100644 --- a/test/gtest-death-test_test.cc +++ b/test/gtest-death-test_test.cc @@ -347,11 +347,13 @@ void SetPthreadFlag() { } // namespace TEST_F(TestForDeathTest, DoesNotExecuteAtforkHooks) { - testing::GTEST_FLAG(death_test_style) = "threadsafe"; - pthread_flag = false; - ASSERT_EQ(0, pthread_atfork(&SetPthreadFlag, NULL, NULL)); - ASSERT_DEATH(_exit(1), ""); - ASSERT_FALSE(pthread_flag); + if (!testing::GTEST_FLAG(death_test_use_fork)) { + testing::GTEST_FLAG(death_test_style) = "threadsafe"; + pthread_flag = false; + ASSERT_EQ(0, pthread_atfork(&SetPthreadFlag, NULL, NULL)); + ASSERT_DEATH(_exit(1), ""); + ASSERT_FALSE(pthread_flag); + } } // Tests that a method of another class can be used in a death test. @@ -561,7 +563,7 @@ TEST_F(TestForDeathTest, AssertDebugDeathAborts) { #endif // _NDEBUG // Tests the *_EXIT family of macros, using a variety of predicates. -TEST_F(TestForDeathTest, ExitMacros) { +static void TestExitMacros() { EXPECT_EXIT(_exit(1), testing::ExitedWithCode(1), ""); ASSERT_EXIT(_exit(42), testing::ExitedWithCode(42), ""); EXPECT_EXIT(raise(SIGKILL), testing::KilledBySignal(SIGKILL), "") << "foo"; @@ -578,6 +580,15 @@ TEST_F(TestForDeathTest, ExitMacros) { }, "This failure is expected, too."); } +TEST_F(TestForDeathTest, ExitMacros) { + TestExitMacros(); +} + +TEST_F(TestForDeathTest, ExitMacrosUsingFork) { + testing::GTEST_FLAG(death_test_use_fork) = true; + TestExitMacros(); +} + TEST_F(TestForDeathTest, InvalidStyle) { testing::GTEST_FLAG(death_test_style) = "rococo"; EXPECT_NONFATAL_FAILURE({ // NOLINT diff --git a/test/gtest_env_var_test.py b/test/gtest_env_var_test.py index 1b86b5a9..67a22493 100755 --- a/test/gtest_env_var_test.py +++ b/test/gtest_env_var_test.py @@ -109,6 +109,7 @@ def TestEnvVarAffectsFlag(command): if IS_LINUX: TestFlag(command, 'stack_trace_depth', '0', '100') TestFlag(command, 'death_test_style', 'thread-safe', 'fast') + TestFlag(command, 'death_test_use_fork', '1', '0') if IS_WINDOWS: diff --git a/test/gtest_env_var_test_.cc b/test/gtest_env_var_test_.cc index 16b31103..bbccd462 100644 --- a/test/gtest_env_var_test_.cc +++ b/test/gtest_env_var_test_.cc @@ -71,6 +71,11 @@ void PrintFlag(const char* flag) { return; } + if (strcmp(flag, "death_test_use_fork") == 0) { + cout << GTEST_FLAG(death_test_use_fork); + return; + } + if (strcmp(flag, "filter") == 0) { cout << GTEST_FLAG(filter); return; diff --git a/test/gtest_nc.cc b/test/gtest_nc.cc index 5cbaeefa..73b5db6d 100644 --- a/test/gtest_nc.cc +++ b/test/gtest_nc.cc @@ -181,6 +181,47 @@ INSTANTIATE_TYPED_TEST_CASE_P(My, FooTest, testing::Types); // Wrong name prefix: "My" has been used. INSTANTIATE_TYPED_TEST_CASE_P(My, FooTest, testing::Types); +#elif defined(TEST_STATIC_ASSERT_TYPE_EQ_IS_NOT_A_TYPE) + +#include + +// Tests that StaticAssertTypeEq cannot be used as a type. +testing::StaticAssertTypeEq dummy; + +#elif defined(TEST_STATIC_ASSERT_TYPE_EQ_WORKS_IN_NAMESPACE) + +#include + +// Tests that StaticAssertTypeEq works in a namespace scope. +static bool dummy = testing::StaticAssertTypeEq(); + +#elif defined(TEST_STATIC_ASSERT_TYPE_EQ_WORKS_IN_CLASS) + +#include + +template +class Helper { + public: + // Tests that StaticAssertTypeEq works in a class. + Helper() { testing::StaticAssertTypeEq(); } + + void DoSomething() {} +}; + +void Test() { + Helper h; + h.DoSomething(); // To avoid the "unused variable" warning. +} + +#elif defined(TEST_STATIC_ASSERT_TYPE_EQ_WORKS_IN_FUNCTION) + +#include + +void Test() { + // Tests that StaticAssertTypeEq works inside a function. + testing::StaticAssertTypeEq(); +} + #else // A sanity test. This should compile. diff --git a/test/gtest_nc_test.py b/test/gtest_nc_test.py index 683bd370..6e77d708 100755 --- a/test/gtest_nc_test.py +++ b/test/gtest_nc_test.py @@ -78,6 +78,18 @@ class GTestNCTest(unittest.TestCase): ('CATCHES_INSTANTIATE_TYPED_TESET_CASE_P_WITH_SAME_NAME_PREFIX', [r'redefinition of.*My.*FooTest']), + ('STATIC_ASSERT_TYPE_EQ_IS_NOT_A_TYPE', + [r'StaticAssertTypeEq.* does not name a type']), + + ('STATIC_ASSERT_TYPE_EQ_WORKS_IN_NAMESPACE', + [r'StaticAssertTypeEq.*int.*const int']), + + ('STATIC_ASSERT_TYPE_EQ_WORKS_IN_CLASS', + [r'StaticAssertTypeEq.*int.*bool']), + + ('STATIC_ASSERT_TYPE_EQ_WORKS_IN_FUNCTION', + [r'StaticAssertTypeEq.*const int.*int']), + ('SANITY', None) ] diff --git a/test/gtest_unittest.cc b/test/gtest_unittest.cc index 1cbb27f6..2794f7ec 100644 --- a/test/gtest_unittest.cc +++ b/test/gtest_unittest.cc @@ -86,6 +86,7 @@ using testing::DoubleLE; using testing::FloatLE; using testing::GTEST_FLAG(break_on_failure); using testing::GTEST_FLAG(catch_exceptions); +using testing::GTEST_FLAG(death_test_use_fork); using testing::GTEST_FLAG(color); using testing::GTEST_FLAG(filter); using testing::GTEST_FLAG(list_tests); @@ -98,6 +99,7 @@ using testing::IsNotSubstring; using testing::IsSubstring; using testing::Message; using testing::ScopedFakeTestPartResultReporter; +using testing::StaticAssertTypeEq; using testing::Test; using testing::TestPartResult; using testing::TestPartResultArray; @@ -1128,6 +1130,7 @@ class GTestFlagSaverTest : public Test { GTEST_FLAG(break_on_failure) = false; GTEST_FLAG(catch_exceptions) = false; + GTEST_FLAG(death_test_use_fork) = false; GTEST_FLAG(color) = "auto"; GTEST_FLAG(filter) = ""; GTEST_FLAG(list_tests) = false; @@ -1149,6 +1152,7 @@ class GTestFlagSaverTest : public Test { EXPECT_FALSE(GTEST_FLAG(break_on_failure)); EXPECT_FALSE(GTEST_FLAG(catch_exceptions)); EXPECT_STREQ("auto", GTEST_FLAG(color).c_str()); + EXPECT_FALSE(GTEST_FLAG(death_test_use_fork)); EXPECT_STREQ("", GTEST_FLAG(filter).c_str()); EXPECT_FALSE(GTEST_FLAG(list_tests)); EXPECT_STREQ("", GTEST_FLAG(output).c_str()); @@ -1158,6 +1162,7 @@ class GTestFlagSaverTest : public Test { GTEST_FLAG(break_on_failure) = true; GTEST_FLAG(catch_exceptions) = true; GTEST_FLAG(color) = "no"; + GTEST_FLAG(death_test_use_fork) = true; GTEST_FLAG(filter) = "abc"; GTEST_FLAG(list_tests) = true; GTEST_FLAG(output) = "xml:foo.xml"; @@ -4064,6 +4069,7 @@ struct Flags { // Constructs a Flags struct where each flag has its default value. Flags() : break_on_failure(false), catch_exceptions(false), + death_test_use_fork(false), filter(""), list_tests(false), output(""), @@ -4088,6 +4094,14 @@ struct Flags { return flags; } + // Creates a Flags struct where the gtest_death_test_use_fork flag has + // the given value. + static Flags DeathTestUseFork(bool death_test_use_fork) { + Flags flags; + flags.death_test_use_fork = death_test_use_fork; + return flags; + } + // Creates a Flags struct where the gtest_filter flag has the given // value. static Flags Filter(const char* filter) { @@ -4131,6 +4145,7 @@ struct Flags { // These fields store the flag values. bool break_on_failure; bool catch_exceptions; + bool death_test_use_fork; const char* filter; bool list_tests; const char* output; @@ -4145,6 +4160,7 @@ class InitGoogleTestTest : public Test { virtual void SetUp() { GTEST_FLAG(break_on_failure) = false; GTEST_FLAG(catch_exceptions) = false; + GTEST_FLAG(death_test_use_fork) = false; GTEST_FLAG(filter) = ""; GTEST_FLAG(list_tests) = false; GTEST_FLAG(output) = ""; @@ -4167,6 +4183,7 @@ class InitGoogleTestTest : public Test { static void CheckFlags(const Flags& expected) { EXPECT_EQ(expected.break_on_failure, GTEST_FLAG(break_on_failure)); EXPECT_EQ(expected.catch_exceptions, GTEST_FLAG(catch_exceptions)); + EXPECT_EQ(expected.death_test_use_fork, GTEST_FLAG(death_test_use_fork)); EXPECT_STREQ(expected.filter, GTEST_FLAG(filter).c_str()); EXPECT_EQ(expected.list_tests, GTEST_FLAG(list_tests)); EXPECT_STREQ(expected.output, GTEST_FLAG(output).c_str()); @@ -4373,6 +4390,22 @@ TEST_F(InitGoogleTestTest, CatchExceptions) { TEST_PARSING_FLAGS(argv, argv2, Flags::CatchExceptions(true)); } +// Tests parsing --gtest_death_test_use_fork. +TEST_F(InitGoogleTestTest, DeathTestUseFork) { + const char* argv[] = { + "foo.exe", + "--gtest_death_test_use_fork", + NULL + }; + + const char* argv2[] = { + "foo.exe", + NULL + }; + + TEST_PARSING_FLAGS(argv, argv2, Flags::DeathTestUseFork(true)); +} + // Tests having the same flag twice with different values. The // expected behavior is that the one coming last takes precedence. TEST_F(InitGoogleTestTest, DuplicatedFlags) { @@ -5000,6 +5033,32 @@ TEST(ColoredOutputTest, UsesColorsWhenTermSupportsColors) { #endif // GTEST_OS_WINDOWS } +// Verifies that StaticAssertTypeEq works in a namespace scope. + +static bool dummy1 = StaticAssertTypeEq(); +static bool dummy2 = StaticAssertTypeEq(); + +// Verifies that StaticAssertTypeEq works in a class. + +template +class StaticAssertTypeEqTestHelper { + public: + StaticAssertTypeEqTestHelper() { StaticAssertTypeEq(); } +}; + +TEST(StaticAssertTypeEqTest, WorksInClass) { + StaticAssertTypeEqTestHelper(); +} + +// Verifies that StaticAssertTypeEq works inside a function. + +typedef int IntAlias; + +TEST(StaticAssertTypeEqTest, CompilesForEqualTypes) { + StaticAssertTypeEq(); + StaticAssertTypeEq(); +} + TEST(ThreadLocalTest, DefaultConstructor) { ThreadLocal t1; EXPECT_EQ(0, t1.get());