diff --git a/include/gtest/gtest.h b/include/gtest/gtest.h index 6d87e035..26d76b26 100644 --- a/include/gtest/gtest.h +++ b/include/gtest/gtest.h @@ -272,6 +272,13 @@ class Test { // Returns true iff the current test has a fatal failure. static bool HasFatalFailure(); + // Returns true iff the current test has a non-fatal failure. + static bool HasNonfatalFailure(); + + // Returns true iff the current test has a (either fatal or + // non-fatal) failure. + static bool HasFailure() { return HasFatalFailure() || HasNonfatalFailure(); } + // Logs a property for the current test. Only the last value for a given // key is remembered. // These are public static so they can be called from utility functions diff --git a/include/gtest/internal/gtest-port.h b/include/gtest/internal/gtest-port.h index 97736314..4267a58f 100644 --- a/include/gtest/internal/gtest-port.h +++ b/include/gtest/internal/gtest-port.h @@ -673,9 +673,9 @@ class ThreadLocal { T value_; }; -// There's no portable way to detect the number of threads, so we just -// return 0 to indicate that we cannot detect it. -inline size_t GetThreadCount() { return 0; } +// Returns the number of threads running in the process, or 0 to indicate that +// we cannot detect it. +size_t GetThreadCount(); // The above synchronization primitives have dummy implementations. // Therefore Google Test is not thread-safe. diff --git a/scons/SConscript b/scons/SConscript index 91bf985b..6a7cc137 100644 --- a/scons/SConscript +++ b/scons/SConscript @@ -273,6 +273,8 @@ if env.get('GTEST_BUILD_SAMPLES', False): GtestSample(env, 'sample2_unittest', gtest_main, additional_sources=['../samples/sample2.cc']) GtestSample(env, 'sample3_unittest', gtest_main) + GtestSample(env, 'sample4_unittest', gtest_main, + additional_sources=['../samples/sample4.cc']) GtestSample(env, 'sample5_unittest', gtest_main, additional_sources=[sample1_obj]) GtestSample(env, 'sample6_unittest', gtest_main) diff --git a/src/gtest-internal-inl.h b/src/gtest-internal-inl.h index dfc1e958..2a90edac 100644 --- a/src/gtest-internal-inl.h +++ b/src/gtest-internal-inl.h @@ -548,6 +548,9 @@ class TestResult { // Returns true iff the test fatally failed. bool HasFatalFailure() const; + // Returns true iff the test has a non-fatal failure. + bool HasNonfatalFailure() const; + // Returns the elapsed time, in milliseconds. TimeInMillis elapsed_time() const { return elapsed_time_; } @@ -575,6 +578,9 @@ class TestResult { // Increments the death test count, returning the new count. int increment_death_test_count() { return ++death_test_count_; } + // Clears the test part results. + void ClearTestPartResults() { test_part_results_.Clear(); } + // Clears the object. void Clear(); private: @@ -1300,6 +1306,11 @@ inline UnitTestImpl* GetUnitTestImpl() { return UnitTest::GetInstance()->impl(); } +// Clears all test part results of the current test. +inline void ClearCurrentTestPartResults() { + GetUnitTestImpl()->current_test_result()->ClearTestPartResults(); +} + // Internal helper functions for implementing the simple regular // expression matcher. bool IsInSet(char ch, const char* str); diff --git a/src/gtest-port.cc b/src/gtest-port.cc index 166ff414..193f5323 100644 --- a/src/gtest-port.cc +++ b/src/gtest-port.cc @@ -42,6 +42,11 @@ #include #endif // GTEST_OS_WINDOWS +#if GTEST_OS_MAC +#include +#include +#endif // GTEST_OS_MAC + #ifdef _WIN32_WCE #include // For TerminateProcess() #endif // _WIN32_WCE @@ -69,6 +74,22 @@ const int kStdErrFileno = 2; const int kStdErrFileno = STDERR_FILENO; #endif // _MSC_VER +// Returns the number of threads running in the process, or 0 to indicate that +// we cannot detect it. +size_t GetThreadCount() { +#if GTEST_OS_MAC + mach_msg_type_number_t thread_count; + thread_act_port_array_t thread_list; + kern_return_t status = task_threads(mach_task_self(), + &thread_list, &thread_count); + return status == KERN_SUCCESS ? static_cast(thread_count) : 0; +#else + // There's no portable way to detect the number of threads, so we just + // return 0 to indicate that we cannot detect it. + return 0; +#endif // GTEST_OS_MAC +} + #if GTEST_USES_POSIX_RE // Implements RE. Currently only needed for death tests. diff --git a/src/gtest.cc b/src/gtest.cc index ac5ed9d5..5903f2ae 100644 --- a/src/gtest.cc +++ b/src/gtest.cc @@ -1852,7 +1852,7 @@ int TestResult::failed_part_count() const { } // Returns true iff the test part fatally failed. -static bool TestPartFatallyFailed(const TestPartResult & result) { +static bool TestPartFatallyFailed(const TestPartResult& result) { return result.fatally_failed(); } @@ -1861,6 +1861,16 @@ bool TestResult::HasFatalFailure() const { return test_part_results_.CountIf(TestPartFatallyFailed) > 0; } +// Returns true iff the test part non-fatally failed. +static bool TestPartNonfatallyFailed(const TestPartResult& result) { + return result.nonfatally_failed(); +} + +// Returns true iff the test has a non-fatal failure. +bool TestResult::HasNonfatalFailure() const { + return test_part_results_.CountIf(TestPartNonfatallyFailed) > 0; +} + // Gets the number of all test parts. This is the sum of the number // of successful test parts and the number of failed test parts. int TestResult::total_part_count() const { @@ -2059,6 +2069,12 @@ bool Test::HasFatalFailure() { return internal::GetUnitTestImpl()->current_test_result()->HasFatalFailure(); } +// Returns true iff the current test has a non-fatal failure. +bool Test::HasNonfatalFailure() { + return internal::GetUnitTestImpl()->current_test_result()-> + HasNonfatalFailure(); +} + // class TestInfo // Constructs a TestInfo object. It assumes ownership of the test factory diff --git a/test/gtest-port_test.cc b/test/gtest-port_test.cc index 0bda6f5e..f4560f19 100644 --- a/test/gtest-port_test.cc +++ b/test/gtest-port_test.cc @@ -32,6 +32,11 @@ // This file tests the internal cross-platform support utilities. #include + +#if GTEST_OS_MAC +#include +#endif // GTEST_OS_MAC + #include #include @@ -76,6 +81,44 @@ TEST(GtestCheckSyntaxTest, WorksWithSwitch) { GTEST_CHECK_(true) << "Check failed in switch case"; } +#if GTEST_OS_MAC +void* ThreadFunc(void* data) { + pthread_mutex_t* mutex = reinterpret_cast(data); + pthread_mutex_lock(mutex); + pthread_mutex_unlock(mutex); + return NULL; +} + +TEST(GetThreadCountTest, ReturnsCorrectValue) { + EXPECT_EQ(1, GetThreadCount()); + pthread_mutex_t mutex; + pthread_attr_t attr; + pthread_t thread_id; + + // TODO(vladl@google.com): turn mutex into internal::Mutex for automatic + // destruction. + pthread_mutex_init(&mutex, NULL); + pthread_mutex_lock(&mutex); + ASSERT_EQ(0, pthread_attr_init(&attr)); + ASSERT_EQ(0, pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE)); + + const int status = pthread_create(&thread_id, &attr, &ThreadFunc, &mutex); + ASSERT_EQ(0, pthread_attr_destroy(&attr)); + ASSERT_EQ(0, status); + EXPECT_EQ(2, GetThreadCount()); + pthread_mutex_unlock(&mutex); + + void* dummy; + ASSERT_EQ(0, pthread_join(thread_id, &dummy)); + EXPECT_EQ(1, GetThreadCount()); + pthread_mutex_destroy(&mutex); +} +#else +TEST(GetThreadCountTest, ReturnsZeroWhenUnableToCountThreads) { + EXPECT_EQ(0, GetThreadCount()); +} +#endif // GTEST_OS_MAC + #if GTEST_HAS_DEATH_TEST TEST(GtestCheckDeathTest, DiesWithCorrectOutputOnFailure) { diff --git a/test/gtest_unittest.cc b/test/gtest_unittest.cc index 8e4b813c..d1c517b5 100644 --- a/test/gtest_unittest.cc +++ b/test/gtest_unittest.cc @@ -131,6 +131,7 @@ using testing::TPRT_SUCCESS; using testing::UnitTest; using testing::internal::kTestTypeIdInGoogleTest; using testing::internal::AppendUserMessage; +using testing::internal::ClearCurrentTestPartResults; using testing::internal::CodePointToUtf8; using testing::internal::EqFailure; using testing::internal::FloatingPoint; @@ -5456,3 +5457,87 @@ TEST(GetCurrentOsStackTraceExceptTopTest, ReturnsTheStackTrace) { EXPECT_STREQ("", GetCurrentOsStackTraceExceptTop(unit_test, 0).c_str()); EXPECT_STREQ("", GetCurrentOsStackTraceExceptTop(unit_test, 1).c_str()); } + +TEST(HasNonfatalFailureTest, ReturnsFalseWhenThereIsNoFailure) { + EXPECT_FALSE(HasNonfatalFailure()); +} + +static void FailFatally() { FAIL(); } + +TEST(HasNonfatalFailureTest, ReturnsFalseWhenThereIsOnlyFatalFailure) { + FailFatally(); + const bool has_nonfatal_failure = HasNonfatalFailure(); + ClearCurrentTestPartResults(); + EXPECT_FALSE(has_nonfatal_failure); +} + +TEST(HasNonfatalFailureTest, ReturnsTrueWhenThereIsNonfatalFailure) { + ADD_FAILURE(); + const bool has_nonfatal_failure = HasNonfatalFailure(); + ClearCurrentTestPartResults(); + EXPECT_TRUE(has_nonfatal_failure); +} + +TEST(HasNonfatalFailureTest, ReturnsTrueWhenThereAreFatalAndNonfatalFailures) { + FailFatally(); + ADD_FAILURE(); + const bool has_nonfatal_failure = HasNonfatalFailure(); + ClearCurrentTestPartResults(); + EXPECT_TRUE(has_nonfatal_failure); +} + +// A wrapper for calling HasNonfatalFailure outside of a test body. +static bool HasNonfatalFailureHelper() { + return testing::Test::HasNonfatalFailure(); +} + +TEST(HasNonfatalFailureTest, WorksOutsideOfTestBody) { + EXPECT_FALSE(HasNonfatalFailureHelper()); +} + +TEST(HasNonfatalFailureTest, WorksOutsideOfTestBody2) { + ADD_FAILURE(); + const bool has_nonfatal_failure = HasNonfatalFailureHelper(); + ClearCurrentTestPartResults(); + EXPECT_TRUE(has_nonfatal_failure); +} + +TEST(HasFailureTest, ReturnsFalseWhenThereIsNoFailure) { + EXPECT_FALSE(HasFailure()); +} + +TEST(HasFailureTest, ReturnsTrueWhenThereIsFatalFailure) { + FailFatally(); + const bool has_failure = HasFailure(); + ClearCurrentTestPartResults(); + EXPECT_TRUE(has_failure); +} + +TEST(HasFailureTest, ReturnsTrueWhenThereIsNonfatalFailure) { + ADD_FAILURE(); + const bool has_failure = HasFailure(); + ClearCurrentTestPartResults(); + EXPECT_TRUE(has_failure); +} + +TEST(HasFailureTest, ReturnsTrueWhenThereAreFatalAndNonfatalFailures) { + FailFatally(); + ADD_FAILURE(); + const bool has_failure = HasFailure(); + ClearCurrentTestPartResults(); + EXPECT_TRUE(has_failure); +} + +// A wrapper for calling HasFailure outside of a test body. +static bool HasFailureHelper() { return testing::Test::HasFailure(); } + +TEST(HasFailureTest, WorksOutsideOfTestBody) { + EXPECT_FALSE(HasFailureHelper()); +} + +TEST(HasFailureTest, WorksOutsideOfTestBody2) { + ADD_FAILURE(); + const bool has_failure = HasFailureHelper(); + ClearCurrentTestPartResults(); + EXPECT_TRUE(has_failure); +}