Skip to content
Permalink
51665236fa
Switch branches/tags

Name already in use

A tag already exists with the provided branch name. Many Git commands accept both tag and branch names, so creating this branch may cause unexpected behavior. Are you sure you want to create this branch?
Go to file
 
 
Cannot retrieve contributors at this time
1253 lines (1032 sloc) 38.2 KB
// 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.
//
// Authors: vladl@google.com (Vlad Losev), wan@google.com (Zhanyong Wan)
//
// This file tests the internal cross-platform support utilities.
#include "gtest/internal/gtest-port.h"
#include <stdio.h>
#if GTEST_OS_MAC
# include <time.h>
#endif // GTEST_OS_MAC
#include <list>
#include <utility> // For std::pair and std::make_pair.
#include <vector>
#include "gtest/gtest.h"
#include "gtest/gtest-spi.h"
// Indicates that this translation unit is part of Google Test's
// implementation. It must come before gtest-internal-inl.h is
// included, or there will be a compiler error. This trick is to
// prevent a user from accidentally including gtest-internal-inl.h in
// his code.
#define GTEST_IMPLEMENTATION_ 1
#include "src/gtest-internal-inl.h"
#undef GTEST_IMPLEMENTATION_
using std::make_pair;
using std::pair;
namespace testing {
namespace internal {
TEST(IsXDigitTest, WorksForNarrowAscii) {
EXPECT_TRUE(IsXDigit('0'));
EXPECT_TRUE(IsXDigit('9'));
EXPECT_TRUE(IsXDigit('A'));
EXPECT_TRUE(IsXDigit('F'));
EXPECT_TRUE(IsXDigit('a'));
EXPECT_TRUE(IsXDigit('f'));
EXPECT_FALSE(IsXDigit('-'));
EXPECT_FALSE(IsXDigit('g'));
EXPECT_FALSE(IsXDigit('G'));
}
TEST(IsXDigitTest, ReturnsFalseForNarrowNonAscii) {
EXPECT_FALSE(IsXDigit(static_cast<char>(0x80)));
EXPECT_FALSE(IsXDigit(static_cast<char>('0' | 0x80)));
}
TEST(IsXDigitTest, WorksForWideAscii) {
EXPECT_TRUE(IsXDigit(L'0'));
EXPECT_TRUE(IsXDigit(L'9'));
EXPECT_TRUE(IsXDigit(L'A'));
EXPECT_TRUE(IsXDigit(L'F'));
EXPECT_TRUE(IsXDigit(L'a'));
EXPECT_TRUE(IsXDigit(L'f'));
EXPECT_FALSE(IsXDigit(L'-'));
EXPECT_FALSE(IsXDigit(L'g'));
EXPECT_FALSE(IsXDigit(L'G'));
}
TEST(IsXDigitTest, ReturnsFalseForWideNonAscii) {
EXPECT_FALSE(IsXDigit(static_cast<wchar_t>(0x80)));
EXPECT_FALSE(IsXDigit(static_cast<wchar_t>(L'0' | 0x80)));
EXPECT_FALSE(IsXDigit(static_cast<wchar_t>(L'0' | 0x100)));
}
class Base {
public:
// Copy constructor and assignment operator do exactly what we need, so we
// use them.
Base() : member_(0) {}
explicit Base(int n) : member_(n) {}
virtual ~Base() {}
int member() { return member_; }
private:
int member_;
};
class Derived : public Base {
public:
explicit Derived(int n) : Base(n) {}
};
TEST(ImplicitCastTest, ConvertsPointers) {
Derived derived(0);
EXPECT_TRUE(&derived == ::testing::internal::ImplicitCast_<Base*>(&derived));
}
TEST(ImplicitCastTest, CanUseInheritance) {
Derived derived(1);
Base base = ::testing::internal::ImplicitCast_<Base>(derived);
EXPECT_EQ(derived.member(), base.member());
}
class Castable {
public:
explicit Castable(bool* converted) : converted_(converted) {}
operator Base() {
*converted_ = true;
return Base();
}
private:
bool* converted_;
};
TEST(ImplicitCastTest, CanUseNonConstCastOperator) {
bool converted = false;
Castable castable(&converted);
Base base = ::testing::internal::ImplicitCast_<Base>(castable);
EXPECT_TRUE(converted);
}
class ConstCastable {
public:
explicit ConstCastable(bool* converted) : converted_(converted) {}
operator Base() const {
*converted_ = true;
return Base();
}
private:
bool* converted_;
};
TEST(ImplicitCastTest, CanUseConstCastOperatorOnConstValues) {
bool converted = false;
const ConstCastable const_castable(&converted);
Base base = ::testing::internal::ImplicitCast_<Base>(const_castable);
EXPECT_TRUE(converted);
}
class ConstAndNonConstCastable {
public:
ConstAndNonConstCastable(bool* converted, bool* const_converted)
: converted_(converted), const_converted_(const_converted) {}
operator Base() {
*converted_ = true;
return Base();
}
operator Base() const {
*const_converted_ = true;
return Base();
}
private:
bool* converted_;
bool* const_converted_;
};
TEST(ImplicitCastTest, CanSelectBetweenConstAndNonConstCasrAppropriately) {
bool converted = false;
bool const_converted = false;
ConstAndNonConstCastable castable(&converted, &const_converted);
Base base = ::testing::internal::ImplicitCast_<Base>(castable);
EXPECT_TRUE(converted);
EXPECT_FALSE(const_converted);
converted = false;
const_converted = false;
const ConstAndNonConstCastable const_castable(&converted, &const_converted);
base = ::testing::internal::ImplicitCast_<Base>(const_castable);
EXPECT_FALSE(converted);
EXPECT_TRUE(const_converted);
}
class To {
public:
To(bool* converted) { *converted = true; } // NOLINT
};
TEST(ImplicitCastTest, CanUseImplicitConstructor) {
bool converted = false;
To to = ::testing::internal::ImplicitCast_<To>(&converted);
(void)to;
EXPECT_TRUE(converted);
}
TEST(IteratorTraitsTest, WorksForSTLContainerIterators) {
StaticAssertTypeEq<int,
IteratorTraits< ::std::vector<int>::const_iterator>::value_type>();
StaticAssertTypeEq<bool,
IteratorTraits< ::std::list<bool>::iterator>::value_type>();
}
TEST(IteratorTraitsTest, WorksForPointerToNonConst) {
StaticAssertTypeEq<char, IteratorTraits<char*>::value_type>();
StaticAssertTypeEq<const void*, IteratorTraits<const void**>::value_type>();
}
TEST(IteratorTraitsTest, WorksForPointerToConst) {
StaticAssertTypeEq<char, IteratorTraits<const char*>::value_type>();
StaticAssertTypeEq<const void*,
IteratorTraits<const void* const*>::value_type>();
}
// Tests that the element_type typedef is available in scoped_ptr and refers
// to the parameter type.
TEST(ScopedPtrTest, DefinesElementType) {
StaticAssertTypeEq<int, ::testing::internal::scoped_ptr<int>::element_type>();
}
// TODO(vladl@google.com): Implement THE REST of scoped_ptr tests.
TEST(GtestCheckSyntaxTest, BehavesLikeASingleStatement) {
if (AlwaysFalse())
GTEST_CHECK_(false) << "This should never be executed; "
"It's a compilation test only.";
if (AlwaysTrue())
GTEST_CHECK_(true);
else
; // NOLINT
if (AlwaysFalse())
; // NOLINT
else
GTEST_CHECK_(true) << "";
}
TEST(GtestCheckSyntaxTest, WorksWithSwitch) {
switch (0) {
case 1:
break;
default:
GTEST_CHECK_(true);
}
switch (0)
case 0:
GTEST_CHECK_(true) << "Check failed in switch case";
}
// Verifies behavior of FormatFileLocation.
TEST(FormatFileLocationTest, FormatsFileLocation) {
EXPECT_PRED_FORMAT2(IsSubstring, "foo.cc", FormatFileLocation("foo.cc", 42));
EXPECT_PRED_FORMAT2(IsSubstring, "42", FormatFileLocation("foo.cc", 42));
}
TEST(FormatFileLocationTest, FormatsUnknownFile) {
EXPECT_PRED_FORMAT2(
IsSubstring, "unknown file", FormatFileLocation(NULL, 42));
EXPECT_PRED_FORMAT2(IsSubstring, "42", FormatFileLocation(NULL, 42));
}
TEST(FormatFileLocationTest, FormatsUknownLine) {
EXPECT_EQ("foo.cc:", FormatFileLocation("foo.cc", -1));
}
TEST(FormatFileLocationTest, FormatsUknownFileAndLine) {
EXPECT_EQ("unknown file:", FormatFileLocation(NULL, -1));
}
// Verifies behavior of FormatCompilerIndependentFileLocation.
TEST(FormatCompilerIndependentFileLocationTest, FormatsFileLocation) {
EXPECT_EQ("foo.cc:42", FormatCompilerIndependentFileLocation("foo.cc", 42));
}
TEST(FormatCompilerIndependentFileLocationTest, FormatsUknownFile) {
EXPECT_EQ("unknown file:42",
FormatCompilerIndependentFileLocation(NULL, 42));
}
TEST(FormatCompilerIndependentFileLocationTest, FormatsUknownLine) {
EXPECT_EQ("foo.cc", FormatCompilerIndependentFileLocation("foo.cc", -1));
}
TEST(FormatCompilerIndependentFileLocationTest, FormatsUknownFileAndLine) {
EXPECT_EQ("unknown file", FormatCompilerIndependentFileLocation(NULL, -1));
}
#if GTEST_OS_MAC || GTEST_OS_QNX
void* ThreadFunc(void* data) {
pthread_mutex_t* mutex = static_cast<pthread_mutex_t*>(data);
pthread_mutex_lock(mutex);
pthread_mutex_unlock(mutex);
return NULL;
}
TEST(GetThreadCountTest, ReturnsCorrectValue) {
EXPECT_EQ(1U, 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(2U, GetThreadCount());
pthread_mutex_unlock(&mutex);
void* dummy;
ASSERT_EQ(0, pthread_join(thread_id, &dummy));
# if GTEST_OS_MAC
// MacOS X 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.
for (int i = 0; i < 5; ++i) {
if (GetThreadCount() == 1)
break;
SleepMilliseconds(100);
}
# endif // GTEST_OS_MAC
EXPECT_EQ(1U, GetThreadCount());
pthread_mutex_destroy(&mutex);
}
#else
TEST(GetThreadCountTest, ReturnsZeroWhenUnableToCountThreads) {
EXPECT_EQ(0U, GetThreadCount());
}
#endif // GTEST_OS_MAC || GTEST_OS_QNX
TEST(GtestCheckDeathTest, DiesWithCorrectOutputOnFailure) {
const bool a_false_condition = false;
const char regex[] =
#ifdef _MSC_VER
"gtest-port_test\\.cc\\(\\d+\\):"
#elif GTEST_USES_POSIX_RE
"gtest-port_test\\.cc:[0-9]+"
#else
"gtest-port_test\\.cc:\\d+"
#endif // _MSC_VER
".*a_false_condition.*Extra info.*";
EXPECT_DEATH_IF_SUPPORTED(GTEST_CHECK_(a_false_condition) << "Extra info",
regex);
}
#if GTEST_HAS_DEATH_TEST
TEST(GtestCheckDeathTest, LivesSilentlyOnSuccess) {
EXPECT_EXIT({
GTEST_CHECK_(true) << "Extra info";
::std::cerr << "Success\n";
exit(0); },
::testing::ExitedWithCode(0), "Success");
}
#endif // GTEST_HAS_DEATH_TEST
// Verifies that Google Test choose regular expression engine appropriate to
// the platform. The test will produce compiler errors in case of failure.
// For simplicity, we only cover the most important platforms here.
TEST(RegexEngineSelectionTest, SelectsCorrectRegexEngine) {
#if GTEST_HAS_POSIX_RE
EXPECT_TRUE(GTEST_USES_POSIX_RE);
#else
EXPECT_TRUE(GTEST_USES_SIMPLE_RE);
#endif
}
#if GTEST_USES_POSIX_RE
# if GTEST_HAS_TYPED_TEST
template <typename Str>
class RETest : public ::testing::Test {};
// Defines StringTypes as the list of all string types that class RE
// supports.
typedef testing::Types<
::std::string,
# if GTEST_HAS_GLOBAL_STRING
::string,
# endif // GTEST_HAS_GLOBAL_STRING
const char*> StringTypes;
TYPED_TEST_CASE(RETest, StringTypes);
// Tests RE's implicit constructors.
TYPED_TEST(RETest, ImplicitConstructorWorks) {
const RE empty(TypeParam(""));
EXPECT_STREQ("", empty.pattern());
const RE simple(TypeParam("hello"));
EXPECT_STREQ("hello", simple.pattern());
const RE normal(TypeParam(".*(\\w+)"));
EXPECT_STREQ(".*(\\w+)", normal.pattern());
}
// Tests that RE's constructors reject invalid regular expressions.
TYPED_TEST(RETest, RejectsInvalidRegex) {
EXPECT_NONFATAL_FAILURE({
const RE invalid(TypeParam("?"));
}, "\"?\" is not a valid POSIX Extended regular expression.");
}
// Tests RE::FullMatch().
TYPED_TEST(RETest, FullMatchWorks) {
const RE empty(TypeParam(""));
EXPECT_TRUE(RE::FullMatch(TypeParam(""), empty));
EXPECT_FALSE(RE::FullMatch(TypeParam("a"), empty));
const RE re(TypeParam("a.*z"));
EXPECT_TRUE(RE::FullMatch(TypeParam("az"), re));
EXPECT_TRUE(RE::FullMatch(TypeParam("axyz"), re));
EXPECT_FALSE(RE::FullMatch(TypeParam("baz"), re));
EXPECT_FALSE(RE::FullMatch(TypeParam("azy"), re));
}
// Tests RE::PartialMatch().
TYPED_TEST(RETest, PartialMatchWorks) {
const RE empty(TypeParam(""));
EXPECT_TRUE(RE::PartialMatch(TypeParam(""), empty));
EXPECT_TRUE(RE::PartialMatch(TypeParam("a"), empty));
const RE re(TypeParam("a.*z"));
EXPECT_TRUE(RE::PartialMatch(TypeParam("az"), re));
EXPECT_TRUE(RE::PartialMatch(TypeParam("axyz"), re));
EXPECT_TRUE(RE::PartialMatch(TypeParam("baz"), re));
EXPECT_TRUE(RE::PartialMatch(TypeParam("azy"), re));
EXPECT_FALSE(RE::PartialMatch(TypeParam("zza"), re));
}
# endif // GTEST_HAS_TYPED_TEST
#elif GTEST_USES_SIMPLE_RE
TEST(IsInSetTest, NulCharIsNotInAnySet) {
EXPECT_FALSE(IsInSet('\0', ""));
EXPECT_FALSE(IsInSet('\0', "\0"));
EXPECT_FALSE(IsInSet('\0', "a"));
}
TEST(IsInSetTest, WorksForNonNulChars) {
EXPECT_FALSE(IsInSet('a', "Ab"));
EXPECT_FALSE(IsInSet('c', ""));
EXPECT_TRUE(IsInSet('b', "bcd"));
EXPECT_TRUE(IsInSet('b', "ab"));
}
TEST(IsAsciiDigitTest, IsFalseForNonDigit) {
EXPECT_FALSE(IsAsciiDigit('\0'));
EXPECT_FALSE(IsAsciiDigit(' '));
EXPECT_FALSE(IsAsciiDigit('+'));
EXPECT_FALSE(IsAsciiDigit('-'));
EXPECT_FALSE(IsAsciiDigit('.'));
EXPECT_FALSE(IsAsciiDigit('a'));
}
TEST(IsAsciiDigitTest, IsTrueForDigit) {
EXPECT_TRUE(IsAsciiDigit('0'));
EXPECT_TRUE(IsAsciiDigit('1'));
EXPECT_TRUE(IsAsciiDigit('5'));
EXPECT_TRUE(IsAsciiDigit('9'));
}
TEST(IsAsciiPunctTest, IsFalseForNonPunct) {
EXPECT_FALSE(IsAsciiPunct('\0'));
EXPECT_FALSE(IsAsciiPunct(' '));
EXPECT_FALSE(IsAsciiPunct('\n'));
EXPECT_FALSE(IsAsciiPunct('a'));
EXPECT_FALSE(IsAsciiPunct('0'));
}
TEST(IsAsciiPunctTest, IsTrueForPunct) {
for (const char* p = "^-!\"#$%&'()*+,./:;<=>?@[\\]_`{|}~"; *p; p++) {
EXPECT_PRED1(IsAsciiPunct, *p);
}
}
TEST(IsRepeatTest, IsFalseForNonRepeatChar) {
EXPECT_FALSE(IsRepeat('\0'));
EXPECT_FALSE(IsRepeat(' '));
EXPECT_FALSE(IsRepeat('a'));
EXPECT_FALSE(IsRepeat('1'));
EXPECT_FALSE(IsRepeat('-'));
}
TEST(IsRepeatTest, IsTrueForRepeatChar) {
EXPECT_TRUE(IsRepeat('?'));
EXPECT_TRUE(IsRepeat('*'));
EXPECT_TRUE(IsRepeat('+'));
}
TEST(IsAsciiWhiteSpaceTest, IsFalseForNonWhiteSpace) {
EXPECT_FALSE(IsAsciiWhiteSpace('\0'));
EXPECT_FALSE(IsAsciiWhiteSpace('a'));
EXPECT_FALSE(IsAsciiWhiteSpace('1'));
EXPECT_FALSE(IsAsciiWhiteSpace('+'));
EXPECT_FALSE(IsAsciiWhiteSpace('_'));
}
TEST(IsAsciiWhiteSpaceTest, IsTrueForWhiteSpace) {
EXPECT_TRUE(IsAsciiWhiteSpace(' '));
EXPECT_TRUE(IsAsciiWhiteSpace('\n'));
EXPECT_TRUE(IsAsciiWhiteSpace('\r'));
EXPECT_TRUE(IsAsciiWhiteSpace('\t'));
EXPECT_TRUE(IsAsciiWhiteSpace('\v'));
EXPECT_TRUE(IsAsciiWhiteSpace('\f'));
}
TEST(IsAsciiWordCharTest, IsFalseForNonWordChar) {
EXPECT_FALSE(IsAsciiWordChar('\0'));
EXPECT_FALSE(IsAsciiWordChar('+'));
EXPECT_FALSE(IsAsciiWordChar('.'));
EXPECT_FALSE(IsAsciiWordChar(' '));
EXPECT_FALSE(IsAsciiWordChar('\n'));
}
TEST(IsAsciiWordCharTest, IsTrueForLetter) {
EXPECT_TRUE(IsAsciiWordChar('a'));
EXPECT_TRUE(IsAsciiWordChar('b'));
EXPECT_TRUE(IsAsciiWordChar('A'));
EXPECT_TRUE(IsAsciiWordChar('Z'));
}
TEST(IsAsciiWordCharTest, IsTrueForDigit) {
EXPECT_TRUE(IsAsciiWordChar('0'));
EXPECT_TRUE(IsAsciiWordChar('1'));
EXPECT_TRUE(IsAsciiWordChar('7'));
EXPECT_TRUE(IsAsciiWordChar('9'));
}
TEST(IsAsciiWordCharTest, IsTrueForUnderscore) {
EXPECT_TRUE(IsAsciiWordChar('_'));
}
TEST(IsValidEscapeTest, IsFalseForNonPrintable) {
EXPECT_FALSE(IsValidEscape('\0'));
EXPECT_FALSE(IsValidEscape('\007'));
}
TEST(IsValidEscapeTest, IsFalseForDigit) {
EXPECT_FALSE(IsValidEscape('0'));
EXPECT_FALSE(IsValidEscape('9'));
}
TEST(IsValidEscapeTest, IsFalseForWhiteSpace) {
EXPECT_FALSE(IsValidEscape(' '));
EXPECT_FALSE(IsValidEscape('\n'));
}
TEST(IsValidEscapeTest, IsFalseForSomeLetter) {
EXPECT_FALSE(IsValidEscape('a'));
EXPECT_FALSE(IsValidEscape('Z'));
}
TEST(IsValidEscapeTest, IsTrueForPunct) {
EXPECT_TRUE(IsValidEscape('.'));
EXPECT_TRUE(IsValidEscape('-'));
EXPECT_TRUE(IsValidEscape('^'));
EXPECT_TRUE(IsValidEscape('$'));
EXPECT_TRUE(IsValidEscape('('));
EXPECT_TRUE(IsValidEscape(']'));
EXPECT_TRUE(IsValidEscape('{'));
EXPECT_TRUE(IsValidEscape('|'));
}
TEST(IsValidEscapeTest, IsTrueForSomeLetter) {
EXPECT_TRUE(IsValidEscape('d'));
EXPECT_TRUE(IsValidEscape('D'));
EXPECT_TRUE(IsValidEscape('s'));
EXPECT_TRUE(IsValidEscape('S'));
EXPECT_TRUE(IsValidEscape('w'));
EXPECT_TRUE(IsValidEscape('W'));
}
TEST(AtomMatchesCharTest, EscapedPunct) {
EXPECT_FALSE(AtomMatchesChar(true, '\\', '\0'));
EXPECT_FALSE(AtomMatchesChar(true, '\\', ' '));
EXPECT_FALSE(AtomMatchesChar(true, '_', '.'));
EXPECT_FALSE(AtomMatchesChar(true, '.', 'a'));
EXPECT_TRUE(AtomMatchesChar(true, '\\', '\\'));
EXPECT_TRUE(AtomMatchesChar(true, '_', '_'));
EXPECT_TRUE(AtomMatchesChar(true, '+', '+'));
EXPECT_TRUE(AtomMatchesChar(true, '.', '.'));
}
TEST(AtomMatchesCharTest, Escaped_d) {
EXPECT_FALSE(AtomMatchesChar(true, 'd', '\0'));
EXPECT_FALSE(AtomMatchesChar(true, 'd', 'a'));
EXPECT_FALSE(AtomMatchesChar(true, 'd', '.'));
EXPECT_TRUE(AtomMatchesChar(true, 'd', '0'));
EXPECT_TRUE(AtomMatchesChar(true, 'd', '9'));
}
TEST(AtomMatchesCharTest, Escaped_D) {
EXPECT_FALSE(AtomMatchesChar(true, 'D', '0'));
EXPECT_FALSE(AtomMatchesChar(true, 'D', '9'));
EXPECT_TRUE(AtomMatchesChar(true, 'D', '\0'));
EXPECT_TRUE(AtomMatchesChar(true, 'D', 'a'));
EXPECT_TRUE(AtomMatchesChar(true, 'D', '-'));
}
TEST(AtomMatchesCharTest, Escaped_s) {
EXPECT_FALSE(AtomMatchesChar(true, 's', '\0'));
EXPECT_FALSE(AtomMatchesChar(true, 's', 'a'));
EXPECT_FALSE(AtomMatchesChar(true, 's', '.'));
EXPECT_FALSE(AtomMatchesChar(true, 's', '9'));
EXPECT_TRUE(AtomMatchesChar(true, 's', ' '));
EXPECT_TRUE(AtomMatchesChar(true, 's', '\n'));
EXPECT_TRUE(AtomMatchesChar(true, 's', '\t'));
}
TEST(AtomMatchesCharTest, Escaped_S) {
EXPECT_FALSE(AtomMatchesChar(true, 'S', ' '));
EXPECT_FALSE(AtomMatchesChar(true, 'S', '\r'));
EXPECT_TRUE(AtomMatchesChar(true, 'S', '\0'));
EXPECT_TRUE(AtomMatchesChar(true, 'S', 'a'));
EXPECT_TRUE(AtomMatchesChar(true, 'S', '9'));
}
TEST(AtomMatchesCharTest, Escaped_w) {
EXPECT_FALSE(AtomMatchesChar(true, 'w', '\0'));
EXPECT_FALSE(AtomMatchesChar(true, 'w', '+'));
EXPECT_FALSE(AtomMatchesChar(true, 'w', ' '));
EXPECT_FALSE(AtomMatchesChar(true, 'w', '\n'));
EXPECT_TRUE(AtomMatchesChar(true, 'w', '0'));
EXPECT_TRUE(AtomMatchesChar(true, 'w', 'b'));
EXPECT_TRUE(AtomMatchesChar(true, 'w', 'C'));
EXPECT_TRUE(AtomMatchesChar(true, 'w', '_'));
}
TEST(AtomMatchesCharTest, Escaped_W) {
EXPECT_FALSE(AtomMatchesChar(true, 'W', 'A'));
EXPECT_FALSE(AtomMatchesChar(true, 'W', 'b'));
EXPECT_FALSE(AtomMatchesChar(true, 'W', '9'));
EXPECT_FALSE(AtomMatchesChar(true, 'W', '_'));
EXPECT_TRUE(AtomMatchesChar(true, 'W', '\0'));
EXPECT_TRUE(AtomMatchesChar(true, 'W', '*'));
EXPECT_TRUE(AtomMatchesChar(true, 'W', '\n'));
}
TEST(AtomMatchesCharTest, EscapedWhiteSpace) {
EXPECT_FALSE(AtomMatchesChar(true, 'f', '\0'));
EXPECT_FALSE(AtomMatchesChar(true, 'f', '\n'));
EXPECT_FALSE(AtomMatchesChar(true, 'n', '\0'));
EXPECT_FALSE(AtomMatchesChar(true, 'n', '\r'));
EXPECT_FALSE(AtomMatchesChar(true, 'r', '\0'));
EXPECT_FALSE(AtomMatchesChar(true, 'r', 'a'));
EXPECT_FALSE(AtomMatchesChar(true, 't', '\0'));
EXPECT_FALSE(AtomMatchesChar(true, 't', 't'));
EXPECT_FALSE(AtomMatchesChar(true, 'v', '\0'));
EXPECT_FALSE(AtomMatchesChar(true, 'v', '\f'));
EXPECT_TRUE(AtomMatchesChar(true, 'f', '\f'));
EXPECT_TRUE(AtomMatchesChar(true, 'n', '\n'));
EXPECT_TRUE(AtomMatchesChar(true, 'r', '\r'));
EXPECT_TRUE(AtomMatchesChar(true, 't', '\t'));
EXPECT_TRUE(AtomMatchesChar(true, 'v', '\v'));
}
TEST(AtomMatchesCharTest, UnescapedDot) {
EXPECT_FALSE(AtomMatchesChar(false, '.', '\n'));
EXPECT_TRUE(AtomMatchesChar(false, '.', '\0'));
EXPECT_TRUE(AtomMatchesChar(false, '.', '.'));
EXPECT_TRUE(AtomMatchesChar(false, '.', 'a'));
EXPECT_TRUE(AtomMatchesChar(false, '.', ' '));
}
TEST(AtomMatchesCharTest, UnescapedChar) {
EXPECT_FALSE(AtomMatchesChar(false, 'a', '\0'));
EXPECT_FALSE(AtomMatchesChar(false, 'a', 'b'));
EXPECT_FALSE(AtomMatchesChar(false, '$', 'a'));
EXPECT_TRUE(AtomMatchesChar(false, '$', '$'));
EXPECT_TRUE(AtomMatchesChar(false, '5', '5'));
EXPECT_TRUE(AtomMatchesChar(false, 'Z', 'Z'));
}
TEST(ValidateRegexTest, GeneratesFailureAndReturnsFalseForInvalid) {
EXPECT_NONFATAL_FAILURE(ASSERT_FALSE(ValidateRegex(NULL)),
"NULL is not a valid simple regular expression");
EXPECT_NONFATAL_FAILURE(
ASSERT_FALSE(ValidateRegex("a\\")),
"Syntax error at index 1 in simple regular expression \"a\\\": ");
EXPECT_NONFATAL_FAILURE(ASSERT_FALSE(ValidateRegex("a\\")),
"'\\' cannot appear at the end");
EXPECT_NONFATAL_FAILURE(ASSERT_FALSE(ValidateRegex("\\n\\")),
"'\\' cannot appear at the end");
EXPECT_NONFATAL_FAILURE(ASSERT_FALSE(ValidateRegex("\\s\\hb")),
"invalid escape sequence \"\\h\"");
EXPECT_NONFATAL_FAILURE(ASSERT_FALSE(ValidateRegex("^^")),
"'^' can only appear at the beginning");
EXPECT_NONFATAL_FAILURE(ASSERT_FALSE(ValidateRegex(".*^b")),
"'^' can only appear at the beginning");
EXPECT_NONFATAL_FAILURE(ASSERT_FALSE(ValidateRegex("$$")),
"'$' can only appear at the end");
EXPECT_NONFATAL_FAILURE(ASSERT_FALSE(ValidateRegex("^$a")),
"'$' can only appear at the end");
EXPECT_NONFATAL_FAILURE(ASSERT_FALSE(ValidateRegex("a(b")),
"'(' is unsupported");
EXPECT_NONFATAL_FAILURE(ASSERT_FALSE(ValidateRegex("ab)")),
"')' is unsupported");
EXPECT_NONFATAL_FAILURE(ASSERT_FALSE(ValidateRegex("[ab")),
"'[' is unsupported");
EXPECT_NONFATAL_FAILURE(ASSERT_FALSE(ValidateRegex("a{2")),
"'{' is unsupported");
EXPECT_NONFATAL_FAILURE(ASSERT_FALSE(ValidateRegex("?")),
"'?' can only follow a repeatable token");
EXPECT_NONFATAL_FAILURE(ASSERT_FALSE(ValidateRegex("^*")),
"'*' can only follow a repeatable token");
EXPECT_NONFATAL_FAILURE(ASSERT_FALSE(ValidateRegex("5*+")),
"'+' can only follow a repeatable token");
}
TEST(ValidateRegexTest, ReturnsTrueForValid) {
EXPECT_TRUE(ValidateRegex(""));
EXPECT_TRUE(ValidateRegex("a"));
EXPECT_TRUE(ValidateRegex(".*"));
EXPECT_TRUE(ValidateRegex("^a_+"));
EXPECT_TRUE(ValidateRegex("^a\\t\\&?"));
EXPECT_TRUE(ValidateRegex("09*$"));
EXPECT_TRUE(ValidateRegex("^Z$"));
EXPECT_TRUE(ValidateRegex("a\\^Z\\$\\(\\)\\|\\[\\]\\{\\}"));
}
TEST(MatchRepetitionAndRegexAtHeadTest, WorksForZeroOrOne) {
EXPECT_FALSE(MatchRepetitionAndRegexAtHead(false, 'a', '?', "a", "ba"));
// Repeating more than once.
EXPECT_FALSE(MatchRepetitionAndRegexAtHead(false, 'a', '?', "b", "aab"));
// Repeating zero times.
EXPECT_TRUE(MatchRepetitionAndRegexAtHead(false, 'a', '?', "b", "ba"));
// Repeating once.
EXPECT_TRUE(MatchRepetitionAndRegexAtHead(false, 'a', '?', "b", "ab"));
EXPECT_TRUE(MatchRepetitionAndRegexAtHead(false, '#', '?', ".", "##"));
}
TEST(MatchRepetitionAndRegexAtHeadTest, WorksForZeroOrMany) {
EXPECT_FALSE(MatchRepetitionAndRegexAtHead(false, '.', '*', "a$", "baab"));
// Repeating zero times.
EXPECT_TRUE(MatchRepetitionAndRegexAtHead(false, '.', '*', "b", "bc"));
// Repeating once.
EXPECT_TRUE(MatchRepetitionAndRegexAtHead(false, '.', '*', "b", "abc"));
// Repeating more than once.
EXPECT_TRUE(MatchRepetitionAndRegexAtHead(true, 'w', '*', "-", "ab_1-g"));
}
TEST(MatchRepetitionAndRegexAtHeadTest, WorksForOneOrMany) {
EXPECT_FALSE(MatchRepetitionAndRegexAtHead(false, '.', '+', "a$", "baab"));
// Repeating zero times.
EXPECT_FALSE(MatchRepetitionAndRegexAtHead(false, '.', '+', "b", "bc"));
// Repeating once.
EXPECT_TRUE(MatchRepetitionAndRegexAtHead(false, '.', '+', "b", "abc"));
// Repeating more than once.
EXPECT_TRUE(MatchRepetitionAndRegexAtHead(true, 'w', '+', "-", "ab_1-g"));
}
TEST(MatchRegexAtHeadTest, ReturnsTrueForEmptyRegex) {
EXPECT_TRUE(MatchRegexAtHead("", ""));
EXPECT_TRUE(MatchRegexAtHead("", "ab"));
}
TEST(MatchRegexAtHeadTest, WorksWhenDollarIsInRegex) {
EXPECT_FALSE(MatchRegexAtHead("$", "a"));
EXPECT_TRUE(MatchRegexAtHead("$", ""));
EXPECT_TRUE(MatchRegexAtHead("a$", "a"));
}
TEST(MatchRegexAtHeadTest, WorksWhenRegexStartsWithEscapeSequence) {
EXPECT_FALSE(MatchRegexAtHead("\\w", "+"));
EXPECT_FALSE(MatchRegexAtHead("\\W", "ab"));
EXPECT_TRUE(MatchRegexAtHead("\\sa", "\nab"));
EXPECT_TRUE(MatchRegexAtHead("\\d", "1a"));
}
TEST(MatchRegexAtHeadTest, WorksWhenRegexStartsWithRepetition) {
EXPECT_FALSE(MatchRegexAtHead(".+a", "abc"));
EXPECT_FALSE(MatchRegexAtHead("a?b", "aab"));
EXPECT_TRUE(MatchRegexAtHead(".*a", "bc12-ab"));
EXPECT_TRUE(MatchRegexAtHead("a?b", "b"));
EXPECT_TRUE(MatchRegexAtHead("a?b", "ab"));
}
TEST(MatchRegexAtHeadTest,
WorksWhenRegexStartsWithRepetionOfEscapeSequence) {
EXPECT_FALSE(MatchRegexAtHead("\\.+a", "abc"));
EXPECT_FALSE(MatchRegexAtHead("\\s?b", " b"));
EXPECT_TRUE(MatchRegexAtHead("\\(*a", "((((ab"));
EXPECT_TRUE(MatchRegexAtHead("\\^?b", "^b"));
EXPECT_TRUE(MatchRegexAtHead("\\\\?b", "b"));
EXPECT_TRUE(MatchRegexAtHead("\\\\?b", "\\b"));
}
TEST(MatchRegexAtHeadTest, MatchesSequentially) {
EXPECT_FALSE(MatchRegexAtHead("ab.*c", "acabc"));
EXPECT_TRUE(MatchRegexAtHead("ab.*c", "ab-fsc"));
}
TEST(MatchRegexAnywhereTest, ReturnsFalseWhenStringIsNull) {
EXPECT_FALSE(MatchRegexAnywhere("", NULL));
}
TEST(MatchRegexAnywhereTest, WorksWhenRegexStartsWithCaret) {
EXPECT_FALSE(MatchRegexAnywhere("^a", "ba"));
EXPECT_FALSE(MatchRegexAnywhere("^$", "a"));
EXPECT_TRUE(MatchRegexAnywhere("^a", "ab"));
EXPECT_TRUE(MatchRegexAnywhere("^", "ab"));
EXPECT_TRUE(MatchRegexAnywhere("^$", ""));
}
TEST(MatchRegexAnywhereTest, ReturnsFalseWhenNoMatch) {
EXPECT_FALSE(MatchRegexAnywhere("a", "bcde123"));
EXPECT_FALSE(MatchRegexAnywhere("a.+a", "--aa88888888"));
}
TEST(MatchRegexAnywhereTest, ReturnsTrueWhenMatchingPrefix) {
EXPECT_TRUE(MatchRegexAnywhere("\\w+", "ab1_ - 5"));
EXPECT_TRUE(MatchRegexAnywhere(".*=", "="));
EXPECT_TRUE(MatchRegexAnywhere("x.*ab?.*bc", "xaaabc"));
}
TEST(MatchRegexAnywhereTest, ReturnsTrueWhenMatchingNonPrefix) {
EXPECT_TRUE(MatchRegexAnywhere("\\w+", "$$$ ab1_ - 5"));
EXPECT_TRUE(MatchRegexAnywhere("\\.+=", "= ...="));
}
// Tests RE's implicit constructors.
TEST(RETest, ImplicitConstructorWorks) {
const RE empty("");
EXPECT_STREQ("", empty.pattern());
const RE simple("hello");
EXPECT_STREQ("hello", simple.pattern());
}
// Tests that RE's constructors reject invalid regular expressions.
TEST(RETest, RejectsInvalidRegex) {
EXPECT_NONFATAL_FAILURE({
const RE normal(NULL);
}, "NULL is not a valid simple regular expression");
EXPECT_NONFATAL_FAILURE({
const RE normal(".*(\\w+");
}, "'(' is unsupported");
EXPECT_NONFATAL_FAILURE({
const RE invalid("^?");
}, "'?' can only follow a repeatable token");
}
// Tests RE::FullMatch().
TEST(RETest, FullMatchWorks) {
const RE empty("");
EXPECT_TRUE(RE::FullMatch("", empty));
EXPECT_FALSE(RE::FullMatch("a", empty));
const RE re1("a");
EXPECT_TRUE(RE::FullMatch("a", re1));
const RE re("a.*z");
EXPECT_TRUE(RE::FullMatch("az", re));
EXPECT_TRUE(RE::FullMatch("axyz", re));
EXPECT_FALSE(RE::FullMatch("baz", re));
EXPECT_FALSE(RE::FullMatch("azy", re));
}
// Tests RE::PartialMatch().
TEST(RETest, PartialMatchWorks) {
const RE empty("");
EXPECT_TRUE(RE::PartialMatch("", empty));
EXPECT_TRUE(RE::PartialMatch("a", empty));
const RE re("a.*z");
EXPECT_TRUE(RE::PartialMatch("az", re));
EXPECT_TRUE(RE::PartialMatch("axyz", re));
EXPECT_TRUE(RE::PartialMatch("baz", re));
EXPECT_TRUE(RE::PartialMatch("azy", re));
EXPECT_FALSE(RE::PartialMatch("zza", re));
}
#endif // GTEST_USES_POSIX_RE
#if !GTEST_OS_WINDOWS_MOBILE
TEST(CaptureTest, CapturesStdout) {
CaptureStdout();
fprintf(stdout, "abc");
EXPECT_STREQ("abc", GetCapturedStdout().c_str());
CaptureStdout();
fprintf(stdout, "def%cghi", '\0');
EXPECT_EQ(::std::string("def\0ghi", 7), ::std::string(GetCapturedStdout()));
}
TEST(CaptureTest, CapturesStderr) {
CaptureStderr();
fprintf(stderr, "jkl");
EXPECT_STREQ("jkl", GetCapturedStderr().c_str());
CaptureStderr();
fprintf(stderr, "jkl%cmno", '\0');
EXPECT_EQ(::std::string("jkl\0mno", 7), ::std::string(GetCapturedStderr()));
}
// Tests that stdout and stderr capture don't interfere with each other.
TEST(CaptureTest, CapturesStdoutAndStderr) {
CaptureStdout();
CaptureStderr();
fprintf(stdout, "pqr");
fprintf(stderr, "stu");
EXPECT_STREQ("pqr", GetCapturedStdout().c_str());
EXPECT_STREQ("stu", GetCapturedStderr().c_str());
}
TEST(CaptureDeathTest, CannotReenterStdoutCapture) {
CaptureStdout();
EXPECT_DEATH_IF_SUPPORTED(CaptureStdout(),
"Only one stdout capturer can exist at a time");
GetCapturedStdout();
// We cannot test stderr capturing using death tests as they use it
// themselves.
}
#endif // !GTEST_OS_WINDOWS_MOBILE
TEST(ThreadLocalTest, DefaultConstructorInitializesToDefaultValues) {
ThreadLocal<int> t1;
EXPECT_EQ(0, t1.get());
ThreadLocal<void*> t2;
EXPECT_TRUE(t2.get() == NULL);
}
TEST(ThreadLocalTest, SingleParamConstructorInitializesToParam) {
ThreadLocal<int> t1(123);
EXPECT_EQ(123, t1.get());
int i = 0;
ThreadLocal<int*> t2(&i);
EXPECT_EQ(&i, t2.get());
}
class NoDefaultContructor {
public:
explicit NoDefaultContructor(const char*) {}
NoDefaultContructor(const NoDefaultContructor&) {}
};
TEST(ThreadLocalTest, ValueDefaultContructorIsNotRequiredForParamVersion) {
ThreadLocal<NoDefaultContructor> bar(NoDefaultContructor("foo"));
bar.pointer();
}
TEST(ThreadLocalTest, GetAndPointerReturnSameValue) {
ThreadLocal<std::string> thread_local_string;
EXPECT_EQ(thread_local_string.pointer(), &(thread_local_string.get()));
// Verifies the condition still holds after calling set.
thread_local_string.set("foo");
EXPECT_EQ(thread_local_string.pointer(), &(thread_local_string.get()));
}
TEST(ThreadLocalTest, PointerAndConstPointerReturnSameValue) {
ThreadLocal<std::string> thread_local_string;
const ThreadLocal<std::string>& const_thread_local_string =
thread_local_string;
EXPECT_EQ(thread_local_string.pointer(), const_thread_local_string.pointer());
thread_local_string.set("foo");
EXPECT_EQ(thread_local_string.pointer(), const_thread_local_string.pointer());
}
#if GTEST_IS_THREADSAFE
void AddTwo(int* param) { *param += 2; }
TEST(ThreadWithParamTest, ConstructorExecutesThreadFunc) {
int i = 40;
ThreadWithParam<int*> thread(&AddTwo, &i, NULL);
thread.Join();
EXPECT_EQ(42, i);
}
TEST(MutexDeathTest, AssertHeldShouldAssertWhenNotLocked) {
// AssertHeld() is flaky only in the presence of multiple threads accessing
// the lock. In this case, the test is robust.
EXPECT_DEATH_IF_SUPPORTED({
Mutex m;
{ MutexLock lock(&m); }
m.AssertHeld();
},
"thread .*hold");
}
TEST(MutexTest, AssertHeldShouldNotAssertWhenLocked) {
Mutex m;
MutexLock lock(&m);
m.AssertHeld();
}
class AtomicCounterWithMutex {
public:
explicit AtomicCounterWithMutex(Mutex* mutex) :
value_(0), mutex_(mutex), random_(42) {}
void Increment() {
MutexLock lock(mutex_);
int temp = value_;
{
// Locking a mutex puts up a memory barrier, preventing reads and
// writes to value_ rearranged when observed from other threads.
//
// We cannot use Mutex and MutexLock here or rely on their memory
// barrier functionality as we are testing them here.
pthread_mutex_t memory_barrier_mutex;
GTEST_CHECK_POSIX_SUCCESS_(
pthread_mutex_init(&memory_barrier_mutex, NULL));
GTEST_CHECK_POSIX_SUCCESS_(pthread_mutex_lock(&memory_barrier_mutex));
SleepMilliseconds(random_.Generate(30));
GTEST_CHECK_POSIX_SUCCESS_(pthread_mutex_unlock(&memory_barrier_mutex));
GTEST_CHECK_POSIX_SUCCESS_(pthread_mutex_destroy(&memory_barrier_mutex));
}
value_ = temp + 1;
}
int value() const { return value_; }
private:
volatile int value_;
Mutex* const mutex_; // Protects value_.
Random random_;
};
void CountingThreadFunc(pair<AtomicCounterWithMutex*, int> param) {
for (int i = 0; i < param.second; ++i)
param.first->Increment();
}
// Tests that the mutex only lets one thread at a time to lock it.
TEST(MutexTest, OnlyOneThreadCanLockAtATime) {
Mutex mutex;
AtomicCounterWithMutex locked_counter(&mutex);
typedef ThreadWithParam<pair<AtomicCounterWithMutex*, int> > ThreadType;
const int kCycleCount = 20;
const int kThreadCount = 7;
scoped_ptr<ThreadType> counting_threads[kThreadCount];
Notification threads_can_start;
// Creates and runs kThreadCount threads that increment locked_counter
// kCycleCount times each.
for (int i = 0; i < kThreadCount; ++i) {
counting_threads[i].reset(new ThreadType(&CountingThreadFunc,
make_pair(&locked_counter,
kCycleCount),
&threads_can_start));
}
threads_can_start.Notify();
for (int i = 0; i < kThreadCount; ++i)
counting_threads[i]->Join();
// 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
// increments overwritten, resulting in the lower then expected counter
// value.
EXPECT_EQ(kCycleCount * kThreadCount, locked_counter.value());
}
template <typename T>
void RunFromThread(void (func)(T), T param) {
ThreadWithParam<T> thread(func, param, NULL);
thread.Join();
}
void RetrieveThreadLocalValue(
pair<ThreadLocal<std::string>*, std::string*> param) {
*param.second = param.first->get();
}
TEST(ThreadLocalTest, ParameterizedConstructorSetsDefault) {
ThreadLocal<std::string> thread_local_string("foo");
EXPECT_STREQ("foo", thread_local_string.get().c_str());
thread_local_string.set("bar");
EXPECT_STREQ("bar", thread_local_string.get().c_str());
std::string result;
RunFromThread(&RetrieveThreadLocalValue,
make_pair(&thread_local_string, &result));
EXPECT_STREQ("foo", result.c_str());
}
// DestructorTracker keeps track of whether its instances have been
// destroyed.
static std::vector<bool> g_destroyed;
class DestructorTracker {
public:
DestructorTracker() : index_(GetNewIndex()) {}
DestructorTracker(const DestructorTracker& /* rhs */)
: index_(GetNewIndex()) {}
~DestructorTracker() {
// We never access g_destroyed concurrently, so we don't need to
// protect the write operation under a mutex.
g_destroyed[index_] = true;
}
private:
static int GetNewIndex() {
g_destroyed.push_back(false);
return g_destroyed.size() - 1;
}
const int index_;
};
typedef ThreadLocal<DestructorTracker>* ThreadParam;
void CallThreadLocalGet(ThreadParam thread_local_param) {
thread_local_param->get();
}
// Tests that when a ThreadLocal object dies in a thread, it destroys
// the managed object for that thread.
TEST(ThreadLocalTest, DestroysManagedObjectForOwnThreadWhenDying) {
g_destroyed.clear();
{
// The next line default constructs a DestructorTracker object as
// the default value of objects managed by thread_local_tracker.
ThreadLocal<DestructorTracker> thread_local_tracker;
ASSERT_EQ(1U, g_destroyed.size());
ASSERT_FALSE(g_destroyed[0]);
// This creates another DestructorTracker object for the main thread.
thread_local_tracker.get();
ASSERT_EQ(2U, g_destroyed.size());
ASSERT_FALSE(g_destroyed[0]);
ASSERT_FALSE(g_destroyed[1]);
}
// Now thread_local_tracker has died. It should have destroyed both the
// default value shared by all threads and the value for the main
// thread.
ASSERT_EQ(2U, g_destroyed.size());
EXPECT_TRUE(g_destroyed[0]);
EXPECT_TRUE(g_destroyed[1]);
g_destroyed.clear();
}
// Tests that when a thread exits, the thread-local object for that
// thread is destroyed.
TEST(ThreadLocalTest, DestroysManagedObjectAtThreadExit) {
g_destroyed.clear();
{
// The next line default constructs a DestructorTracker object as
// the default value of objects managed by thread_local_tracker.
ThreadLocal<DestructorTracker> thread_local_tracker;
ASSERT_EQ(1U, g_destroyed.size());
ASSERT_FALSE(g_destroyed[0]);
// This creates another DestructorTracker object in the new thread.
ThreadWithParam<ThreadParam> thread(
&CallThreadLocalGet, &thread_local_tracker, NULL);
thread.Join();
// Now the new thread has exited. The per-thread object for it
// should have been destroyed.
ASSERT_EQ(2U, g_destroyed.size());
ASSERT_FALSE(g_destroyed[0]);
ASSERT_TRUE(g_destroyed[1]);
}
// Now thread_local_tracker has died. The default value should have been
// destroyed too.
ASSERT_EQ(2U, g_destroyed.size());
EXPECT_TRUE(g_destroyed[0]);
EXPECT_TRUE(g_destroyed[1]);
g_destroyed.clear();
}
TEST(ThreadLocalTest, ThreadLocalMutationsAffectOnlyCurrentThread) {
ThreadLocal<std::string> thread_local_string;
thread_local_string.set("Foo");
EXPECT_STREQ("Foo", thread_local_string.get().c_str());
std::string result;
RunFromThread(&RetrieveThreadLocalValue,
make_pair(&thread_local_string, &result));
EXPECT_TRUE(result.empty());
}
#endif // GTEST_IS_THREADSAFE
} // namespace internal
} // namespace testing