googletest-port-test.cc (googletest-release-1.11.0) | : | googletest-port-test.cc (googletest-release-1.12.0) | ||
---|---|---|---|---|
skipping to change at line 36 | skipping to change at line 36 | |||
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | |||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE | // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE | |||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | |||
// | // | |||
// This file tests the internal cross-platform support utilities. | // This file tests the internal cross-platform support utilities. | |||
#include <stdio.h> | #include <stdio.h> | |||
#include "gtest/internal/gtest-port.h" | #include "gtest/internal/gtest-port.h" | |||
#if GTEST_OS_MAC | #if GTEST_OS_MAC | |||
# include <time.h> | #include <time.h> | |||
#endif // GTEST_OS_MAC | #endif // GTEST_OS_MAC | |||
#include <chrono> // NOLINT | ||||
#include <list> | #include <list> | |||
#include <memory> | #include <memory> | |||
#include <thread> // NOLINT | ||||
#include <utility> // For std::pair and std::make_pair. | #include <utility> // For std::pair and std::make_pair. | |||
#include <vector> | #include <vector> | |||
#include "gtest/gtest.h" | ||||
#include "gtest/gtest-spi.h" | #include "gtest/gtest-spi.h" | |||
#include "gtest/gtest.h" | ||||
#include "src/gtest-internal-inl.h" | #include "src/gtest-internal-inl.h" | |||
using std::make_pair; | using std::make_pair; | |||
using std::pair; | using std::pair; | |||
namespace testing { | namespace testing { | |||
namespace internal { | namespace internal { | |||
TEST(IsXDigitTest, WorksForNarrowAscii) { | TEST(IsXDigitTest, WorksForNarrowAscii) { | |||
EXPECT_TRUE(IsXDigit('0')); | EXPECT_TRUE(IsXDigit('0')); | |||
skipping to change at line 239 | skipping to change at line 241 | |||
TEST(GtestCheckSyntaxTest, WorksWithSwitch) { | TEST(GtestCheckSyntaxTest, WorksWithSwitch) { | |||
switch (0) { | switch (0) { | |||
case 1: | case 1: | |||
break; | break; | |||
default: | default: | |||
GTEST_CHECK_(true); | GTEST_CHECK_(true); | |||
} | } | |||
switch (0) | switch (0) | |||
case 0: | case 0: | |||
GTEST_CHECK_(true) << "Check failed in switch case"; | GTEST_CHECK_(true) << "Check failed in switch case"; | |||
} | } | |||
// Verifies behavior of FormatFileLocation. | // Verifies behavior of FormatFileLocation. | |||
TEST(FormatFileLocationTest, FormatsFileLocation) { | TEST(FormatFileLocationTest, FormatsFileLocation) { | |||
EXPECT_PRED_FORMAT2(IsSubstring, "foo.cc", FormatFileLocation("foo.cc", 42)); | EXPECT_PRED_FORMAT2(IsSubstring, "foo.cc", FormatFileLocation("foo.cc", 42)); | |||
EXPECT_PRED_FORMAT2(IsSubstring, "42", FormatFileLocation("foo.cc", 42)); | EXPECT_PRED_FORMAT2(IsSubstring, "42", FormatFileLocation("foo.cc", 42)); | |||
} | } | |||
TEST(FormatFileLocationTest, FormatsUnknownFile) { | TEST(FormatFileLocationTest, FormatsUnknownFile) { | |||
EXPECT_PRED_FORMAT2(IsSubstring, "unknown file", | EXPECT_PRED_FORMAT2(IsSubstring, "unknown file", | |||
skipping to change at line 282 | skipping to change at line 284 | |||
TEST(FormatCompilerIndependentFileLocationTest, FormatsUknownLine) { | TEST(FormatCompilerIndependentFileLocationTest, FormatsUknownLine) { | |||
EXPECT_EQ("foo.cc", FormatCompilerIndependentFileLocation("foo.cc", -1)); | EXPECT_EQ("foo.cc", FormatCompilerIndependentFileLocation("foo.cc", -1)); | |||
} | } | |||
TEST(FormatCompilerIndependentFileLocationTest, FormatsUknownFileAndLine) { | TEST(FormatCompilerIndependentFileLocationTest, FormatsUknownFileAndLine) { | |||
EXPECT_EQ("unknown file", FormatCompilerIndependentFileLocation(nullptr, -1)); | EXPECT_EQ("unknown file", FormatCompilerIndependentFileLocation(nullptr, -1)); | |||
} | } | |||
#if GTEST_OS_LINUX || GTEST_OS_MAC || GTEST_OS_QNX || GTEST_OS_FUCHSIA || \ | #if GTEST_OS_LINUX || GTEST_OS_MAC || GTEST_OS_QNX || GTEST_OS_FUCHSIA || \ | |||
GTEST_OS_DRAGONFLY || GTEST_OS_FREEBSD || GTEST_OS_GNU_KFREEBSD || \ | GTEST_OS_DRAGONFLY || GTEST_OS_FREEBSD || GTEST_OS_GNU_KFREEBSD || \ | |||
GTEST_OS_NETBSD || GTEST_OS_OPENBSD | GTEST_OS_NETBSD || GTEST_OS_OPENBSD || GTEST_OS_GNU_HURD | |||
void* ThreadFunc(void* data) { | void* ThreadFunc(void* data) { | |||
internal::Mutex* mutex = static_cast<internal::Mutex*>(data); | internal::Mutex* mutex = static_cast<internal::Mutex*>(data); | |||
mutex->Lock(); | mutex->Lock(); | |||
mutex->Unlock(); | mutex->Unlock(); | |||
return nullptr; | return nullptr; | |||
} | } | |||
TEST(GetThreadCountTest, ReturnsCorrectValue) { | TEST(GetThreadCountTest, ReturnsCorrectValue) { | |||
const size_t starting_count = GetThreadCount(); | size_t starting_count; | |||
pthread_t thread_id; | size_t thread_count_after_create; | |||
size_t thread_count_after_join; | ||||
// We can't guarantee that no other thread was created or destroyed between | ||||
// any two calls to GetThreadCount(). We make multiple attempts, hoping that | ||||
// background noise is not constant and we would see the "right" values at | ||||
// some point. | ||||
for (int attempt = 0; attempt < 20; ++attempt) { | ||||
starting_count = GetThreadCount(); | ||||
pthread_t thread_id; | ||||
internal::Mutex mutex; | internal::Mutex mutex; | |||
{ | { | |||
internal::MutexLock lock(&mutex); | internal::MutexLock lock(&mutex); | |||
pthread_attr_t attr; | pthread_attr_t attr; | |||
ASSERT_EQ(0, pthread_attr_init(&attr)); | ASSERT_EQ(0, pthread_attr_init(&attr)); | |||
ASSERT_EQ(0, pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE)); | ASSERT_EQ(0, pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE)); | |||
const int status = pthread_create(&thread_id, &attr, &ThreadFunc, &mutex); | const int status = pthread_create(&thread_id, &attr, &ThreadFunc, &mutex); | |||
ASSERT_EQ(0, pthread_attr_destroy(&attr)); | ASSERT_EQ(0, pthread_attr_destroy(&attr)); | |||
ASSERT_EQ(0, status); | ASSERT_EQ(0, status); | |||
EXPECT_EQ(starting_count + 1, GetThreadCount()); | } | |||
} | ||||
void* dummy; | thread_count_after_create = GetThreadCount(); | |||
ASSERT_EQ(0, pthread_join(thread_id, &dummy)); | ||||
// The OS may not immediately report the updated thread count after | void* dummy; | |||
// joining a thread, causing flakiness in this test. To counter that, we | ASSERT_EQ(0, pthread_join(thread_id, &dummy)); | |||
// wait for up to .5 seconds for the OS to report the correct value. | ||||
for (int i = 0; i < 5; ++i) { | ||||
if (GetThreadCount() == starting_count) | ||||
break; | ||||
SleepMilliseconds(100); | // Join before we decide whether we need to retry the test. Retry if an | |||
// arbitrary other thread was created or destroyed in the meantime. | ||||
if (thread_count_after_create != starting_count + 1) continue; | ||||
// The OS may not immediately report the updated thread count after | ||||
// joining a thread, causing flakiness in this test. To counter that, we | ||||
// wait for up to .5 seconds for the OS to report the correct value. | ||||
bool thread_count_matches = false; | ||||
for (int i = 0; i < 5; ++i) { | ||||
thread_count_after_join = GetThreadCount(); | ||||
if (thread_count_after_join == starting_count) { | ||||
thread_count_matches = true; | ||||
break; | ||||
} | ||||
std::this_thread::sleep_for(std::chrono::milliseconds(100)); | ||||
} | ||||
// Retry if an arbitrary other thread was created or destroyed. | ||||
if (!thread_count_matches) continue; | ||||
break; | ||||
} | } | |||
EXPECT_EQ(starting_count, GetThreadCount()); | EXPECT_EQ(thread_count_after_create, starting_count + 1); | |||
EXPECT_EQ(thread_count_after_join, starting_count); | ||||
} | } | |||
#else | #else | |||
TEST(GetThreadCountTest, ReturnsZeroWhenUnableToCountThreads) { | TEST(GetThreadCountTest, ReturnsZeroWhenUnableToCountThreads) { | |||
EXPECT_EQ(0U, GetThreadCount()); | EXPECT_EQ(0U, GetThreadCount()); | |||
} | } | |||
#endif // GTEST_OS_LINUX || GTEST_OS_MAC || GTEST_OS_QNX || GTEST_OS_FUCHSIA | #endif // GTEST_OS_LINUX || GTEST_OS_MAC || GTEST_OS_QNX || GTEST_OS_FUCHSIA | |||
TEST(GtestCheckDeathTest, DiesWithCorrectOutputOnFailure) { | TEST(GtestCheckDeathTest, DiesWithCorrectOutputOnFailure) { | |||
const bool a_false_condition = false; | const bool a_false_condition = false; | |||
const char regex[] = | const char regex[] = | |||
#ifdef _MSC_VER | #ifdef _MSC_VER | |||
"googletest-port-test\\.cc\\(\\d+\\):" | "googletest-port-test\\.cc\\(\\d+\\):" | |||
#elif GTEST_USES_POSIX_RE | #elif GTEST_USES_POSIX_RE | |||
"googletest-port-test\\.cc:[0-9]+" | "googletest-port-test\\.cc:[0-9]+" | |||
#else | #else | |||
"googletest-port-test\\.cc:\\d+" | "googletest-port-test\\.cc:\\d+" | |||
#endif // _MSC_VER | #endif // _MSC_VER | |||
".*a_false_condition.*Extra info.*"; | ".*a_false_condition.*Extra info.*"; | |||
EXPECT_DEATH_IF_SUPPORTED(GTEST_CHECK_(a_false_condition) << "Extra info", | EXPECT_DEATH_IF_SUPPORTED(GTEST_CHECK_(a_false_condition) << "Extra info", | |||
regex); | regex); | |||
} | } | |||
#if GTEST_HAS_DEATH_TEST | #if GTEST_HAS_DEATH_TEST | |||
TEST(GtestCheckDeathTest, LivesSilentlyOnSuccess) { | TEST(GtestCheckDeathTest, LivesSilentlyOnSuccess) { | |||
EXPECT_EXIT({ | EXPECT_EXIT( | |||
GTEST_CHECK_(true) << "Extra info"; | { | |||
::std::cerr << "Success\n"; | GTEST_CHECK_(true) << "Extra info"; | |||
exit(0); }, | ::std::cerr << "Success\n"; | |||
exit(0); | ||||
}, | ||||
::testing::ExitedWithCode(0), "Success"); | ::testing::ExitedWithCode(0), "Success"); | |||
} | } | |||
#endif // GTEST_HAS_DEATH_TEST | #endif // GTEST_HAS_DEATH_TEST | |||
// Verifies that Google Test choose regular expression engine appropriate to | // Verifies that Google Test choose regular expression engine appropriate to | |||
// the platform. The test will produce compiler errors in case of failure. | // the platform. The test will produce compiler errors in case of failure. | |||
// For simplicity, we only cover the most important platforms here. | // For simplicity, we only cover the most important platforms here. | |||
TEST(RegexEngineSelectionTest, SelectsCorrectRegexEngine) { | TEST(RegexEngineSelectionTest, SelectsCorrectRegexEngine) { | |||
#if !GTEST_USES_PCRE | #if GTEST_HAS_ABSL | |||
# if GTEST_HAS_POSIX_RE | EXPECT_TRUE(GTEST_USES_RE2); | |||
#elif GTEST_HAS_POSIX_RE | ||||
EXPECT_TRUE(GTEST_USES_POSIX_RE); | EXPECT_TRUE(GTEST_USES_POSIX_RE); | |||
#else | ||||
# else | ||||
EXPECT_TRUE(GTEST_USES_SIMPLE_RE); | EXPECT_TRUE(GTEST_USES_SIMPLE_RE); | |||
#endif | ||||
# endif | ||||
#endif // !GTEST_USES_PCRE | ||||
} | } | |||
#if GTEST_USES_POSIX_RE | #if GTEST_USES_POSIX_RE | |||
template <typename Str> | template <typename Str> | |||
class RETest : public ::testing::Test {}; | class RETest : public ::testing::Test {}; | |||
// Defines StringTypes as the list of all string types that class RE | // Defines StringTypes as the list of all string types that class RE | |||
// supports. | // supports. | |||
typedef testing::Types< ::std::string, const char*> StringTypes; | typedef testing::Types< ::std::string, const char*> StringTypes; | |||
skipping to change at line 399 | skipping to change at line 424 | |||
const RE simple(TypeParam("hello")); | const RE simple(TypeParam("hello")); | |||
EXPECT_STREQ("hello", simple.pattern()); | EXPECT_STREQ("hello", simple.pattern()); | |||
const RE normal(TypeParam(".*(\\w+)")); | const RE normal(TypeParam(".*(\\w+)")); | |||
EXPECT_STREQ(".*(\\w+)", normal.pattern()); | EXPECT_STREQ(".*(\\w+)", normal.pattern()); | |||
} | } | |||
// Tests that RE's constructors reject invalid regular expressions. | // Tests that RE's constructors reject invalid regular expressions. | |||
TYPED_TEST(RETest, RejectsInvalidRegex) { | TYPED_TEST(RETest, RejectsInvalidRegex) { | |||
EXPECT_NONFATAL_FAILURE({ | EXPECT_NONFATAL_FAILURE( | |||
const RE invalid(TypeParam("?")); | { const RE invalid(TypeParam("?")); }, | |||
}, "\"?\" is not a valid POSIX Extended regular expression."); | "\"?\" is not a valid POSIX Extended regular expression."); | |||
} | } | |||
// Tests RE::FullMatch(). | // Tests RE::FullMatch(). | |||
TYPED_TEST(RETest, FullMatchWorks) { | TYPED_TEST(RETest, FullMatchWorks) { | |||
const RE empty(TypeParam("")); | const RE empty(TypeParam("")); | |||
EXPECT_TRUE(RE::FullMatch(TypeParam(""), empty)); | EXPECT_TRUE(RE::FullMatch(TypeParam(""), empty)); | |||
EXPECT_FALSE(RE::FullMatch(TypeParam("a"), empty)); | EXPECT_FALSE(RE::FullMatch(TypeParam("a"), empty)); | |||
const RE re(TypeParam("a.*z")); | const RE re(TypeParam("a.*z")); | |||
EXPECT_TRUE(RE::FullMatch(TypeParam("az"), re)); | EXPECT_TRUE(RE::FullMatch(TypeParam("az"), re)); | |||
skipping to change at line 795 | skipping to change at line 820 | |||
TEST(MatchRegexAtHeadTest, WorksWhenRegexStartsWithRepetition) { | TEST(MatchRegexAtHeadTest, WorksWhenRegexStartsWithRepetition) { | |||
EXPECT_FALSE(MatchRegexAtHead(".+a", "abc")); | EXPECT_FALSE(MatchRegexAtHead(".+a", "abc")); | |||
EXPECT_FALSE(MatchRegexAtHead("a?b", "aab")); | EXPECT_FALSE(MatchRegexAtHead("a?b", "aab")); | |||
EXPECT_TRUE(MatchRegexAtHead(".*a", "bc12-ab")); | EXPECT_TRUE(MatchRegexAtHead(".*a", "bc12-ab")); | |||
EXPECT_TRUE(MatchRegexAtHead("a?b", "b")); | EXPECT_TRUE(MatchRegexAtHead("a?b", "b")); | |||
EXPECT_TRUE(MatchRegexAtHead("a?b", "ab")); | EXPECT_TRUE(MatchRegexAtHead("a?b", "ab")); | |||
} | } | |||
TEST(MatchRegexAtHeadTest, | TEST(MatchRegexAtHeadTest, WorksWhenRegexStartsWithRepetionOfEscapeSequence) { | |||
WorksWhenRegexStartsWithRepetionOfEscapeSequence) { | ||||
EXPECT_FALSE(MatchRegexAtHead("\\.+a", "abc")); | EXPECT_FALSE(MatchRegexAtHead("\\.+a", "abc")); | |||
EXPECT_FALSE(MatchRegexAtHead("\\s?b", " b")); | EXPECT_FALSE(MatchRegexAtHead("\\s?b", " b")); | |||
EXPECT_TRUE(MatchRegexAtHead("\\(*a", "((((ab")); | EXPECT_TRUE(MatchRegexAtHead("\\(*a", "((((ab")); | |||
EXPECT_TRUE(MatchRegexAtHead("\\^?b", "^b")); | EXPECT_TRUE(MatchRegexAtHead("\\^?b", "^b")); | |||
EXPECT_TRUE(MatchRegexAtHead("\\\\?b", "b")); | EXPECT_TRUE(MatchRegexAtHead("\\\\?b", "b")); | |||
EXPECT_TRUE(MatchRegexAtHead("\\\\?b", "\\b")); | EXPECT_TRUE(MatchRegexAtHead("\\\\?b", "\\b")); | |||
} | } | |||
TEST(MatchRegexAtHeadTest, MatchesSequentially) { | TEST(MatchRegexAtHeadTest, MatchesSequentially) { | |||
skipping to change at line 852 | skipping to change at line 876 | |||
TEST(RETest, ImplicitConstructorWorks) { | TEST(RETest, ImplicitConstructorWorks) { | |||
const RE empty(""); | const RE empty(""); | |||
EXPECT_STREQ("", empty.pattern()); | EXPECT_STREQ("", empty.pattern()); | |||
const RE simple("hello"); | const RE simple("hello"); | |||
EXPECT_STREQ("hello", simple.pattern()); | EXPECT_STREQ("hello", simple.pattern()); | |||
} | } | |||
// Tests that RE's constructors reject invalid regular expressions. | // Tests that RE's constructors reject invalid regular expressions. | |||
TEST(RETest, RejectsInvalidRegex) { | TEST(RETest, RejectsInvalidRegex) { | |||
EXPECT_NONFATAL_FAILURE({ | EXPECT_NONFATAL_FAILURE({ const RE normal(NULL); }, | |||
const RE normal(NULL); | "NULL is not a valid simple regular expression"); | |||
}, "NULL is not a valid simple regular expression"); | ||||
EXPECT_NONFATAL_FAILURE({ const RE normal(".*(\\w+"); }, | ||||
EXPECT_NONFATAL_FAILURE({ | "'(' is unsupported"); | |||
const RE normal(".*(\\w+"); | ||||
}, "'(' is unsupported"); | EXPECT_NONFATAL_FAILURE({ const RE invalid("^?"); }, | |||
"'?' can only follow a repeatable token"); | ||||
EXPECT_NONFATAL_FAILURE({ | ||||
const RE invalid("^?"); | ||||
}, "'?' can only follow a repeatable token"); | ||||
} | } | |||
// Tests RE::FullMatch(). | // Tests RE::FullMatch(). | |||
TEST(RETest, FullMatchWorks) { | TEST(RETest, FullMatchWorks) { | |||
const RE empty(""); | const RE empty(""); | |||
EXPECT_TRUE(RE::FullMatch("", empty)); | EXPECT_TRUE(RE::FullMatch("", empty)); | |||
EXPECT_FALSE(RE::FullMatch("a", empty)); | EXPECT_FALSE(RE::FullMatch("a", empty)); | |||
const RE re1("a"); | const RE re1("a"); | |||
EXPECT_TRUE(RE::FullMatch("a", re1)); | EXPECT_TRUE(RE::FullMatch("a", re1)); | |||
skipping to change at line 1004 | skipping to change at line 1025 | |||
TEST(ThreadWithParamTest, ConstructorExecutesThreadFunc) { | TEST(ThreadWithParamTest, ConstructorExecutesThreadFunc) { | |||
int i = 40; | int i = 40; | |||
ThreadWithParam<int*> thread(&AddTwo, &i, nullptr); | ThreadWithParam<int*> thread(&AddTwo, &i, nullptr); | |||
thread.Join(); | thread.Join(); | |||
EXPECT_EQ(42, i); | EXPECT_EQ(42, i); | |||
} | } | |||
TEST(MutexDeathTest, AssertHeldShouldAssertWhenNotLocked) { | TEST(MutexDeathTest, AssertHeldShouldAssertWhenNotLocked) { | |||
// AssertHeld() is flaky only in the presence of multiple threads accessing | // AssertHeld() is flaky only in the presence of multiple threads accessing | |||
// the lock. In this case, the test is robust. | // the lock. In this case, the test is robust. | |||
EXPECT_DEATH_IF_SUPPORTED({ | EXPECT_DEATH_IF_SUPPORTED( | |||
Mutex m; | { | |||
{ MutexLock lock(&m); } | Mutex m; | |||
m.AssertHeld(); | { MutexLock lock(&m); } | |||
}, | m.AssertHeld(); | |||
"thread .*hold"); | }, | |||
"thread .*hold"); | ||||
} | } | |||
TEST(MutexTest, AssertHeldShouldNotAssertWhenLocked) { | TEST(MutexTest, AssertHeldShouldNotAssertWhenLocked) { | |||
Mutex m; | Mutex m; | |||
MutexLock lock(&m); | MutexLock lock(&m); | |||
m.AssertHeld(); | m.AssertHeld(); | |||
} | } | |||
class AtomicCounterWithMutex { | class AtomicCounterWithMutex { | |||
public: | public: | |||
explicit AtomicCounterWithMutex(Mutex* mutex) : | explicit AtomicCounterWithMutex(Mutex* mutex) | |||
value_(0), mutex_(mutex), random_(42) {} | : value_(0), mutex_(mutex), random_(42) {} | |||
void Increment() { | void Increment() { | |||
MutexLock lock(mutex_); | MutexLock lock(mutex_); | |||
int temp = value_; | int temp = value_; | |||
{ | { | |||
// We need to put up a memory barrier to prevent reads and writes to | // We need to put up a memory barrier to prevent reads and writes to | |||
// value_ rearranged with the call to SleepMilliseconds when observed | // value_ rearranged with the call to sleep_for when observed | |||
// from other threads. | // from other threads. | |||
#if GTEST_HAS_PTHREAD | #if GTEST_HAS_PTHREAD | |||
// On POSIX, locking a mutex puts up a memory barrier. We cannot use | // On POSIX, locking a mutex puts up a memory barrier. We cannot use | |||
// Mutex and MutexLock here or rely on their memory barrier | // Mutex and MutexLock here or rely on their memory barrier | |||
// functionality as we are testing them here. | // functionality as we are testing them here. | |||
pthread_mutex_t memory_barrier_mutex; | pthread_mutex_t memory_barrier_mutex; | |||
GTEST_CHECK_POSIX_SUCCESS_( | GTEST_CHECK_POSIX_SUCCESS_( | |||
pthread_mutex_init(&memory_barrier_mutex, nullptr)); | pthread_mutex_init(&memory_barrier_mutex, nullptr)); | |||
GTEST_CHECK_POSIX_SUCCESS_(pthread_mutex_lock(&memory_barrier_mutex)); | GTEST_CHECK_POSIX_SUCCESS_(pthread_mutex_lock(&memory_barrier_mutex)); | |||
SleepMilliseconds(static_cast<int>(random_.Generate(30))); | std::this_thread::sleep_for( | |||
std::chrono::milliseconds(random_.Generate(30))); | ||||
GTEST_CHECK_POSIX_SUCCESS_(pthread_mutex_unlock(&memory_barrier_mutex)); | GTEST_CHECK_POSIX_SUCCESS_(pthread_mutex_unlock(&memory_barrier_mutex)); | |||
GTEST_CHECK_POSIX_SUCCESS_(pthread_mutex_destroy(&memory_barrier_mutex)); | GTEST_CHECK_POSIX_SUCCESS_(pthread_mutex_destroy(&memory_barrier_mutex)); | |||
#elif GTEST_OS_WINDOWS | #elif GTEST_OS_WINDOWS | |||
// On Windows, performing an interlocked access puts up a memory barrier. | // On Windows, performing an interlocked access puts up a memory barrier. | |||
volatile LONG dummy = 0; | volatile LONG dummy = 0; | |||
::InterlockedIncrement(&dummy); | ::InterlockedIncrement(&dummy); | |||
SleepMilliseconds(static_cast<int>(random_.Generate(30))); | std::this_thread::sleep_for( | |||
std::chrono::milliseconds(random_.Generate(30))); | ||||
::InterlockedIncrement(&dummy); | ::InterlockedIncrement(&dummy); | |||
#else | #else | |||
# error "Memory barrier not implemented on this platform." | #error "Memory barrier not implemented on this platform." | |||
#endif // GTEST_HAS_PTHREAD | #endif // GTEST_HAS_PTHREAD | |||
} | } | |||
value_ = temp + 1; | value_ = temp + 1; | |||
} | } | |||
int value() const { return value_; } | int value() const { return value_; } | |||
private: | private: | |||
volatile int value_; | volatile int value_; | |||
Mutex* const mutex_; // Protects value_. | Mutex* const mutex_; // Protects value_. | |||
Random random_; | Random random_; | |||
}; | }; | |||
void CountingThreadFunc(pair<AtomicCounterWithMutex*, int> param) { | void CountingThreadFunc(pair<AtomicCounterWithMutex*, int> param) { | |||
for (int i = 0; i < param.second; ++i) | for (int i = 0; i < param.second; ++i) param.first->Increment(); | |||
param.first->Increment(); | ||||
} | } | |||
// Tests that the mutex only lets one thread at a time to lock it. | // Tests that the mutex only lets one thread at a time to lock it. | |||
TEST(MutexTest, OnlyOneThreadCanLockAtATime) { | TEST(MutexTest, OnlyOneThreadCanLockAtATime) { | |||
Mutex mutex; | Mutex mutex; | |||
AtomicCounterWithMutex locked_counter(&mutex); | AtomicCounterWithMutex locked_counter(&mutex); | |||
typedef ThreadWithParam<pair<AtomicCounterWithMutex*, int> > ThreadType; | typedef ThreadWithParam<pair<AtomicCounterWithMutex*, int> > ThreadType; | |||
const int kCycleCount = 20; | const int kCycleCount = 20; | |||
const int kThreadCount = 7; | const int kThreadCount = 7; | |||
std::unique_ptr<ThreadType> counting_threads[kThreadCount]; | std::unique_ptr<ThreadType> counting_threads[kThreadCount]; | |||
Notification threads_can_start; | Notification threads_can_start; | |||
// Creates and runs kThreadCount threads that increment locked_counter | // Creates and runs kThreadCount threads that increment locked_counter | |||
// kCycleCount times each. | // kCycleCount times each. | |||
for (int i = 0; i < kThreadCount; ++i) { | for (int i = 0; i < kThreadCount; ++i) { | |||
counting_threads[i].reset(new ThreadType(&CountingThreadFunc, | counting_threads[i].reset(new ThreadType( | |||
make_pair(&locked_counter, | &CountingThreadFunc, make_pair(&locked_counter, kCycleCount), | |||
kCycleCount), | &threads_can_start)); | |||
&threads_can_start)); | ||||
} | } | |||
threads_can_start.Notify(); | threads_can_start.Notify(); | |||
for (int i = 0; i < kThreadCount; ++i) | for (int i = 0; i < kThreadCount; ++i) counting_threads[i]->Join(); | |||
counting_threads[i]->Join(); | ||||
// If the mutex lets more than one thread to increment the counter at a | // If the mutex lets more than one thread to increment the counter at a | |||
// time, they are likely to encounter a race condition and have some | // time, they are likely to encounter a race condition and have some | |||
// increments overwritten, resulting in the lower then expected counter | // increments overwritten, resulting in the lower then expected counter | |||
// value. | // value. | |||
EXPECT_EQ(kCycleCount * kThreadCount, locked_counter.value()); | EXPECT_EQ(kCycleCount * kThreadCount, locked_counter.value()); | |||
} | } | |||
template <typename T> | template <typename T> | |||
void RunFromThread(void (func)(T), T param) { | void RunFromThread(void(func)(T), T param) { | |||
ThreadWithParam<T> thread(func, param, nullptr); | ThreadWithParam<T> thread(func, param, nullptr); | |||
thread.Join(); | thread.Join(); | |||
} | } | |||
void RetrieveThreadLocalValue( | void RetrieveThreadLocalValue( | |||
pair<ThreadLocal<std::string>*, std::string*> param) { | pair<ThreadLocal<std::string>*, std::string*> param) { | |||
*param.second = param.first->get(); | *param.second = param.first->get(); | |||
} | } | |||
TEST(ThreadLocalTest, ParameterizedConstructorSetsDefault) { | TEST(ThreadLocalTest, ParameterizedConstructorSetsDefault) { | |||
skipping to change at line 1164 | skipping to change at line 1185 | |||
list_->clear(); | list_->clear(); | |||
} | } | |||
private: | private: | |||
bool invoked_; | bool invoked_; | |||
#if GTEST_OS_WINDOWS | #if GTEST_OS_WINDOWS | |||
AutoHandle wait_event_; | AutoHandle wait_event_; | |||
#endif | #endif | |||
static std::vector<DestructorCall*>* const list_; | static std::vector<DestructorCall*>* const list_; | |||
GTEST_DISALLOW_COPY_AND_ASSIGN_(DestructorCall); | DestructorCall(const DestructorCall&) = delete; | |||
DestructorCall& operator=(const DestructorCall&) = delete; | ||||
}; | }; | |||
std::vector<DestructorCall*>* const DestructorCall::list_ = | std::vector<DestructorCall*>* const DestructorCall::list_ = | |||
new std::vector<DestructorCall*>; | new std::vector<DestructorCall*>; | |||
// DestructorTracker keeps track of whether its instances have been | // DestructorTracker keeps track of whether its instances have been | |||
// destroyed. | // destroyed. | |||
class DestructorTracker { | class DestructorTracker { | |||
public: | public: | |||
DestructorTracker() : index_(GetNewIndex()) {} | DestructorTracker() : index_(GetNewIndex()) {} | |||
End of changes. 36 change blocks. | ||||
86 lines changed or deleted | 108 lines changed or added |