Updated gtest to upstream rev616

This commit is contained in:
Andrey Kamaev 2012-06-24 18:25:58 +00:00
parent cfa9aa9206
commit 1ee5c95ee9
2 changed files with 1195 additions and 478 deletions

File diff suppressed because it is too large Load Diff

View File

@ -40,6 +40,7 @@
#ifdef __GNUC__ #ifdef __GNUC__
# pragma GCC diagnostic ignored "-Wmissing-declarations" # pragma GCC diagnostic ignored "-Wmissing-declarations"
# pragma GCC diagnostic ignored "-Wmissing-field-initializers"
#endif #endif
// The following lines pull in the real gtest *.cc files. // The following lines pull in the real gtest *.cc files.
@ -300,7 +301,7 @@ class GTEST_API_ SingleFailureChecker {
(substr));\ (substr));\
{\ {\
::testing::ScopedFakeTestPartResultReporter gtest_reporter(\ ::testing::ScopedFakeTestPartResultReporter gtest_reporter(\
::testing::ScopedFakeTestPartResultReporter::INTERCEPT_ALL_THREADS,\ ::testing::ScopedFakeTestPartResultReporter::INTERCEPT_ALL_THREADS, \
&gtest_failures);\ &gtest_failures);\
if (::testing::internal::AlwaysTrue()) { statement; }\ if (::testing::internal::AlwaysTrue()) { statement; }\
}\ }\
@ -313,6 +314,7 @@ class GTEST_API_ SingleFailureChecker {
#include <stdarg.h> #include <stdarg.h>
#include <stdio.h> #include <stdio.h>
#include <stdlib.h> #include <stdlib.h>
#include <time.h>
#include <wchar.h> #include <wchar.h>
#include <wctype.h> #include <wctype.h>
@ -514,6 +516,12 @@ GTEST_API_ bool ShouldUseColor(bool stdout_is_tty);
// Formats the given time in milliseconds as seconds. // Formats the given time in milliseconds as seconds.
GTEST_API_ std::string FormatTimeInMillisAsSeconds(TimeInMillis ms); GTEST_API_ std::string FormatTimeInMillisAsSeconds(TimeInMillis ms);
// Converts the given time in milliseconds to a date string in the ISO 8601
// format, without the timezone information. N.B.: due to the use the
// non-reentrant localtime() function, this function is not thread safe. Do
// not use it in any code that can be called from multiple threads.
GTEST_API_ std::string FormatEpochTimeInMillisAsIso8601(TimeInMillis ms);
// Parses a string for an Int32 flag, in the form of "--flag=value". // Parses a string for an Int32 flag, in the form of "--flag=value".
// //
// On success, stores the value of the flag in *value, and returns // On success, stores the value of the flag in *value, and returns
@ -592,6 +600,7 @@ class GTestFlagSaver {
GTEST_FLAG(stream_result_to) = stream_result_to_; GTEST_FLAG(stream_result_to) = stream_result_to_;
GTEST_FLAG(throw_on_failure) = throw_on_failure_; GTEST_FLAG(throw_on_failure) = throw_on_failure_;
} }
private: private:
// Fields for saving the original values of flags. // Fields for saving the original values of flags.
bool also_run_disabled_tests_; bool also_run_disabled_tests_;
@ -834,8 +843,11 @@ class OsStackTraceGetterInterface {
class OsStackTraceGetter : public OsStackTraceGetterInterface { class OsStackTraceGetter : public OsStackTraceGetterInterface {
public: public:
OsStackTraceGetter() : caller_frame_(NULL) {} OsStackTraceGetter() : caller_frame_(NULL) {}
virtual String CurrentStackTrace(int max_depth, int skip_count);
virtual void UponLeavingGTest(); virtual String CurrentStackTrace(int max_depth, int skip_count)
GTEST_LOCK_EXCLUDED_(mutex_);
virtual void UponLeavingGTest() GTEST_LOCK_EXCLUDED_(mutex_);
// This string is inserted in place of stack frames that are part of // This string is inserted in place of stack frames that are part of
// Google Test's implementation. // Google Test's implementation.
@ -950,6 +962,10 @@ class GTEST_API_ UnitTestImpl {
// Gets the number of tests that should run. // Gets the number of tests that should run.
int test_to_run_count() const; int test_to_run_count() const;
// Gets the time of the test program start, in ms from the start of the
// UNIX epoch.
TimeInMillis start_timestamp() const { return start_timestamp_; }
// Gets the elapsed time, in milliseconds. // Gets the elapsed time, in milliseconds.
TimeInMillis elapsed_time() const { return elapsed_time_; } TimeInMillis elapsed_time() const { return elapsed_time_; }
@ -1008,7 +1024,7 @@ class GTEST_API_ UnitTestImpl {
// For example, if Foo() calls Bar(), which in turn calls // For example, if Foo() calls Bar(), which in turn calls
// CurrentOsStackTraceExceptTop(1), Foo() will be included in the // CurrentOsStackTraceExceptTop(1), Foo() will be included in the
// trace but Bar() and CurrentOsStackTraceExceptTop() won't. // trace but Bar() and CurrentOsStackTraceExceptTop() won't.
String CurrentOsStackTraceExceptTop(int skip_count); String CurrentOsStackTraceExceptTop(int skip_count) GTEST_NO_INLINE_;
// Finds and returns a TestCase with the given name. If one doesn't // Finds and returns a TestCase with the given name. If one doesn't
// exist, creates one and returns it. // exist, creates one and returns it.
@ -1282,6 +1298,10 @@ class GTEST_API_ UnitTestImpl {
// Our random number generator. // Our random number generator.
internal::Random random_; internal::Random random_;
// The time of the test program start, in ms from the start of the
// UNIX epoch.
TimeInMillis start_timestamp_;
// How long the test took to run, in milliseconds. // How long the test took to run, in milliseconds.
TimeInMillis elapsed_time_; TimeInMillis elapsed_time_;
@ -1613,7 +1633,7 @@ UInt32 Random::Generate(UInt32 range) {
// Test. g_init_gtest_count is set to the number of times // Test. g_init_gtest_count is set to the number of times
// InitGoogleTest() has been called. We don't protect this variable // InitGoogleTest() has been called. We don't protect this variable
// under a mutex as it is only accessed in the main thread. // under a mutex as it is only accessed in the main thread.
int g_init_gtest_count = 0; GTEST_API_ int g_init_gtest_count = 0;
static bool GTestIsInitialized() { return g_init_gtest_count != 0; } static bool GTestIsInitialized() { return g_init_gtest_count != 0; }
// Iterates over a vector of TestCases, keeping a running sum of the // Iterates over a vector of TestCases, keeping a running sum of the
@ -1668,7 +1688,7 @@ void AssertHelper::operator=(const Message& message) const {
} }
// Mutex for linked pointers. // Mutex for linked pointers.
GTEST_DEFINE_STATIC_MUTEX_(g_linked_ptr_mutex); GTEST_API_ GTEST_DEFINE_STATIC_MUTEX_(g_linked_ptr_mutex);
// Application pathname gotten in InitGoogleTest. // Application pathname gotten in InitGoogleTest.
String g_executable_path; String g_executable_path;
@ -2125,17 +2145,6 @@ TimeInMillis GetTimeInMillis() {
// class String // class String
// Returns the input enclosed in double quotes if it's not NULL;
// otherwise returns "(null)". For example, "\"Hello\"" is returned
// for input "Hello".
//
// This is useful for printing a C string in the syntax of a literal.
//
// Known issue: escape sequences are not handled yet.
String String::ShowCStringQuoted(const char* c_str) {
return c_str ? String::Format("\"%s\"", c_str) : String("(null)");
}
// Copies at most length characters from str into a newly-allocated // Copies at most length characters from str into a newly-allocated
// piece of memory of size length+1. The memory is allocated with new[]. // piece of memory of size length+1. The memory is allocated with new[].
// A terminating null byte is written to the memory, and a pointer to it // A terminating null byte is written to the memory, and a pointer to it
@ -2476,8 +2485,8 @@ AssertionResult CmpHelperSTREQ(const char* expected_expression,
return EqFailure(expected_expression, return EqFailure(expected_expression,
actual_expression, actual_expression,
String::ShowCStringQuoted(expected), PrintToString(expected),
String::ShowCStringQuoted(actual), PrintToString(actual),
false); false);
} }
@ -2492,8 +2501,8 @@ AssertionResult CmpHelperSTRCASEEQ(const char* expected_expression,
return EqFailure(expected_expression, return EqFailure(expected_expression,
actual_expression, actual_expression,
String::ShowCStringQuoted(expected), PrintToString(expected),
String::ShowCStringQuoted(actual), PrintToString(actual),
true); true);
} }
@ -2841,15 +2850,6 @@ String String::ShowWideCString(const wchar_t * wide_c_str) {
return String(internal::WideStringToUtf8(wide_c_str, -1).c_str()); return String(internal::WideStringToUtf8(wide_c_str, -1).c_str());
} }
// Similar to ShowWideCString(), except that this function encloses
// the converted string in double quotes.
String String::ShowWideCStringQuoted(const wchar_t* wide_c_str) {
if (wide_c_str == NULL) return String("(null)");
return String::Format("L\"%s\"",
String::ShowWideCString(wide_c_str).c_str());
}
// Compares two wide C strings. Returns true iff they have the same // Compares two wide C strings. Returns true iff they have the same
// content. // content.
// //
@ -2875,8 +2875,8 @@ AssertionResult CmpHelperSTREQ(const char* expected_expression,
return EqFailure(expected_expression, return EqFailure(expected_expression,
actual_expression, actual_expression,
String::ShowWideCStringQuoted(expected), PrintToString(expected),
String::ShowWideCStringQuoted(actual), PrintToString(actual),
false); false);
} }
@ -2891,8 +2891,8 @@ AssertionResult CmpHelperSTRNE(const char* s1_expression,
return AssertionFailure() << "Expected: (" << s1_expression << ") != (" return AssertionFailure() << "Expected: (" << s1_expression << ") != ("
<< s2_expression << "), actual: " << s2_expression << "), actual: "
<< String::ShowWideCStringQuoted(s1) << PrintToString(s1)
<< " vs " << String::ShowWideCStringQuoted(s2); << " vs " << PrintToString(s2);
} }
// Compares two C strings, ignoring case. Returns true iff they have // Compares two C strings, ignoring case. Returns true iff they have
@ -4015,8 +4015,6 @@ class PrettyUnitTestResultPrinter : public TestEventListener {
private: private:
static void PrintFailedTests(const UnitTest& unit_test); static void PrintFailedTests(const UnitTest& unit_test);
internal::String test_case_name_;
}; };
// Fired before each iteration of tests starts. // Fired before each iteration of tests starts.
@ -4063,11 +4061,10 @@ void PrettyUnitTestResultPrinter::OnEnvironmentsSetUpStart(
} }
void PrettyUnitTestResultPrinter::OnTestCaseStart(const TestCase& test_case) { void PrettyUnitTestResultPrinter::OnTestCaseStart(const TestCase& test_case) {
test_case_name_ = test_case.name();
const internal::String counts = const internal::String counts =
FormatCountableNoun(test_case.test_to_run_count(), "test", "tests"); FormatCountableNoun(test_case.test_to_run_count(), "test", "tests");
ColoredPrintf(COLOR_GREEN, "[----------] "); ColoredPrintf(COLOR_GREEN, "[----------] ");
printf("%s from %s", counts.c_str(), test_case_name_.c_str()); printf("%s from %s", counts.c_str(), test_case.name());
if (test_case.type_param() == NULL) { if (test_case.type_param() == NULL) {
printf("\n"); printf("\n");
} else { } else {
@ -4078,7 +4075,7 @@ void PrettyUnitTestResultPrinter::OnTestCaseStart(const TestCase& test_case) {
void PrettyUnitTestResultPrinter::OnTestStart(const TestInfo& test_info) { void PrettyUnitTestResultPrinter::OnTestStart(const TestInfo& test_info) {
ColoredPrintf(COLOR_GREEN, "[ RUN ] "); ColoredPrintf(COLOR_GREEN, "[ RUN ] ");
PrintTestName(test_case_name_.c_str(), test_info.name()); PrintTestName(test_info.test_case_name(), test_info.name());
printf("\n"); printf("\n");
fflush(stdout); fflush(stdout);
} }
@ -4101,7 +4098,7 @@ void PrettyUnitTestResultPrinter::OnTestEnd(const TestInfo& test_info) {
} else { } else {
ColoredPrintf(COLOR_RED, "[ FAILED ] "); ColoredPrintf(COLOR_RED, "[ FAILED ] ");
} }
PrintTestName(test_case_name_.c_str(), test_info.name()); PrintTestName(test_info.test_case_name(), test_info.name());
if (test_info.result()->Failed()) if (test_info.result()->Failed())
PrintFullTestCommentIfPresent(test_info); PrintFullTestCommentIfPresent(test_info);
@ -4117,12 +4114,11 @@ void PrettyUnitTestResultPrinter::OnTestEnd(const TestInfo& test_info) {
void PrettyUnitTestResultPrinter::OnTestCaseEnd(const TestCase& test_case) { void PrettyUnitTestResultPrinter::OnTestCaseEnd(const TestCase& test_case) {
if (!GTEST_FLAG(print_time)) return; if (!GTEST_FLAG(print_time)) return;
test_case_name_ = test_case.name();
const internal::String counts = const internal::String counts =
FormatCountableNoun(test_case.test_to_run_count(), "test", "tests"); FormatCountableNoun(test_case.test_to_run_count(), "test", "tests");
ColoredPrintf(COLOR_GREEN, "[----------] "); ColoredPrintf(COLOR_GREEN, "[----------] ");
printf("%s from %s (%s ms total)\n\n", printf("%s from %s (%s ms total)\n\n",
counts.c_str(), test_case_name_.c_str(), counts.c_str(), test_case.name(),
internal::StreamableToString(test_case.elapsed_time()).c_str()); internal::StreamableToString(test_case.elapsed_time()).c_str());
fflush(stdout); fflush(stdout);
} }
@ -4507,6 +4503,32 @@ std::string FormatTimeInMillisAsSeconds(TimeInMillis ms) {
return ss.str(); return ss.str();
} }
// Converts the given epoch time in milliseconds to a date string in the ISO
// 8601 format, without the timezone information.
std::string FormatEpochTimeInMillisAsIso8601(TimeInMillis ms) {
// Using non-reentrant version as localtime_r is not portable.
time_t seconds = static_cast<time_t>(ms / 1000);
#ifdef _MSC_VER
# pragma warning(push) // Saves the current warning state.
# pragma warning(disable:4996) // Temporarily disables warning 4996
// (function or variable may be unsafe).
const struct tm* const time_struct = localtime(&seconds); // NOLINT
# pragma warning(pop) // Restores the warning state again.
#else
const struct tm* const time_struct = localtime(&seconds); // NOLINT
#endif
if (time_struct == NULL)
return ""; // Invalid ms value
return String::Format("%d-%02d-%02dT%02d:%02d:%02d", // YYYY-MM-DDThh:mm:ss
time_struct->tm_year + 1900,
time_struct->tm_mon + 1,
time_struct->tm_mday,
time_struct->tm_hour,
time_struct->tm_min,
time_struct->tm_sec);
}
// Streams an XML CDATA section, escaping invalid CDATA sequences as needed. // Streams an XML CDATA section, escaping invalid CDATA sequences as needed.
void XmlUnitTestResultPrinter::OutputXmlCDataSection(::std::ostream* stream, void XmlUnitTestResultPrinter::OutputXmlCDataSection(::std::ostream* stream,
const char* data) { const char* data) {
@ -4556,16 +4578,17 @@ void XmlUnitTestResultPrinter::OutputXmlTestInfo(::std::ostream* stream,
for (int i = 0; i < result.total_part_count(); ++i) { for (int i = 0; i < result.total_part_count(); ++i) {
const TestPartResult& part = result.GetTestPartResult(i); const TestPartResult& part = result.GetTestPartResult(i);
if (part.failed()) { if (part.failed()) {
if (++failures == 1) if (++failures == 1) {
*stream << ">\n"; *stream << ">\n";
*stream << " <failure message=\"" }
<< EscapeXmlAttribute(part.summary()).c_str()
<< "\" type=\"\">";
const string location = internal::FormatCompilerIndependentFileLocation( const string location = internal::FormatCompilerIndependentFileLocation(
part.file_name(), part.line_number()); part.file_name(), part.line_number());
const string message = location + "\n" + part.message(); const string summary = location + "\n" + part.summary();
OutputXmlCDataSection(stream, *stream << " <failure message=\""
RemoveInvalidXmlCharacters(message).c_str()); << EscapeXmlAttribute(summary.c_str())
<< "\" type=\"\">";
const string detail = location + "\n" + part.message();
OutputXmlCDataSection(stream, RemoveInvalidXmlCharacters(detail).c_str());
*stream << "</failure>\n"; *stream << "</failure>\n";
} }
} }
@ -4603,10 +4626,11 @@ void XmlUnitTestResultPrinter::PrintXmlUnitTest(FILE* out,
fprintf(out, "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n"); fprintf(out, "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n");
fprintf(out, fprintf(out,
"<testsuites tests=\"%d\" failures=\"%d\" disabled=\"%d\" " "<testsuites tests=\"%d\" failures=\"%d\" disabled=\"%d\" "
"errors=\"0\" time=\"%s\" ", "errors=\"0\" timestamp=\"%s\" time=\"%s\" ",
unit_test.total_test_count(), unit_test.total_test_count(),
unit_test.failed_test_count(), unit_test.failed_test_count(),
unit_test.disabled_test_count(), unit_test.disabled_test_count(),
FormatEpochTimeInMillisAsIso8601(unit_test.start_timestamp()).c_str(),
FormatTimeInMillisAsSeconds(unit_test.elapsed_time()).c_str()); FormatTimeInMillisAsSeconds(unit_test.elapsed_time()).c_str());
if (GTEST_FLAG(shuffle)) { if (GTEST_FLAG(shuffle)) {
fprintf(out, "random_seed=\"%d\" ", unit_test.random_seed()); fprintf(out, "random_seed=\"%d\" ", unit_test.random_seed());
@ -4812,8 +4836,8 @@ void StreamingListener::MakeConnection() {
// Pushes the given source file location and message onto a per-thread // Pushes the given source file location and message onto a per-thread
// trace stack maintained by Google Test. // trace stack maintained by Google Test.
// L < UnitTest::mutex_ ScopedTrace::ScopedTrace(const char* file, int line, const Message& message)
ScopedTrace::ScopedTrace(const char* file, int line, const Message& message) { GTEST_LOCK_EXCLUDED_(&UnitTest::mutex_) {
TraceInfo trace; TraceInfo trace;
trace.file = file; trace.file = file;
trace.line = line; trace.line = line;
@ -4823,8 +4847,8 @@ ScopedTrace::ScopedTrace(const char* file, int line, const Message& message) {
} }
// Pops the info pushed by the c'tor. // Pops the info pushed by the c'tor.
// L < UnitTest::mutex_ ScopedTrace::~ScopedTrace()
ScopedTrace::~ScopedTrace() { GTEST_LOCK_EXCLUDED_(&UnitTest::mutex_) {
UnitTest::GetInstance()->PopGTestTrace(); UnitTest::GetInstance()->PopGTestTrace();
} }
@ -4838,14 +4862,14 @@ ScopedTrace::~ScopedTrace() {
// skip_count - the number of top frames to be skipped; doesn't count // skip_count - the number of top frames to be skipped; doesn't count
// against max_depth. // against max_depth.
// //
// L < mutex_ String OsStackTraceGetter::CurrentStackTrace(int /* max_depth */,
// We use "L < mutex_" to denote that the function may acquire mutex_. int /* skip_count */)
String OsStackTraceGetter::CurrentStackTrace(int, int) { GTEST_LOCK_EXCLUDED_(mutex_) {
return String(""); return String("");
} }
// L < mutex_ void OsStackTraceGetter::UponLeavingGTest()
void OsStackTraceGetter::UponLeavingGTest() { GTEST_LOCK_EXCLUDED_(mutex_) {
} }
const char* const const char* const
@ -4999,6 +5023,12 @@ int UnitTest::total_test_count() const { return impl()->total_test_count(); }
// Gets the number of tests that should run. // Gets the number of tests that should run.
int UnitTest::test_to_run_count() const { return impl()->test_to_run_count(); } int UnitTest::test_to_run_count() const { return impl()->test_to_run_count(); }
// Gets the time of the test program start, in ms from the start of the
// UNIX epoch.
internal::TimeInMillis UnitTest::start_timestamp() const {
return impl()->start_timestamp();
}
// Gets the elapsed time, in milliseconds. // Gets the elapsed time, in milliseconds.
internal::TimeInMillis UnitTest::elapsed_time() const { internal::TimeInMillis UnitTest::elapsed_time() const {
return impl()->elapsed_time(); return impl()->elapsed_time();
@ -5052,12 +5082,13 @@ Environment* UnitTest::AddEnvironment(Environment* env) {
// assertion macros (e.g. ASSERT_TRUE, EXPECT_EQ, etc) eventually call // assertion macros (e.g. ASSERT_TRUE, EXPECT_EQ, etc) eventually call
// this to report their results. The user code should use the // this to report their results. The user code should use the
// assertion macros instead of calling this directly. // assertion macros instead of calling this directly.
// L < mutex_ void UnitTest::AddTestPartResult(
void UnitTest::AddTestPartResult(TestPartResult::Type result_type, TestPartResult::Type result_type,
const char* file_name, const char* file_name,
int line_number, int line_number,
const internal::String& message, const internal::String& message,
const internal::String& os_stack_trace) { const internal::String& os_stack_trace)
GTEST_LOCK_EXCLUDED_(mutex_) {
Message msg; Message msg;
msg << message; msg << message;
@ -5141,7 +5172,6 @@ int UnitTest::Run() {
// process. In either case the user does not want to see pop-up dialogs // process. In either case the user does not want to see pop-up dialogs
// about crashes - they are expected. // about crashes - they are expected.
if (impl()->catch_exceptions() || in_death_test_child_process) { if (impl()->catch_exceptions() || in_death_test_child_process) {
# if !GTEST_OS_WINDOWS_MOBILE # if !GTEST_OS_WINDOWS_MOBILE
// SetErrorMode doesn't exist on CE. // SetErrorMode doesn't exist on CE.
SetErrorMode(SEM_FAILCRITICALERRORS | SEM_NOALIGNMENTFAULTEXCEPT | SetErrorMode(SEM_FAILCRITICALERRORS | SEM_NOALIGNMENTFAULTEXCEPT |
@ -5172,7 +5202,6 @@ int UnitTest::Run() {
0x0, // Clear the following flags: 0x0, // Clear the following flags:
_WRITE_ABORT_MSG | _CALL_REPORTFAULT); // pop-up window, core dump. _WRITE_ABORT_MSG | _CALL_REPORTFAULT); // pop-up window, core dump.
# endif # endif
} }
#endif // GTEST_HAS_SEH #endif // GTEST_HAS_SEH
@ -5190,16 +5219,16 @@ const char* UnitTest::original_working_dir() const {
// Returns the TestCase object for the test that's currently running, // Returns the TestCase object for the test that's currently running,
// or NULL if no test is running. // or NULL if no test is running.
// L < mutex_ const TestCase* UnitTest::current_test_case() const
const TestCase* UnitTest::current_test_case() const { GTEST_LOCK_EXCLUDED_(mutex_) {
internal::MutexLock lock(&mutex_); internal::MutexLock lock(&mutex_);
return impl_->current_test_case(); return impl_->current_test_case();
} }
// Returns the TestInfo object for the test that's currently running, // Returns the TestInfo object for the test that's currently running,
// or NULL if no test is running. // or NULL if no test is running.
// L < mutex_ const TestInfo* UnitTest::current_test_info() const
const TestInfo* UnitTest::current_test_info() const { GTEST_LOCK_EXCLUDED_(mutex_) {
internal::MutexLock lock(&mutex_); internal::MutexLock lock(&mutex_);
return impl_->current_test_info(); return impl_->current_test_info();
} }
@ -5210,9 +5239,9 @@ int UnitTest::random_seed() const { return impl_->random_seed(); }
#if GTEST_HAS_PARAM_TEST #if GTEST_HAS_PARAM_TEST
// Returns ParameterizedTestCaseRegistry object used to keep track of // Returns ParameterizedTestCaseRegistry object used to keep track of
// value-parameterized tests and instantiate and register them. // value-parameterized tests and instantiate and register them.
// L < mutex_
internal::ParameterizedTestCaseRegistry& internal::ParameterizedTestCaseRegistry&
UnitTest::parameterized_test_registry() { UnitTest::parameterized_test_registry()
GTEST_LOCK_EXCLUDED_(mutex_) {
return impl_->parameterized_test_registry(); return impl_->parameterized_test_registry();
} }
#endif // GTEST_HAS_PARAM_TEST #endif // GTEST_HAS_PARAM_TEST
@ -5229,15 +5258,15 @@ UnitTest::~UnitTest() {
// Pushes a trace defined by SCOPED_TRACE() on to the per-thread // Pushes a trace defined by SCOPED_TRACE() on to the per-thread
// Google Test trace stack. // Google Test trace stack.
// L < mutex_ void UnitTest::PushGTestTrace(const internal::TraceInfo& trace)
void UnitTest::PushGTestTrace(const internal::TraceInfo& trace) { GTEST_LOCK_EXCLUDED_(mutex_) {
internal::MutexLock lock(&mutex_); internal::MutexLock lock(&mutex_);
impl_->gtest_trace_stack().push_back(trace); impl_->gtest_trace_stack().push_back(trace);
} }
// Pops a trace from the per-thread Google Test trace stack. // Pops a trace from the per-thread Google Test trace stack.
// L < mutex_ void UnitTest::PopGTestTrace()
void UnitTest::PopGTestTrace() { GTEST_LOCK_EXCLUDED_(mutex_) {
internal::MutexLock lock(&mutex_); internal::MutexLock lock(&mutex_);
impl_->gtest_trace_stack().pop_back(); impl_->gtest_trace_stack().pop_back();
} }
@ -5273,6 +5302,7 @@ UnitTestImpl::UnitTestImpl(UnitTest* parent)
post_flag_parse_init_performed_(false), post_flag_parse_init_performed_(false),
random_seed_(0), // Will be overridden by the flag before first use. random_seed_(0), // Will be overridden by the flag before first use.
random_(0), // Will be reseeded before first use. random_(0), // Will be reseeded before first use.
start_timestamp_(0),
elapsed_time_(0), elapsed_time_(0),
#if GTEST_HAS_DEATH_TEST #if GTEST_HAS_DEATH_TEST
internal_run_death_test_flag_(NULL), internal_run_death_test_flag_(NULL),
@ -5504,6 +5534,7 @@ bool UnitTestImpl::RunAllTests() {
TestEventListener* repeater = listeners()->repeater(); TestEventListener* repeater = listeners()->repeater();
start_timestamp_ = GetTimeInMillis();
repeater->OnTestProgramStart(*parent_); repeater->OnTestProgramStart(*parent_);
// How many times to repeat the tests? We don't want to repeat them // How many times to repeat the tests? We don't want to repeat them
@ -5865,7 +5896,7 @@ bool SkipPrefix(const char* prefix, const char** pstr) {
// part can be omitted. // part can be omitted.
// //
// Returns the value of the flag, or NULL if the parsing failed. // Returns the value of the flag, or NULL if the parsing failed.
static const char* ParseFlagValue(const char* str, const char* ParseFlagValue(const char* str,
const char* flag, const char* flag,
bool def_optional) { bool def_optional) {
// str and flag must not be NULL. // str and flag must not be NULL.
@ -6240,13 +6271,18 @@ void InitGoogleTest(int* argc, wchar_t** argv) {
#if GTEST_HAS_DEATH_TEST #if GTEST_HAS_DEATH_TEST
# if GTEST_OS_MAC && !GTEST_OS_MAC_IOS # if GTEST_OS_MAC
# include <crt_externs.h> # include <crt_externs.h>
# endif // GTEST_OS_MAC # endif // GTEST_OS_MAC
# include <errno.h> # include <errno.h>
# include <fcntl.h> # include <fcntl.h>
# include <limits.h> # include <limits.h>
# if GTEST_OS_LINUX
# include <signal.h>
# endif // GTEST_OS_LINUX
# include <stdarg.h> # include <stdarg.h>
# if GTEST_OS_WINDOWS # if GTEST_OS_WINDOWS
@ -6256,6 +6292,10 @@ void InitGoogleTest(int* argc, wchar_t** argv) {
# include <sys/wait.h> # include <sys/wait.h>
# endif // GTEST_OS_WINDOWS # endif // GTEST_OS_WINDOWS
# if GTEST_OS_QNX
# include <spawn.h>
# endif // GTEST_OS_QNX
#endif // GTEST_HAS_DEATH_TEST #endif // GTEST_HAS_DEATH_TEST
@ -6301,13 +6341,42 @@ GTEST_DEFINE_string_(
"Indicates the file, line number, temporal index of " "Indicates the file, line number, temporal index of "
"the single death test to run, and a file descriptor to " "the single death test to run, and a file descriptor to "
"which a success code may be sent, all separated by " "which a success code may be sent, all separated by "
"colons. This flag is specified if and only if the current " "the '|' characters. This flag is specified if and only if the current "
"process is a sub-process launched for running a thread-safe " "process is a sub-process launched for running a thread-safe "
"death test. FOR INTERNAL USE ONLY."); "death test. FOR INTERNAL USE ONLY.");
} // namespace internal } // namespace internal
#if GTEST_HAS_DEATH_TEST #if GTEST_HAS_DEATH_TEST
namespace internal {
// Valid only for fast death tests. Indicates the code is running in the
// child process of a fast style death test.
static bool g_in_fast_death_test_child = false;
// Returns a Boolean value indicating whether the caller is currently
// executing in the context of the death test child process. Tools such as
// Valgrind heap checkers may need this to modify their behavior in death
// tests. IMPORTANT: This is an internal utility. Using it may break the
// implementation of death tests. User code MUST NOT use it.
bool InDeathTestChild() {
# if GTEST_OS_WINDOWS
// On Windows, death tests are thread-safe regardless of the value of the
// death_test_style flag.
return !GTEST_FLAG(internal_run_death_test).empty();
# else
if (GTEST_FLAG(death_test_style) == "threadsafe")
return !GTEST_FLAG(internal_run_death_test).empty();
else
return g_in_fast_death_test_child;
#endif
}
} // namespace internal
// ExitedWithCode constructor. // ExitedWithCode constructor.
ExitedWithCode::ExitedWithCode(int exit_code) : exit_code_(exit_code) { ExitedWithCode::ExitedWithCode(int exit_code) : exit_code_(exit_code) {
} }
@ -7017,6 +7086,7 @@ DeathTest::TestRole NoExecDeathTest::AssumeRole() {
// Event forwarding to the listeners of event listener API mush be shut // Event forwarding to the listeners of event listener API mush be shut
// down in death test subprocesses. // down in death test subprocesses.
GetUnitTestImpl()->listeners()->SuppressEventForwarding(); GetUnitTestImpl()->listeners()->SuppressEventForwarding();
g_in_fast_death_test_child = true;
return EXECUTE_TEST; return EXECUTE_TEST;
} else { } else {
GTEST_DEATH_TEST_CHECK_SYSCALL_(close(pipe_fd[1])); GTEST_DEATH_TEST_CHECK_SYSCALL_(close(pipe_fd[1]));
@ -7036,6 +7106,11 @@ class ExecDeathTest : public ForkingDeathTest {
ForkingDeathTest(a_statement, a_regex), file_(file), line_(line) { } ForkingDeathTest(a_statement, a_regex), file_(file), line_(line) { }
virtual TestRole AssumeRole(); virtual TestRole AssumeRole();
private: private:
static ::std::vector<testing::internal::string>
GetArgvsForDeathTestChildProcess() {
::std::vector<testing::internal::string> args = GetInjectableArgvs();
return args;
}
// The name of the file in which the death test is located. // The name of the file in which the death test is located.
const char* const file_; const char* const file_;
// The line number on which the death test is located. // The line number on which the death test is located.
@ -7070,6 +7145,7 @@ class Arguments {
char* const* Argv() { char* const* Argv() {
return &args_[0]; return &args_[0];
} }
private: private:
std::vector<char*> args_; std::vector<char*> args_;
}; };
@ -7081,7 +7157,7 @@ struct ExecDeathTestArgs {
int close_fd; // File descriptor to close; the read end of a pipe int close_fd; // File descriptor to close; the read end of a pipe
}; };
# if GTEST_OS_MAC && !GTEST_OS_MAC_IOS # if GTEST_OS_MAC
inline char** GetEnviron() { inline char** GetEnviron() {
// When Google Test is built as a framework on MacOS X, the environ variable // When Google Test is built as a framework on MacOS X, the environ variable
// is unavailable. Apple's documentation (man environ) recommends using // is unavailable. Apple's documentation (man environ) recommends using
@ -7095,6 +7171,7 @@ extern "C" char** environ;
inline char** GetEnviron() { return environ; } inline char** GetEnviron() { return environ; }
# endif // GTEST_OS_MAC # endif // GTEST_OS_MAC
# if !GTEST_OS_QNX
// The main function for a threadsafe-style death test child process. // The main function for a threadsafe-style death test child process.
// This function is called in a clone()-ed process and thus must avoid // This function is called in a clone()-ed process and thus must avoid
// any potentially unsafe operations like malloc or libc functions. // any potentially unsafe operations like malloc or libc functions.
@ -7127,6 +7204,7 @@ static int ExecDeathTestChildMain(void* child_arg) {
GetLastErrnoDescription().c_str())); GetLastErrnoDescription().c_str()));
return EXIT_FAILURE; return EXIT_FAILURE;
} }
# endif // !GTEST_OS_QNX
// Two utility routines that together determine the direction the stack // Two utility routines that together determine the direction the stack
// grows. // grows.
@ -7137,25 +7215,76 @@ static int ExecDeathTestChildMain(void* child_arg) {
// GTEST_NO_INLINE_ is required to prevent GCC 4.6 from inlining // GTEST_NO_INLINE_ is required to prevent GCC 4.6 from inlining
// StackLowerThanAddress into StackGrowsDown, which then doesn't give // StackLowerThanAddress into StackGrowsDown, which then doesn't give
// correct answer. // correct answer.
bool StackLowerThanAddress(const void* ptr) GTEST_NO_INLINE_; void StackLowerThanAddress(const void* ptr, bool* result) GTEST_NO_INLINE_;
bool StackLowerThanAddress(const void* ptr) { void StackLowerThanAddress(const void* ptr, bool* result) {
int dummy; int dummy;
return &dummy < ptr; *result = (&dummy < ptr);
} }
static bool StackGrowsDown() { static bool StackGrowsDown() {
int dummy; int dummy;
return StackLowerThanAddress(&dummy); bool result;
StackLowerThanAddress(&dummy, &result);
return result;
} }
// A threadsafe implementation of fork(2) for threadsafe-style death tests // Spawns a child process with the same executable as the current process in
// that uses clone(2). It dies with an error message if anything goes // a thread-safe manner and instructs it to run the death test. The
// wrong. // implementation uses fork(2) + exec. On systems where clone(2) is
static pid_t ExecDeathTestFork(char* const* argv, int close_fd) { // available, it is used instead, being slightly more thread-safe. On QNX,
// fork supports only single-threaded environments, so this function uses
// spawn(2) there instead. The function dies with an error message if
// anything goes wrong.
static pid_t ExecDeathTestSpawnChild(char* const* argv, int close_fd) {
ExecDeathTestArgs args = { argv, close_fd }; ExecDeathTestArgs args = { argv, close_fd };
pid_t child_pid = -1; pid_t child_pid = -1;
# if GTEST_HAS_CLONE # if GTEST_OS_QNX
// Obtains the current directory and sets it to be closed in the child
// process.
const int cwd_fd = open(".", O_RDONLY);
GTEST_DEATH_TEST_CHECK_(cwd_fd != -1);
GTEST_DEATH_TEST_CHECK_SYSCALL_(fcntl(cwd_fd, F_SETFD, FD_CLOEXEC));
// We need to execute the test program in the same environment where
// it was originally invoked. Therefore we change to the original
// working directory first.
const char* const original_dir =
UnitTest::GetInstance()->original_working_dir();
// We can safely call chdir() as it's a direct system call.
if (chdir(original_dir) != 0) {
DeathTestAbort(String::Format("chdir(\"%s\") failed: %s",
original_dir,
GetLastErrnoDescription().c_str()));
return EXIT_FAILURE;
}
int fd_flags;
// Set close_fd to be closed after spawn.
GTEST_DEATH_TEST_CHECK_SYSCALL_(fd_flags = fcntl(close_fd, F_GETFD));
GTEST_DEATH_TEST_CHECK_SYSCALL_(fcntl(close_fd, F_SETFD,
fd_flags | FD_CLOEXEC));
struct inheritance inherit = {0};
// spawn is a system call.
child_pid = spawn(args.argv[0], 0, NULL, &inherit, args.argv, GetEnviron());
// Restores the current working directory.
GTEST_DEATH_TEST_CHECK_(fchdir(cwd_fd) != -1);
GTEST_DEATH_TEST_CHECK_SYSCALL_(close(cwd_fd));
# else // GTEST_OS_QNX
# if GTEST_OS_LINUX
// When a SIGPROF signal is received while fork() or clone() are executing,
// the process may hang. To avoid this, we ignore SIGPROF here and re-enable
// it after the call to fork()/clone() is complete.
struct sigaction saved_sigprof_action;
struct sigaction ignore_sigprof_action;
memset(&ignore_sigprof_action, 0, sizeof(ignore_sigprof_action));
sigemptyset(&ignore_sigprof_action.sa_mask);
ignore_sigprof_action.sa_handler = SIG_IGN;
GTEST_DEATH_TEST_CHECK_SYSCALL_(sigaction(
SIGPROF, &ignore_sigprof_action, &saved_sigprof_action));
# endif // GTEST_OS_LINUX
# if GTEST_HAS_CLONE
const bool use_fork = GTEST_FLAG(death_test_use_fork); const bool use_fork = GTEST_FLAG(death_test_use_fork);
if (!use_fork) { if (!use_fork) {
@ -7172,14 +7301,19 @@ static pid_t ExecDeathTestFork(char* const* argv, int close_fd) {
GTEST_DEATH_TEST_CHECK_(munmap(stack, stack_size) != -1); GTEST_DEATH_TEST_CHECK_(munmap(stack, stack_size) != -1);
} }
# else # else
const bool use_fork = true; const bool use_fork = true;
# endif // GTEST_HAS_CLONE # endif // GTEST_HAS_CLONE
if (use_fork && (child_pid = fork()) == 0) { if (use_fork && (child_pid = fork()) == 0) {
ExecDeathTestChildMain(&args); ExecDeathTestChildMain(&args);
_exit(0); _exit(0);
} }
# endif // GTEST_OS_QNX
# if GTEST_OS_LINUX
GTEST_DEATH_TEST_CHECK_SYSCALL_(
sigaction(SIGPROF, &saved_sigprof_action, NULL));
# endif // GTEST_OS_LINUX
GTEST_DEATH_TEST_CHECK_(child_pid != -1); GTEST_DEATH_TEST_CHECK_(child_pid != -1);
return child_pid; return child_pid;
@ -7216,7 +7350,7 @@ DeathTest::TestRole ExecDeathTest::AssumeRole() {
GTEST_FLAG_PREFIX_, kInternalRunDeathTestFlag, GTEST_FLAG_PREFIX_, kInternalRunDeathTestFlag,
file_, line_, death_test_index, pipe_fd[1]); file_, line_, death_test_index, pipe_fd[1]);
Arguments args; Arguments args;
args.AddArguments(GetArgvs()); args.AddArguments(GetArgvsForDeathTestChildProcess());
args.AddArgument(filter_flag.c_str()); args.AddArgument(filter_flag.c_str());
args.AddArgument(internal_flag.c_str()); args.AddArgument(internal_flag.c_str());
@ -7227,7 +7361,7 @@ DeathTest::TestRole ExecDeathTest::AssumeRole() {
// is necessary. // is necessary.
FlushInfoLog(); FlushInfoLog();
const pid_t child_pid = ExecDeathTestFork(args.Argv(), pipe_fd[0]); const pid_t child_pid = ExecDeathTestSpawnChild(args.Argv(), pipe_fd[0]);
GTEST_DEATH_TEST_CHECK_SYSCALL_(close(pipe_fd[1])); GTEST_DEATH_TEST_CHECK_SYSCALL_(close(pipe_fd[1]));
set_child_pid(child_pid); set_child_pid(child_pid);
set_read_fd(pipe_fd[0]); set_read_fd(pipe_fd[0]);
@ -7862,6 +7996,11 @@ void FilePath::Normalize() {
# include <mach/vm_map.h> # include <mach/vm_map.h>
#endif // GTEST_OS_MAC #endif // GTEST_OS_MAC
#if GTEST_OS_QNX
# include <devctl.h>
# include <sys/procfs.h>
#endif // GTEST_OS_QNX
// Indicates that this translation unit is part of Google Test's // Indicates that this translation unit is part of Google Test's
// implementation. It must come before gtest-internal-inl.h is // implementation. It must come before gtest-internal-inl.h is
@ -7904,6 +8043,26 @@ size_t GetThreadCount() {
} }
} }
#elif GTEST_OS_QNX
// Returns the number of threads running in the process, or 0 to indicate that
// we cannot detect it.
size_t GetThreadCount() {
const int fd = open("/proc/self/as", O_RDONLY);
if (fd < 0) {
return 0;
}
procfs_info process_info;
const int status =
devctl(fd, DCMD_PROC_INFO, &process_info, sizeof(process_info), NULL);
close(fd);
if (status == EOK) {
return static_cast<size_t>(process_info.num_threads);
} else {
return 0;
}
}
#else #else
size_t GetThreadCount() { size_t GetThreadCount() {
@ -8295,7 +8454,6 @@ class CapturedStream {
public: public:
// The ctor redirects the stream to a temporary file. // The ctor redirects the stream to a temporary file.
CapturedStream(int fd) : fd_(fd), uncaptured_fd_(dup(fd)) { CapturedStream(int fd) : fd_(fd), uncaptured_fd_(dup(fd)) {
# if GTEST_OS_WINDOWS # if GTEST_OS_WINDOWS
char temp_dir_path[MAX_PATH + 1] = { '\0' }; // NOLINT char temp_dir_path[MAX_PATH + 1] = { '\0' }; // NOLINT
char temp_file_path[MAX_PATH + 1] = { '\0' }; // NOLINT char temp_file_path[MAX_PATH + 1] = { '\0' }; // NOLINT
@ -8312,10 +8470,15 @@ class CapturedStream {
<< temp_file_path; << temp_file_path;
filename_ = temp_file_path; filename_ = temp_file_path;
# else # else
// There's no guarantee that a test has write access to the // There's no guarantee that a test has write access to the current
// current directory, so we create the temporary file in the /tmp // directory, so we create the temporary file in the /tmp directory instead.
// directory instead. // We use /tmp on most systems, and /mnt/sdcard on Android. That's because
// Android doesn't have /tmp.
# if GTEST_OS_LINUX_ANDROID
char name_template[] = "/mnt/sdcard/gtest_captured_stream.XXXXXX";
# else
char name_template[] = "/tmp/captured_stream.XXXXXX"; char name_template[] = "/tmp/captured_stream.XXXXXX";
# endif // GTEST_OS_LINUX_ANDROID
const int captured_fd = mkstemp(name_template); const int captured_fd = mkstemp(name_template);
filename_ = name_template; filename_ = name_template;
# endif // GTEST_OS_WINDOWS # endif // GTEST_OS_WINDOWS
@ -8434,11 +8597,23 @@ String GetCapturedStderr() { return GetCapturedStream(&g_captured_stderr); }
#if GTEST_HAS_DEATH_TEST #if GTEST_HAS_DEATH_TEST
// A copy of all command line arguments. Set by InitGoogleTest(). // A copy of all command line arguments. Set by InitGoogleTest().
::std::vector<String> g_argvs; ::std::vector<testing::internal::string> g_argvs;
// Returns the command line as a vector of strings. static const ::std::vector<testing::internal::string>* g_injected_test_argvs =
const ::std::vector<String>& GetArgvs() { return g_argvs; } NULL; // Owned.
void SetInjectableArgvs(const ::std::vector<testing::internal::string>* argvs) {
if (g_injected_test_argvs != argvs)
delete g_injected_test_argvs;
g_injected_test_argvs = argvs;
}
const ::std::vector<testing::internal::string>& GetInjectableArgvs() {
if (g_injected_test_argvs != NULL) {
return *g_injected_test_argvs;
}
return g_argvs;
}
#endif // GTEST_HAS_DEATH_TEST #endif // GTEST_HAS_DEATH_TEST
#if GTEST_OS_WINDOWS_MOBILE #if GTEST_OS_WINDOWS_MOBILE
@ -8605,14 +8780,6 @@ namespace {
using ::std::ostream; using ::std::ostream;
#if GTEST_OS_WINDOWS_MOBILE // Windows CE does not define _snprintf_s.
# define snprintf _snprintf
#elif defined(_MSC_VER) && _MSC_VER >= 1400 // VC 8.0 and later deprecate snprintf and _snprintf.
# define snprintf _snprintf_s
#elif defined(_MSC_VER) && _MSC_VER
# define snprintf _snprintf
#endif // GTEST_OS_WINDOWS_MOBILE
// Prints a segment of bytes in the given object. // Prints a segment of bytes in the given object.
void PrintByteSegmentInObjectTo(const unsigned char* obj_bytes, size_t start, void PrintByteSegmentInObjectTo(const unsigned char* obj_bytes, size_t start,
size_t count, ostream* os) { size_t count, ostream* os) {
@ -8627,7 +8794,7 @@ void PrintByteSegmentInObjectTo(const unsigned char* obj_bytes, size_t start,
else else
*os << '-'; *os << '-';
} }
snprintf(text, sizeof(text), "%02X", obj_bytes[j]); GTEST_SNPRINTF_(text, sizeof(text), "%02X", obj_bytes[j]);
*os << text; *os << text;
} }
} }
@ -8741,9 +8908,9 @@ static CharFormat PrintAsCharLiteralTo(Char c, ostream* os) {
return kSpecialEscape; return kSpecialEscape;
} }
// Prints a char c as if it's part of a string literal, escaping it when // Prints a wchar_t c as if it's part of a string literal, escaping it when
// necessary; returns how c was formatted. // necessary; returns how c was formatted.
static CharFormat PrintAsWideStringLiteralTo(wchar_t c, ostream* os) { static CharFormat PrintAsStringLiteralTo(wchar_t c, ostream* os) {
switch (c) { switch (c) {
case L'\'': case L'\'':
*os << "'"; *os << "'";
@ -8758,8 +8925,9 @@ static CharFormat PrintAsWideStringLiteralTo(wchar_t c, ostream* os) {
// Prints a char c as if it's part of a string literal, escaping it when // Prints a char c as if it's part of a string literal, escaping it when
// necessary; returns how c was formatted. // necessary; returns how c was formatted.
static CharFormat PrintAsNarrowStringLiteralTo(char c, ostream* os) { static CharFormat PrintAsStringLiteralTo(char c, ostream* os) {
return PrintAsWideStringLiteralTo(static_cast<unsigned char>(c), os); return PrintAsStringLiteralTo(
static_cast<wchar_t>(static_cast<unsigned char>(c)), os);
} }
// Prints a wide or narrow character c and its code. '\0' is printed // Prints a wide or narrow character c and its code. '\0' is printed
@ -8805,48 +8973,63 @@ void PrintTo(wchar_t wc, ostream* os) {
PrintCharAndCodeTo<wchar_t>(wc, os); PrintCharAndCodeTo<wchar_t>(wc, os);
} }
// Prints the given array of characters to the ostream. // Prints the given array of characters to the ostream. CharType must be either
// The array starts at *begin, the length is len, it may include '\0' characters // char or wchar_t.
// and may not be null-terminated. // The array starts at begin, the length is len, it may include '\0' characters
static void PrintCharsAsStringTo(const char* begin, size_t len, ostream* os) { // and may not be NUL-terminated.
*os << "\""; template <typename CharType>
static void PrintCharsAsStringTo(
const CharType* begin, size_t len, ostream* os) {
const char* const kQuoteBegin = sizeof(CharType) == 1 ? "\"" : "L\"";
*os << kQuoteBegin;
bool is_previous_hex = false; bool is_previous_hex = false;
for (size_t index = 0; index < len; ++index) { for (size_t index = 0; index < len; ++index) {
const char cur = begin[index]; const CharType cur = begin[index];
if (is_previous_hex && IsXDigit(cur)) { if (is_previous_hex && IsXDigit(cur)) {
// Previous character is of '\x..' form and this character can be // Previous character is of '\x..' form and this character can be
// interpreted as another hexadecimal digit in its number. Break string to // interpreted as another hexadecimal digit in its number. Break string to
// disambiguate. // disambiguate.
*os << "\" \""; *os << "\" " << kQuoteBegin;
} }
is_previous_hex = PrintAsNarrowStringLiteralTo(cur, os) == kHexEscape; is_previous_hex = PrintAsStringLiteralTo(cur, os) == kHexEscape;
} }
*os << "\""; *os << "\"";
} }
// Prints a (const) char/wchar_t array of 'len' elements, starting at address
// 'begin'. CharType must be either char or wchar_t.
template <typename CharType>
static void UniversalPrintCharArray(
const CharType* begin, size_t len, ostream* os) {
// The code
// const char kFoo[] = "foo";
// generates an array of 4, not 3, elements, with the last one being '\0'.
//
// Therefore when printing a char array, we don't print the last element if
// it's '\0', such that the output matches the string literal as it's
// written in the source code.
if (len > 0 && begin[len - 1] == '\0') {
PrintCharsAsStringTo(begin, len - 1, os);
return;
}
// If, however, the last element in the array is not '\0', e.g.
// const char kFoo[] = { 'f', 'o', 'o' };
// we must print the entire array. We also print a message to indicate
// that the array is not NUL-terminated.
PrintCharsAsStringTo(begin, len, os);
*os << " (no terminating NUL)";
}
// Prints a (const) char array of 'len' elements, starting at address 'begin'. // Prints a (const) char array of 'len' elements, starting at address 'begin'.
void UniversalPrintArray(const char* begin, size_t len, ostream* os) { void UniversalPrintArray(const char* begin, size_t len, ostream* os) {
PrintCharsAsStringTo(begin, len, os); UniversalPrintCharArray(begin, len, os);
} }
// Prints the given array of wide characters to the ostream. // Prints a (const) wchar_t array of 'len' elements, starting at address
// The array starts at *begin, the length is len, it may include L'\0' // 'begin'.
// characters and may not be null-terminated. void UniversalPrintArray(const wchar_t* begin, size_t len, ostream* os) {
static void PrintWideCharsAsStringTo(const wchar_t* begin, size_t len, UniversalPrintCharArray(begin, len, os);
ostream* os) {
*os << "L\"";
bool is_previous_hex = false;
for (size_t index = 0; index < len; ++index) {
const wchar_t cur = begin[index];
if (is_previous_hex && isascii(cur) && IsXDigit(static_cast<char>(cur))) {
// Previous character is of '\x..' form and this character can be
// interpreted as another hexadecimal digit in its number. Break string to
// disambiguate.
*os << "\" L\"";
}
is_previous_hex = PrintAsWideStringLiteralTo(cur, os) == kHexEscape;
}
*os << "\"";
} }
// Prints the given C string to the ostream. // Prints the given C string to the ostream.
@ -8872,7 +9055,7 @@ void PrintTo(const wchar_t* s, ostream* os) {
*os << "NULL"; *os << "NULL";
} else { } else {
*os << ImplicitCast_<const void*>(s) << " pointing to "; *os << ImplicitCast_<const void*>(s) << " pointing to ";
PrintWideCharsAsStringTo(s, wcslen(s), os); PrintCharsAsStringTo(s, wcslen(s), os);
} }
} }
#endif // wchar_t is native #endif // wchar_t is native
@ -8891,13 +9074,13 @@ void PrintStringTo(const ::std::string& s, ostream* os) {
// Prints a ::wstring object. // Prints a ::wstring object.
#if GTEST_HAS_GLOBAL_WSTRING #if GTEST_HAS_GLOBAL_WSTRING
void PrintWideStringTo(const ::wstring& s, ostream* os) { void PrintWideStringTo(const ::wstring& s, ostream* os) {
PrintWideCharsAsStringTo(s.data(), s.size(), os); PrintCharsAsStringTo(s.data(), s.size(), os);
} }
#endif // GTEST_HAS_GLOBAL_WSTRING #endif // GTEST_HAS_GLOBAL_WSTRING
#if GTEST_HAS_STD_WSTRING #if GTEST_HAS_STD_WSTRING
void PrintWideStringTo(const ::std::wstring& s, ostream* os) { void PrintWideStringTo(const ::std::wstring& s, ostream* os) {
PrintWideCharsAsStringTo(s.data(), s.size(), os); PrintCharsAsStringTo(s.data(), s.size(), os);
} }
#endif // GTEST_HAS_STD_WSTRING #endif // GTEST_HAS_STD_WSTRING