From d201456903f3ecae1f7794edfab0d5678e642265 Mon Sep 17 00:00:00 2001 From: shiqian Date: Thu, 3 Jul 2008 22:38:12 +0000 Subject: Initial import. --- src/gtest-death-test.cc | 751 ++++++++++ src/gtest-filepath.cc | 208 +++ src/gtest-internal-inl.h | 1118 +++++++++++++++ src/gtest-port.cc | 292 ++++ src/gtest.cc | 3545 ++++++++++++++++++++++++++++++++++++++++++++++ src/gtest_main.cc | 39 + 6 files changed, 5953 insertions(+) create mode 100644 src/gtest-death-test.cc create mode 100644 src/gtest-filepath.cc create mode 100644 src/gtest-internal-inl.h create mode 100644 src/gtest-port.cc create mode 100644 src/gtest.cc create mode 100644 src/gtest_main.cc (limited to 'src') diff --git a/src/gtest-death-test.cc b/src/gtest-death-test.cc new file mode 100644 index 00000000..09fdd3ff --- /dev/null +++ b/src/gtest-death-test.cc @@ -0,0 +1,751 @@ +// Copyright 2005, 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. +// +// Author: wan@google.com (Zhanyong Wan) +// +// This file implements death tests. + +#include +#include + +#include +#include +#include + +#include +#include + +// 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 +#include "gtest-internal-inl.h" +#undef GTEST_IMPLEMENTATION + +namespace testing { + +// Constants. + +// The default death test style. +static const char kDefaultDeathTestStyle[] = "fast"; + +GTEST_DEFINE_string( + death_test_style, + internal::StringFromGTestEnv("death_test_style", kDefaultDeathTestStyle), + "Indicates how to run a death test in a forked child process: " + "\"threadsafe\" (child process re-executes the test binary " + "from the beginning, running only the specific death test) or " + "\"fast\" (child process runs the death test immediately " + "after forking)."); + +namespace internal { +GTEST_DEFINE_string( + internal_run_death_test, "", + "Indicates the file, line number, temporal index of " + "the single death test to run, and a file descriptor to " + "which a success code may be sent, all separated by " + "colons. This flag is specified if and only if the current " + "process is a sub-process launched for running a thread-safe " + "death test. FOR INTERNAL USE ONLY."); +} // namespace internal + +#ifdef GTEST_HAS_DEATH_TEST + +// ExitedWithCode constructor. +ExitedWithCode::ExitedWithCode(int exit_code) : exit_code_(exit_code) { +} + +// ExitedWithCode function-call operator. +bool ExitedWithCode::operator()(int exit_status) const { + return WIFEXITED(exit_status) && WEXITSTATUS(exit_status) == exit_code_; +} + +// KilledBySignal constructor. +KilledBySignal::KilledBySignal(int signum) : signum_(signum) { +} + +// KilledBySignal function-call operator. +bool KilledBySignal::operator()(int exit_status) const { + return WIFSIGNALED(exit_status) && WTERMSIG(exit_status) == signum_; +} + +namespace internal { + +// Utilities needed for death tests. + +// Generates a textual description of a given exit code, in the format +// specified by wait(2). +static String ExitSummary(int exit_code) { + Message m; + if (WIFEXITED(exit_code)) { + m << "Exited with exit status " << WEXITSTATUS(exit_code); + } else if (WIFSIGNALED(exit_code)) { + m << "Terminated by signal " << WTERMSIG(exit_code); + } +#ifdef WCOREDUMP + if (WCOREDUMP(exit_code)) { + m << " (core dumped)"; + } +#endif + return m.GetString(); +} + +// Returns true if exit_status describes a process that was terminated +// by a signal, or exited normally with a nonzero exit code. +bool ExitedUnsuccessfully(int exit_status) { + return !ExitedWithCode(0)(exit_status); +} + +// Generates a textual failure message when a death test finds more than +// one thread running, or cannot determine the number of threads, prior +// to executing the given statement. It is the responsibility of the +// caller not to pass a thread_count of 1. +static String DeathTestThreadWarning(size_t thread_count) { + Message msg; + msg << "Death tests use fork(), which is unsafe particularly" + << " in a threaded context. For this test, " << GTEST_NAME << " "; + if (thread_count == 0) + msg << "couldn't detect the number of threads."; + else + msg << "detected " << thread_count << " threads."; + return msg.GetString(); +} + +// Static string containing a description of the outcome of the +// last death test. +static String last_death_test_message; + +// Flag characters for reporting a death test that did not die. +static const char kDeathTestLived = 'L'; +static const char kDeathTestReturned = 'R'; +static const char kDeathTestInternalError = 'I'; + +// An enumeration describing all of the possible ways that a death test +// can conclude. DIED means that the process died while executing the +// test code; LIVED means that process lived beyond the end of the test +// code; and RETURNED means that the test statement attempted a "return," +// which is not allowed. IN_PROGRESS means the test has not yet +// concluded. +enum DeathTestOutcome { IN_PROGRESS, DIED, LIVED, RETURNED }; + +// Routine for aborting the program which is safe to call from an +// exec-style death test child process, in which case the the error +// message is propagated back to the parent process. Otherwise, the +// message is simply printed to stderr. In either case, the program +// then exits with status 1. +void DeathTestAbort(const char* format, ...) { + // This function may be called from a threadsafe-style death test + // child process, which operates on a very small stack. Use the + // heap for any additional non-miniscule memory requirements. + const InternalRunDeathTestFlag* const flag = + GetUnitTestImpl()->internal_run_death_test_flag(); + va_list args; + va_start(args, format); + + if (flag != NULL) { + FILE* parent = fdopen(flag->status_fd, "w"); + fputc(kDeathTestInternalError, parent); + vfprintf(parent, format, args); + fclose(parent); + va_end(args); + _exit(1); + } else { + vfprintf(stderr, format, args); + va_end(args); + abort(); + } +} + +// A replacement for CHECK that calls DeathTestAbort if the assertion +// fails. +#define GTEST_DEATH_TEST_CHECK(expression) \ + do { \ + if (!(expression)) { \ + DeathTestAbort("CHECK failed: File %s, line %d: %s", \ + __FILE__, __LINE__, #expression); \ + } \ + } while (0) + +// This macro is similar to GTEST_DEATH_TEST_CHECK, but it is meant for +// evaluating any system call that fulfills two conditions: it must return +// -1 on failure, and set errno to EINTR when it is interrupted and +// should be tried again. The macro expands to a loop that repeatedly +// evaluates the expression as long as it evaluates to -1 and sets +// errno to EINTR. If the expression evaluates to -1 but errno is +// something other than EINTR, DeathTestAbort is called. +#define GTEST_DEATH_TEST_CHECK_SYSCALL(expression) \ + do { \ + int retval; \ + do { \ + retval = (expression); \ + } while (retval == -1 && errno == EINTR); \ + if (retval == -1) { \ + DeathTestAbort("CHECK failed: File %s, line %d: %s != -1", \ + __FILE__, __LINE__, #expression); \ + } \ + } while (0) + +// Death test constructor. Increments the running death test count +// for the current test. +DeathTest::DeathTest() { + TestInfo* const info = GetUnitTestImpl()->current_test_info(); + if (info == NULL) { + DeathTestAbort("Cannot run a death test outside of a TEST or " + "TEST_F construct"); + } +} + +// Creates and returns a death test by dispatching to the current +// death test factory. +bool DeathTest::Create(const char* statement, const RE* regex, + const char* file, int line, DeathTest** test) { + return GetUnitTestImpl()->death_test_factory()->Create( + statement, regex, file, line, test); +} + +const char* DeathTest::LastMessage() { + return last_death_test_message.c_str(); +} + +// ForkingDeathTest provides implementations for most of the abstract +// methods of the DeathTest interface. Only the AssumeRole method is +// left undefined. +class ForkingDeathTest : public DeathTest { + public: + ForkingDeathTest(const char* statement, const RE* regex); + + // All of these virtual functions are inherited from DeathTest. + virtual int Wait(); + virtual bool Passed(bool status_ok); + virtual void Abort(AbortReason reason); + + protected: + void set_forked(bool forked) { forked_ = forked; } + void set_child_pid(pid_t child_pid) { child_pid_ = child_pid; } + void set_read_fd(int fd) { read_fd_ = fd; } + void set_write_fd(int fd) { write_fd_ = fd; } + + private: + // The textual content of the code this object is testing. + const char* const statement_; + // The regular expression which test output must match. + const RE* const regex_; + // True if the death test successfully forked. + bool forked_; + // PID of child process during death test; 0 in the child process itself. + pid_t child_pid_; + // File descriptors for communicating the death test's status byte. + int read_fd_; // Always -1 in the child process. + int write_fd_; // Always -1 in the parent process. + // The exit status of the child process. + int status_; + // How the death test concluded. + DeathTestOutcome outcome_; +}; + +// Constructs a ForkingDeathTest. +ForkingDeathTest::ForkingDeathTest(const char* statement, const RE* regex) + : DeathTest(), + statement_(statement), + regex_(regex), + forked_(false), + child_pid_(-1), + read_fd_(-1), + write_fd_(-1), + status_(-1), + outcome_(IN_PROGRESS) { +} + +// Reads an internal failure message from a file descriptor, then calls +// LOG(FATAL) with that message. Called from a death test parent process +// to read a failure message from the death test child process. +static void FailFromInternalError(int fd) { + Message error; + char buffer[256]; + ssize_t num_read; + + do { + while ((num_read = read(fd, buffer, 255)) > 0) { + buffer[num_read] = '\0'; + error << buffer; + } + } while (num_read == -1 && errno == EINTR); + + // TODO(smcafee): Maybe just FAIL the test instead? + if (num_read == 0) { + GTEST_LOG(FATAL, error); + } else { + GTEST_LOG(FATAL, + Message() << "Error while reading death test internal: " + << strerror(errno) << " [" << errno << "]"); + } +} + +// Waits for the child in a death test to exit, returning its exit +// status, or 0 if no child process exists. As a side effect, sets the +// outcome data member. +int ForkingDeathTest::Wait() { + if (!forked_) + return 0; + + // The read() here blocks until data is available (signifying the + // failure of the death test) or until the pipe is closed (signifying + // its success), so it's okay to call this in the parent before + // the child process has exited. + char flag; + ssize_t bytes_read; + + do { + bytes_read = read(read_fd_, &flag, 1); + } while (bytes_read == -1 && errno == EINTR); + + if (bytes_read == 0) { + outcome_ = DIED; + } else if (bytes_read == 1) { + switch (flag) { + case kDeathTestReturned: + outcome_ = RETURNED; + break; + case kDeathTestLived: + outcome_ = LIVED; + break; + case kDeathTestInternalError: + FailFromInternalError(read_fd_); // Does not return. + break; + default: + GTEST_LOG(FATAL, + Message() << "Death test child process reported unexpected " + << "status byte (" << static_cast(flag) + << ")"); + } + } else { + GTEST_LOG(FATAL, + Message() << "Read from death test child process failed: " + << strerror(errno)); + } + + GTEST_DEATH_TEST_CHECK_SYSCALL(close(read_fd_)); + GTEST_DEATH_TEST_CHECK_SYSCALL(waitpid(child_pid_, &status_, 0)); + return status_; +} + +// Assesses the success or failure of a death test, using both private +// members which have previously been set, and one argument: +// +// Private data members: +// outcome: an enumeration describing how the death test +// concluded: DIED, LIVED, or RETURNED. The death test fails +// in the latter two cases +// status: the exit status of the child process, in the format +// specified by wait(2) +// regex: a regular expression object to be applied to +// the test's captured standard error output; the death test +// fails if it does not match +// +// Argument: +// status_ok: true if exit_status is acceptable in the context of +// this particular death test, which fails if it is false +// +// Returns true iff all of the above conditions are met. Otherwise, the +// first failing condition, in the order given above, is the one that is +// reported. Also sets the static variable last_death_test_message. +bool ForkingDeathTest::Passed(bool status_ok) { + if (!forked_) + return false; + +#if GTEST_HAS_GLOBAL_STRING + const ::string error_message = GetCapturedStderr(); +#else + const ::std::string error_message = GetCapturedStderr(); +#endif // GTEST_HAS_GLOBAL_STRING + + bool success = false; + Message buffer; + + buffer << "Death test: " << statement_ << "\n"; + switch (outcome_) { + case LIVED: + buffer << " Result: failed to die.\n" + << " Error msg: " << error_message; + break; + case RETURNED: + buffer << " Result: illegal return in test statement.\n" + << " Error msg: " << error_message; + break; + case DIED: + if (status_ok) { + if (RE::PartialMatch(error_message, *regex_)) { + success = true; + } else { + buffer << " Result: died but not with expected error.\n" + << " Expected: " << regex_->pattern() << "\n" + << "Actual msg: " << error_message; + } + } else { + buffer << " Result: died but not with expected exit code:\n" + << " " << ExitSummary(status_) << "\n"; + } + break; + default: + GTEST_LOG(FATAL, + "DeathTest::Passed somehow called before conclusion of test"); + } + + last_death_test_message = buffer.GetString(); + return success; +} + +// Signals that the death test code which should have exited, didn't. +// Should be called only in a death test child process. +// Writes a status byte to the child's status file desriptor, then +// calls _exit(1). +void ForkingDeathTest::Abort(AbortReason reason) { + // The parent process considers the death test to be a failure if + // it finds any data in our pipe. So, here we write a single flag byte + // to the pipe, then exit. + const char flag = + reason == TEST_DID_NOT_DIE ? kDeathTestLived : kDeathTestReturned; + GTEST_DEATH_TEST_CHECK_SYSCALL(write(write_fd_, &flag, 1)); + GTEST_DEATH_TEST_CHECK_SYSCALL(close(write_fd_)); + _exit(1); // Exits w/o any normal exit hooks (we were supposed to crash) +} + +// A concrete death test class that forks, then immediately runs the test +// in the child process. +class NoExecDeathTest : public ForkingDeathTest { + public: + NoExecDeathTest(const char* statement, const RE* regex) : + ForkingDeathTest(statement, regex) { } + virtual TestRole AssumeRole(); +}; + +// The AssumeRole process for a fork-and-run death test. It implements a +// straightforward fork, with a simple pipe to transmit the status byte. +DeathTest::TestRole NoExecDeathTest::AssumeRole() { + const size_t thread_count = GetThreadCount(); + if (thread_count != 1) { + GTEST_LOG(WARNING, DeathTestThreadWarning(thread_count)); + } + + int pipe_fd[2]; + GTEST_DEATH_TEST_CHECK(pipe(pipe_fd) != -1); + + last_death_test_message = ""; + CaptureStderr(); + // When we fork the process below, the log file buffers are copied, but the + // file descriptors are shared. We flush all log files here so that closing + // the file descriptors in the child process doesn't throw off the + // synchronization between descriptors and buffers in the parent process. + // This is as close to the fork as possible to avoid a race condition in case + // there are multiple threads running before the death test, and another + // thread writes to the log file. + FlushInfoLog(); + + const pid_t child_pid = fork(); + GTEST_DEATH_TEST_CHECK(child_pid != -1); + set_child_pid(child_pid); + if (child_pid == 0) { + GTEST_DEATH_TEST_CHECK_SYSCALL(close(pipe_fd[0])); + set_write_fd(pipe_fd[1]); + // Redirects all logging to stderr in the child process to prevent + // concurrent writes to the log files. We capture stderr in the parent + // process and append the child process' output to a log. + LogToStderr(); + return EXECUTE_TEST; + } else { + GTEST_DEATH_TEST_CHECK_SYSCALL(close(pipe_fd[1])); + set_read_fd(pipe_fd[0]); + set_forked(true); + return OVERSEE_TEST; + } +} + +// A concrete death test class that forks and re-executes the main +// program from the beginning, with command-line flags set that cause +// only this specific death test to be run. +class ExecDeathTest : public ForkingDeathTest { + public: + ExecDeathTest(const char* statement, const RE* regex, + const char* file, int line) : + ForkingDeathTest(statement, regex), file_(file), line_(line) { } + virtual TestRole AssumeRole(); + private: + // The name of the file in which the death test is located. + const char* const file_; + // The line number on which the death test is located. + const int line_; +}; + +// Utility class for accumulating command-line arguments. +class Arguments { + public: + Arguments() { + args_.push_back(NULL); + } + ~Arguments() { + for (std::vector::iterator i = args_.begin(); + i + 1 != args_.end(); + ++i) { + free(*i); + } + } + void AddArgument(const char* argument) { + args_.insert(args_.end() - 1, strdup(argument)); + } + + template + void AddArguments(const ::std::vector& arguments) { + for (typename ::std::vector::const_iterator i = arguments.begin(); + i != arguments.end(); + ++i) { + args_.insert(args_.end() - 1, strdup(i->c_str())); + } + } + char* const* Argv() { + return &args_[0]; + } + private: + std::vector args_; +}; + +// A struct that encompasses the arguments to the child process of a +// threadsafe-style death test process. +struct ExecDeathTestArgs { + char* const* argv; // Command-line arguments for the child's call to exec + int close_fd; // File descriptor to close; the read end of a pipe +}; + +// The main function for a threadsafe-style death test child process. +static int ExecDeathTestChildMain(void* child_arg) { + ExecDeathTestArgs* const args = static_cast(child_arg); + GTEST_DEATH_TEST_CHECK_SYSCALL(close(args->close_fd)); + execve(args->argv[0], args->argv, environ); + DeathTestAbort("execve failed: %s", strerror(errno)); + return EXIT_FAILURE; +} + +// Two utility routines that together determine the direction the stack +// grows. +// This could be accomplished more elegantly by a single recursive +// function, but we want to guard against the unlikely possibility of +// a smart compiler optimizing the recursion away. +static bool StackLowerThanAddress(const void* ptr) { + int dummy; + return &dummy < ptr; +} + +static bool StackGrowsDown() { + int dummy; + return StackLowerThanAddress(&dummy); +} + +// A threadsafe implementation of fork(2) for threadsafe-style death tests +// that uses clone(2). It dies with an error message if anything goes +// wrong. +static pid_t ExecDeathTestFork(char* const* argv, int close_fd) { + static const bool stack_grows_down = StackGrowsDown(); + const size_t stack_size = getpagesize(); + void* const stack = mmap(NULL, stack_size, PROT_READ | PROT_WRITE, + MAP_ANONYMOUS | MAP_PRIVATE, -1, 0); + GTEST_DEATH_TEST_CHECK(stack != MAP_FAILED); + void* const stack_top = + static_cast(stack) + (stack_grows_down ? stack_size : 0); + ExecDeathTestArgs args = { argv, close_fd }; + const pid_t child_pid = clone(&ExecDeathTestChildMain, stack_top, + SIGCHLD, &args); + GTEST_DEATH_TEST_CHECK(child_pid != -1); + GTEST_DEATH_TEST_CHECK(munmap(stack, stack_size) != -1); + return child_pid; +} + +// The AssumeRole process for a fork-and-exec death test. It re-executes the +// main program from the beginning, setting the --gtest_filter +// and --gtest_internal_run_death_test flags to cause only the current +// death test to be re-run. +DeathTest::TestRole ExecDeathTest::AssumeRole() { + const UnitTestImpl* const impl = GetUnitTestImpl(); + const InternalRunDeathTestFlag* const flag = + impl->internal_run_death_test_flag(); + const TestInfo* const info = impl->current_test_info(); + const int death_test_index = info->result()->death_test_count(); + + if (flag != NULL) { + set_write_fd(flag->status_fd); + return EXECUTE_TEST; + } + + int pipe_fd[2]; + GTEST_DEATH_TEST_CHECK(pipe(pipe_fd) != -1); + // Clear the close-on-exec flag on the write end of the pipe, lest + // it be closed when the child process does an exec: + GTEST_DEATH_TEST_CHECK(fcntl(pipe_fd[1], F_SETFD, 0) != -1); + + const String filter_flag = + String::Format("--%s%s=%s.%s", + GTEST_FLAG_PREFIX, kFilterFlag, + info->test_case_name(), info->name()); + const String internal_flag = + String::Format("--%s%s=%s:%d:%d:%d", + GTEST_FLAG_PREFIX, kInternalRunDeathTestFlag, file_, line_, + death_test_index, pipe_fd[1]); + Arguments args; + args.AddArguments(GetArgvs()); + args.AddArgument("--logtostderr"); + args.AddArgument(filter_flag.c_str()); + args.AddArgument(internal_flag.c_str()); + + last_death_test_message = ""; + + CaptureStderr(); + // See the comment in NoExecDeathTest::AssumeRole for why the next line + // is necessary. + FlushInfoLog(); + + const pid_t child_pid = ExecDeathTestFork(args.Argv(), pipe_fd[0]); + GTEST_DEATH_TEST_CHECK_SYSCALL(close(pipe_fd[1])); + set_child_pid(child_pid); + set_read_fd(pipe_fd[0]); + set_forked(true); + return OVERSEE_TEST; +} + +// Creates a concrete DeathTest-derived class that depends on the +// --gtest_death_test_style flag, and sets the pointer pointed to +// by the "test" argument to its address. If the test should be +// skipped, sets that pointer to NULL. Returns true, unless the +// flag is set to an invalid value. +bool DefaultDeathTestFactory::Create(const char* statement, const RE* regex, + const char* file, int line, + DeathTest** test) { + UnitTestImpl* const impl = GetUnitTestImpl(); + const InternalRunDeathTestFlag* const flag = + impl->internal_run_death_test_flag(); + const int death_test_index = impl->current_test_info() + ->increment_death_test_count(); + + if (flag != NULL) { + if (death_test_index > flag->index) { + last_death_test_message = String::Format( + "Death test count (%d) somehow exceeded expected maximum (%d)", + death_test_index, flag->index); + return false; + } + + if (!(flag->file == file && flag->line == line && + flag->index == death_test_index)) { + *test = NULL; + return true; + } + } + + if (GTEST_FLAG(death_test_style) == "threadsafe") { + *test = new ExecDeathTest(statement, regex, file, line); + } else if (GTEST_FLAG(death_test_style) == "fast") { + *test = new NoExecDeathTest(statement, regex); + } else { + last_death_test_message = String::Format( + "Unknown death test style \"%s\" encountered", + GTEST_FLAG(death_test_style).c_str()); + return false; + } + + return true; +} + +// Splits a given string on a given delimiter, populating a given +// vector with the fields. GTEST_HAS_DEATH_TEST implies that we have +// ::std::string, so we can use it here. +static void SplitString(const ::std::string& str, char delimiter, + ::std::vector< ::std::string>* dest) { + ::std::vector< ::std::string> parsed; + ::std::string::size_type pos = 0; + while (true) { + const ::std::string::size_type colon = str.find(':', pos); + if (colon == ::std::string::npos) { + parsed.push_back(str.substr(pos)); + break; + } else { + parsed.push_back(str.substr(pos, colon - pos)); + pos = colon + 1; + } + } + dest->swap(parsed); +} + +// Attempts to parse a string into a positive integer. Returns true +// if that is possible. GTEST_HAS_DEATH_TEST implies that we have +// ::std::string, so we can use it here. +static bool ParsePositiveInt(const ::std::string& str, int* number) { + // Fail fast if the given string does not begin with a digit; + // this bypasses strtol's "optional leading whitespace and plus + // or minus sign" semantics, which are undesirable here. + if (str.empty() || !isdigit(str[0])) { + return false; + } + char* endptr; + const long parsed = strtol(str.c_str(), &endptr, 10); // NOLINT + if (*endptr == '\0' && parsed <= INT_MAX) { + *number = static_cast(parsed); + return true; + } else { + return false; + } +} + +// Returns a newly created InternalRunDeathTestFlag object with fields +// initialized from the GTEST_FLAG(internal_run_death_test) flag if +// the flag is specified; otherwise returns NULL. +InternalRunDeathTestFlag* ParseInternalRunDeathTestFlag() { + if (GTEST_FLAG(internal_run_death_test) == "") return NULL; + + InternalRunDeathTestFlag* const internal_run_death_test_flag = + new InternalRunDeathTestFlag; + // GTEST_HAS_DEATH_TEST implies that we have ::std::string, so we + // can use it here. + ::std::vector< ::std::string> fields; + SplitString(GTEST_FLAG(internal_run_death_test).c_str(), ':', &fields); + if (fields.size() != 4 + || !ParsePositiveInt(fields[1], &internal_run_death_test_flag->line) + || !ParsePositiveInt(fields[2], &internal_run_death_test_flag->index) + || !ParsePositiveInt(fields[3], + &internal_run_death_test_flag->status_fd)) { + DeathTestAbort("Bad --gtest_internal_run_death_test flag: %s", + GTEST_FLAG(internal_run_death_test).c_str()); + } + internal_run_death_test_flag->file = fields[0].c_str(); + return internal_run_death_test_flag; +} + +} // namespace internal + +#endif // GTEST_HAS_DEATH_TEST + +} // namespace testing diff --git a/src/gtest-filepath.cc b/src/gtest-filepath.cc new file mode 100644 index 00000000..2fba96ea --- /dev/null +++ b/src/gtest-filepath.cc @@ -0,0 +1,208 @@ +// 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: keith.ray@gmail.com (Keith Ray) + +#include +#include + +#ifdef _WIN32 +#include +#include +#endif // _WIN32 + +#include + +#include + +namespace testing { +namespace internal { + +#ifdef GTEST_OS_WINDOWS +const char kPathSeparator = '\\'; +const char kPathSeparatorString[] = "\\"; +const char kCurrentDirectoryString[] = ".\\"; +#else +const char kPathSeparator = '/'; +const char kPathSeparatorString[] = "/"; +const char kCurrentDirectoryString[] = "./"; +#endif // GTEST_OS_WINDOWS + +// Returns a copy of the FilePath with the case-insensitive extension removed. +// Example: FilePath("dir/file.exe").RemoveExtension("EXE") returns +// FilePath("dir/file"). If a case-insensitive extension is not +// found, returns a copy of the original FilePath. +FilePath FilePath::RemoveExtension(const char* extension) const { + String dot_extension(String::Format(".%s", extension)); + if (pathname_.EndsWithCaseInsensitive(dot_extension.c_str())) { + return FilePath(String(pathname_.c_str(), pathname_.GetLength() - 4)); + } + return *this; +} + +// Returns a copy of the FilePath with the directory part removed. +// Example: FilePath("path/to/file").RemoveDirectoryName() returns +// FilePath("file"). If there is no directory part ("just_a_file"), it returns +// the FilePath unmodified. If there is no file part ("just_a_dir/") it +// returns an empty FilePath (""). +// On Windows platform, '\' is the path separator, otherwise it is '/'. +FilePath FilePath::RemoveDirectoryName() const { + const char* const last_sep = strrchr(c_str(), kPathSeparator); + return last_sep ? FilePath(String(last_sep + 1)) : *this; +} + +// RemoveFileName returns the directory path with the filename removed. +// Example: FilePath("path/to/file").RemoveFileName() returns "path/to/". +// If the FilePath is "a_file" or "/a_file", RemoveFileName returns +// FilePath("./") or, on Windows, FilePath(".\\"). If the filepath does +// not have a file, like "just/a/dir/", it returns the FilePath unmodified. +// On Windows platform, '\' is the path separator, otherwise it is '/'. +FilePath FilePath::RemoveFileName() const { + const char* const last_sep = strrchr(c_str(), kPathSeparator); + return FilePath(last_sep ? String(c_str(), last_sep + 1 - c_str()) + : String(kCurrentDirectoryString)); +} + +// Helper functions for naming files in a directory for xml output. + +// Given directory = "dir", base_name = "test", number = 0, +// extension = "xml", returns "dir/test.xml". If number is greater +// than zero (e.g., 12), returns "dir/test_12.xml". +// On Windows platform, uses \ as the separator rather than /. +FilePath FilePath::MakeFileName(const FilePath& directory, + const FilePath& base_name, + int number, + const char* extension) { + FilePath dir(directory.RemoveTrailingPathSeparator()); + if (number == 0) { + return FilePath(String::Format("%s%c%s.%s", dir.c_str(), kPathSeparator, + base_name.c_str(), extension)); + } + return FilePath(String::Format("%s%c%s_%d.%s", dir.c_str(), kPathSeparator, + base_name.c_str(), number, extension)); +} + +// Returns true if pathname describes something findable in the file-system, +// either a file, directory, or whatever. +bool FilePath::FileOrDirectoryExists() const { +#ifdef GTEST_OS_WINDOWS + struct _stat file_stat = {}; + return _stat(pathname_.c_str(), &file_stat) == 0; +#else + struct stat file_stat = {}; + return stat(pathname_.c_str(), &file_stat) == 0; +#endif // GTEST_OS_WINDOWS +} + +// Returns true if pathname describes a directory in the file-system +// that exists. +bool FilePath::DirectoryExists() const { + bool result = false; +#ifdef _WIN32 + FilePath removed_sep(this->RemoveTrailingPathSeparator()); + struct _stat file_stat = {}; + result = _stat(removed_sep.c_str(), &file_stat) == 0 && + (_S_IFDIR & file_stat.st_mode) != 0; +#else + struct stat file_stat = {}; + result = stat(pathname_.c_str(), &file_stat) == 0 && + S_ISDIR(file_stat.st_mode); +#endif // _WIN32 + return result; +} + +// Returns a pathname for a file that does not currently exist. The pathname +// will be directory/base_name.extension or +// directory/base_name_.extension if directory/base_name.extension +// already exists. The number will be incremented until a pathname is found +// that does not already exist. +// Examples: 'dir/foo_test.xml' or 'dir/foo_test_1.xml'. +// There could be a race condition if two or more processes are calling this +// function at the same time -- they could both pick the same filename. +FilePath FilePath::GenerateUniqueFileName(const FilePath& directory, + const FilePath& base_name, + const char* extension) { + FilePath full_pathname; + int number = 0; + do { + full_pathname.Set(MakeFileName(directory, base_name, number++, extension)); + } while (full_pathname.FileOrDirectoryExists()); + return full_pathname; +} + +// Returns true if FilePath ends with a path separator, which indicates that +// it is intended to represent a directory. Returns false otherwise. +// This does NOT check that a directory (or file) actually exists. +bool FilePath::IsDirectory() const { + return pathname_.EndsWith(kPathSeparatorString); +} + +// Create directories so that path exists. Returns true if successful or if +// the directories already exist; returns false if unable to create directories +// for any reason. +bool FilePath::CreateDirectoriesRecursively() const { + if (!this->IsDirectory()) { + return false; + } + + if (pathname_.GetLength() == 0 || this->DirectoryExists()) { + return true; + } + + const FilePath parent(this->RemoveTrailingPathSeparator().RemoveFileName()); + return parent.CreateDirectoriesRecursively() && this->CreateFolder(); +} + +// Create the directory so that path exists. Returns true if successful or +// if the directory already exists; returns false if unable to create the +// directory for any reason, including if the parent directory does not +// exist. Not named "CreateDirectory" because that's a macro on Windows. +bool FilePath::CreateFolder() const { +#ifdef _WIN32 + int result = _mkdir(pathname_.c_str()); +#else + int result = mkdir(pathname_.c_str(), 0777); +#endif // _WIN32 + if (result == -1) { + return this->DirectoryExists(); // An error is OK if the directory exists. + } + return true; // No error. +} + +// If input name has a trailing separator character, remove it and return the +// name, otherwise return the name string unmodified. +// On Windows platform, uses \ as the separator, other platforms use /. +FilePath FilePath::RemoveTrailingPathSeparator() const { + return pathname_.EndsWith(kPathSeparatorString) + ? FilePath(String(pathname_.c_str(), pathname_.GetLength() - 1)) + : *this; +} + +} // namespace internal +} // namespace testing diff --git a/src/gtest-internal-inl.h b/src/gtest-internal-inl.h new file mode 100644 index 00000000..2a7d71cb --- /dev/null +++ b/src/gtest-internal-inl.h @@ -0,0 +1,1118 @@ +// Copyright 2005, 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. + +// Utility functions and classes used by the Google C++ testing framework. +// +// Author: wan@google.com (Zhanyong Wan) +// +// This file contains purely Google Test's internal implementation. Please +// DO NOT #INCLUDE IT IN A USER PROGRAM. + +#ifndef GTEST_SRC_GTEST_INTERNAL_INL_H_ +#define GTEST_SRC_GTEST_INTERNAL_INL_H_ + +// GTEST_IMPLEMENTATION is defined iff the current translation unit is +// part of Google Test's implementation. +#ifndef GTEST_IMPLEMENTATION +// A user is trying to include this from his code - just say no. +#error "gtest-internal-inl.h is part of Google Test's internal implementation." +#error "It must not be included except by Google Test itself." +#endif // GTEST_IMPLEMENTATION + +#include + +#include + +#ifdef GTEST_OS_WINDOWS +#include // NOLINT +#endif // GTEST_OS_WINDOWS + +#include // NOLINT +#include +#include + +namespace testing { + +// Declares the flags. +// +// We don't want the users to modify these flags in the code, but want +// Google Test's own unit tests to be able to access them. Therefore we +// declare them here as opposed to in gtest.h. +GTEST_DECLARE_bool(break_on_failure); +GTEST_DECLARE_bool(catch_exceptions); +GTEST_DECLARE_string(color); +GTEST_DECLARE_string(filter); +GTEST_DECLARE_bool(list_tests); +GTEST_DECLARE_string(output); +GTEST_DECLARE_int32(repeat); +GTEST_DECLARE_int32(stack_trace_depth); +GTEST_DECLARE_bool(show_internal_stack_frames); + +namespace internal { + +// Names of the flags (needed for parsing Google Test flags). +const char kBreakOnFailureFlag[] = "break_on_failure"; +const char kCatchExceptionsFlag[] = "catch_exceptions"; +const char kFilterFlag[] = "filter"; +const char kListTestsFlag[] = "list_tests"; +const char kOutputFlag[] = "output"; +const char kColorFlag[] = "color"; +const char kRepeatFlag[] = "repeat"; + +// This class saves the values of all Google Test flags in its c'tor, and +// restores them in its d'tor. +class GTestFlagSaver { + public: + // The c'tor. + GTestFlagSaver() { + break_on_failure_ = GTEST_FLAG(break_on_failure); + catch_exceptions_ = GTEST_FLAG(catch_exceptions); + color_ = GTEST_FLAG(color); + death_test_style_ = GTEST_FLAG(death_test_style); + filter_ = GTEST_FLAG(filter); + internal_run_death_test_ = GTEST_FLAG(internal_run_death_test); + list_tests_ = GTEST_FLAG(list_tests); + output_ = GTEST_FLAG(output); + repeat_ = GTEST_FLAG(repeat); + } + + // The d'tor is not virtual. DO NOT INHERIT FROM THIS CLASS. + ~GTestFlagSaver() { + GTEST_FLAG(break_on_failure) = break_on_failure_; + GTEST_FLAG(catch_exceptions) = catch_exceptions_; + GTEST_FLAG(color) = color_; + GTEST_FLAG(death_test_style) = death_test_style_; + GTEST_FLAG(filter) = filter_; + GTEST_FLAG(internal_run_death_test) = internal_run_death_test_; + GTEST_FLAG(list_tests) = list_tests_; + GTEST_FLAG(output) = output_; + GTEST_FLAG(repeat) = repeat_; + } + private: + // Fields for saving the original values of flags. + bool break_on_failure_; + bool catch_exceptions_; + String color_; + String death_test_style_; + String filter_; + String internal_run_death_test_; + bool list_tests_; + String output_; + bool pretty_; + internal::Int32 repeat_; +} GTEST_ATTRIBUTE_UNUSED; + +// Converts a Unicode code-point to its UTF-8 encoding. +String ToUtf8String(wchar_t wchar); + +// Returns the number of active threads, or 0 when there is an error. +size_t GetThreadCount(); + +// List is a simple singly-linked list container. +// +// We cannot use std::list as Microsoft's implementation of STL has +// problems when exception is disabled. There is a hack to work +// around this, but we've seen cases where the hack fails to work. +// +// TODO(wan): switch to std::list when we have a reliable fix for the +// STL problem, e.g. when we upgrade to the next version of Visual +// C++, or (more likely) switch to STLport. +// +// The element type must support copy constructor. + +// Forward declare List +template // E is the element type. +class List; + +// ListNode is a node in a singly-linked list. It consists of an +// element and a pointer to the next node. The last node in the list +// has a NULL value for its next pointer. +template // E is the element type. +class ListNode { + friend class List; + + private: + + E element_; + ListNode * next_; + + // The c'tor is private s.t. only in the ListNode class and in its + // friend class List we can create a ListNode object. + // + // Creates a node with a given element value. The next pointer is + // set to NULL. + // + // ListNode does NOT have a default constructor. Always use this + // constructor (with parameter) to create a ListNode object. + explicit ListNode(const E & element) : element_(element), next_(NULL) {} + + // We disallow copying ListNode + GTEST_DISALLOW_COPY_AND_ASSIGN(ListNode); + + public: + + // Gets the element in this node. + E & element() { return element_; } + const E & element() const { return element_; } + + // Gets the next node in the list. + ListNode * next() { return next_; } + const ListNode * next() const { return next_; } +}; + + +// List is a simple singly-linked list container. +template // E is the element type. +class List { + public: + + // Creates an empty list. + List() : head_(NULL), last_(NULL), size_(0) {} + + // D'tor. + virtual ~List(); + + // Clears the list. + void Clear() { + if ( size_ > 0 ) { + // 1. Deletes every node. + ListNode * node = head_; + ListNode * next = node->next(); + for ( ; ; ) { + delete node; + node = next; + if ( node == NULL ) break; + next = node->next(); + } + + // 2. Resets the member variables. + head_ = last_ = NULL; + size_ = 0; + } + } + + // Gets the number of elements. + int size() const { return size_; } + + // Returns true if the list is empty. + bool IsEmpty() const { return size() == 0; } + + // Gets the first element of the list, or NULL if the list is empty. + ListNode * Head() { return head_; } + const ListNode * Head() const { return head_; } + + // Gets the last element of the list, or NULL if the list is empty. + ListNode * Last() { return last_; } + const ListNode * Last() const { return last_; } + + // Adds an element to the end of the list. A copy of the element is + // created using the copy constructor, and then stored in the list. + // Changes made to the element in the list doesn't affect the source + // object, and vice versa. + void PushBack(const E & element) { + ListNode * new_node = new ListNode(element); + + if ( size_ == 0 ) { + head_ = last_ = new_node; + size_ = 1; + } else { + last_->next_ = new_node; + last_ = new_node; + size_++; + } + } + + // Adds an element to the beginning of this list. + void PushFront(const E& element) { + ListNode* const new_node = new ListNode(element); + + if ( size_ == 0 ) { + head_ = last_ = new_node; + size_ = 1; + } else { + new_node->next_ = head_; + head_ = new_node; + size_++; + } + } + + // Removes an element from the beginning of this list. If the + // result argument is not NULL, the removed element is stored in the + // memory it points to. Otherwise the element is thrown away. + // Returns true iff the list wasn't empty before the operation. + bool PopFront(E* result) { + if (size_ == 0) return false; + + if (result != NULL) { + *result = head_->element_; + } + + ListNode* const old_head = head_; + size_--; + if (size_ == 0) { + head_ = last_ = NULL; + } else { + head_ = head_->next_; + } + delete old_head; + + return true; + } + + // Inserts an element after a given node in the list. It's the + // caller's responsibility to ensure that the given node is in the + // list. If the given node is NULL, inserts the element at the + // front of the list. + ListNode* InsertAfter(ListNode* node, const E& element) { + if (node == NULL) { + PushFront(element); + return Head(); + } + + ListNode* const new_node = new ListNode(element); + new_node->next_ = node->next_; + node->next_ = new_node; + size_++; + if (node == last_) { + last_ = new_node; + } + + return new_node; + } + + // Returns the number of elements that satisfy a given predicate. + // The parameter 'predicate' is a Boolean function or functor that + // accepts a 'const E &', where E is the element type. + template // P is the type of the predicate function/functor + int CountIf(P predicate) const { + int count = 0; + for ( const ListNode * node = Head(); + node != NULL; + node = node->next() ) { + if ( predicate(node->element()) ) { + count++; + } + } + + return count; + } + + // Applies a function/functor to each element in the list. The + // parameter 'functor' is a function/functor that accepts a 'const + // E &', where E is the element type. This method does not change + // the elements. + template // F is the type of the function/functor + void ForEach(F functor) const { + for ( const ListNode * node = Head(); + node != NULL; + node = node->next() ) { + functor(node->element()); + } + } + + // Returns the first node whose element satisfies a given predicate, + // or NULL if none is found. The parameter 'predicate' is a + // function/functor that accepts a 'const E &', where E is the + // element type. This method does not change the elements. + template // P is the type of the predicate function/functor. + const ListNode * FindIf(P predicate) const { + for ( const ListNode * node = Head(); + node != NULL; + node = node->next() ) { + if ( predicate(node->element()) ) { + return node; + } + } + + return NULL; + } + + template + ListNode * FindIf(P predicate) { + for ( ListNode * node = Head(); + node != NULL; + node = node->next() ) { + if ( predicate(node->element() ) ) { + return node; + } + } + + return NULL; + } + + private: + ListNode* head_; // The first node of the list. + ListNode* last_; // The last node of the list. + int size_; // The number of elements in the list. + + // We disallow copying List. + GTEST_DISALLOW_COPY_AND_ASSIGN(List); +}; + +// The virtual destructor of List. +template +List::~List() { + Clear(); +} + +// A function for deleting an object. Handy for being used as a +// functor. +template +static void Delete(T * x) { + delete x; +} + +// A copyable object representing a user specified test property which can be +// output as a key/value string pair. +// +// Don't inherit from TestProperty as its destructor is not virtual. +class TestProperty { + public: + // C'tor. TestProperty does NOT have a default constructor. + // Always use this constructor (with parameters) to create a + // TestProperty object. + TestProperty(const char* key, const char* value) : + key_(key), value_(value) { + } + + // Gets the user supplied key. + const char* key() const { + return key_.c_str(); + } + + // Gets the user supplied value. + const char* value() const { + return value_.c_str(); + } + + // Sets a new value, overriding the one supplied in the constructor. + void SetValue(const char* new_value) { + value_ = new_value; + } + + private: + // The key supplied by the user. + String key_; + // The value supplied by the user. + String value_; +}; + +// A predicate that checks the key of a TestProperty against a known key. +// +// TestPropertyKeyIs is copyable. +class TestPropertyKeyIs { + public: + // Constructor. + // + // TestPropertyKeyIs has NO default constructor. + explicit TestPropertyKeyIs(const char* key) + : key_(key) {} + + // Returns true iff the test name of test property matches on key_. + bool operator()(const TestProperty& test_property) const { + return String(test_property.key()).Compare(key_) == 0; + } + + private: + String key_; +}; + +// The result of a single Test. This includes a list of +// TestPartResults, a list of TestProperties, a count of how many +// death tests there are in the Test, and how much time it took to run +// the Test. +// +// TestResult is not copyable. +class TestResult { + public: + // Creates an empty TestResult. + TestResult(); + + // D'tor. Do not inherit from TestResult. + ~TestResult(); + + // Gets the list of TestPartResults. + const internal::List & test_part_results() const { + return test_part_results_; + } + + // Gets the list of TestProperties. + const internal::List & test_properties() const { + return test_properties_; + } + + // Gets the number of successful test parts. + int successful_part_count() const; + + // Gets the number of failed test parts. + int failed_part_count() const; + + // Gets the number of all test parts. This is the sum of the number + // of successful test parts and the number of failed test parts. + int total_part_count() const; + + // Returns true iff the test passed (i.e. no test part failed). + bool Passed() const { return !Failed(); } + + // Returns true iff the test failed. + bool Failed() const { return failed_part_count() > 0; } + + // Returns true iff the test fatally failed. + bool HasFatalFailure() const; + + // Returns the elapsed time, in milliseconds. + TimeInMillis elapsed_time() const { return elapsed_time_; } + + // Sets the elapsed time. + void set_elapsed_time(TimeInMillis elapsed) { elapsed_time_ = elapsed; } + + // Adds a test part result to the list. + void AddTestPartResult(const TestPartResult& test_part_result); + + // Adds a test property to the list. The property is validated and may add + // a non-fatal failure if invalid (e.g., if it conflicts with reserved + // key names). If a property is already recorded for the same key, the + // value will be updated, rather than storing multiple values for the same + // key. + void RecordProperty(const internal::TestProperty& test_property); + + // Adds a failure if the key is a reserved attribute of Google Test + // testcase tags. Returns true if the property is valid. + // TODO(russr): Validate attribute names are legal and human readable. + static bool ValidateTestProperty(const internal::TestProperty& test_property); + + // Returns the death test count. + int death_test_count() const { return death_test_count_; } + + // Increments the death test count, returning the new count. + int increment_death_test_count() { return ++death_test_count_; } + + // Clears the object. + void Clear(); + private: + // Protects mutable state of the property list and of owned properties, whose + // values may be updated. + internal::Mutex test_properites_mutex_; + + // The list of TestPartResults + internal::List test_part_results_; + // The list of TestProperties + internal::List test_properties_; + // Running count of death tests. + int death_test_count_; + // The elapsed time, in milliseconds. + TimeInMillis elapsed_time_; + + // We disallow copying TestResult. + GTEST_DISALLOW_COPY_AND_ASSIGN(TestResult); +}; // class TestResult + +class TestInfoImpl { + public: + TestInfoImpl(TestInfo* parent, const char* test_case_name, + const char* name, TypeId fixture_class_id, + TestMaker maker); + ~TestInfoImpl(); + + // Returns true if this test should run. + bool should_run() const { return should_run_; } + + // Sets the should_run member. + void set_should_run(bool should) { should_run_ = should; } + + // Returns true if this test is disabled. Disabled tests are not run. + bool is_disabled() const { return is_disabled_; } + + // Sets the is_disabled member. + void set_is_disabled(bool is) { is_disabled_ = is; } + + // Returns the test case name. + const char* test_case_name() const { return test_case_name_.c_str(); } + + // Returns the test name. + const char* name() const { return name_.c_str(); } + + // Returns the ID of the test fixture class. + TypeId fixture_class_id() const { return fixture_class_id_; } + + // Returns the test result. + internal::TestResult* result() { return &result_; } + const internal::TestResult* result() const { return &result_; } + + // Creates the test object, runs it, records its result, and then + // deletes it. + void Run(); + + // Calls the given TestInfo object's Run() method. + static void RunTest(TestInfo * test_info) { + test_info->impl()->Run(); + } + + // Clears the test result. + void ClearResult() { result_.Clear(); } + + // Clears the test result in the given TestInfo object. + static void ClearTestResult(TestInfo * test_info) { + test_info->impl()->ClearResult(); + } + + private: + // These fields are immutable properties of the test. + TestInfo* const parent_; // The owner of this object + const String test_case_name_; // Test case name + const String name_; // Test name + const TypeId fixture_class_id_; // ID of the test fixture class + bool should_run_; // True iff this test should run + bool is_disabled_; // True iff this test is disabled + const TestMaker maker_; // The function that creates the test object + + // This field is mutable and needs to be reset before running the + // test for the second time. + internal::TestResult result_; + + GTEST_DISALLOW_COPY_AND_ASSIGN(TestInfoImpl); +}; + +} // namespace internal + +// A test case, which consists of a list of TestInfos. +// +// TestCase is not copyable. +class TestCase { + public: + // Creates a TestCase with the given name. + // + // TestCase does NOT have a default constructor. Always use this + // constructor to create a TestCase object. + // + // Arguments: + // + // name: name of the test case + // set_up_tc: pointer to the function that sets up the test case + // tear_down_tc: pointer to the function that tears down the test case + TestCase(const char* name, + Test::SetUpTestCaseFunc set_up_tc, + Test::TearDownTestCaseFunc tear_down_tc); + + // Destructor of TestCase. + virtual ~TestCase(); + + // Gets the name of the TestCase. + const char* name() const { return name_.c_str(); } + + // Returns true if any test in this test case should run. + bool should_run() const { return should_run_; } + + // Sets the should_run member. + void set_should_run(bool should) { should_run_ = should; } + + // Gets the (mutable) list of TestInfos in this TestCase. + internal::List& test_info_list() { return *test_info_list_; } + + // Gets the (immutable) list of TestInfos in this TestCase. + const internal::List & test_info_list() const { + return *test_info_list_; + } + + // Gets the number of successful tests in this test case. + int successful_test_count() const; + + // Gets the number of failed tests in this test case. + int failed_test_count() const; + + // Gets the number of disabled tests in this test case. + int disabled_test_count() const; + + // Get the number of tests in this test case that should run. + int test_to_run_count() const; + + // Gets the number of all tests in this test case. + int total_test_count() const; + + // Returns true iff the test case passed. + bool Passed() const { return !Failed(); } + + // Returns true iff the test case failed. + bool Failed() const { return failed_test_count() > 0; } + + // Returns the elapsed time, in milliseconds. + internal::TimeInMillis elapsed_time() const { return elapsed_time_; } + + // Adds a TestInfo to this test case. Will delete the TestInfo upon + // destruction of the TestCase object. + void AddTestInfo(TestInfo * test_info); + + // Finds and returns a TestInfo with the given name. If one doesn't + // exist, returns NULL. + TestInfo* GetTestInfo(const char* test_name); + + // Clears the results of all tests in this test case. + void ClearResult(); + + // Clears the results of all tests in the given test case. + static void ClearTestCaseResult(TestCase* test_case) { + test_case->ClearResult(); + } + + // Runs every test in this TestCase. + void Run(); + + // Runs every test in the given TestCase. + static void RunTestCase(TestCase * test_case) { test_case->Run(); } + + // Returns true iff test passed. + static bool TestPassed(const TestInfo * test_info) { + const internal::TestInfoImpl* const impl = test_info->impl(); + return impl->should_run() && impl->result()->Passed(); + } + + // Returns true iff test failed. + static bool TestFailed(const TestInfo * test_info) { + const internal::TestInfoImpl* const impl = test_info->impl(); + return impl->should_run() && impl->result()->Failed(); + } + + // Returns true iff test is disabled. + static bool TestDisabled(const TestInfo * test_info) { + return test_info->impl()->is_disabled(); + } + + // Returns true if the given test should run. + static bool ShouldRunTest(const TestInfo *test_info) { + return test_info->impl()->should_run(); + } + + private: + // Name of the test case. + internal::String name_; + // List of TestInfos. + internal::List* test_info_list_; + // Pointer to the function that sets up the test case. + Test::SetUpTestCaseFunc set_up_tc_; + // Pointer to the function that tears down the test case. + Test::TearDownTestCaseFunc tear_down_tc_; + // True iff any test in this test case should run. + bool should_run_; + // Elapsed time, in milliseconds. + internal::TimeInMillis elapsed_time_; + + // We disallow copying TestCases. + GTEST_DISALLOW_COPY_AND_ASSIGN(TestCase); +}; + +namespace internal { + +// Class UnitTestOptions. +// +// This class contains functions for processing options the user +// specifies when running the tests. It has only static members. +// +// In most cases, the user can specify an option using either an +// environment variable or a command line flag. E.g. you can set the +// test filter using either GTEST_FILTER or --gtest_filter. If both +// the variable and the flag are present, the latter overrides the +// former. +class UnitTestOptions { + public: + // Functions for processing the gtest_output flag. + + // Returns the output format, or "" for normal printed output. + static String GetOutputFormat(); + + // Returns the name of the requested output file, or the default if none + // was explicitly specified. + static String GetOutputFile(); + + // Functions for processing the gtest_filter flag. + + // Returns true iff the wildcard pattern matches the string. The + // first ':' or '\0' character in pattern marks the end of it. + // + // This recursive algorithm isn't very efficient, but is clear and + // works well enough for matching test names, which are short. + static bool PatternMatchesString(const char *pattern, const char *str); + + // Returns true iff the user-specified filter matches the test case + // name and the test name. + static bool FilterMatchesTest(const String &test_case_name, + const String &test_name); + +#ifdef GTEST_OS_WINDOWS + // Function for supporting the gtest_catch_exception flag. + + // Returns EXCEPTION_EXECUTE_HANDLER if Google Test should handle the + // given SEH exception, or EXCEPTION_CONTINUE_SEARCH otherwise. + // This function is useful as an __except condition. + static int GTestShouldProcessSEH(DWORD exception_code); +#endif // GTEST_OS_WINDOWS + private: + // Returns true if "name" matches the ':' separated list of glob-style + // filters in "filter". + static bool MatchesFilter(const String& name, const char* filter); +}; + +// Returns the current application's name, removing directory path if that +// is present. Used by UnitTestOptions::GetOutputFile. +FilePath GetCurrentExecutableName(); + +// The role interface for getting the OS stack trace as a string. +class OsStackTraceGetterInterface { + public: + OsStackTraceGetterInterface() {} + virtual ~OsStackTraceGetterInterface() {} + + // Returns the current OS stack trace as a String. Parameters: + // + // max_depth - the maximum number of stack frames to be included + // in the trace. + // skip_count - the number of top frames to be skipped; doesn't count + // against max_depth. + virtual String CurrentStackTrace(int max_depth, int skip_count) = 0; + + // UponLeavingGTest() should be called immediately before Google Test calls + // user code. It saves some information about the current stack that + // CurrentStackTrace() will use to find and hide Google Test stack frames. + virtual void UponLeavingGTest() = 0; + + private: + GTEST_DISALLOW_COPY_AND_ASSIGN(OsStackTraceGetterInterface); +}; + +// A working implemenation of the OsStackTraceGetterInterface interface. +class OsStackTraceGetter : public OsStackTraceGetterInterface { + public: + OsStackTraceGetter() {} + virtual String CurrentStackTrace(int max_depth, int skip_count); + virtual void UponLeavingGTest(); + + // This string is inserted in place of stack frames that are part of + // Google Test's implementation. + static const char* const kElidedFramesMarker; + + private: + Mutex mutex_; // protects all internal state + + // We save the stack frame below the frame that calls user code. + // We do this because the address of the frame immediately below + // the user code changes between the call to UponLeavingGTest() + // and any calls to CurrentStackTrace() from within the user code. + void* caller_frame_; + + GTEST_DISALLOW_COPY_AND_ASSIGN(OsStackTraceGetter); +}; + +// Information about a Google Test trace point. +struct TraceInfo { + const char* file; + int line; + String message; +}; + +// The private implementation of the UnitTest class. We don't protect +// the methods under a mutex, as this class is not accessible by a +// user and the UnitTest class that delegates work to this class does +// proper locking. +class UnitTestImpl : public TestPartResultReporterInterface { + public: + explicit UnitTestImpl(UnitTest* parent); + virtual ~UnitTestImpl(); + + // Reports a test part result. This method is from the + // TestPartResultReporterInterface interface. + virtual void ReportTestPartResult(const TestPartResult& result); + + // Returns the current test part result reporter. + TestPartResultReporterInterface* test_part_result_reporter(); + + // Sets the current test part result reporter. + void set_test_part_result_reporter(TestPartResultReporterInterface* reporter); + + // Gets the number of successful test cases. + int successful_test_case_count() const; + + // Gets the number of failed test cases. + int failed_test_case_count() const; + + // Gets the number of all test cases. + int total_test_case_count() const; + + // Gets the number of all test cases that contain at least one test + // that should run. + int test_case_to_run_count() const; + + // Gets the number of successful tests. + int successful_test_count() const; + + // Gets the number of failed tests. + int failed_test_count() const; + + // Gets the number of disabled tests. + int disabled_test_count() const; + + // Gets the number of all tests. + int total_test_count() const; + + // Gets the number of tests that should run. + int test_to_run_count() const; + + // Gets the elapsed time, in milliseconds. + TimeInMillis elapsed_time() const { return elapsed_time_; } + + // Returns true iff the unit test passed (i.e. all test cases passed). + bool Passed() const { return !Failed(); } + + // Returns true iff the unit test failed (i.e. some test case failed + // or something outside of all tests failed). + bool Failed() const { + return failed_test_case_count() > 0 || ad_hoc_test_result()->Failed(); + } + + // Returns the TestResult for the test that's currently running, or + // the TestResult for the ad hoc test if no test is running. + internal::TestResult* current_test_result(); + + // Returns the TestResult for the ad hoc test. + const internal::TestResult* ad_hoc_test_result() const { + return &ad_hoc_test_result_; + } + + // Sets the unit test result printer. + // + // Does nothing if the input and the current printer object are the + // same; otherwise, deletes the old printer object and makes the + // input the current printer. + void set_result_printer(UnitTestEventListenerInterface * result_printer); + + // Returns the current unit test result printer if it is not NULL; + // otherwise, creates an appropriate result printer, makes it the + // current printer, and returns it. + UnitTestEventListenerInterface* result_printer(); + + // Sets the OS stack trace getter. + // + // Does nothing if the input and the current OS stack trace getter + // are the same; otherwise, deletes the old getter and makes the + // input the current getter. + void set_os_stack_trace_getter(OsStackTraceGetterInterface* getter); + + // Returns the current OS stack trace getter if it is not NULL; + // otherwise, creates an OsStackTraceGetter, makes it the current + // getter, and returns it. + OsStackTraceGetterInterface* os_stack_trace_getter(); + + // Returns the current OS stack trace as a String. + // + // The maximum number of stack frames to be included is specified by + // the gtest_stack_trace_depth flag. The skip_count parameter + // specifies the number of top frames to be skipped, which doesn't + // count against the number of frames to be included. + // + // For example, if Foo() calls Bar(), which in turn calls + // CurrentOsStackTraceExceptTop(1), Foo() will be included in the + // trace but Bar() and CurrentOsStackTraceExceptTop() won't. + String CurrentOsStackTraceExceptTop(int skip_count); + + // Finds and returns a TestCase with the given name. If one doesn't + // exist, creates one and returns it. + // + // Arguments: + // + // test_case_name: name of the test case + // set_up_tc: pointer to the function that sets up the test case + // tear_down_tc: pointer to the function that tears down the test case + TestCase* GetTestCase(const char* test_case_name, + Test::SetUpTestCaseFunc set_up_tc, + Test::TearDownTestCaseFunc tear_down_tc); + + // Adds a TestInfo to the unit test. + // + // Arguments: + // + // set_up_tc: pointer to the function that sets up the test case + // tear_down_tc: pointer to the function that tears down the test case + // test_info: the TestInfo object + void AddTestInfo(Test::SetUpTestCaseFunc set_up_tc, + Test::TearDownTestCaseFunc tear_down_tc, + TestInfo * test_info) { + GetTestCase(test_info->test_case_name(), + set_up_tc, + tear_down_tc)->AddTestInfo(test_info); + } + + // Sets the TestCase object for the test that's currently running. + void set_current_test_case(TestCase* current_test_case) { + current_test_case_ = current_test_case; + } + + // Sets the TestInfo object for the test that's currently running. If + // current_test_info is NULL, the assertion results will be stored in + // ad_hoc_test_result_. + void set_current_test_info(TestInfo* current_test_info) { + current_test_info_ = current_test_info; + } + + // Runs all tests in this UnitTest object, prints the result, and + // returns 0 if all tests are successful, or 1 otherwise. If any + // exception is thrown during a test on Windows, this test is + // considered to be failed, but the rest of the tests will still be + // run. (We disable exceptions on Linux and Mac OS X, so the issue + // doesn't apply there.) + int RunAllTests(); + + // Clears the results of all tests, including the ad hoc test. + void ClearResult() { + test_cases_.ForEach(TestCase::ClearTestCaseResult); + ad_hoc_test_result_.Clear(); + } + + // Matches the full name of each test against the user-specified + // filter to decide whether the test should run, then records the + // result in each TestCase and TestInfo object. + // Returns the number of tests that should run. + int FilterTests(); + + // Lists all the tests by name. + void ListAllTests(); + + const TestCase* current_test_case() const { return current_test_case_; } + TestInfo* current_test_info() { return current_test_info_; } + const TestInfo* current_test_info() const { return current_test_info_; } + + // Returns the list of environments that need to be set-up/torn-down + // before/after the tests are run. + internal::List* environments() { return &environments_; } + internal::List* environments_in_reverse_order() { + return &environments_in_reverse_order_; + } + + internal::List* test_cases() { return &test_cases_; } + const internal::List* test_cases() const { return &test_cases_; } + + // Getters for the per-thread Google Test trace stack. + internal::List* gtest_trace_stack() { + return gtest_trace_stack_.pointer(); + } + const internal::List* gtest_trace_stack() const { + return gtest_trace_stack_.pointer(); + } + +#ifdef GTEST_HAS_DEATH_TEST + // Returns a pointer to the parsed --gtest_internal_run_death_test + // flag, or NULL if that flag was not specified. + // This information is useful only in a death test child process. + const InternalRunDeathTestFlag* internal_run_death_test_flag() const { + return internal_run_death_test_flag_.get(); + } + + // Returns a pointer to the current death test factory. + internal::DeathTestFactory* death_test_factory() { + return death_test_factory_.get(); + } + + friend class ReplaceDeathTestFactory; +#endif // GTEST_HAS_DEATH_TEST + + private: + // The UnitTest object that owns this implementation object. + UnitTest* const parent_; + + // Points to (but doesn't own) the test part result reporter. + TestPartResultReporterInterface* test_part_result_reporter_; + + // The list of environments that need to be set-up/torn-down + // before/after the tests are run. environments_in_reverse_order_ + // simply mirrors environments_ in reverse order. + internal::List environments_; + internal::List environments_in_reverse_order_; + + internal::List test_cases_; // The list of TestCases. + + // Points to the last death test case registered. Initially NULL. + internal::ListNode* last_death_test_case_; + + // This points to the TestCase for the currently running test. It + // changes as Google Test goes through one test case after another. + // When no test is running, this is set to NULL and Google Test + // stores assertion results in ad_hoc_test_result_. Initally NULL. + TestCase* current_test_case_; + + // This points to the TestInfo for the currently running test. It + // changes as Google Test goes through one test after another. When + // no test is running, this is set to NULL and Google Test stores + // assertion results in ad_hoc_test_result_. Initially NULL. + TestInfo* current_test_info_; + + // Normally, a user only writes assertions inside a TEST or TEST_F, + // or inside a function called by a TEST or TEST_F. Since Google + // Test keeps track of which test is current running, it can + // associate such an assertion with the test it belongs to. + // + // If an assertion is encountered when no TEST or TEST_F is running, + // Google Test attributes the assertion result to an imaginary "ad hoc" + // test, and records the result in ad_hoc_test_result_. + internal::TestResult ad_hoc_test_result_; + + // The unit test result printer. Will be deleted when the UnitTest + // object is destructed. By default, a plain text printer is used, + // but the user can set this field to use a custom printer if that + // is desired. + UnitTestEventListenerInterface* result_printer_; + + // The OS stack trace getter. Will be deleted when the UnitTest + // object is destructed. By default, an OsStackTraceGetter is used, + // but the user can set this field to use a custom getter if that is + // desired. + OsStackTraceGetterInterface* os_stack_trace_getter_; + + // How long the test took to run, in milliseconds. + TimeInMillis elapsed_time_; + +#ifdef GTEST_HAS_DEATH_TEST + // The decomposed components of the gtest_internal_run_death_test flag, + // parsed when RUN_ALL_TESTS is called. + internal::scoped_ptr internal_run_death_test_flag_; + internal::scoped_ptr death_test_factory_; +#endif // GTEST_HAS_DEATH_TEST + + // A per-thread stack of traces created by the SCOPED_TRACE() macro. + internal::ThreadLocal > gtest_trace_stack_; + + GTEST_DISALLOW_COPY_AND_ASSIGN(UnitTestImpl); +}; // class UnitTestImpl + +// Convenience function for accessing the global UnitTest +// implementation object. +inline UnitTestImpl* GetUnitTestImpl() { + return UnitTest::GetInstance()->impl(); +} + +} // namespace internal +} // namespace testing + +#endif // GTEST_SRC_GTEST_INTERNAL_INL_H_ diff --git a/src/gtest-port.cc b/src/gtest-port.cc new file mode 100644 index 00000000..2a4d37a4 --- /dev/null +++ b/src/gtest-port.cc @@ -0,0 +1,292 @@ +// 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. +// +// Author: wan@google.com (Zhanyong Wan) + +#include + +#include +#ifdef GTEST_HAS_DEATH_TEST +#include +#endif // GTEST_HAS_DEATH_TEST +#include +#include + +#include +#include +#include + +namespace testing { +namespace internal { + +#ifdef GTEST_HAS_DEATH_TEST + +// Implements RE. Currently only needed for death tests. + +RE::~RE() { + regfree(®ex_); + free(const_cast(pattern_)); +} + +// Returns true iff str contains regular expression re. +bool RE::PartialMatch(const char* str, const RE& re) { + if (!re.is_valid_) return false; + + regmatch_t match; + return regexec(&re.regex_, str, 1, &match, 0) == 0; +} + +// Initializes an RE from its string representation. +void RE::Init(const char* regex) { + pattern_ = strdup(regex); + is_valid_ = regcomp(®ex_, regex, REG_EXTENDED) == 0; + EXPECT_TRUE(is_valid_) + << "Regular expression \"" << regex + << "\" is not a valid POSIX Extended regular expression."; +} + +#endif // GTEST_HAS_DEATH_TEST + +// Logs a message at the given severity level. +void GTestLog(GTestLogSeverity severity, const char* file, + int line, const char* msg) { + const char* const marker = + severity == GTEST_INFO ? "[ INFO ]" : + severity == GTEST_WARNING ? "[WARNING]" : + severity == GTEST_ERROR ? "[ ERROR ]" : "[ FATAL ]"; + fprintf(stderr, "\n%s %s:%d: %s\n", marker, file, line, msg); + if (severity == GTEST_FATAL) { + abort(); + } +} + +#ifdef GTEST_HAS_DEATH_TEST + +// Defines the stderr capturer. + +class CapturedStderr { + public: + // The ctor redirects stderr to a temporary file. + CapturedStderr() { + uncaptured_fd_ = dup(STDERR_FILENO); + + char name_template[] = "captured_stderr.XXXXXX"; + const int captured_fd = mkstemp(name_template); + filename_ = name_template; + fflush(NULL); + dup2(captured_fd, STDERR_FILENO); + close(captured_fd); + } + + ~CapturedStderr() { + remove(filename_.c_str()); + } + + // Stops redirecting stderr. + void StopCapture() { + // Restores the original stream. + fflush(NULL); + dup2(uncaptured_fd_, STDERR_FILENO); + close(uncaptured_fd_); + uncaptured_fd_ = -1; + } + + // Returns the name of the temporary file holding the stderr output. + // GTEST_HAS_DEATH_TEST implies that we have ::std::string, so we + // can use it here. + ::std::string filename() const { return filename_; } + + private: + int uncaptured_fd_; + ::std::string filename_; +}; + +static CapturedStderr* g_captured_stderr = NULL; + +// Returns the size (in bytes) of a file. +static size_t GetFileSize(FILE * file) { + fseek(file, 0, SEEK_END); + return static_cast(ftell(file)); +} + +// Reads the entire content of a file as a string. +// GTEST_HAS_DEATH_TEST implies that we have ::std::string, so we can +// use it here. +static ::std::string ReadEntireFile(FILE * file) { + const size_t file_size = GetFileSize(file); + char* const buffer = new char[file_size]; + + size_t bytes_last_read = 0; // # of bytes read in the last fread() + size_t bytes_read = 0; // # of bytes read so far + + fseek(file, 0, SEEK_SET); + + // Keeps reading the file until we cannot read further or the + // pre-determined file size is reached. + do { + bytes_last_read = fread(buffer+bytes_read, 1, file_size-bytes_read, file); + bytes_read += bytes_last_read; + } while (bytes_last_read > 0 && bytes_read < file_size); + + const ::std::string content(buffer, buffer+bytes_read); + delete[] buffer; + + return content; +} + +// Starts capturing stderr. +void CaptureStderr() { + if (g_captured_stderr != NULL) { + GTEST_LOG(FATAL, "Only one stderr capturer can exist at one time."); + } + g_captured_stderr = new CapturedStderr; +} + +// Stops capturing stderr and returns the captured string. +// GTEST_HAS_DEATH_TEST implies that we have ::std::string, so we can +// use it here. +::std::string GetCapturedStderr() { + g_captured_stderr->StopCapture(); + FILE* const file = fopen(g_captured_stderr->filename().c_str(), "r"); + const ::std::string content = ReadEntireFile(file); + fclose(file); + + delete g_captured_stderr; + g_captured_stderr = NULL; + + return content; +} + +// A copy of all command line arguments. Set by InitGoogleTest(). +::std::vector g_argvs; + +// Returns the command line as a vector of strings. +const ::std::vector& GetArgvs() { return g_argvs; } + +#endif // GTEST_HAS_DEATH_TEST + +// Returns the name of the environment variable corresponding to the +// given flag. For example, FlagToEnvVar("foo") will return +// "GTEST_FOO" in the open-source version. +static String FlagToEnvVar(const char* flag) { + const String full_flag = (Message() << GTEST_FLAG_PREFIX << flag).GetString(); + + Message env_var; + for (int i = 0; i != full_flag.GetLength(); i++) { + env_var << static_cast(toupper(full_flag.c_str()[i])); + } + + return env_var.GetString(); +} + +// Reads and returns the Boolean environment variable corresponding to +// the given flag; if it's not set, returns default_value. +// +// The value is considered true iff it's not "0". +bool BoolFromGTestEnv(const char* flag, bool default_value) { + const String env_var = FlagToEnvVar(flag); + const char* const string_value = GetEnv(env_var.c_str()); + return string_value == NULL ? + default_value : strcmp(string_value, "0") != 0; +} + +// Parses 'str' for a 32-bit signed integer. If successful, writes +// the result to *value and returns true; otherwise leaves *value +// unchanged and returns false. +bool ParseInt32(const Message& src_text, const char* str, Int32* value) { + // Parses the environment variable as a decimal integer. + char* end = NULL; + const long long_value = strtol(str, &end, 10); // NOLINT + + // Has strtol() consumed all characters in the string? + if (*end != '\0') { + // No - an invalid character was encountered. + Message msg; + msg << "WARNING: " << src_text + << " is expected to be a 32-bit integer, but actually" + << " has value \"" << str << "\".\n"; + printf("%s", msg.GetString().c_str()); + fflush(stdout); + return false; + } + + // Is the parsed value in the range of an Int32? + const Int32 result = static_cast(long_value); + if (long_value == LONG_MAX || long_value == LONG_MIN || + // The parsed value overflows as a long. (strtol() returns + // LONG_MAX or LONG_MIN when the input overflows.) + result != long_value + // The parsed value overflows as an Int32. + ) { + Message msg; + msg << "WARNING: " << src_text + << " is expected to be a 32-bit integer, but actually" + << " has value " << str << ", which overflows.\n"; + printf("%s", msg.GetString().c_str()); + fflush(stdout); + return false; + } + + *value = result; + return true; +} + +// Reads and returns a 32-bit integer stored in the environment +// variable corresponding to the given flag; if it isn't set or +// doesn't represent a valid 32-bit integer, returns default_value. +Int32 Int32FromGTestEnv(const char* flag, Int32 default_value) { + const String env_var = FlagToEnvVar(flag); + const char* const string_value = GetEnv(env_var.c_str()); + if (string_value == NULL) { + // The environment variable is not set. + return default_value; + } + + Int32 result = default_value; + if (!ParseInt32(Message() << "Environment variable " << env_var, + string_value, &result)) { + printf("The default value %s is used.\n", + (Message() << default_value).GetString().c_str()); + fflush(stdout); + return default_value; + } + + return result; +} + +// Reads and returns the string environment variable corresponding to +// the given flag; if it's not set, returns default_value. +const char* StringFromGTestEnv(const char* flag, const char* default_value) { + const String env_var = FlagToEnvVar(flag); + const char* const value = GetEnv(env_var.c_str()); + return value == NULL ? default_value : value; +} + +} // namespace internal +} // namespace testing diff --git a/src/gtest.cc b/src/gtest.cc new file mode 100644 index 00000000..235ec5ad --- /dev/null +++ b/src/gtest.cc @@ -0,0 +1,3545 @@ +// Copyright 2005, 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. +// +// Author: wan@google.com (Zhanyong Wan) +// +// The Google C++ Testing Framework (Google Test) + +#include +#include + +#include +#include +#include +#include +#include +#include + +#ifdef GTEST_OS_LINUX + +// TODO(kenton@google.com): Use autoconf to detect availability of +// gettimeofday(). +#define GTEST_HAS_GETTIMEOFDAY + +#include +#include +#include +// Declares vsnprintf(). This header is not available on Windows. +#include +#include +#include +#include +#include +#include + +#elif defined(_WIN32_WCE) // We are on Windows CE. + +#include // NOLINT + +#elif defined(_WIN32) // We are on Windows proper. + +#include // NOLINT +#include // NOLINT +#include // NOLINT +#include // NOLINT + +#if defined(__MINGW__) || defined(__MINGW32__) +// MinGW has gettimeofday() but not _ftime64(). +// TODO(kenton@google.com): Use autoconf to detect availability of +// gettimeofday(). +// TODO(kenton@google.com): There are other ways to get the time on +// Windows, like GetTickCount() or GetSystemTimeAsFileTime(). MinGW +// supports these. consider using them instead. +#define GTEST_HAS_GETTIMEOFDAY +#include // NOLINT +#endif + +// cpplint thinks that the header is already included, so we want to +// silence it. +#include // NOLINT + +#else + +// Assume other platforms have gettimeofday(). +// TODO(kenton@google.com): Use autoconf to detect availability of +// gettimeofday(). +#define GTEST_HAS_GETTIMEOFDAY + +// cpplint thinks that the header is already included, so we want to +// silence it. +#include // NOLINT +#include // NOLINT + +#endif + +// 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 +#include "src/gtest-internal-inl.h" +#undef GTEST_IMPLEMENTATION + +#ifdef GTEST_OS_WINDOWS +#define fileno _fileno +#define isatty _isatty +#define vsnprintf _vsnprintf +#endif // GTEST_OS_WINDOWS + +namespace testing { + +// Constants. + +// A test that matches this pattern is disabled and not run. +static const char kDisableTestPattern[] = "DISABLED_*"; + +// A test filter that matches everything. +static const char kUniversalFilter[] = "*"; + +// The default output file for XML output. +static const char kDefaultOutputFile[] = "test_detail.xml"; + +GTEST_DEFINE_bool( + break_on_failure, + internal::BoolFromGTestEnv("break_on_failure", false), + "True iff a failed assertion should be a debugger break-point."); + +GTEST_DEFINE_bool( + catch_exceptions, + internal::BoolFromGTestEnv("catch_exceptions", false), + "True iff " GTEST_NAME + " should catch exceptions and treat them as test failures."); + +GTEST_DEFINE_string( + color, + internal::StringFromGTestEnv("color", "auto"), + "Whether to use colors in the output. Valid values: yes, no, " + "and auto. 'auto' means to use colors if the output is " + "being sent to a terminal and the TERM environment variable " + "is set to xterm or xterm-color."); + +GTEST_DEFINE_string( + filter, + internal::StringFromGTestEnv("filter", kUniversalFilter), + "A colon-separated list of glob (not regex) patterns " + "for filtering the tests to run, optionally followed by a " + "'-' and a : separated list of negative patterns (tests to " + "exclude). A test is run if it matches one of the positive " + "patterns and does not match any of the negative patterns."); + +GTEST_DEFINE_bool(list_tests, false, + "List all tests without running them."); + +GTEST_DEFINE_string( + output, + internal::StringFromGTestEnv("output", ""), + "A format (currently must be \"xml\"), optionally followed " + "by a colon and an output file name or directory. A directory " + "is indicated by a trailing pathname separator. " + "Examples: \"xml:filename.xml\", \"xml::directoryname/\". " + "If a directory is specified, output files will be created " + "within that directory, with file-names based on the test " + "executable's name and, if necessary, made unique by adding " + "digits."); + +GTEST_DEFINE_int32( + repeat, + internal::Int32FromGTestEnv("repeat", 1), + "How many times to repeat each test. Specify a negative number " + "for repeating forever. Useful for shaking out flaky tests."); + +GTEST_DEFINE_int32( + stack_trace_depth, + internal::Int32FromGTestEnv("stack_trace_depth", kMaxStackTraceDepth), + "The maximum number of stack frames to print when an " + "assertion fails. The valid range is 0 through 100, inclusive."); + +GTEST_DEFINE_bool( + show_internal_stack_frames, false, + "True iff " GTEST_NAME " should include internal stack frames when " + "printing test failure stack traces."); + +namespace internal { + +// GTestIsInitialized() returns true iff the user has initialized +// Google Test. Useful for catching the user mistake of not initializing +// Google Test before calling RUN_ALL_TESTS(). + +// A user must call testing::InitGoogleTest() to initialize Google +// Test. g_parse_gtest_flags_called is set to true iff +// InitGoogleTest() has been called. We don't protect this variable +// under a mutex as it is only accessed in the main thread. +static bool g_parse_gtest_flags_called = false; +static bool GTestIsInitialized() { return g_parse_gtest_flags_called; } + +// Iterates over a list of TestCases, keeping a running sum of the +// results of calling a given int-returning method on each. +// Returns the sum. +static int SumOverTestCaseList(const internal::List& case_list, + int (TestCase::*method)() const) { + int sum = 0; + for (const internal::ListNode* node = case_list.Head(); + node != NULL; + node = node->next()) { + sum += (node->element()->*method)(); + } + return sum; +} + +// Returns true iff the test case passed. +static bool TestCasePassed(const TestCase* test_case) { + return test_case->should_run() && test_case->Passed(); +} + +// Returns true iff the test case failed. +static bool TestCaseFailed(const TestCase* test_case) { + return test_case->should_run() && test_case->Failed(); +} + +// Returns true iff test_case contains at least one test that should +// run. +static bool ShouldRunTestCase(const TestCase* test_case) { + return test_case->should_run(); +} + +#ifdef _WIN32_WCE +// Windows CE has no C library. The abort() function is used in +// several places in Google Test. This implementation provides a reasonable +// imitation of standard behaviour. +static void abort() { + DebugBreak(); + TerminateProcess(GetCurrentProcess(), 1); +} +#endif // _WIN32_WCE + +// AssertHelper constructor. +AssertHelper::AssertHelper(TestPartResultType type, const char* file, + int line, const char* message) + : type_(type), file_(file), line_(line), message_(message) { +} + +// Message assignment, for assertion streaming support. +void AssertHelper::operator=(const Message& message) const { + UnitTest::GetInstance()-> + AddTestPartResult(type_, file_, line_, + AppendUserMessage(message_, message), + UnitTest::GetInstance()->impl() + ->CurrentOsStackTraceExceptTop(1) + // Skips the stack frame for this function itself. + ); // NOLINT +} + +// Application pathname gotten in InitGoogleTest. +String g_executable_path; + +// Returns the current application's name, removing directory path if that +// is present. +FilePath GetCurrentExecutableName() { + FilePath result; + +#if defined(_WIN32_WCE) || defined(_WIN32) + result.Set(FilePath(g_executable_path).RemoveExtension("exe")); +#else + result.Set(FilePath(g_executable_path)); +#endif // _WIN32_WCE || _WIN32 + + return result.RemoveDirectoryName(); +} + +// Functions for processing the gtest_output flag. + +// Returns the output format, or "" for normal printed output. +String UnitTestOptions::GetOutputFormat() { + const char* const gtest_output_flag = GTEST_FLAG(output).c_str(); + if (gtest_output_flag == NULL) return String(""); + + const char* const colon = strchr(gtest_output_flag, ':'); + return (colon == NULL) ? + String(gtest_output_flag) : + String(gtest_output_flag, colon - gtest_output_flag); +} + +// Returns the name of the requested output file, or the default if none +// was explicitly specified. +String UnitTestOptions::GetOutputFile() { + const char* const gtest_output_flag = GTEST_FLAG(output).c_str(); + if (gtest_output_flag == NULL) + return String(""); + + const char* const colon = strchr(gtest_output_flag, ':'); + if (colon == NULL) + return String(kDefaultOutputFile); + + internal::FilePath output_name(colon + 1); + if (!output_name.IsDirectory()) + return output_name.ToString(); + + internal::FilePath result(internal::FilePath::GenerateUniqueFileName( + output_name, internal::GetCurrentExecutableName(), + GetOutputFormat().c_str())); + return result.ToString(); +} + +// Returns true iff the wildcard pattern matches the string. The +// first ':' or '\0' character in pattern marks the end of it. +// +// This recursive algorithm isn't very efficient, but is clear and +// works well enough for matching test names, which are short. +bool UnitTestOptions::PatternMatchesString(const char *pattern, + const char *str) { + switch (*pattern) { + case '\0': + case ':': // Either ':' or '\0' marks the end of the pattern. + return *str == '\0'; + case '?': // Matches any single character. + return *str != '\0' && PatternMatchesString(pattern + 1, str + 1); + case '*': // Matches any string (possibly empty) of characters. + return (*str != '\0' && PatternMatchesString(pattern, str + 1)) || + PatternMatchesString(pattern + 1, str); + default: // Non-special character. Matches itself. + return *pattern == *str && + PatternMatchesString(pattern + 1, str + 1); + } +} + +bool UnitTestOptions::MatchesFilter(const String& name, const char* filter) { + const char *cur_pattern = filter; + while (true) { + if (PatternMatchesString(cur_pattern, name.c_str())) { + return true; + } + + // Finds the next pattern in the filter. + cur_pattern = strchr(cur_pattern, ':'); + + // Returns if no more pattern can be found. + if (cur_pattern == NULL) { + return false; + } + + // Skips the pattern separater (the ':' character). + cur_pattern++; + } +} + +// TODO(keithray): move String function implementations to gtest-string.cc. + +// Returns true iff the user-specified filter matches the test case +// name and the test name. +bool UnitTestOptions::FilterMatchesTest(const String &test_case_name, + const String &test_name) { + const String& full_name = String::Format("%s.%s", + test_case_name.c_str(), + test_name.c_str()); + + // Split --gtest_filter at '-', if there is one, to separate into + // positive filter and negative filter portions + const char* const p = GTEST_FLAG(filter).c_str(); + const char* const dash = strchr(p, '-'); + String positive; + String negative; + if (dash == NULL) { + positive = GTEST_FLAG(filter).c_str(); // Whole string is a positive filter + negative = String(""); + } else { + positive.Set(p, dash - p); // Everything up to the dash + negative = String(dash+1); // Everything after the dash + if (positive.empty()) { + // Treat '-test1' as the same as '*-test1' + positive = kUniversalFilter; + } + } + + // A filter is a colon-separated list of patterns. It matches a + // test if any pattern in it matches the test. + return (MatchesFilter(full_name, positive.c_str()) && + !MatchesFilter(full_name, negative.c_str())); +} + +#ifdef GTEST_OS_WINDOWS +// Returns EXCEPTION_EXECUTE_HANDLER if Google Test should handle the +// given SEH exception, or EXCEPTION_CONTINUE_SEARCH otherwise. +// This function is useful as an __except condition. +int UnitTestOptions::GTestShouldProcessSEH(DWORD exception_code) { + // Google Test should handle an exception if: + // 1. the user wants it to, AND + // 2. this is not a breakpoint exception. + return (GTEST_FLAG(catch_exceptions) && + exception_code != EXCEPTION_BREAKPOINT) ? + EXCEPTION_EXECUTE_HANDLER : + EXCEPTION_CONTINUE_SEARCH; +} +#endif // GTEST_OS_WINDOWS + +} // namespace internal + +// The interface for printing the result of a UnitTest +class UnitTestEventListenerInterface { + public: + // The d'tor is pure virtual as this is an abstract class. + virtual ~UnitTestEventListenerInterface() = 0; + + // Called before the unit test starts. + virtual void OnUnitTestStart(const UnitTest*) {} + + // Called after the unit test ends. + virtual void OnUnitTestEnd(const UnitTest*) {} + + // Called before the test case starts. + virtual void OnTestCaseStart(const TestCase*) {} + + // Called after the test case ends. + virtual void OnTestCaseEnd(const TestCase*) {} + + // Called before the global set-up starts. + virtual void OnGlobalSetUpStart(const UnitTest*) {} + + // Called after the global set-up ends. + virtual void OnGlobalSetUpEnd(const UnitTest*) {} + + // Called before the global tear-down starts. + virtual void OnGlobalTearDownStart(const UnitTest*) {} + + // Called after the global tear-down ends. + virtual void OnGlobalTearDownEnd(const UnitTest*) {} + + // Called before the test starts. + virtual void OnTestStart(const TestInfo*) {} + + // Called after the test ends. + virtual void OnTestEnd(const TestInfo*) {} + + // Called after an assertion. + virtual void OnNewTestPartResult(const TestPartResult*) {} +}; + +// Constructs an empty TestPartResultArray. +TestPartResultArray::TestPartResultArray() + : list_(new internal::List) { +} + +// Destructs a TestPartResultArray. +TestPartResultArray::~TestPartResultArray() { + delete list_; +} + +// Appends a TestPartResult to the array. +void TestPartResultArray::Append(const TestPartResult& result) { + list_->PushBack(result); +} + +// Returns the TestPartResult at the given index (0-based). +const TestPartResult& TestPartResultArray::GetTestPartResult(int index) const { + if (index < 0 || index >= size()) { + printf("\nInvalid index (%d) into TestPartResultArray.\n", index); + abort(); + } + + const internal::ListNode* p = list_->Head(); + for (int i = 0; i < index; i++) { + p = p->next(); + } + + return p->element(); +} + +// Returns the number of TestPartResult objects in the array. +int TestPartResultArray::size() const { + return list_->size(); +} + +// The c'tor sets this object as the test part result reporter used by +// Google Test. The 'result' parameter specifies where to report the +// results. +ScopedFakeTestPartResultReporter::ScopedFakeTestPartResultReporter( + TestPartResultArray* result) + : old_reporter_(UnitTest::GetInstance()->impl()-> + test_part_result_reporter()), + result_(result) { + internal::UnitTestImpl* const impl = UnitTest::GetInstance()->impl(); + impl->set_test_part_result_reporter(this); +} + +// The d'tor restores the test part result reporter used by Google Test +// before. +ScopedFakeTestPartResultReporter::~ScopedFakeTestPartResultReporter() { + UnitTest::GetInstance()->impl()-> + set_test_part_result_reporter(old_reporter_); +} + +// Increments the test part result count and remembers the result. +// This method is from the TestPartResultReporterInterface interface. +void ScopedFakeTestPartResultReporter::ReportTestPartResult( + const TestPartResult& result) { + result_->Append(result); +} + +namespace internal { + +// This predicate-formatter checks that 'results' contains a test part +// failure of the given type and that the failure message contains the +// given substring. +AssertionResult HasOneFailure(const char* /* results_expr */, + const char* /* type_expr */, + const char* /* substr_expr */, + const TestPartResultArray& results, + TestPartResultType type, + const char* substr) { + const String expected( + type == TPRT_FATAL_FAILURE ? "1 fatal failure" : + "1 non-fatal failure"); + Message msg; + if (results.size() != 1) { + msg << "Expected: " << expected << "\n" + << " Actual: " << results.size() << " failures"; + for (int i = 0; i < results.size(); i++) { + msg << "\n" << results.GetTestPartResult(i); + } + return AssertionFailure(msg); + } + + const TestPartResult& r = results.GetTestPartResult(0); + if (r.type() != type) { + msg << "Expected: " << expected << "\n" + << " Actual:\n" + << r; + return AssertionFailure(msg); + } + + if (strstr(r.message(), substr) == NULL) { + msg << "Expected: " << expected << " containing \"" + << substr << "\"\n" + << " Actual:\n" + << r; + return AssertionFailure(msg); + } + + return AssertionSuccess(); +} + +// The constructor of SingleFailureChecker remembers where to look up +// test part results, what type of failure we expect, and what +// substring the failure message should contain. +SingleFailureChecker:: SingleFailureChecker( + const TestPartResultArray* results, + TestPartResultType type, + const char* substr) + : results_(results), + type_(type), + substr_(substr) {} + +// The destructor of SingleFailureChecker verifies that the given +// TestPartResultArray contains exactly one failure that has the given +// type and contains the given substring. If that's not the case, a +// non-fatal failure will be generated. +SingleFailureChecker::~SingleFailureChecker() { + EXPECT_PRED_FORMAT3(HasOneFailure, *results_, type_, substr_.c_str()); +} + +// Reports a test part result. +void UnitTestImpl::ReportTestPartResult(const TestPartResult& result) { + current_test_result()->AddTestPartResult(result); + result_printer()->OnNewTestPartResult(&result); +} + +// Returns the current test part result reporter. +TestPartResultReporterInterface* UnitTestImpl::test_part_result_reporter() { + return test_part_result_reporter_; +} + +// Sets the current test part result reporter. +void UnitTestImpl::set_test_part_result_reporter( + TestPartResultReporterInterface* reporter) { + test_part_result_reporter_ = reporter; +} + +// Gets the number of successful test cases. +int UnitTestImpl::successful_test_case_count() const { + return test_cases_.CountIf(TestCasePassed); +} + +// Gets the number of failed test cases. +int UnitTestImpl::failed_test_case_count() const { + return test_cases_.CountIf(TestCaseFailed); +} + +// Gets the number of all test cases. +int UnitTestImpl::total_test_case_count() const { + return test_cases_.size(); +} + +// Gets the number of all test cases that contain at least one test +// that should run. +int UnitTestImpl::test_case_to_run_count() const { + return test_cases_.CountIf(ShouldRunTestCase); +} + +// Gets the number of successful tests. +int UnitTestImpl::successful_test_count() const { + return SumOverTestCaseList(test_cases_, &TestCase::successful_test_count); +} + +// Gets the number of failed tests. +int UnitTestImpl::failed_test_count() const { + return SumOverTestCaseList(test_cases_, &TestCase::failed_test_count); +} + +// Gets the number of disabled tests. +int UnitTestImpl::disabled_test_count() const { + return SumOverTestCaseList(test_cases_, &TestCase::disabled_test_count); +} + +// Gets the number of all tests. +int UnitTestImpl::total_test_count() const { + return SumOverTestCaseList(test_cases_, &TestCase::total_test_count); +} + +// Gets the number of tests that should run. +int UnitTestImpl::test_to_run_count() const { + return SumOverTestCaseList(test_cases_, &TestCase::test_to_run_count); +} + +// Returns the current OS stack trace as a String. +// +// The maximum number of stack frames to be included is specified by +// the gtest_stack_trace_depth flag. The skip_count parameter +// specifies the number of top frames to be skipped, which doesn't +// count against the number of frames to be included. +// +// For example, if Foo() calls Bar(), which in turn calls +// CurrentOsStackTraceExceptTop(1), Foo() will be included in the +// trace but Bar() and CurrentOsStackTraceExceptTop() won't. +String UnitTestImpl::CurrentOsStackTraceExceptTop(int skip_count) { + (void)skip_count; + return String(""); +} + +static TimeInMillis GetTimeInMillis() { +#ifdef _WIN32_WCE // We are on Windows CE + // Difference between 1970-01-01 and 1601-01-01 in miliseconds. + // http://analogous.blogspot.com/2005/04/epoch.html + const TimeInMillis kJavaEpochToWinFileTimeDelta = 11644473600000UL; + const DWORD kTenthMicrosInMilliSecond = 10000; + + SYSTEMTIME now_systime; + FILETIME now_filetime; + ULARGE_INTEGER now_int64; + // TODO(kenton@google.com): Shouldn't this just use + // GetSystemTimeAsFileTime()? + GetSystemTime(&now_systime); + if (SystemTimeToFileTime(&now_systime, &now_filetime)) { + now_int64.LowPart = now_filetime.dwLowDateTime; + now_int64.HighPart = now_filetime.dwHighDateTime; + now_int64.QuadPart = (now_int64.QuadPart / kTenthMicrosInMilliSecond) - + kJavaEpochToWinFileTimeDelta; + return now_int64.QuadPart; + } + return 0; +#elif defined(_WIN32) && !defined(GTEST_HAS_GETTIMEOFDAY) + __timeb64 now; +#ifdef _MSC_VER + // MSVC 8 deprecates _ftime64(), so we want to suppress warning 4996 + // (deprecated function) there. + // TODO(kenton@google.com): Use GetTickCount()? Or use + // SystemTimeToFileTime() +#pragma warning(push) // Saves the current warning state. +#pragma warning(disable:4996) // Temporarily disables warning 4996. + _ftime64(&now); +#pragma warning(pop) // Restores the warning state. +#else + _ftime64(&now); +#endif // _MSC_VER + return static_cast(now.time) * 1000 + now.millitm; +#elif defined(GTEST_HAS_GETTIMEOFDAY) + struct timeval now; + gettimeofday(&now, NULL); + return static_cast(now.tv_sec) * 1000 + now.tv_usec / 1000; +#else +#error "Don't know how to get the current time on your system." +#endif +} + +// Utilities + +// 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 +// 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 +// is returned. If str is NULL, NULL is returned. +static char* CloneString(const char* str, size_t length) { + if (str == NULL) { + return NULL; + } else { + char* const clone = new char[length + 1]; + // MSVC 8 deprecates strncpy(), so we want to suppress warning + // 4996 (deprecated function) there. +#ifdef GTEST_OS_WINDOWS // We are on Windows. +#pragma warning(push) // Saves the current warning state. +#pragma warning(disable:4996) // Temporarily disables warning 4996. + strncpy(clone, str, length); +#pragma warning(pop) // Restores the warning state. +#else // We are on Linux or Mac OS. + strncpy(clone, str, length); +#endif // GTEST_OS_WINDOWS + clone[length] = '\0'; + return clone; + } +} + +// Clones a 0-terminated C string, allocating memory using new. The +// caller is responsible for deleting[] the return value. Returns the +// cloned string, or NULL if the input is NULL. +const char * String::CloneCString(const char* c_str) { + return (c_str == NULL) ? + NULL : CloneString(c_str, strlen(c_str)); +} + +// Compares two C strings. Returns true iff they have the same content. +// +// Unlike strcmp(), this function can handle NULL argument(s). A NULL +// C string is considered different to any non-NULL C string, +// including the empty string. +bool String::CStringEquals(const char * lhs, const char * rhs) { + if ( lhs == NULL ) return rhs == NULL; + + if ( rhs == NULL ) return false; + + return strcmp(lhs, rhs) == 0; +} + +#if GTEST_HAS_STD_WSTRING || GTEST_HAS_GLOBAL_WSTRING + +// Converts an array of wide chars to a narrow string using the UTF-8 +// encoding, and streams the result to the given Message object. +static void StreamWideCharsToMessage(const wchar_t* wstr, size_t len, + Message* msg) { + for (size_t i = 0; i != len; i++) { + // TODO(wan): consider allowing a testing::String object to + // contain '\0'. This will make it behave more like std::string, + // and will allow ToUtf8String() to return the correct encoding + // for '\0' s.t. we can get rid of the conditional here (and in + // several other places). + if (wstr[i]) { + *msg << internal::ToUtf8String(wstr[i]); + } else { + *msg << '\0'; + } + } +} + +#endif // GTEST_HAS_STD_WSTRING || GTEST_HAS_GLOBAL_WSTRING + +} // namespace internal + +#if GTEST_HAS_STD_WSTRING +// Converts the given wide string to a narrow string using the UTF-8 +// encoding, and streams the result to this Message object. +Message& Message::operator <<(const ::std::wstring& wstr) { + internal::StreamWideCharsToMessage(wstr.c_str(), wstr.length(), this); + return *this; +} +#endif // GTEST_HAS_STD_WSTRING + +#if GTEST_HAS_GLOBAL_WSTRING +// Converts the given wide string to a narrow string using the UTF-8 +// encoding, and streams the result to this Message object. +Message& Message::operator <<(const ::wstring& wstr) { + internal::StreamWideCharsToMessage(wstr.c_str(), wstr.length(), this); + return *this; +} +#endif // GTEST_HAS_GLOBAL_WSTRING + +namespace internal { + +// Formats a value to be used in a failure message. + +// For a char value, we print it as a C++ char literal and as an +// unsigned integer (both in decimal and in hexadecimal). +String FormatForFailureMessage(char ch) { + const unsigned int ch_as_uint = ch; + // A String object cannot contain '\0', so we print "\\0" when ch is + // '\0'. + return String::Format("'%s' (%u, 0x%X)", + ch ? String::Format("%c", ch).c_str() : "\\0", + ch_as_uint, ch_as_uint); +} + +// For a wchar_t value, we print it as a C++ wchar_t literal and as an +// unsigned integer (both in decimal and in hexidecimal). +String FormatForFailureMessage(wchar_t wchar) { + // The C++ standard doesn't specify the exact size of the wchar_t + // type. It just says that it shall have the same size as another + // integral type, called its underlying type. + // + // Therefore, in order to print a wchar_t value in the numeric form, + // we first convert it to the largest integral type (UInt64) and + // then print the converted value. + // + // We use streaming to print the value as "%llu" doesn't work + // correctly with MSVC 7.1. + const UInt64 wchar_as_uint64 = wchar; + Message msg; + // A String object cannot contain '\0', so we print "\\0" when wchar is + // L'\0'. + msg << "L'" << (wchar ? ToUtf8String(wchar).c_str() : "\\0") << "' (" + << wchar_as_uint64 << ", 0x" << ::std::setbase(16) + << wchar_as_uint64 << ")"; + return msg.GetString(); +} + +} // namespace internal + +// AssertionResult constructor. +AssertionResult::AssertionResult(const internal::String& failure_message) + : failure_message_(failure_message) { +} + + +// Makes a successful assertion result. +AssertionResult AssertionSuccess() { + return AssertionResult(); +} + + +// Makes a failed assertion result with the given failure message. +AssertionResult AssertionFailure(const Message& message) { + return AssertionResult(message.GetString()); +} + +namespace internal { + +// Constructs and returns the message for an equality assertion +// (e.g. ASSERT_EQ, EXPECT_STREQ, etc) failure. +// +// The first four parameters are the expressions used in the assertion +// and their values, as strings. For example, for ASSERT_EQ(foo, bar) +// where foo is 5 and bar is 6, we have: +// +// expected_expression: "foo" +// actual_expression: "bar" +// expected_value: "5" +// actual_value: "6" +// +// The ignoring_case parameter is true iff the assertion is a +// *_STRCASEEQ*. When it's true, the string " (ignoring case)" will +// be inserted into the message. +AssertionResult EqFailure(const char* expected_expression, + const char* actual_expression, + const String& expected_value, + const String& actual_value, + bool ignoring_case) { + Message msg; + msg << "Value of: " << actual_expression; + if (actual_value != actual_expression) { + msg << "\n Actual: " << actual_value; + } + + msg << "\nExpected: " << expected_expression; + if (ignoring_case) { + msg << " (ignoring case)"; + } + if (expected_value != expected_expression) { + msg << "\nWhich is: " << expected_value; + } + + return AssertionFailure(msg); +} + + +// Helper function for implementing ASSERT_NEAR. +AssertionResult DoubleNearPredFormat(const char* expr1, + const char* expr2, + const char* abs_error_expr, + double val1, + double val2, + double abs_error) { + const double diff = fabs(val1 - val2); + if (diff <= abs_error) return AssertionSuccess(); + + // TODO(wan): do not print the value of an expression if it's + // already a literal. + Message msg; + msg << "The difference between " << expr1 << " and " << expr2 + << " is " << diff << ", which exceeds " << abs_error_expr << ", where\n" + << expr1 << " evaluates to " << val1 << ",\n" + << expr2 << " evaluates to " << val2 << ", and\n" + << abs_error_expr << " evaluates to " << abs_error << "."; + return AssertionFailure(msg); +} + + +// Helper template for implementing FloatLE() and DoubleLE(). +template +AssertionResult FloatingPointLE(const char* expr1, + const char* expr2, + RawType val1, + RawType val2) { + // Returns success if val1 is less than val2, + if (val1 < val2) { + return AssertionSuccess(); + } + + // or if val1 is almost equal to val2. + const FloatingPoint lhs(val1), rhs(val2); + if (lhs.AlmostEquals(rhs)) { + return AssertionSuccess(); + } + + // Note that the above two checks will both fail if either val1 or + // val2 is NaN, as the IEEE floating-point standard requires that + // any predicate involving a NaN must return false. + + StrStream val1_ss; + val1_ss << std::setprecision(std::numeric_limits::digits10 + 2) + << val1; + + StrStream val2_ss; + val2_ss << std::setprecision(std::numeric_limits::digits10 + 2) + << val2; + + Message msg; + msg << "Expected: (" << expr1 << ") <= (" << expr2 << ")\n" + << " Actual: " << StrStreamToString(&val1_ss) << " vs " + << StrStreamToString(&val2_ss); + + return AssertionFailure(msg); +} + +} // namespace internal + +// Asserts that val1 is less than, or almost equal to, val2. Fails +// otherwise. In particular, it fails if either val1 or val2 is NaN. +AssertionResult FloatLE(const char* expr1, const char* expr2, + float val1, float val2) { + return internal::FloatingPointLE(expr1, expr2, val1, val2); +} + +// Asserts that val1 is less than, or almost equal to, val2. Fails +// otherwise. In particular, it fails if either val1 or val2 is NaN. +AssertionResult DoubleLE(const char* expr1, const char* expr2, + double val1, double val2) { + return internal::FloatingPointLE(expr1, expr2, val1, val2); +} + +namespace internal { + +// The helper function for {ASSERT|EXPECT}_EQ with int or enum +// arguments. +AssertionResult CmpHelperEQ(const char* expected_expression, + const char* actual_expression, + BiggestInt expected, + BiggestInt actual) { + if (expected == actual) { + return AssertionSuccess(); + } + + return EqFailure(expected_expression, + actual_expression, + FormatForComparisonFailureMessage(expected, actual), + FormatForComparisonFailureMessage(actual, expected), + false); +} + +// A macro for implementing the helper functions needed to implement +// ASSERT_?? and EXPECT_?? with integer or enum arguments. It is here +// just to avoid copy-and-paste of similar code. +#define GTEST_IMPL_CMP_HELPER(op_name, op)\ +AssertionResult CmpHelper##op_name(const char* expr1, const char* expr2, \ + BiggestInt val1, BiggestInt val2) {\ + if (val1 op val2) {\ + return AssertionSuccess();\ + } else {\ + Message msg;\ + msg << "Expected: (" << expr1 << ") " #op " (" << expr2\ + << "), actual: " << FormatForComparisonFailureMessage(val1, val2)\ + << " vs " << FormatForComparisonFailureMessage(val2, val1);\ + return AssertionFailure(msg);\ + }\ +} + +// Implements the helper function for {ASSERT|EXPECT}_NE with int or +// enum arguments. +GTEST_IMPL_CMP_HELPER(NE, !=) +// Implements the helper function for {ASSERT|EXPECT}_LE with int or +// enum arguments. +GTEST_IMPL_CMP_HELPER(LE, <=) +// Implements the helper function for {ASSERT|EXPECT}_LT with int or +// enum arguments. +GTEST_IMPL_CMP_HELPER(LT, < ) +// Implements the helper function for {ASSERT|EXPECT}_GE with int or +// enum arguments. +GTEST_IMPL_CMP_HELPER(GE, >=) +// Implements the helper function for {ASSERT|EXPECT}_GT with int or +// enum arguments. +GTEST_IMPL_CMP_HELPER(GT, > ) + +#undef GTEST_IMPL_CMP_HELPER + +// The helper function for {ASSERT|EXPECT}_STREQ. +AssertionResult CmpHelperSTREQ(const char* expected_expression, + const char* actual_expression, + const char* expected, + const char* actual) { + if (String::CStringEquals(expected, actual)) { + return AssertionSuccess(); + } + + return EqFailure(expected_expression, + actual_expression, + String::ShowCStringQuoted(expected), + String::ShowCStringQuoted(actual), + false); +} + +// The helper function for {ASSERT|EXPECT}_STRCASEEQ. +AssertionResult CmpHelperSTRCASEEQ(const char* expected_expression, + const char* actual_expression, + const char* expected, + const char* actual) { + if (String::CaseInsensitiveCStringEquals(expected, actual)) { + return AssertionSuccess(); + } + + return EqFailure(expected_expression, + actual_expression, + String::ShowCStringQuoted(expected), + String::ShowCStringQuoted(actual), + true); +} + +// The helper function for {ASSERT|EXPECT}_STRNE. +AssertionResult CmpHelperSTRNE(const char* s1_expression, + const char* s2_expression, + const char* s1, + const char* s2) { + if (!String::CStringEquals(s1, s2)) { + return AssertionSuccess(); + } else { + Message msg; + msg << "Expected: (" << s1_expression << ") != (" + << s2_expression << "), actual: \"" + << s1 << "\" vs \"" << s2 << "\""; + return AssertionFailure(msg); + } +} + +// The helper function for {ASSERT|EXPECT}_STRCASENE. +AssertionResult CmpHelperSTRCASENE(const char* s1_expression, + const char* s2_expression, + const char* s1, + const char* s2) { + if (!String::CaseInsensitiveCStringEquals(s1, s2)) { + return AssertionSuccess(); + } else { + Message msg; + msg << "Expected: (" << s1_expression << ") != (" + << s2_expression << ") (ignoring case), actual: \"" + << s1 << "\" vs \"" << s2 << "\""; + return AssertionFailure(msg); + } +} + +} // namespace internal + +namespace { + +// Helper functions for implementing IsSubString() and IsNotSubstring(). + +// This group of overloaded functions return true iff needle is a +// substring of haystack. NULL is considered a substring of itself +// only. + +bool IsSubstringPred(const char* needle, const char* haystack) { + if (needle == NULL || haystack == NULL) + return needle == haystack; + + return strstr(haystack, needle) != NULL; +} + +bool IsSubstringPred(const wchar_t* needle, const wchar_t* haystack) { + if (needle == NULL || haystack == NULL) + return needle == haystack; + + return wcsstr(haystack, needle) != NULL; +} + +// StringType here can be either ::std::string or ::std::wstring. +template +bool IsSubstringPred(const StringType& needle, + const StringType& haystack) { + return haystack.find(needle) != StringType::npos; +} + +// This function implements either IsSubstring() or IsNotSubstring(), +// depending on the value of the expected_to_be_substring parameter. +// StringType here can be const char*, const wchar_t*, ::std::string, +// or ::std::wstring. +template +AssertionResult IsSubstringImpl( + bool expected_to_be_substring, + const char* needle_expr, const char* haystack_expr, + const StringType& needle, const StringType& haystack) { + if (IsSubstringPred(needle, haystack) == expected_to_be_substring) + return AssertionSuccess(); + + const bool is_wide_string = sizeof(needle[0]) > 1; + const char* const begin_string_quote = is_wide_string ? "L\"" : "\""; + return AssertionFailure( + Message() + << "Value of: " << needle_expr << "\n" + << " Actual: " << begin_string_quote << needle << "\"\n" + << "Expected: " << (expected_to_be_substring ? "" : "not ") + << "a substring of " << haystack_expr << "\n" + << "Which is: " << begin_string_quote << haystack << "\""); +} + +} // namespace + +// IsSubstring() and IsNotSubstring() check whether needle is a +// substring of haystack (NULL is considered a substring of itself +// only), and return an appropriate error message when they fail. + +AssertionResult IsSubstring( + const char* needle_expr, const char* haystack_expr, + const char* needle, const char* haystack) { + return IsSubstringImpl(true, needle_expr, haystack_expr, needle, haystack); +} + +AssertionResult IsSubstring( + const char* needle_expr, const char* haystack_expr, + const wchar_t* needle, const wchar_t* haystack) { + return IsSubstringImpl(true, needle_expr, haystack_expr, needle, haystack); +} + +AssertionResult IsNotSubstring( + const char* needle_expr, const char* haystack_expr, + const char* needle, const char* haystack) { + return IsSubstringImpl(false, needle_expr, haystack_expr, needle, haystack); +} + +AssertionResult IsNotSubstring( + const char* needle_expr, const char* haystack_expr, + const wchar_t* needle, const wchar_t* haystack) { + return IsSubstringImpl(false, needle_expr, haystack_expr, needle, haystack); +} + +#if GTEST_HAS_STD_STRING +AssertionResult IsSubstring( + const char* needle_expr, const char* haystack_expr, + const ::std::string& needle, const ::std::string& haystack) { + return IsSubstringImpl(true, needle_expr, haystack_expr, needle, haystack); +} + +AssertionResult IsNotSubstring( + const char* needle_expr, const char* haystack_expr, + const ::std::string& needle, const ::std::string& haystack) { + return IsSubstringImpl(false, needle_expr, haystack_expr, needle, haystack); +} +#endif // GTEST_HAS_STD_STRING + +#if GTEST_HAS_STD_WSTRING +AssertionResult IsSubstring( + const char* needle_expr, const char* haystack_expr, + const ::std::wstring& needle, const ::std::wstring& haystack) { + return IsSubstringImpl(true, needle_expr, haystack_expr, needle, haystack); +} + +AssertionResult IsNotSubstring( + const char* needle_expr, const char* haystack_expr, + const ::std::wstring& needle, const ::std::wstring& haystack) { + return IsSubstringImpl(false, needle_expr, haystack_expr, needle, haystack); +} +#endif // GTEST_HAS_STD_WSTRING + +namespace internal { + +#ifdef GTEST_OS_WINDOWS + +namespace { + +// Helper function for IsHRESULT{SuccessFailure} predicates +AssertionResult HRESULTFailureHelper(const char* expr, + const char* expected, + long hr) { // NOLINT +#ifdef _WIN32_WCE + // Windows CE doesn't support FormatMessage. + const char error_text[] = ""; +#else + // Looks up the human-readable system message for the HRESULT code + // and since we're not passing any params to FormatMessage, we don't + // want inserts expanded. + const DWORD kFlags = FORMAT_MESSAGE_FROM_SYSTEM | + FORMAT_MESSAGE_IGNORE_INSERTS; + const DWORD kBufSize = 4096; // String::Format can't exceed this length. + // Gets the system's human readable message string for this HRESULT. + char error_text[kBufSize] = { '\0' }; + DWORD message_length = ::FormatMessageA(kFlags, + 0, // no source, we're asking system + hr, // the error + 0, // no line width restrictions + error_text, // output buffer + kBufSize, // buf size + NULL); // no arguments for inserts + // Trims tailing white space (FormatMessage leaves a trailing cr-lf) + for (; message_length && isspace(error_text[message_length - 1]); + --message_length) { + error_text[message_length - 1] = '\0'; + } +#endif // _WIN32_WCE + + const String error_hex(String::Format("0x%08X ", hr)); + Message msg; + msg << "Expected: " << expr << " " << expected << ".\n" + << " Actual: " << error_hex << error_text << "\n"; + + return ::testing::AssertionFailure(msg); +} + +} // namespace + +AssertionResult IsHRESULTSuccess(const char* expr, long hr) { // NOLINT + if (SUCCEEDED(hr)) { + return AssertionSuccess(); + } + return HRESULTFailureHelper(expr, "succeeds", hr); +} + +AssertionResult IsHRESULTFailure(const char* expr, long hr) { // NOLINT + if (FAILED(hr)) { + return AssertionSuccess(); + } + return HRESULTFailureHelper(expr, "fails", hr); +} + +#endif // GTEST_OS_WINDOWS + +// Utility functions for encoding Unicode text (wide strings) in +// UTF-8. + +// A Unicode code-point can have upto 21 bits, and is encoded in UTF-8 +// like this: +// +// Code-point length Encoding +// 0 - 7 bits 0xxxxxxx +// 8 - 11 bits 110xxxxx 10xxxxxx +// 12 - 16 bits 1110xxxx 10xxxxxx 10xxxxxx +// 17 - 21 bits 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx + +// The maximum code-point a one-byte UTF-8 sequence can represent. +const UInt32 kMaxCodePoint1 = (static_cast(1) << 7) - 1; + +// The maximum code-point a two-byte UTF-8 sequence can represent. +const UInt32 kMaxCodePoint2 = (static_cast(1) << (5 + 6)) - 1; + +// The maximum code-point a three-byte UTF-8 sequence can represent. +const UInt32 kMaxCodePoint3 = (static_cast(1) << (4 + 2*6)) - 1; + +// The maximum code-point a four-byte UTF-8 sequence can represent. +const UInt32 kMaxCodePoint4 = (static_cast(1) << (3 + 3*6)) - 1; + +// Chops off the n lowest bits from a bit pattern. Returns the n +// lowest bits. As a side effect, the original bit pattern will be +// shifted to the right by n bits. +inline UInt32 ChopLowBits(UInt32* bits, int n) { + const UInt32 low_bits = *bits & ((static_cast(1) << n) - 1); + *bits >>= n; + return low_bits; +} + +// Converts a Unicode code-point to its UTF-8 encoding. +String ToUtf8String(wchar_t wchar) { + char str[5] = {}; // Initializes str to all '\0' characters. + + UInt32 code = static_cast(wchar); + if (code <= kMaxCodePoint1) { + str[0] = static_cast(code); // 0xxxxxxx + } else if (code <= kMaxCodePoint2) { + str[1] = static_cast(0x80 | ChopLowBits(&code, 6)); // 10xxxxxx + str[0] = static_cast(0xC0 | code); // 110xxxxx + } else if (code <= kMaxCodePoint3) { + str[2] = static_cast(0x80 | ChopLowBits(&code, 6)); // 10xxxxxx + str[1] = static_cast(0x80 | ChopLowBits(&code, 6)); // 10xxxxxx + str[0] = static_cast(0xE0 | code); // 1110xxxx + } else if (code <= kMaxCodePoint4) { + str[3] = static_cast(0x80 | ChopLowBits(&code, 6)); // 10xxxxxx + str[2] = static_cast(0x80 | ChopLowBits(&code, 6)); // 10xxxxxx + str[1] = static_cast(0x80 | ChopLowBits(&code, 6)); // 10xxxxxx + str[0] = static_cast(0xF0 | code); // 11110xxx + } else { + return String::Format("(Invalid Unicode 0x%llX)", + static_cast(wchar)); + } + + return String(str); +} + +// Converts a wide C string to a String using the UTF-8 encoding. +// NULL will be converted to "(null)". +String String::ShowWideCString(const wchar_t * wide_c_str) { + if (wide_c_str == NULL) return String("(null)"); + + StrStream ss; + while (*wide_c_str) { + ss << internal::ToUtf8String(*wide_c_str++); + } + + return internal::StrStreamToString(&ss); +} + +// 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 +// content. +// +// Unlike wcscmp(), this function can handle NULL argument(s). A NULL +// C string is considered different to any non-NULL C string, +// including the empty string. +bool String::WideCStringEquals(const wchar_t * lhs, const wchar_t * rhs) { + if (lhs == NULL) return rhs == NULL; + + if (rhs == NULL) return false; + + return wcscmp(lhs, rhs) == 0; +} + +// Helper function for *_STREQ on wide strings. +AssertionResult CmpHelperSTREQ(const char* expected_expression, + const char* actual_expression, + const wchar_t* expected, + const wchar_t* actual) { + if (String::WideCStringEquals(expected, actual)) { + return AssertionSuccess(); + } + + return EqFailure(expected_expression, + actual_expression, + String::ShowWideCStringQuoted(expected), + String::ShowWideCStringQuoted(actual), + false); +} + +// Helper function for *_STRNE on wide strings. +AssertionResult CmpHelperSTRNE(const char* s1_expression, + const char* s2_expression, + const wchar_t* s1, + const wchar_t* s2) { + if (!String::WideCStringEquals(s1, s2)) { + return AssertionSuccess(); + } + + Message msg; + msg << "Expected: (" << s1_expression << ") != (" + << s2_expression << "), actual: " + << String::ShowWideCStringQuoted(s1) + << " vs " << String::ShowWideCStringQuoted(s2); + return AssertionFailure(msg); +} + +// Compares two C strings, ignoring case. Returns true iff they have +// the same content. +// +// Unlike strcasecmp(), this function can handle NULL argument(s). A +// NULL C string is considered different to any non-NULL C string, +// including the empty string. +bool String::CaseInsensitiveCStringEquals(const char * lhs, const char * rhs) { + if ( lhs == NULL ) return rhs == NULL; + + if ( rhs == NULL ) return false; + +#ifdef GTEST_OS_WINDOWS + return _stricmp(lhs, rhs) == 0; +#else // GTEST_OS_WINDOWS + return strcasecmp(lhs, rhs) == 0; +#endif // GTEST_OS_WINDOWS +} + +// Constructs a String by copying a given number of chars from a +// buffer. E.g. String("hello", 3) will create the string "hel". +String::String(const char * buffer, size_t len) { + char * const temp = new char[ len + 1 ]; + memcpy(temp, buffer, len); + temp[ len ] = '\0'; + c_str_ = temp; +} + +// Compares this with another String. +// Returns < 0 if this is less than rhs, 0 if this is equal to rhs, or > 0 +// if this is greater than rhs. +int String::Compare(const String & rhs) const { + if ( c_str_ == NULL ) { + return rhs.c_str_ == NULL ? 0 : -1; // NULL < anything except NULL + } + + return rhs.c_str_ == NULL ? 1 : strcmp(c_str_, rhs.c_str_); +} + +// Returns true iff this String ends with the given suffix. *Any* +// String is considered to end with a NULL or empty suffix. +bool String::EndsWith(const char* suffix) const { + if (suffix == NULL || CStringEquals(suffix, "")) return true; + + if (c_str_ == NULL) return false; + + const size_t this_len = strlen(c_str_); + const size_t suffix_len = strlen(suffix); + return (this_len >= suffix_len) && + CStringEquals(c_str_ + this_len - suffix_len, suffix); +} + +// Returns true iff this String ends with the given suffix, ignoring case. +// Any String is considered to end with a NULL or empty suffix. +bool String::EndsWithCaseInsensitive(const char* suffix) const { + if (suffix == NULL || CStringEquals(suffix, "")) return true; + + if (c_str_ == NULL) return false; + + const size_t this_len = strlen(c_str_); + const size_t suffix_len = strlen(suffix); + return (this_len >= suffix_len) && + CaseInsensitiveCStringEquals(c_str_ + this_len - suffix_len, suffix); +} + +// Sets the 0-terminated C string this String object represents. The +// old string in this object is deleted, and this object will own a +// clone of the input string. This function copies only up to length +// bytes (plus a terminating null byte), or until the first null byte, +// whichever comes first. +// +// This function works even when the c_str parameter has the same +// value as that of the c_str_ field. +void String::Set(const char * c_str, size_t length) { + // Makes sure this works when c_str == c_str_ + const char* const temp = CloneString(c_str, length); + delete[] c_str_; + c_str_ = temp; +} + +// Assigns a C string to this object. Self-assignment works. +const String& String::operator=(const char* c_str) { + // Makes sure this works when c_str == c_str_ + if (c_str != c_str_) { + delete[] c_str_; + c_str_ = CloneCString(c_str); + } + return *this; +} + +// Formats a list of arguments to a String, using the same format +// spec string as for printf. +// +// We do not use the StringPrintf class as it is not universally +// available. +// +// The result is limited to 4096 characters (including the tailing 0). +// If 4096 characters are not enough to format the input, +// "" is returned. +String String::Format(const char * format, ...) { + va_list args; + va_start(args, format); + + char buffer[4096]; + // MSVC 8 deprecates vsnprintf(), so we want to suppress warning + // 4996 (deprecated function) there. +#ifdef GTEST_OS_WINDOWS // We are on Windows. +#pragma warning(push) // Saves the current warning state. +#pragma warning(disable:4996) // Temporarily disables warning 4996. + const int size = + vsnprintf(buffer, sizeof(buffer)/sizeof(buffer[0]) - 1, format, args); +#pragma warning(pop) // Restores the warning state. +#else // We are on Linux or Mac OS. + const int size = + vsnprintf(buffer, sizeof(buffer)/sizeof(buffer[0]) - 1, format, args); +#endif // GTEST_OS_WINDOWS + va_end(args); + + return String(size >= 0 ? buffer : ""); +} + +// Converts the buffer in a StrStream to a String, converting NUL +// bytes to "\\0" along the way. +String StrStreamToString(StrStream* ss) { +#if GTEST_HAS_STD_STRING + const ::std::string& str = ss->str(); + const char* const start = str.c_str(); + const char* const end = start + str.length(); +#else + const char* const start = ss->str(); + const char* const end = start + ss->pcount(); +#endif // GTEST_HAS_STD_STRING + + // We need to use a helper StrStream to do this transformation + // because String doesn't support push_back(). + StrStream helper; + for (const char* ch = start; ch != end; ++ch) { + if (*ch == '\0') { + helper << "\\0"; // Replaces NUL with "\\0"; + } else { + helper.put(*ch); + } + } + +#if GTEST_HAS_STD_STRING + return String(helper.str().c_str()); +#else + const String str(helper.str(), helper.pcount()); + helper.freeze(false); + ss->freeze(false); + return str; +#endif // GTEST_HAS_STD_STRING +} + +// Appends the user-supplied message to the Google-Test-generated message. +String AppendUserMessage(const String& gtest_msg, + const Message& user_msg) { + // Appends the user message if it's non-empty. + const String user_msg_string = user_msg.GetString(); + if (user_msg_string.empty()) { + return gtest_msg; + } + + Message msg; + msg << gtest_msg << "\n" << user_msg_string; + + return msg.GetString(); +} + +} // namespace internal + +// Prints a TestPartResult object. +std::ostream& operator<<(std::ostream& os, const TestPartResult& result) { + return os << result.file_name() << ":" + << result.line_number() << ": " + << (result.type() == TPRT_SUCCESS ? "Success" : + result.type() == TPRT_FATAL_FAILURE ? "Fatal failure" : + "Non-fatal failure") << ":\n" + << result.message() << std::endl; +} + +namespace internal { +// class TestResult + +// Creates an empty TestResult. +TestResult::TestResult() + : death_test_count_(0), + elapsed_time_(0) { +} + +// D'tor. +TestResult::~TestResult() { +} + +// Adds a test part result to the list. +void TestResult::AddTestPartResult(const TestPartResult& test_part_result) { + test_part_results_.PushBack(test_part_result); +} + +// Adds a test property to the list. If a property with the same key as the +// supplied property is already represented, the value of this test_property +// replaces the old value for that key. +void TestResult::RecordProperty(const TestProperty& test_property) { + if (!ValidateTestProperty(test_property)) { + return; + } + MutexLock lock(&test_properites_mutex_); + ListNode* const node_with_matching_key = + test_properties_.FindIf(TestPropertyKeyIs(test_property.key())); + if (node_with_matching_key == NULL) { + test_properties_.PushBack(test_property); + return; + } + TestProperty& property_with_matching_key = node_with_matching_key->element(); + property_with_matching_key.SetValue(test_property.value()); +} + +// Adds a failure if the key is a reserved attribute of Google Test testcase tags. +// Returns true if the property is valid. +bool TestResult::ValidateTestProperty(const TestProperty& test_property) { + String key(test_property.key()); + if (key == "name" || key == "status" || key == "time" || key == "classname") { + ADD_FAILURE() + << "Reserved key used in RecordProperty(): " + << key + << " ('name', 'status', 'time', and 'classname' are reserved by " + << GTEST_NAME << ")"; + return false; + } + return true; +} + +// Clears the object. +void TestResult::Clear() { + test_part_results_.Clear(); + test_properties_.Clear(); + death_test_count_ = 0; + elapsed_time_ = 0; +} + +// Returns true iff the test part passed. +static bool TestPartPassed(const TestPartResult & result) { + return result.passed(); +} + +// Gets the number of successful test parts. +int TestResult::successful_part_count() const { + return test_part_results_.CountIf(TestPartPassed); +} + +// Returns true iff the test part failed. +static bool TestPartFailed(const TestPartResult & result) { + return result.failed(); +} + +// Gets the number of failed test parts. +int TestResult::failed_part_count() const { + return test_part_results_.CountIf(TestPartFailed); +} + +// Returns true iff the test part fatally failed. +static bool TestPartFatallyFailed(const TestPartResult & result) { + return result.fatally_failed(); +} + +// Returns true iff the test fatally failed. +bool TestResult::HasFatalFailure() const { + return test_part_results_.CountIf(TestPartFatallyFailed) > 0; +} + +// Gets the number of all test parts. This is the sum of the number +// of successful test parts and the number of failed test parts. +int TestResult::total_part_count() const { + return test_part_results_.size(); +} + +} // namespace internal + +// class Test + +// Creates a Test object. + +// The c'tor saves the values of all Google Test flags. +Test::Test() + : gtest_flag_saver_(new internal::GTestFlagSaver) { +} + +// The d'tor restores the values of all Google Test flags. +Test::~Test() { + delete gtest_flag_saver_; +} + +// Sets up the test fixture. +// +// A sub-class may override this. +void Test::SetUp() { +} + +// Tears down the test fixture. +// +// A sub-class may override this. +void Test::TearDown() { +} + +// Allows user supplied key value pairs to be recorded for later output. +void Test::RecordProperty(const char* key, const char* value) { + UnitTest::GetInstance()->RecordPropertyForCurrentTest(key, value); +} + +// Allows user supplied key value pairs to be recorded for later output. +void Test::RecordProperty(const char* key, int value) { + Message value_message; + value_message << value; + RecordProperty(key, value_message.GetString().c_str()); +} + +#ifdef GTEST_OS_WINDOWS +// We are on Windows. + +// Adds an "exception thrown" fatal failure to the current test. +static void AddExceptionThrownFailure(DWORD exception_code, + const char* location) { + Message message; + message << "Exception thrown with code 0x" << std::setbase(16) << + exception_code << std::setbase(10) << " in " << location << "."; + + UnitTest* const unit_test = UnitTest::GetInstance(); + unit_test->AddTestPartResult( + TPRT_FATAL_FAILURE, + static_cast(NULL), + // We have no info about the source file where the exception + // occurred. + -1, // We have no info on which line caused the exception. + message.GetString(), + internal::String("")); +} + +#endif // GTEST_OS_WINDOWS + +// Google Test requires all tests in the same test case to use the same test +// fixture class. This function checks if the current test has the +// same fixture class as the first test in the current test case. If +// yes, it returns true; otherwise it generates a Google Test failure and +// returns false. +bool Test::HasSameFixtureClass() { + internal::UnitTestImpl* const impl = internal::GetUnitTestImpl(); + const TestCase* const test_case = impl->current_test_case(); + + // Info about the first test in the current test case. + const internal::TestInfoImpl* const first_test_info = + test_case->test_info_list().Head()->element()->impl(); + const internal::TypeId first_fixture_id = first_test_info->fixture_class_id(); + const char* const first_test_name = first_test_info->name(); + + // Info about the current test. + const internal::TestInfoImpl* const this_test_info = + impl->current_test_info()->impl(); + const internal::TypeId this_fixture_id = this_test_info->fixture_class_id(); + const char* const this_test_name = this_test_info->name(); + + if (this_fixture_id != first_fixture_id) { + // Is the first test defined using TEST? + const bool first_is_TEST = first_fixture_id == internal::GetTypeId(); + // Is this test defined using TEST? + const bool this_is_TEST = this_fixture_id == internal::GetTypeId(); + + if (first_is_TEST || this_is_TEST) { + // The user mixed TEST and TEST_F in this test case - we'll tell + // him/her how to fix it. + + // Gets the name of the TEST and the name of the TEST_F. Note + // that first_is_TEST and this_is_TEST cannot both be true, as + // the fixture IDs are different for the two tests. + const char* const TEST_name = + first_is_TEST ? first_test_name : this_test_name; + const char* const TEST_F_name = + first_is_TEST ? this_test_name : first_test_name; + + ADD_FAILURE() + << "All tests in the same test case must use the same test fixture\n" + << "class, so mixing TEST_F and TEST in the same test case is\n" + << "illegal. In test case " << this_test_info->test_case_name() + << ",\n" + << "test " << TEST_F_name << " is defined using TEST_F but\n" + << "test " << TEST_name << " is defined using TEST. You probably\n" + << "want to change the TEST to TEST_F or move it to another test\n" + << "case."; + } else { + // The user defined two fixture classes with the same name in + // two namespaces - we'll tell him/her how to fix it. + ADD_FAILURE() + << "All tests in the same test case must use the same test fixture\n" + << "class. However, in test case " + << this_test_info->test_case_name() << ",\n" + << "you defined test " << first_test_name + << " and test " << this_test_name << "\n" + << "using two different test fixture classes. This can happen if\n" + << "the two classes are from different namespaces or translation\n" + << "units and have the same name. You should probably rename one\n" + << "of the classes to put the tests into different test cases."; + } + return false; + } + + return true; +} + +// Runs the test and updates the test result. +void Test::Run() { + if (!HasSameFixtureClass()) return; + + internal::UnitTestImpl* const impl = internal::GetUnitTestImpl(); +#ifdef GTEST_OS_WINDOWS + // We are on Windows. + impl->os_stack_trace_getter()->UponLeavingGTest(); + __try { + SetUp(); + } __except(internal::UnitTestOptions::GTestShouldProcessSEH( + GetExceptionCode())) { + AddExceptionThrownFailure(GetExceptionCode(), "SetUp()"); + } + + // We will run the test only if SetUp() had no fatal failure. + if (!HasFatalFailure()) { + impl->os_stack_trace_getter()->UponLeavingGTest(); + __try { + TestBody(); + } __except(internal::UnitTestOptions::GTestShouldProcessSEH( + GetExceptionCode())) { + AddExceptionThrownFailure(GetExceptionCode(), "the test body"); + } + } + + // However, we want to clean up as much as possible. Hence we will + // always call TearDown(), even if SetUp() or the test body has + // failed. + impl->os_stack_trace_getter()->UponLeavingGTest(); + __try { + TearDown(); + } __except(internal::UnitTestOptions::GTestShouldProcessSEH( + GetExceptionCode())) { + AddExceptionThrownFailure(GetExceptionCode(), "TearDown()"); + } + +#else // We are on Linux or Mac - exceptions are disabled. + impl->os_stack_trace_getter()->UponLeavingGTest(); + SetUp(); + + // We will run the test only if SetUp() was successful. + if (!HasFatalFailure()) { + impl->os_stack_trace_getter()->UponLeavingGTest(); + TestBody(); + } + + // However, we want to clean up as much as possible. Hence we will + // always call TearDown(), even if SetUp() or the test body has + // failed. + impl->os_stack_trace_getter()->UponLeavingGTest(); + TearDown(); +#endif // GTEST_OS_WINDOWS +} + + +// Returns true iff the current test has a fatal failure. +bool Test::HasFatalFailure() { + return internal::GetUnitTestImpl()->current_test_result()->HasFatalFailure(); +} + +// class TestInfo + +// Constructs a TestInfo object. +TestInfo::TestInfo(const char* test_case_name, + const char* name, + internal::TypeId fixture_class_id, + TestMaker maker) { + impl_ = new internal::TestInfoImpl(this, test_case_name, name, + fixture_class_id, maker); +} + +// Destructs a TestInfo object. +TestInfo::~TestInfo() { + delete impl_; +} + +// Creates a TestInfo object and registers it with the UnitTest +// singleton; returns the created object. +// +// Arguments: +// +// test_case_name: name of the test case +// name: name of the test +// set_up_tc: pointer to the function that sets up the test case +// tear_down_tc: pointer to the function that tears down the test case +// maker: pointer to the function that creates a test object +TestInfo* TestInfo::MakeAndRegisterInstance( + const char* test_case_name, + const char* name, + internal::TypeId fixture_class_id, + Test::SetUpTestCaseFunc set_up_tc, + Test::TearDownTestCaseFunc tear_down_tc, + TestMaker maker) { + TestInfo* const test_info = + new TestInfo(test_case_name, name, fixture_class_id, maker); + internal::GetUnitTestImpl()->AddTestInfo(set_up_tc, tear_down_tc, test_info); + return test_info; +} + +// Returns the test case name. +const char* TestInfo::test_case_name() const { + return impl_->test_case_name(); +} + +// Returns the test name. +const char* TestInfo::name() const { + return impl_->name(); +} + +// Returns true if this test should run. +bool TestInfo::should_run() const { return impl_->should_run(); } + +// Returns the result of the test. +const internal::TestResult* TestInfo::result() const { return impl_->result(); } + +// Increments the number of death tests encountered in this test so +// far. +int TestInfo::increment_death_test_count() { + return impl_->result()->increment_death_test_count(); +} + +namespace { + +// A predicate that checks the test name of a TestInfo against a known +// value. +// +// This is used for implementation of the TestCase class only. We put +// it in the anonymous namespace to prevent polluting the outer +// namespace. +// +// TestNameIs is copyable. +class TestNameIs { + public: + // Constructor. + // + // TestNameIs has NO default constructor. + explicit TestNameIs(const char* name) + : name_(name) {} + + // Returns true iff the test name of test_info matches name_. + bool operator()(const TestInfo * test_info) const { + return test_info && internal::String(test_info->name()).Compare(name_) == 0; + } + + private: + internal::String name_; +}; + +} // namespace + +// Finds and returns a TestInfo with the given name. If one doesn't +// exist, returns NULL. +TestInfo * TestCase::GetTestInfo(const char* test_name) { + // Can we find a TestInfo with the given name? + internal::ListNode * const node = test_info_list_->FindIf( + TestNameIs(test_name)); + + // Returns the TestInfo found. + return node ? node->element() : NULL; +} + +namespace internal { + +// Creates the test object, runs it, records its result, and then +// deletes it. +void TestInfoImpl::Run() { + if (!should_run_) return; + + // Tells UnitTest where to store test result. + UnitTestImpl* const impl = internal::GetUnitTestImpl(); + impl->set_current_test_info(parent_); + + // Notifies the unit test event listener that a test is about to + // start. + UnitTestEventListenerInterface* const result_printer = + impl->result_printer(); + result_printer->OnTestStart(parent_); + + const TimeInMillis start = GetTimeInMillis(); + + impl->os_stack_trace_getter()->UponLeavingGTest(); +#ifdef GTEST_OS_WINDOWS + // We are on Windows. + Test* test = NULL; + + __try { + // Creates the test object. + test = (*maker_)(); + } __except(internal::UnitTestOptions::GTestShouldProcessSEH( + GetExceptionCode())) { + AddExceptionThrownFailure(GetExceptionCode(), + "the test fixture's constructor"); + return; + } +#else // We are on Linux or Mac OS - exceptions are disabled. + + // TODO(wan): If test->Run() throws, test won't be deleted. This is + // not a problem now as we don't use exceptions. If we were to + // enable exceptions, we should revise the following to be + // exception-safe. + + // Creates the test object. + Test* test = (*maker_)(); +#endif // GTEST_OS_WINDOWS + + // Runs the test only if the constructor of the test fixture didn't + // generate a fatal failure. + if (!Test::HasFatalFailure()) { + test->Run(); + } + + // Deletes the test object. + impl->os_stack_trace_getter()->UponLeavingGTest(); + delete test; + test = NULL; + + result_.set_elapsed_time(GetTimeInMillis() - start); + + // Notifies the unit test event listener that a test has just finished. + result_printer->OnTestEnd(parent_); + + // Tells UnitTest to stop associating assertion results to this + // test. + impl->set_current_test_info(NULL); +} + +} // namespace internal + +// class TestCase + +// Gets the number of successful tests in this test case. +int TestCase::successful_test_count() const { + return test_info_list_->CountIf(TestPassed); +} + +// Gets the number of failed tests in this test case. +int TestCase::failed_test_count() const { + return test_info_list_->CountIf(TestFailed); +} + +int TestCase::disabled_test_count() const { + return test_info_list_->CountIf(TestDisabled); +} + +// Get the number of tests in this test case that should run. +int TestCase::test_to_run_count() const { + return test_info_list_->CountIf(ShouldRunTest); +} + +// Gets the number of all tests. +int TestCase::total_test_count() const { + return test_info_list_->size(); +} + +// Creates a TestCase with the given name. +// +// Arguments: +// +// name: name of the test case +// set_up_tc: pointer to the function that sets up the test case +// tear_down_tc: pointer to the function that tears down the test case +TestCase::TestCase(const char* name, + Test::SetUpTestCaseFunc set_up_tc, + Test::TearDownTestCaseFunc tear_down_tc) + : name_(name), + set_up_tc_(set_up_tc), + tear_down_tc_(tear_down_tc), + should_run_(false), + elapsed_time_(0) { + test_info_list_ = new internal::List; +} + +// Destructor of TestCase. +TestCase::~TestCase() { + // Deletes every Test in the collection. + test_info_list_->ForEach(internal::Delete); + + // Then deletes the Test collection. + delete test_info_list_; + test_info_list_ = NULL; +} + +// Adds a test to this test case. Will delete the test upon +// destruction of the TestCase object. +void TestCase::AddTestInfo(TestInfo * test_info) { + test_info_list_->PushBack(test_info); +} + +// Runs every test in this TestCase. +void TestCase::Run() { + if (!should_run_) return; + + internal::UnitTestImpl* const impl = internal::GetUnitTestImpl(); + impl->set_current_test_case(this); + + UnitTestEventListenerInterface * const result_printer = + impl->result_printer(); + + result_printer->OnTestCaseStart(this); + impl->os_stack_trace_getter()->UponLeavingGTest(); + set_up_tc_(); + + const internal::TimeInMillis start = internal::GetTimeInMillis(); + test_info_list_->ForEach(internal::TestInfoImpl::RunTest); + elapsed_time_ = internal::GetTimeInMillis() - start; + + impl->os_stack_trace_getter()->UponLeavingGTest(); + tear_down_tc_(); + result_printer->OnTestCaseEnd(this); + impl->set_current_test_case(NULL); +} + +// Clears the results of all tests in this test case. +void TestCase::ClearResult() { + test_info_list_->ForEach(internal::TestInfoImpl::ClearTestResult); +} + + +// class UnitTestEventListenerInterface + +// The virtual d'tor. +UnitTestEventListenerInterface::~UnitTestEventListenerInterface() { +} + +// A result printer that never prints anything. Used in the child process +// of an exec-style death test to avoid needless output clutter. +class NullUnitTestResultPrinter : public UnitTestEventListenerInterface {}; + +// Formats a countable noun. Depending on its quantity, either the +// singular form or the plural form is used. e.g. +// +// FormatCountableNoun(1, "formula", "formuli") returns "1 formula". +// FormatCountableNoun(5, "book", "books") returns "5 books". +static internal::String FormatCountableNoun(int count, + const char * singular_form, + const char * plural_form) { + return internal::String::Format("%d %s", count, + count == 1 ? singular_form : plural_form); +} + +// Formats the count of tests. +static internal::String FormatTestCount(int test_count) { + return FormatCountableNoun(test_count, "test", "tests"); +} + +// Formats the count of test cases. +static internal::String FormatTestCaseCount(int test_case_count) { + return FormatCountableNoun(test_case_count, "test case", "test cases"); +} + +// Converts a TestPartResultType enum to human-friendly string +// representation. Both TPRT_NONFATAL_FAILURE and TPRT_FATAL_FAILURE +// are translated to "Failure", as the user usually doesn't care about +// the difference between the two when viewing the test result. +static const char * TestPartResultTypeToString(TestPartResultType type) { + switch (type) { + case TPRT_SUCCESS: + return "Success"; + + case TPRT_NONFATAL_FAILURE: + case TPRT_FATAL_FAILURE: + return "Failure"; + } + + return "Unknown result type"; +} + +// Prints a TestPartResult. +static void PrintTestPartResult( + const TestPartResult & test_part_result) { + const char * const file_name = test_part_result.file_name(); + + printf("%s", file_name == NULL ? "unknown file" : file_name); + if (test_part_result.line_number() >= 0) { + printf(":%d", test_part_result.line_number()); + } + printf(": %s\n", TestPartResultTypeToString(test_part_result.type())); + printf("%s\n", test_part_result.message()); + fflush(stdout); +} + +// class PrettyUnitTestResultPrinter + +namespace internal { + +enum GTestColor { + COLOR_RED, + COLOR_GREEN, + COLOR_YELLOW +}; + +#ifdef _WIN32 + +// Returns the character attribute for the given color. +WORD GetColorAttribute(GTestColor color) { + switch (color) { + case COLOR_RED: return FOREGROUND_RED; + case COLOR_GREEN: return FOREGROUND_GREEN; + case COLOR_YELLOW: return FOREGROUND_RED | FOREGROUND_GREEN; + } + return 0; +} + +#else + +// Returns the ANSI color code for the given color. +const char* GetAnsiColorCode(GTestColor color) { + switch (color) { + case COLOR_RED: return "1"; + case COLOR_GREEN: return "2"; + case COLOR_YELLOW: return "3"; + }; + return NULL; +} + +#endif // _WIN32 + +// Returns true iff Google Test should use colors in the output. +bool ShouldUseColor(bool stdout_is_tty) { + const char* const gtest_color = GTEST_FLAG(color).c_str(); + + if (String::CaseInsensitiveCStringEquals(gtest_color, "auto")) { +#ifdef _WIN32 + // On Windows the TERM variable is usually not set, but the + // console there does support colors. + return stdout_is_tty; +#else + // On non-Windows platforms, we rely on the TERM variable. + const char* const term = GetEnv("TERM"); + const bool term_supports_color = + String::CStringEquals(term, "xterm") || + String::CStringEquals(term, "xterm-color") || + String::CStringEquals(term, "cygwin"); + return stdout_is_tty && term_supports_color; +#endif // _WIN32 + } + + return String::CaseInsensitiveCStringEquals(gtest_color, "yes") || + String::CaseInsensitiveCStringEquals(gtest_color, "true") || + String::CaseInsensitiveCStringEquals(gtest_color, "t") || + String::CStringEquals(gtest_color, "1"); + // We take "yes", "true", "t", and "1" as meaning "yes". If the + // value is neither one of these nor "auto", we treat it as "no" to + // be conservative. +} + +// Helpers for printing colored strings to stdout. Note that on Windows, we +// cannot simply emit special characters and have the terminal change colors. +// This routine must actually emit the characters rather than return a string +// that would be colored when printed, as can be done on Linux. +void ColoredPrintf(GTestColor color, const char* fmt, ...) { + va_list args; + va_start(args, fmt); + + static const bool use_color = ShouldUseColor(isatty(fileno(stdout)) != 0); + // The '!= 0' comparison is necessary to satisfy MSVC 7.1. + + if (!use_color) { + vprintf(fmt, args); + va_end(args); + return; + } + +#ifdef _WIN32 + const HANDLE stdout_handle = GetStdHandle(STD_OUTPUT_HANDLE); + + // Gets the current text color. + CONSOLE_SCREEN_BUFFER_INFO buffer_info; + GetConsoleScreenBufferInfo(stdout_handle, &buffer_info); + const WORD old_color_attrs = buffer_info.wAttributes; + + SetConsoleTextAttribute(stdout_handle, + GetColorAttribute(color) | FOREGROUND_INTENSITY); + vprintf(fmt, args); + + // Restores the text color. + SetConsoleTextAttribute(stdout_handle, old_color_attrs); +#else + printf("\033[0;3%sm", GetAnsiColorCode(color)); + vprintf(fmt, args); + printf("\033[m"); // Resets the terminal to default. +#endif // _WIN32 + va_end(args); +} + +} // namespace internal + +using internal::ColoredPrintf; +using internal::COLOR_RED; +using internal::COLOR_GREEN; +using internal::COLOR_YELLOW; + +// This class implements the UnitTestEventListenerInterface interface. +// +// Class PrettyUnitTestResultPrinter is copyable. +class PrettyUnitTestResultPrinter : public UnitTestEventListenerInterface { + public: + PrettyUnitTestResultPrinter() {} + static void PrintTestName(const char * test_case, const char * test) { + printf("%s.%s", test_case, test); + } + + // The following methods override what's in the + // UnitTestEventListenerInterface class. + virtual void OnUnitTestStart(const UnitTest * unit_test); + virtual void OnGlobalSetUpStart(const UnitTest*); + virtual void OnTestCaseStart(const TestCase * test_case); + virtual void OnTestStart(const TestInfo * test_info); + virtual void OnNewTestPartResult(const TestPartResult * result); + virtual void OnTestEnd(const TestInfo * test_info); + virtual void OnGlobalTearDownStart(const UnitTest*); + virtual void OnUnitTestEnd(const UnitTest * unit_test); + + private: + internal::String test_case_name_; +}; + +// Called before the unit test starts. +void PrettyUnitTestResultPrinter::OnUnitTestStart( + const UnitTest * unit_test) { + const char * const filter = GTEST_FLAG(filter).c_str(); + + // Prints the filter if it's not *. This reminds the user that some + // tests may be skipped. + if (!internal::String::CStringEquals(filter, kUniversalFilter)) { + ColoredPrintf(COLOR_YELLOW, + "Note: %s filter = %s\n", GTEST_NAME, filter); + } + + const internal::UnitTestImpl* const impl = unit_test->impl(); + ColoredPrintf(COLOR_GREEN, "[==========] "); + printf("Running %s from %s.\n", + FormatTestCount(impl->test_to_run_count()).c_str(), + FormatTestCaseCount(impl->test_case_to_run_count()).c_str()); + fflush(stdout); +} + +void PrettyUnitTestResultPrinter::OnGlobalSetUpStart(const UnitTest*) { + ColoredPrintf(COLOR_GREEN, "[----------] "); + printf("Global test environment set-up.\n"); + fflush(stdout); +} + +void PrettyUnitTestResultPrinter::OnTestCaseStart( + const TestCase * test_case) { + test_case_name_ = test_case->name(); + const internal::String counts = + FormatCountableNoun(test_case->test_to_run_count(), "test", "tests"); + ColoredPrintf(COLOR_GREEN, "[----------] "); + printf("%s from %s\n", counts.c_str(), test_case_name_.c_str()); + fflush(stdout); +} + +void PrettyUnitTestResultPrinter::OnTestStart(const TestInfo * test_info) { + ColoredPrintf(COLOR_GREEN, "[ RUN ] "); + PrintTestName(test_case_name_.c_str(), test_info->name()); + printf("\n"); + fflush(stdout); +} + +void PrettyUnitTestResultPrinter::OnTestEnd(const TestInfo * test_info) { + if (test_info->result()->Passed()) { + ColoredPrintf(COLOR_GREEN, "[ OK ] "); + } else { + ColoredPrintf(COLOR_RED, "[ FAILED ] "); + } + PrintTestName(test_case_name_.c_str(), test_info->name()); + printf("\n"); + fflush(stdout); +} + +// Called after an assertion failure. +void PrettyUnitTestResultPrinter::OnNewTestPartResult( + const TestPartResult * result) { + // If the test part succeeded, we don't need to do anything. + if (result->type() == TPRT_SUCCESS) + return; + + // Print failure message from the assertion (e.g. expected this and got that). + PrintTestPartResult(*result); + fflush(stdout); +} + +void PrettyUnitTestResultPrinter::OnGlobalTearDownStart(const UnitTest*) { + ColoredPrintf(COLOR_GREEN, "[----------] "); + printf("Global test environment tear-down\n"); + fflush(stdout); +} + +namespace internal { + +// Internal helper for printing the list of failed tests. +static void PrintFailedTestsPretty(const UnitTestImpl* impl) { + const int failed_test_count = impl->failed_test_count(); + if (failed_test_count == 0) { + return; + } + + for (const internal::ListNode* node = impl->test_cases()->Head(); + node != NULL; node = node->next()) { + const TestCase* const tc = node->element(); + if (!tc->should_run() || (tc->failed_test_count() == 0)) { + continue; + } + for (const internal::ListNode* tinode = + tc->test_info_list().Head(); + tinode != NULL; tinode = tinode->next()) { + const TestInfo* const ti = tinode->element(); + if (!tc->ShouldRunTest(ti) || tc->TestPassed(ti)) { + continue; + } + ColoredPrintf(COLOR_RED, "[ FAILED ] "); + printf("%s.%s\n", ti->test_case_name(), ti->name()); + } + } +} + +} // namespace internal + +void PrettyUnitTestResultPrinter::OnUnitTestEnd( + const UnitTest * unit_test) { + const internal::UnitTestImpl* const impl = unit_test->impl(); + + ColoredPrintf(COLOR_GREEN, "[==========] "); + printf("%s from %s ran.\n", + FormatTestCount(impl->test_to_run_count()).c_str(), + FormatTestCaseCount(impl->test_case_to_run_count()).c_str()); + ColoredPrintf(COLOR_GREEN, "[ PASSED ] "); + printf("%s.\n", FormatTestCount(impl->successful_test_count()).c_str()); + + int num_failures = impl->failed_test_count(); + if (!impl->Passed()) { + const int failed_test_count = impl->failed_test_count(); + ColoredPrintf(COLOR_RED, "[ FAILED ] "); + printf("%s, listed below:\n", FormatTestCount(failed_test_count).c_str()); + internal::PrintFailedTestsPretty(impl); + printf("\n%2d FAILED %s\n", num_failures, + num_failures == 1 ? "TEST" : "TESTS"); + } + + int num_disabled = impl->disabled_test_count(); + if (num_disabled) { + if (!num_failures) { + printf("\n"); // Add a spacer if no FAILURE banner is displayed. + } + ColoredPrintf(COLOR_YELLOW, + " YOU HAVE %d DISABLED %s\n\n", + num_disabled, + num_disabled == 1 ? "TEST" : "TESTS"); + } + // Ensure that Google Test output is printed before, e.g., heapchecker output. + fflush(stdout); +} + +// End PrettyUnitTestResultPrinter + +// class UnitTestEventsRepeater +// +// This class forwards events to other event listeners. +class UnitTestEventsRepeater : public UnitTestEventListenerInterface { + public: + typedef internal::List Listeners; + typedef internal::ListNode ListenersNode; + UnitTestEventsRepeater() {} + virtual ~UnitTestEventsRepeater(); + void AddListener(UnitTestEventListenerInterface *listener); + + virtual void OnUnitTestStart(const UnitTest* unit_test); + virtual void OnUnitTestEnd(const UnitTest* unit_test); + virtual void OnGlobalSetUpStart(const UnitTest* unit_test); + virtual void OnGlobalSetUpEnd(const UnitTest* unit_test); + virtual void OnGlobalTearDownStart(const UnitTest* unit_test); + virtual void OnGlobalTearDownEnd(const UnitTest* unit_test); + virtual void OnTestCaseStart(const TestCase* test_case); + virtual void OnTestCaseEnd(const TestCase* test_case); + virtual void OnTestStart(const TestInfo* test_info); + virtual void OnTestEnd(const TestInfo* test_info); + virtual void OnNewTestPartResult(const TestPartResult* result); + + private: + Listeners listeners_; + + GTEST_DISALLOW_COPY_AND_ASSIGN(UnitTestEventsRepeater); +}; + +UnitTestEventsRepeater::~UnitTestEventsRepeater() { + for (ListenersNode* listener = listeners_.Head(); + listener != NULL; + listener = listener->next()) { + delete listener->element(); + } +} + +void UnitTestEventsRepeater::AddListener( + UnitTestEventListenerInterface *listener) { + listeners_.PushBack(listener); +} + +// Since the methods are identical, use a macro to reduce boilerplate. +// This defines a member that repeats the call to all listeners. +#define GTEST_REPEATER_METHOD(Name, Type) \ +void UnitTestEventsRepeater::Name(const Type* parameter) { \ + for (ListenersNode* listener = listeners_.Head(); \ + listener != NULL; \ + listener = listener->next()) { \ + listener->element()->Name(parameter); \ + } \ +} + +GTEST_REPEATER_METHOD(OnUnitTestStart, UnitTest) +GTEST_REPEATER_METHOD(OnUnitTestEnd, UnitTest) +GTEST_REPEATER_METHOD(OnGlobalSetUpStart, UnitTest) +GTEST_REPEATER_METHOD(OnGlobalSetUpEnd, UnitTest) +GTEST_REPEATER_METHOD(OnGlobalTearDownStart, UnitTest) +GTEST_REPEATER_METHOD(OnGlobalTearDownEnd, UnitTest) +GTEST_REPEATER_METHOD(OnTestCaseStart, TestCase) +GTEST_REPEATER_METHOD(OnTestCaseEnd, TestCase) +GTEST_REPEATER_METHOD(OnTestStart, TestInfo) +GTEST_REPEATER_METHOD(OnTestEnd, TestInfo) +GTEST_REPEATER_METHOD(OnNewTestPartResult, TestPartResult) + +#undef GTEST_REPEATER_METHOD + +// End PrettyUnitTestResultPrinter + +// This class generates an XML output file. +class XmlUnitTestResultPrinter : public UnitTestEventListenerInterface { + public: + explicit XmlUnitTestResultPrinter(const char* output_file); + + virtual void OnUnitTestEnd(const UnitTest* unit_test); + + private: + // Is c a whitespace character that is normalized to a space character + // when it appears in an XML attribute value? + static bool IsNormalizableWhitespace(char c) { + return c == 0x9 || c == 0xA || c == 0xD; + } + + // May c appear in a well-formed XML document? + static bool IsValidXmlCharacter(char c) { + return IsNormalizableWhitespace(c) || c >= 0x20; + } + + // Returns an XML-escaped copy of the input string str. If + // is_attribute is true, the text is meant to appear as an attribute + // value, and normalizable whitespace is preserved by replacing it + // with character references. + static internal::String EscapeXml(const char* str, + bool is_attribute); + + // Convenience wrapper around EscapeXml when str is an attribute value. + static internal::String EscapeXmlAttribute(const char* str) { + return EscapeXml(str, true); + } + + // Convenience wrapper around EscapeXml when str is not an attribute value. + static internal::String EscapeXmlText(const char* str) { + return EscapeXml(str, false); + } + + // Prints an XML representation of a TestInfo object. + static void PrintXmlTestInfo(FILE* out, + const char* test_case_name, + const TestInfo* test_info); + + // Prints an XML representation of a TestCase object + static void PrintXmlTestCase(FILE* out, const TestCase* test_case); + + // Prints an XML summary of unit_test to output stream out. + static void PrintXmlUnitTest(FILE* out, const UnitTest* unit_test); + + // Produces a string representing the test properties in a result as space + // delimited XML attributes based on the property key="value" pairs. + // When the String is not empty, it includes a space at the beginning, + // to delimit this attribute from prior attributes. + static internal::String TestPropertiesAsXmlAttributes( + const internal::TestResult* result); + + // The output file. + const internal::String output_file_; + + GTEST_DISALLOW_COPY_AND_ASSIGN(XmlUnitTestResultPrinter); +}; + +// Creates a new XmlUnitTestResultPrinter. +XmlUnitTestResultPrinter::XmlUnitTestResultPrinter(const char* output_file) + : output_file_(output_file) { + if (output_file_.c_str() == NULL || output_file_.empty()) { + fprintf(stderr, "XML output file may not be null\n"); + fflush(stderr); + exit(EXIT_FAILURE); + } +} + +// Called after the unit test ends. +void XmlUnitTestResultPrinter::OnUnitTestEnd(const UnitTest* unit_test) { + FILE* xmlout = NULL; + internal::FilePath output_file(output_file_); + internal::FilePath output_dir(output_file.RemoveFileName()); + + if (output_dir.CreateDirectoriesRecursively()) { + // MSVC 8 deprecates fopen(), so we want to suppress warning 4996 + // (deprecated function) there. +#ifdef GTEST_OS_WINDOWS + // We are on Windows. +#pragma warning(push) // Saves the current warning state. +#pragma warning(disable:4996) // Temporarily disables warning 4996. + xmlout = fopen(output_file_.c_str(), "w"); +#pragma warning(pop) // Restores the warning state. +#else // We are on Linux or Mac OS. + xmlout = fopen(output_file_.c_str(), "w"); +#endif // GTEST_OS_WINDOWS + } + if (xmlout == NULL) { + // TODO(wan): report the reason of the failure. + // + // We don't do it for now as: + // + // 1. There is no urgent need for it. + // 2. It's a bit involved to make the errno variable thread-safe on + // all three operating systems (Linux, Windows, and Mac OS). + // 3. To interpret the meaning of errno in a thread-safe way, + // we need the strerror_r() function, which is not available on + // Windows. + fprintf(stderr, + "Unable to open file \"%s\"\n", + output_file_.c_str()); + fflush(stderr); + exit(EXIT_FAILURE); + } + PrintXmlUnitTest(xmlout, unit_test); + fclose(xmlout); +} + +// Returns an XML-escaped copy of the input string str. If is_attribute +// is true, the text is meant to appear as an attribute value, and +// normalizable whitespace is preserved by replacing it with character +// references. +// +// Invalid XML characters in str, if any, are stripped from the output. +// It is expected that most, if not all, of the text processed by this +// module will consist of ordinary English text. +// If this module is ever modified to produce version 1.1 XML output, +// most invalid characters can be retained using character references. +// TODO(wan): It might be nice to have a minimally invasive, human-readable +// escaping scheme for invalid characters, rather than dropping them. +internal::String XmlUnitTestResultPrinter::EscapeXml(const char* str, + bool is_attribute) { + Message m; + + if (str != NULL) { + for (const char* src = str; *src; ++src) { + switch (*src) { + case '<': + m << "<"; + break; + case '>': + m << ">"; + break; + case '&': + m << "&"; + break; + case '\'': + if (is_attribute) + m << "'"; + else + m << '\''; + break; + case '"': + if (is_attribute) + m << """; + else + m << '"'; + break; + default: + if (IsValidXmlCharacter(*src)) { + if (is_attribute && IsNormalizableWhitespace(*src)) + m << internal::String::Format("&#x%02X;", unsigned(*src)); + else + m << *src; + } + break; + } + } + } + + return m.GetString(); +} + + +// The following routines generate an XML representation of a UnitTest +// object. +// +// This is how Google Test concepts map to the DTD: +// +// <-- corresponds to a UnitTest object +// <-- corresponds to a TestCase object +// <-- corresponds to a TestInfo object +// +// <-- individual assertion failures +// +// +// +// + +// Prints an XML representation of a TestInfo object. +// TODO(wan): There is also value in printing properties with the plain printer. +void XmlUnitTestResultPrinter::PrintXmlTestInfo(FILE* out, + const char* test_case_name, + const TestInfo* test_info) { + const internal::TestResult * const result = test_info->result(); + const internal::List &results = result->test_part_results(); + fprintf(out, + " name()).c_str(), + test_info->should_run() ? "run" : "notrun", + internal::StreamableToString(result->elapsed_time()).c_str(), + EscapeXmlAttribute(test_case_name).c_str(), + TestPropertiesAsXmlAttributes(result).c_str()); + + int failures = 0; + for (const internal::ListNode* part_node = results.Head(); + part_node != NULL; + part_node = part_node->next()) { + const TestPartResult& part = part_node->element(); + if (part.failed()) { + const internal::String message = + internal::String::Format("%s:%d\n%s", part.file_name(), + part.line_number(), part.message()); + if (++failures == 1) + fprintf(out, ">\n"); + fprintf(out, + " \n", + EscapeXmlAttribute(message.c_str()).c_str()); + } + } + + if (failures == 0) + fprintf(out, " />\n"); + else + fprintf(out, " \n"); +} + +// Prints an XML representation of a TestCase object +void XmlUnitTestResultPrinter::PrintXmlTestCase(FILE* out, + const TestCase* test_case) { + fprintf(out, + " name()).c_str(), + test_case->total_test_count(), + test_case->failed_test_count(), + test_case->disabled_test_count()); + fprintf(out, + "errors=\"0\" time=\"%s\">\n", + internal::StreamableToString(test_case->elapsed_time()).c_str()); + for (const internal::ListNode* info_node = + test_case->test_info_list().Head(); + info_node != NULL; + info_node = info_node->next()) { + PrintXmlTestInfo(out, test_case->name(), info_node->element()); + } + fprintf(out, " \n"); +} + +// Prints an XML summary of unit_test to output stream out. +void XmlUnitTestResultPrinter::PrintXmlUnitTest(FILE* out, + const UnitTest* unit_test) { + const internal::UnitTestImpl* const impl = unit_test->impl(); + fprintf(out, "\n"); + fprintf(out, + "total_test_count(), + impl->failed_test_count(), + impl->disabled_test_count(), + internal::StreamableToString(impl->elapsed_time()).c_str()); + fprintf(out, "name=\"AllTests\">\n"); + for (const internal::ListNode* case_node = + impl->test_cases()->Head(); + case_node != NULL; + case_node = case_node->next()) { + PrintXmlTestCase(out, case_node->element()); + } + fprintf(out, "\n"); +} + +// Produces a string representing the test properties in a result as space +// delimited XML attributes based on the property key="value" pairs. +internal::String XmlUnitTestResultPrinter::TestPropertiesAsXmlAttributes( + const internal::TestResult* result) { + using internal::TestProperty; + Message attributes; + const internal::List& properties = result->test_properties(); + for (const internal::ListNode* property_node = + properties.Head(); + property_node != NULL; + property_node = property_node->next()) { + const TestProperty& property = property_node->element(); + attributes << " " << property.key() << "=" + << "\"" << EscapeXmlAttribute(property.value()) << "\""; + } + return attributes.GetString(); +} + +// End XmlUnitTestResultPrinter + +namespace internal { + +// Class ScopedTrace + +// Pushes the given source file location and message onto a per-thread +// trace stack maintained by Google Test. +// L < UnitTest::mutex_ +ScopedTrace::ScopedTrace(const char* file, int line, const Message& message) { + TraceInfo trace; + trace.file = file; + trace.line = line; + trace.message = message.GetString(); + + UnitTest::GetInstance()->PushGTestTrace(trace); +} + +// Pops the info pushed by the c'tor. +// L < UnitTest::mutex_ +ScopedTrace::~ScopedTrace() { + UnitTest::GetInstance()->PopGTestTrace(); +} + + +// class OsStackTraceGetter + +// Returns the current OS stack trace as a String. Parameters: +// +// max_depth - the maximum number of stack frames to be included +// in the trace. +// skip_count - the number of top frames to be skipped; doesn't count +// against max_depth. +// +// L < mutex_ +// We use "L < mutex_" to denote that the function may acquire mutex_. +String OsStackTraceGetter::CurrentStackTrace(int, int) { + return String(""); +} + +// L < mutex_ +void OsStackTraceGetter::UponLeavingGTest() { +} + +const char* const +OsStackTraceGetter::kElidedFramesMarker = + "... " GTEST_NAME " internal frames ..."; + +} // namespace internal + +// class UnitTest + +// Gets the singleton UnitTest object. The first time this method is +// called, a UnitTest object is constructed and returned. Consecutive +// calls will return the same object. +// +// We don't protect this under mutex_ as a user is not supposed to +// call this before main() starts, from which point on the return +// value will never change. +UnitTest * UnitTest::GetInstance() { + // When compiled with MSVC 7.1 in optimized mode, destroying the + // UnitTest object upon exiting the program messes up the exit code, + // causing successful tests to appear failed. We have to use a + // different implementation in this case to bypass the compiler bug. + // This implementation makes the compiler happy, at the cost of + // leaking the UnitTest object. +#if _MSC_VER == 1310 && !defined(_DEBUG) // MSVC 7.1 and optimized build. + static UnitTest* const instance = new UnitTest; + return instance; +#else + static UnitTest instance; + return &instance; +#endif // _MSC_VER==1310 && !defined(_DEBUG) +} + +// Registers and returns a global test environment. When a test +// program is run, all global test environments will be set-up in the +// order they were registered. After all tests in the program have +// finished, all global test environments will be torn-down in the +// *reverse* order they were registered. +// +// The UnitTest object takes ownership of the given environment. +// +// We don't protect this under mutex_, as we only support calling it +// from the main thread. +Environment* UnitTest::AddEnvironment(Environment* env) { + if (env == NULL) { + return NULL; + } + + impl_->environments()->PushBack(env); + impl_->environments_in_reverse_order()->PushFront(env); + return env; +} + +// Adds a TestPartResult to the current TestResult object. All Google Test +// assertion macros (e.g. ASSERT_TRUE, EXPECT_EQ, etc) eventually call +// this to report their results. The user code should use the +// assertion macros instead of calling this directly. +// L < mutex_ +void UnitTest::AddTestPartResult(TestPartResultType result_type, + const char* file_name, + int line_number, + const internal::String& message, + const internal::String& os_stack_trace) { + Message msg; + msg << message; + + internal::MutexLock lock(&mutex_); + if (impl_->gtest_trace_stack()->size() > 0) { + msg << "\n" << GTEST_NAME << " trace:"; + + for (internal::ListNode* node = + impl_->gtest_trace_stack()->Head(); + node != NULL; + node = node->next()) { + const internal::TraceInfo& trace = node->element(); + msg << "\n" << trace.file << ":" << trace.line << ": " << trace.message; + } + } + + if (os_stack_trace.c_str() != NULL && !os_stack_trace.empty()) { + msg << "\nStack trace:\n" << os_stack_trace; + } + + const TestPartResult result = + TestPartResult(result_type, file_name, line_number, + msg.GetString().c_str()); + impl_->test_part_result_reporter()->ReportTestPartResult(result); + + // If this is a failure and the user wants the debugger to break on + // failures ... + if (result_type != TPRT_SUCCESS && GTEST_FLAG(break_on_failure)) { + // ... then we generate a seg fault. + *static_cast(NULL) = 1; + } +} + +// Creates and adds a property to the current TestResult. If a property matching +// the supplied value already exists, updates its value instead. +void UnitTest::RecordPropertyForCurrentTest(const char* key, + const char* value) { + const internal::TestProperty test_property(key, value); + impl_->current_test_result()->RecordProperty(test_property); +} + +// Runs all tests in this UnitTest object and prints the result. +// Returns 0 if successful, or 1 otherwise. +// +// We don't protect this under mutex_, as we only support calling it +// from the main thread. +int UnitTest::Run() { +#ifdef GTEST_OS_WINDOWS + +#if !defined(_WIN32_WCE) + // SetErrorMode doesn't exist on CE. + if (GTEST_FLAG(catch_exceptions)) { + // The user wants Google Test to catch exceptions thrown by the tests. + + // This lets fatal errors be handled by us, instead of causing pop-ups. + SetErrorMode(SEM_FAILCRITICALERRORS | SEM_NOALIGNMENTFAULTEXCEPT | + SEM_NOGPFAULTERRORBOX | SEM_NOOPENFILEERRORBOX); + } +#endif // _WIN32_WCE + + __try { + return impl_->RunAllTests(); + } __except(internal::UnitTestOptions::GTestShouldProcessSEH( + GetExceptionCode())) { + printf("Exception thrown with code 0x%x.\nFAIL\n", GetExceptionCode()); + fflush(stdout); + return 1; + } + +#else + // We are on Linux or Mac OS. There is no exception of any kind. + + return impl_->RunAllTests(); +#endif // GTEST_OS_WINDOWS +} + +// Returns the TestCase object for the test that's currently running, +// or NULL if no test is running. +// L < mutex_ +const TestCase* UnitTest::current_test_case() const { + internal::MutexLock lock(&mutex_); + return impl_->current_test_case(); +} + +// Returns the TestInfo object for the test that's currently running, +// or NULL if no test is running. +// L < mutex_ +const TestInfo* UnitTest::current_test_info() const { + internal::MutexLock lock(&mutex_); + return impl_->current_test_info(); +} + +// Creates an empty UnitTest. +UnitTest::UnitTest() { + impl_ = new internal::UnitTestImpl(this); +} + +// Destructor of UnitTest. +UnitTest::~UnitTest() { + delete impl_; +} + +// Pushes a trace defined by SCOPED_TRACE() on to the per-thread +// Google Test trace stack. +// L < mutex_ +void UnitTest::PushGTestTrace(const internal::TraceInfo& trace) { + internal::MutexLock lock(&mutex_); + impl_->gtest_trace_stack()->PushFront(trace); +} + +// Pops a trace from the per-thread Google Test trace stack. +// L < mutex_ +void UnitTest::PopGTestTrace() { + internal::MutexLock lock(&mutex_); + impl_->gtest_trace_stack()->PopFront(NULL); +} + +namespace internal { + +UnitTestImpl::UnitTestImpl(UnitTest* parent) + : parent_(parent), + test_cases_(), + last_death_test_case_(NULL), + current_test_case_(NULL), + current_test_info_(NULL), + ad_hoc_test_result_(), + result_printer_(NULL), + os_stack_trace_getter_(NULL), +#ifdef GTEST_HAS_DEATH_TEST + elapsed_time_(0), + internal_run_death_test_flag_(NULL), + death_test_factory_(new DefaultDeathTestFactory) { +#else + elapsed_time_(0) { +#endif // GTEST_HAS_DEATH_TEST + // We do the assignment here instead of in the initializer list, as + // doing that latter causes MSVC to issue a warning about using + // 'this' in initializers. + test_part_result_reporter_ = this; +} + +UnitTestImpl::~UnitTestImpl() { + // Deletes every TestCase. + test_cases_.ForEach(internal::Delete); + + // Deletes every Environment. + environments_.ForEach(internal::Delete); + + // Deletes the current test result printer. + delete result_printer_; + + delete os_stack_trace_getter_; +} + +// A predicate that checks the name of a TestCase against a known +// value. +// +// This is used for implementation of the UnitTest class only. We put +// it in the anonymous namespace to prevent polluting the outer +// namespace. +// +// TestCaseNameIs is copyable. +class TestCaseNameIs { + public: + // Constructor. + explicit TestCaseNameIs(const String& name) + : name_(name) {} + + // Returns true iff the name of test_case matches name_. + bool operator()(const TestCase* test_case) const { + return test_case != NULL && strcmp(test_case->name(), name_.c_str()) == 0; + } + + private: + String name_; +}; + +// Finds and returns a TestCase with the given name. If one doesn't +// exist, creates one and returns it. +// +// Arguments: +// +// test_case_name: name of the test case +// set_up_tc: pointer to the function that sets up the test case +// tear_down_tc: pointer to the function that tears down the test case +TestCase* UnitTestImpl::GetTestCase(const char* test_case_name, + Test::SetUpTestCaseFunc set_up_tc, + Test::TearDownTestCaseFunc tear_down_tc) { + // Can we find a TestCase with the given name? + internal::ListNode* node = test_cases_.FindIf( + TestCaseNameIs(test_case_name)); + + if (node == NULL) { + // No. Let's create one. + TestCase* const test_case = + new TestCase(test_case_name, set_up_tc, tear_down_tc); + + // Is this a death test case? + if (String(test_case_name).EndsWith("DeathTest")) { + // Yes. Inserts the test case after the last death test case + // defined so far. + node = test_cases_.InsertAfter(last_death_test_case_, test_case); + last_death_test_case_ = node; + } else { + // No. Appends to the end of the list. + test_cases_.PushBack(test_case); + node = test_cases_.Last(); + } + } + + // Returns the TestCase found. + return node->element(); +} + +// Helpers for setting up / tearing down the given environment. They +// are for use in the List::ForEach() method. +static void SetUpEnvironment(Environment* env) { env->SetUp(); } +static void TearDownEnvironment(Environment* env) { env->TearDown(); } + +// Runs all tests in this UnitTest object, prints the result, and +// returns 0 if all tests are successful, or 1 otherwise. If any +// exception is thrown during a test on Windows, this test is +// considered to be failed, but the rest of the tests will still be +// run. (We disable exceptions on Linux and Mac OS X, so the issue +// doesn't apply there.) +int UnitTestImpl::RunAllTests() { + // Makes sure InitGoogleTest() was called. + if (!GTestIsInitialized()) { + printf("%s", + "\nThis test program did NOT call ::testing::InitGoogleTest " + "before calling RUN_ALL_TESTS(). Please fix it.\n"); + return 1; + } + + // Lists all the tests and exits if the --gtest_list_tests + // flag was specified. + if (GTEST_FLAG(list_tests)) { + ListAllTests(); + return 0; + } + + // True iff we are in a subprocess for running a thread-safe-style + // death test. + bool in_subprocess_for_death_test = false; + +#ifdef GTEST_HAS_DEATH_TEST + internal_run_death_test_flag_.reset(ParseInternalRunDeathTestFlag()); + in_subprocess_for_death_test = (internal_run_death_test_flag_.get() != NULL); +#endif // GTEST_HAS_DEATH_TEST + + UnitTestEventListenerInterface * const printer = result_printer(); + + // Compares the full test names with the filter to decide which + // tests to run. + const bool has_tests_to_run = FilterTests() > 0; + // True iff at least one test has failed. + bool failed = false; + + // How many times to repeat the tests? We don't want to repeat them + // when we are inside the subprocess of a death test. + const int repeat = in_subprocess_for_death_test ? 1 : GTEST_FLAG(repeat); + // Repeats forever if the repeat count is negative. + const bool forever = repeat < 0; + for (int i = 0; forever || i != repeat; i++) { + if (repeat != 1) { + printf("\nRepeating all tests (iteration %d) . . .\n\n", i + 1); + } + + // Tells the unit test event listener that the tests are about to + // start. + printer->OnUnitTestStart(parent_); + + const TimeInMillis start = GetTimeInMillis(); + + // Runs each test case if there is at least one test to run. + if (has_tests_to_run) { + // Sets up all environments beforehand. + printer->OnGlobalSetUpStart(parent_); + environments_.ForEach(SetUpEnvironment); + printer->OnGlobalSetUpEnd(parent_); + + // Runs the tests only if there was no fatal failure during global + // set-up. + if (!Test::HasFatalFailure()) { + test_cases_.ForEach(TestCase::RunTestCase); + } + + // Tears down all environments in reverse order afterwards. + printer->OnGlobalTearDownStart(parent_); + environments_in_reverse_order_.ForEach(TearDownEnvironment); + printer->OnGlobalTearDownEnd(parent_); + } + + elapsed_time_ = GetTimeInMillis() - start; + + // Tells the unit test event listener that the tests have just + // finished. + printer->OnUnitTestEnd(parent_); + + // Gets the result and clears it. + if (!Passed()) { + failed = true; + } + ClearResult(); + } + + // Returns 0 if all tests passed, or 1 other wise. + return failed ? 1 : 0; +} + +// Compares the name of each test with the user-specified filter to +// decide whether the test should be run, then records the result in +// each TestCase and TestInfo object. +// Returns the number of tests that should run. +int UnitTestImpl::FilterTests() { + int num_runnable_tests = 0; + for (const internal::ListNode *test_case_node = + test_cases_.Head(); + test_case_node != NULL; + test_case_node = test_case_node->next()) { + TestCase * const test_case = test_case_node->element(); + const String &test_case_name = test_case->name(); + test_case->set_should_run(false); + + for (const internal::ListNode *test_info_node = + test_case->test_info_list().Head(); + test_info_node != NULL; + test_info_node = test_info_node->next()) { + TestInfo * const test_info = test_info_node->element(); + const String test_name(test_info->name()); + // A test is disabled if test case name or test name matches + // kDisableTestPattern. + const bool is_disabled = + internal::UnitTestOptions::PatternMatchesString(kDisableTestPattern, + test_case_name.c_str()) || + internal::UnitTestOptions::PatternMatchesString(kDisableTestPattern, + test_name.c_str()); + test_info->impl()->set_is_disabled(is_disabled); + + const bool should_run = !is_disabled && + internal::UnitTestOptions::FilterMatchesTest(test_case_name, + test_name); + test_info->impl()->set_should_run(should_run); + test_case->set_should_run(test_case->should_run() || should_run); + if (should_run) { + num_runnable_tests++; + } + } + } + return num_runnable_tests; +} + +// Lists all tests by name. +void UnitTestImpl::ListAllTests() { + for (const internal::ListNode* test_case_node = test_cases_.Head(); + test_case_node != NULL; + test_case_node = test_case_node->next()) { + const TestCase* const test_case = test_case_node->element(); + + // Prints the test case name following by an indented list of test nodes. + printf("%s.\n", test_case->name()); + + for (const internal::ListNode* test_info_node = + test_case->test_info_list().Head(); + test_info_node != NULL; + test_info_node = test_info_node->next()) { + const TestInfo* const test_info = test_info_node->element(); + + printf(" %s\n", test_info->name()); + } + } + fflush(stdout); +} + +// Sets the unit test result printer. +// +// Does nothing if the input and the current printer object are the +// same; otherwise, deletes the old printer object and makes the +// input the current printer. +void UnitTestImpl::set_result_printer( + UnitTestEventListenerInterface* result_printer) { + if (result_printer_ != result_printer) { + delete result_printer_; + result_printer_ = result_printer; + } +} + +// Returns the current unit test result printer if it is not NULL; +// otherwise, creates an appropriate result printer, makes it the +// current printer, and returns it. +UnitTestEventListenerInterface* UnitTestImpl::result_printer() { + if (result_printer_ != NULL) { + return result_printer_; + } + +#ifdef GTEST_HAS_DEATH_TEST + if (internal_run_death_test_flag_.get() != NULL) { + result_printer_ = new NullUnitTestResultPrinter; + return result_printer_; + } +#endif // GTEST_HAS_DEATH_TEST + + UnitTestEventsRepeater *repeater = new UnitTestEventsRepeater; + const String& output_format = internal::UnitTestOptions::GetOutputFormat(); + if (output_format == "xml") { + repeater->AddListener(new XmlUnitTestResultPrinter( + internal::UnitTestOptions::GetOutputFile().c_str())); + } else if (output_format != "") { + printf("WARNING: unrecognized output format \"%s\" ignored.\n", + output_format.c_str()); + fflush(stdout); + } + repeater->AddListener(new PrettyUnitTestResultPrinter); + result_printer_ = repeater; + return result_printer_; +} + +// Sets the OS stack trace getter. +// +// Does nothing if the input and the current OS stack trace getter are +// the same; otherwise, deletes the old getter and makes the input the +// current getter. +void UnitTestImpl::set_os_stack_trace_getter( + OsStackTraceGetterInterface* getter) { + if (os_stack_trace_getter_ != getter) { + delete os_stack_trace_getter_; + os_stack_trace_getter_ = getter; + } +} + +// Returns the current OS stack trace getter if it is not NULL; +// otherwise, creates an OsStackTraceGetter, makes it the current +// getter, and returns it. +OsStackTraceGetterInterface* UnitTestImpl::os_stack_trace_getter() { + if (os_stack_trace_getter_ == NULL) { + os_stack_trace_getter_ = new OsStackTraceGetter; + } + + return os_stack_trace_getter_; +} + +// Returns the TestResult for the test that's currently running, or +// the TestResult for the ad hoc test if no test is running. +internal::TestResult* UnitTestImpl::current_test_result() { + return current_test_info_ ? + current_test_info_->impl()->result() : &ad_hoc_test_result_; +} + +// TestInfoImpl constructor. +TestInfoImpl::TestInfoImpl(TestInfo* parent, + const char* test_case_name, + const char* name, + TypeId fixture_class_id, + TestMaker maker) : + parent_(parent), + test_case_name_(String(test_case_name)), + name_(String(name)), + fixture_class_id_(fixture_class_id), + should_run_(false), + is_disabled_(false), + maker_(maker) { +} + +// TestInfoImpl destructor. +TestInfoImpl::~TestInfoImpl() { +} + +} // namespace internal + +namespace internal { + +// Parses a string as a command line flag. The string should have +// the format "--flag=value". When def_optional is true, the "=value" +// part can be omitted. +// +// Returns the value of the flag, or NULL if the parsing failed. +const char* ParseFlagValue(const char* str, + const char* flag, + bool def_optional) { + // str and flag must not be NULL. + if (str == NULL || flag == NULL) return NULL; + + // The flag must start with "--" followed by GTEST_FLAG_PREFIX. + const String flag_str = String::Format("--%s%s", GTEST_FLAG_PREFIX, flag); + const size_t flag_len = flag_str.GetLength(); + if (strncmp(str, flag_str.c_str(), flag_len) != 0) return NULL; + + // Skips the flag name. + const char* flag_end = str + flag_len; + + // When def_optional is true, it's OK to not have a "=value" part. + if (def_optional && (flag_end[0] == '\0')) { + return flag_end; + } + + // If def_optional is true and there are more characters after the + // flag name, or if def_optional is false, there must be a '=' after + // the flag name. + if (flag_end[0] != '=') return NULL; + + // Returns the string after "=". + return flag_end + 1; +} + +// Parses a string for a bool flag, in the form of either +// "--flag=value" or "--flag". +// +// In the former case, the value is taken as true as long as it does +// not start with '0', 'f', or 'F'. +// +// In the latter case, the value is taken as true. +// +// On success, stores the value of the flag in *value, and returns +// true. On failure, returns false without changing *value. +bool ParseBoolFlag(const char* str, const char* flag, bool* value) { + // Gets the value of the flag as a string. + const char* const value_str = ParseFlagValue(str, flag, true); + + // Aborts if the parsing failed. + if (value_str == NULL) return false; + + // Converts the string value to a bool. + *value = !(*value_str == '0' || *value_str == 'f' || *value_str == 'F'); + return true; +} + +// 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 +// true. On failure, returns false without changing *value. +bool ParseInt32Flag(const char* str, const char* flag, Int32* value) { + // Gets the value of the flag as a string. + const char* const value_str = ParseFlagValue(str, flag, false); + + // Aborts if the parsing failed. + if (value_str == NULL) return false; + + // Sets *value to the value of the flag. + return ParseInt32(Message() << "The value of flag --" << flag, + value_str, value); +} + +// Parses a string for a string flag, in the form of +// "--flag=value". +// +// On success, stores the value of the flag in *value, and returns +// true. On failure, returns false without changing *value. +bool ParseStringFlag(const char* str, const char* flag, String* value) { + // Gets the value of the flag as a string. + const char* const value_str = ParseFlagValue(str, flag, false); + + // Aborts if the parsing failed. + if (value_str == NULL) return false; + + // Sets *value to the value of the flag. + *value = value_str; + return true; +} + +// The internal implementation of InitGoogleTest(). +// +// The type parameter CharType can be instantiated to either char or +// wchar_t. +template +void InitGoogleTestImpl(int* argc, CharType** argv) { + g_parse_gtest_flags_called = true; + if (*argc <= 0) return; + +#ifdef GTEST_HAS_DEATH_TEST + g_argvs.clear(); + for (int i = 0; i != *argc; i++) { + g_argvs.push_back(StreamableToString(argv[i])); + } +#endif // GTEST_HAS_DEATH_TEST + + for (int i = 1; i != *argc; i++) { + const String arg_string = StreamableToString(argv[i]); + const char* const arg = arg_string.c_str(); + + using internal::ParseBoolFlag; + using internal::ParseInt32Flag; + using internal::ParseStringFlag; + + // Do we see a Google Test flag? + if (ParseBoolFlag(arg, kBreakOnFailureFlag, + >EST_FLAG(break_on_failure)) || + ParseBoolFlag(arg, kCatchExceptionsFlag, + >EST_FLAG(catch_exceptions)) || + ParseStringFlag(arg, kColorFlag, >EST_FLAG(color)) || + ParseStringFlag(arg, kDeathTestStyleFlag, + >EST_FLAG(death_test_style)) || + ParseStringFlag(arg, kFilterFlag, >EST_FLAG(filter)) || + ParseStringFlag(arg, kInternalRunDeathTestFlag, + >EST_FLAG(internal_run_death_test)) || + ParseBoolFlag(arg, kListTestsFlag, >EST_FLAG(list_tests)) || + ParseStringFlag(arg, kOutputFlag, >EST_FLAG(output)) || + ParseInt32Flag(arg, kRepeatFlag, >EST_FLAG(repeat)) + ) { + // Yes. Shift the remainder of the argv list left by one. Note + // that argv has (*argc + 1) elements, the last one always being + // NULL. The following loop moves the trailing NULL element as + // well. + for (int j = i; j != *argc; j++) { + argv[j] = argv[j + 1]; + } + + // Decrements the argument count. + (*argc)--; + + // We also need to decrement the iterator as we just removed + // an element. + i--; + } + } +} + +} // namespace internal + +// Initializes Google Test. This must be called before calling +// RUN_ALL_TESTS(). In particular, it parses a command line for the +// flags that Google Test recognizes. Whenever a Google Test flag is +// seen, it is removed from argv, and *argc is decremented. +// +// No value is returned. Instead, the Google Test flag variables are +// updated. +void InitGoogleTest(int* argc, char** argv) { + internal::g_executable_path = argv[0]; + internal::InitGoogleTestImpl(argc, argv); +} + +// This overloaded version can be used in Windows programs compiled in +// UNICODE mode. +#ifdef GTEST_OS_WINDOWS +void InitGoogleTest(int* argc, wchar_t** argv) { + // g_executable_path uses normal characters rather than wide chars, so call + // StreamableToString to convert argv[0] to normal characters (utf8 encoding). + internal::g_executable_path = internal::StreamableToString(argv[0]); + internal::InitGoogleTestImpl(argc, argv); +} +#endif // GTEST_OS_WINDOWS + +} // namespace testing diff --git a/src/gtest_main.cc b/src/gtest_main.cc new file mode 100644 index 00000000..d20c02fd --- /dev/null +++ b/src/gtest_main.cc @@ -0,0 +1,39 @@ +// Copyright 2006, 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. + +#include + +#include + +int main(int argc, char **argv) { + std::cout << "Running main() from gtest_main.cc\n"; + + testing::InitGoogleTest(&argc, argv); + return RUN_ALL_TESTS(); +} -- cgit v1.2.3 From b75872639683cf572253f20863982324b113205e Mon Sep 17 00:00:00 2001 From: shiqian Date: Wed, 23 Jul 2008 20:28:27 +0000 Subject: Fixes some style nits; also fixes minor bugs in gtest-death-test.cc. --- src/gtest-death-test.cc | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'src') diff --git a/src/gtest-death-test.cc b/src/gtest-death-test.cc index 09fdd3ff..919fb53a 100644 --- a/src/gtest-death-test.cc +++ b/src/gtest-death-test.cc @@ -47,7 +47,7 @@ // prevent a user from accidentally including gtest-internal-inl.h in // his code. #define GTEST_IMPLEMENTATION -#include "gtest-internal-inl.h" +#include "src/gtest-internal-inl.h" #undef GTEST_IMPLEMENTATION namespace testing { @@ -688,7 +688,7 @@ static void SplitString(const ::std::string& str, char delimiter, ::std::vector< ::std::string> parsed; ::std::string::size_type pos = 0; while (true) { - const ::std::string::size_type colon = str.find(':', pos); + const ::std::string::size_type colon = str.find(delimiter, pos); if (colon == ::std::string::npos) { parsed.push_back(str.substr(pos)); break; -- cgit v1.2.3 From 253d2bc5760533c136f5b1b34b8c6f03d79fc538 Mon Sep 17 00:00:00 2001 From: shiqian Date: Wed, 23 Jul 2008 20:32:11 +0000 Subject: Makes the output understandable by VS when compiled by MSVC. --- src/gtest.cc | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) (limited to 'src') diff --git a/src/gtest.cc b/src/gtest.cc index 235ec5ad..57ff15a6 100644 --- a/src/gtest.cc +++ b/src/gtest.cc @@ -2149,7 +2149,11 @@ static const char * TestPartResultTypeToString(TestPartResultType type) { case TPRT_NONFATAL_FAILURE: case TPRT_FATAL_FAILURE: - return "Failure"; +#ifdef _MSC_VER + return "error: "; +#else + return "Failure\n"; +#endif } return "Unknown result type"; @@ -2162,9 +2166,13 @@ static void PrintTestPartResult( printf("%s", file_name == NULL ? "unknown file" : file_name); if (test_part_result.line_number() >= 0) { +#ifdef _MSC_VER + printf("(%d)", test_part_result.line_number()); +#else printf(":%d", test_part_result.line_number()); +#endif } - printf(": %s\n", TestPartResultTypeToString(test_part_result.type())); + printf(": %s", TestPartResultTypeToString(test_part_result.type())); printf("%s\n", test_part_result.message()); fflush(stdout); } -- cgit v1.2.3 From 15cbe5f70adaade1a8a11afc37601fc6606e7e0d Mon Sep 17 00:00:00 2001 From: shiqian Date: Fri, 25 Jul 2008 04:06:16 +0000 Subject: Adds --gtest_print_test for printing the elapsed time of tests. --- src/gtest-internal-inl.h | 7 ++++++- src/gtest.cc | 36 ++++++++++++++++++++++++++++++++++-- 2 files changed, 40 insertions(+), 3 deletions(-) (limited to 'src') diff --git a/src/gtest-internal-inl.h b/src/gtest-internal-inl.h index 2a7d71cb..5546a77a 100644 --- a/src/gtest-internal-inl.h +++ b/src/gtest-internal-inl.h @@ -70,6 +70,7 @@ GTEST_DECLARE_string(color); GTEST_DECLARE_string(filter); GTEST_DECLARE_bool(list_tests); GTEST_DECLARE_string(output); +GTEST_DECLARE_bool(print_time); GTEST_DECLARE_int32(repeat); GTEST_DECLARE_int32(stack_trace_depth); GTEST_DECLARE_bool(show_internal_stack_frames); @@ -79,10 +80,11 @@ namespace internal { // Names of the flags (needed for parsing Google Test flags). const char kBreakOnFailureFlag[] = "break_on_failure"; const char kCatchExceptionsFlag[] = "catch_exceptions"; +const char kColorFlag[] = "color"; const char kFilterFlag[] = "filter"; const char kListTestsFlag[] = "list_tests"; const char kOutputFlag[] = "output"; -const char kColorFlag[] = "color"; +const char kPrintTimeFlag[] = "print_time"; const char kRepeatFlag[] = "repeat"; // This class saves the values of all Google Test flags in its c'tor, and @@ -99,6 +101,7 @@ class GTestFlagSaver { internal_run_death_test_ = GTEST_FLAG(internal_run_death_test); list_tests_ = GTEST_FLAG(list_tests); output_ = GTEST_FLAG(output); + print_time_ = GTEST_FLAG(print_time); repeat_ = GTEST_FLAG(repeat); } @@ -112,6 +115,7 @@ class GTestFlagSaver { GTEST_FLAG(internal_run_death_test) = internal_run_death_test_; GTEST_FLAG(list_tests) = list_tests_; GTEST_FLAG(output) = output_; + GTEST_FLAG(print_time) = print_time_; GTEST_FLAG(repeat) = repeat_; } private: @@ -124,6 +128,7 @@ class GTestFlagSaver { String internal_run_death_test_; bool list_tests_; String output_; + bool print_time_; bool pretty_; internal::Int32 repeat_; } GTEST_ATTRIBUTE_UNUSED; diff --git a/src/gtest.cc b/src/gtest.cc index 57ff15a6..5e4c5880 100644 --- a/src/gtest.cc +++ b/src/gtest.cc @@ -169,6 +169,12 @@ GTEST_DEFINE_string( "executable's name and, if necessary, made unique by adding " "digits."); +GTEST_DEFINE_bool( + print_time, + internal::BoolFromGTestEnv("print_time", false), + "True iff " GTEST_NAME + " should display elapsed time in text output."); + GTEST_DEFINE_int32( repeat, internal::Int32FromGTestEnv("repeat", 1), @@ -2303,6 +2309,7 @@ class PrettyUnitTestResultPrinter : public UnitTestEventListenerInterface { virtual void OnUnitTestStart(const UnitTest * unit_test); virtual void OnGlobalSetUpStart(const UnitTest*); virtual void OnTestCaseStart(const TestCase * test_case); + virtual void OnTestCaseEnd(const TestCase * test_case); virtual void OnTestStart(const TestInfo * test_info); virtual void OnNewTestPartResult(const TestPartResult * result); virtual void OnTestEnd(const TestInfo * test_info); @@ -2349,6 +2356,20 @@ void PrettyUnitTestResultPrinter::OnTestCaseStart( fflush(stdout); } +void PrettyUnitTestResultPrinter::OnTestCaseEnd( + const TestCase * test_case) { + if (!GTEST_FLAG(print_time)) return; + + test_case_name_ = test_case->name(); + const internal::String counts = + FormatCountableNoun(test_case->test_to_run_count(), "test", "tests"); + ColoredPrintf(COLOR_GREEN, "[----------] "); + printf("%s from %s (%s ms total)\n\n", + counts.c_str(), test_case_name_.c_str(), + internal::StreamableToString(test_case->elapsed_time()).c_str()); + fflush(stdout); +} + void PrettyUnitTestResultPrinter::OnTestStart(const TestInfo * test_info) { ColoredPrintf(COLOR_GREEN, "[ RUN ] "); PrintTestName(test_case_name_.c_str(), test_info->name()); @@ -2363,7 +2384,12 @@ void PrettyUnitTestResultPrinter::OnTestEnd(const TestInfo * test_info) { ColoredPrintf(COLOR_RED, "[ FAILED ] "); } PrintTestName(test_case_name_.c_str(), test_info->name()); - printf("\n"); + if (GTEST_FLAG(print_time)) { + printf(" (%s ms)\n", internal::StreamableToString( + test_info->result()->elapsed_time()).c_str()); + } else { + printf("\n"); + } fflush(stdout); } @@ -2420,9 +2446,14 @@ void PrettyUnitTestResultPrinter::OnUnitTestEnd( const internal::UnitTestImpl* const impl = unit_test->impl(); ColoredPrintf(COLOR_GREEN, "[==========] "); - printf("%s from %s ran.\n", + printf("%s from %s ran.", FormatTestCount(impl->test_to_run_count()).c_str(), FormatTestCaseCount(impl->test_case_to_run_count()).c_str()); + if (GTEST_FLAG(print_time)) { + printf(" (%s ms total)", + internal::StreamableToString(impl->elapsed_time()).c_str()); + } + printf("\n"); ColoredPrintf(COLOR_GREEN, "[ PASSED ] "); printf("%s.\n", FormatTestCount(impl->successful_test_count()).c_str()); @@ -3505,6 +3536,7 @@ void InitGoogleTestImpl(int* argc, CharType** argv) { >EST_FLAG(internal_run_death_test)) || ParseBoolFlag(arg, kListTestsFlag, >EST_FLAG(list_tests)) || ParseStringFlag(arg, kOutputFlag, >EST_FLAG(output)) || + ParseBoolFlag(arg, kPrintTimeFlag, >EST_FLAG(print_time)) || ParseInt32Flag(arg, kRepeatFlag, >EST_FLAG(repeat)) ) { // Yes. Shift the remainder of the argv list left by one. Note -- cgit v1.2.3 From dc6ee0e36df772499e5a86ee638f5aae160c1023 Mon Sep 17 00:00:00 2001 From: shiqian Date: Tue, 29 Jul 2008 23:15:28 +0000 Subject: Makes death tests create temporary files in /tmp instead of the current folder. --- src/gtest-port.cc | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) (limited to 'src') diff --git a/src/gtest-port.cc b/src/gtest-port.cc index 2a4d37a4..efc40ca7 100644 --- a/src/gtest-port.cc +++ b/src/gtest-port.cc @@ -96,7 +96,10 @@ class CapturedStderr { CapturedStderr() { uncaptured_fd_ = dup(STDERR_FILENO); - char name_template[] = "captured_stderr.XXXXXX"; + // There's no guarantee that a test has write access to the + // current directory, so we create the temporary file in the /tmp + // directory instead. + char name_template[] = "/tmp/captured_stderr.XXXXXX"; const int captured_fd = mkstemp(name_template); filename_ = name_template; fflush(NULL); -- cgit v1.2.3 From bf9b4b48dc65adc2edd44175f77b4a7363c59234 Mon Sep 17 00:00:00 2001 From: shiqian Date: Thu, 31 Jul 2008 18:34:08 +0000 Subject: Makes gtest work on Windows Mobile and Symbian. By Mika Raento. --- src/gtest-death-test.cc | 2 ++ src/gtest-filepath.cc | 42 +++++++++++++++++++++++++++++++--- src/gtest-port.cc | 17 ++++++++++++-- src/gtest.cc | 60 ++++++++++++++++++++++++++++++++++++------------- 4 files changed, 101 insertions(+), 20 deletions(-) (limited to 'src') diff --git a/src/gtest-death-test.cc b/src/gtest-death-test.cc index 919fb53a..cb0d3cd7 100644 --- a/src/gtest-death-test.cc +++ b/src/gtest-death-test.cc @@ -34,9 +34,11 @@ #include #include +#ifdef GTEST_HAS_DEATH_TEST #include #include #include +#endif // GTEST_HAS_DEATH_TEST #include #include diff --git a/src/gtest-filepath.cc b/src/gtest-filepath.cc index 2fba96ea..3c32c705 100644 --- a/src/gtest-filepath.cc +++ b/src/gtest-filepath.cc @@ -32,12 +32,15 @@ #include #include -#ifdef _WIN32 +#ifdef _WIN32_WCE +#include +#elif defined(_WIN32) #include #include -#endif // _WIN32 - #include +#else +#include +#endif // _WIN32_WCE or _WIN32 #include @@ -47,7 +50,16 @@ namespace internal { #ifdef GTEST_OS_WINDOWS const char kPathSeparator = '\\'; const char kPathSeparatorString[] = "\\"; +#ifdef _WIN32_WCE +// Windows CE doesn't have a current directory. You should not use +// the current directory in tests on Windows CE, but this at least +// provides a reasonable fallback. +const char kCurrentDirectoryString[] = "\\"; +// Windows CE doesn't define INVALID_FILE_ATTRIBUTES +const DWORD kInvalidFileAttributes = 0xffffffff; +#else const char kCurrentDirectoryString[] = ".\\"; +#endif // _WIN32_WCE #else const char kPathSeparator = '/'; const char kPathSeparatorString[] = "/"; @@ -112,8 +124,15 @@ FilePath FilePath::MakeFileName(const FilePath& directory, // either a file, directory, or whatever. bool FilePath::FileOrDirectoryExists() const { #ifdef GTEST_OS_WINDOWS +#ifdef _WIN32_WCE + LPCWSTR unicode = String::AnsiToUtf16(pathname_.c_str()); + const DWORD attributes = GetFileAttributes(unicode); + delete [] unicode; + return attributes != kInvalidFileAttributes; +#else struct _stat file_stat = {}; return _stat(pathname_.c_str(), &file_stat) == 0; +#endif // _WIN32_WCE #else struct stat file_stat = {}; return stat(pathname_.c_str(), &file_stat) == 0; @@ -126,9 +145,19 @@ bool FilePath::DirectoryExists() const { bool result = false; #ifdef _WIN32 FilePath removed_sep(this->RemoveTrailingPathSeparator()); +#ifdef _WIN32_WCE + LPCWSTR unicode = String::AnsiToUtf16(removed_sep.c_str()); + const DWORD attributes = GetFileAttributes(unicode); + delete [] unicode; + if ((attributes != kInvalidFileAttributes) && + (attributes & FILE_ATTRIBUTE_DIRECTORY)) { + result = true; + } +#else struct _stat file_stat = {}; result = _stat(removed_sep.c_str(), &file_stat) == 0 && (_S_IFDIR & file_stat.st_mode) != 0; +#endif // _WIN32_WCE #else struct stat file_stat = {}; result = stat(pathname_.c_str(), &file_stat) == 0 && @@ -185,7 +214,14 @@ bool FilePath::CreateDirectoriesRecursively() const { // exist. Not named "CreateDirectory" because that's a macro on Windows. bool FilePath::CreateFolder() const { #ifdef _WIN32 +#ifdef _WIN32_WCE + FilePath removed_sep(this->RemoveTrailingPathSeparator()); + LPCWSTR unicode = String::AnsiToUtf16(removed_sep.c_str()); + int result = CreateDirectory(unicode, NULL) ? 0 : -1; + delete [] unicode; +#else int result = _mkdir(pathname_.c_str()); +#endif // !WIN32_WCE #else int result = mkdir(pathname_.c_str(), 0777); #endif // _WIN32 diff --git a/src/gtest-port.cc b/src/gtest-port.cc index efc40ca7..b2871b8b 100644 --- a/src/gtest-port.cc +++ b/src/gtest-port.cc @@ -32,16 +32,22 @@ #include #include +#include +#include + #ifdef GTEST_HAS_DEATH_TEST #include #endif // GTEST_HAS_DEATH_TEST -#include -#include + +#ifdef _WIN32_WCE +#include // For TerminateProcess() +#endif // _WIN32_WCE #include #include #include + namespace testing { namespace internal { @@ -194,6 +200,13 @@ const ::std::vector& GetArgvs() { return g_argvs; } #endif // GTEST_HAS_DEATH_TEST +#ifdef _WIN32_WCE +void abort() { + DebugBreak(); + TerminateProcess(GetCurrentProcess(), 1); +} +#endif // _WIN32_WCE + // Returns the name of the environment variable corresponding to the // given flag. For example, FlagToEnvVar("foo") will return // "GTEST_FOO" in the open-source version. diff --git a/src/gtest.cc b/src/gtest.cc index 5e4c5880..720341b0 100644 --- a/src/gtest.cc +++ b/src/gtest.cc @@ -235,16 +235,6 @@ static bool ShouldRunTestCase(const TestCase* test_case) { return test_case->should_run(); } -#ifdef _WIN32_WCE -// Windows CE has no C library. The abort() function is used in -// several places in Google Test. This implementation provides a reasonable -// imitation of standard behaviour. -static void abort() { - DebugBreak(); - TerminateProcess(GetCurrentProcess(), 1); -} -#endif // _WIN32_WCE - // AssertHelper constructor. AssertHelper::AssertHelper(TestPartResultType type, const char* file, int line, const char* message) @@ -465,7 +455,7 @@ void TestPartResultArray::Append(const TestPartResult& result) { const TestPartResult& TestPartResultArray::GetTestPartResult(int index) const { if (index < 0 || index >= size()) { printf("\nInvalid index (%d) into TestPartResultArray.\n", index); - abort(); + internal::abort(); } const internal::ListNode* p = list_->Head(); @@ -739,6 +729,42 @@ const char * String::CloneCString(const char* c_str) { NULL : CloneString(c_str, strlen(c_str)); } +#ifdef _WIN32_WCE +// Creates a UTF-16 wide string from the given ANSI string, allocating +// memory using new. The caller is responsible for deleting the return +// value using delete[]. Returns the wide string, or NULL if the +// input is NULL. +LPCWSTR String::AnsiToUtf16(const char* ansi) { + if (!ansi) return NULL; + const int length = strlen(ansi); + const int unicode_length = + MultiByteToWideChar(CP_ACP, 0, ansi, length, + NULL, 0); + WCHAR* unicode = new WCHAR[unicode_length + 1]; + MultiByteToWideChar(CP_ACP, 0, ansi, length, + unicode, unicode_length); + unicode[unicode_length] = 0; + return unicode; +} + +// Creates an ANSI string from the given wide string, allocating +// memory using new. The caller is responsible for deleting the return +// value using delete[]. Returns the ANSI string, or NULL if the +// input is NULL. +const char* String::Utf16ToAnsi(LPCWSTR utf16_str) { + if (!utf16_str) return NULL; + const int ansi_length = + WideCharToMultiByte(CP_ACP, 0, utf16_str, -1, + NULL, 0, NULL, NULL); + char* ansi = new char[ansi_length + 1]; + WideCharToMultiByte(CP_ACP, 0, utf16_str, -1, + ansi, ansi_length, NULL, NULL); + ansi[ansi_length] = 0; + return ansi; +} + +#endif // _WIN32_WCE + // Compares two C strings. Returns true iff they have the same content. // // Unlike strcmp(), this function can handle NULL argument(s). A NULL @@ -2193,7 +2219,7 @@ enum GTestColor { COLOR_YELLOW }; -#ifdef _WIN32 +#if defined(_WIN32) && !defined(_WIN32_WCE) // Returns the character attribute for the given color. WORD GetColorAttribute(GTestColor color) { @@ -2217,7 +2243,7 @@ const char* GetAnsiColorCode(GTestColor color) { return NULL; } -#endif // _WIN32 +#endif // _WIN32 && !_WIN32_WCE // Returns true iff Google Test should use colors in the output. bool ShouldUseColor(bool stdout_is_tty) { @@ -2256,7 +2282,11 @@ void ColoredPrintf(GTestColor color, const char* fmt, ...) { va_list args; va_start(args, fmt); +#ifdef _WIN32_WCE + static const bool use_color = false; +#else static const bool use_color = ShouldUseColor(isatty(fileno(stdout)) != 0); +#endif // !_WIN32_WCE // The '!= 0' comparison is necessary to satisfy MSVC 7.1. if (!use_color) { @@ -2265,7 +2295,7 @@ void ColoredPrintf(GTestColor color, const char* fmt, ...) { return; } -#ifdef _WIN32 +#if defined(_WIN32) && !defined(_WIN32_WCE) const HANDLE stdout_handle = GetStdHandle(STD_OUTPUT_HANDLE); // Gets the current text color. @@ -2283,7 +2313,7 @@ void ColoredPrintf(GTestColor color, const char* fmt, ...) { printf("\033[0;3%sm", GetAnsiColorCode(color)); vprintf(fmt, args); printf("\033[m"); // Resets the terminal to default. -#endif // _WIN32 +#endif // _WIN32 && !_WIN32_WCE va_end(args); } -- cgit v1.2.3 From d5f13d4a257b6bfc43068f3a918989cf89af75ec Mon Sep 17 00:00:00 2001 From: shiqian Date: Wed, 6 Aug 2008 21:44:19 +0000 Subject: Changes test creation functions to factories. By Vlad Losev. --- src/gtest-internal-inl.h | 5 +++-- src/gtest.cc | 26 +++++++++++++++----------- 2 files changed, 18 insertions(+), 13 deletions(-) (limited to 'src') diff --git a/src/gtest-internal-inl.h b/src/gtest-internal-inl.h index 5546a77a..77571918 100644 --- a/src/gtest-internal-inl.h +++ b/src/gtest-internal-inl.h @@ -542,7 +542,7 @@ class TestInfoImpl { public: TestInfoImpl(TestInfo* parent, const char* test_case_name, const char* name, TypeId fixture_class_id, - TestMaker maker); + internal::TestFactoryBase* factory); ~TestInfoImpl(); // Returns true if this test should run. @@ -595,7 +595,8 @@ class TestInfoImpl { const TypeId fixture_class_id_; // ID of the test fixture class bool should_run_; // True iff this test should run bool is_disabled_; // True iff this test is disabled - const TestMaker maker_; // The function that creates the test object + internal::TestFactoryBase* const factory_; // The factory that creates + // the test object // This field is mutable and needs to be reset before running the // test for the second time. diff --git a/src/gtest.cc b/src/gtest.cc index 720341b0..a0a05208 100644 --- a/src/gtest.cc +++ b/src/gtest.cc @@ -1882,13 +1882,14 @@ bool Test::HasFatalFailure() { // class TestInfo -// Constructs a TestInfo object. +// Constructs a TestInfo object. It assumes ownership of the test factory +// object via impl_. TestInfo::TestInfo(const char* test_case_name, const char* name, internal::TypeId fixture_class_id, - TestMaker maker) { + internal::TestFactoryBase* factory) { impl_ = new internal::TestInfoImpl(this, test_case_name, name, - fixture_class_id, maker); + fixture_class_id, factory); } // Destructs a TestInfo object. @@ -1905,16 +1906,17 @@ TestInfo::~TestInfo() { // name: name of the test // set_up_tc: pointer to the function that sets up the test case // tear_down_tc: pointer to the function that tears down the test case -// maker: pointer to the function that creates a test object +// factory factory object that creates a test object. The new +// TestInfo instance assumes ownership of the factory object. TestInfo* TestInfo::MakeAndRegisterInstance( const char* test_case_name, const char* name, internal::TypeId fixture_class_id, Test::SetUpTestCaseFunc set_up_tc, Test::TearDownTestCaseFunc tear_down_tc, - TestMaker maker) { + internal::TestFactoryBase* factory) { TestInfo* const test_info = - new TestInfo(test_case_name, name, fixture_class_id, maker); + new TestInfo(test_case_name, name, fixture_class_id, factory); internal::GetUnitTestImpl()->AddTestInfo(set_up_tc, tear_down_tc, test_info); return test_info; } @@ -2007,7 +2009,7 @@ void TestInfoImpl::Run() { __try { // Creates the test object. - test = (*maker_)(); + test = factory_->CreateTest(); } __except(internal::UnitTestOptions::GTestShouldProcessSEH( GetExceptionCode())) { AddExceptionThrownFailure(GetExceptionCode(), @@ -2022,7 +2024,7 @@ void TestInfoImpl::Run() { // exception-safe. // Creates the test object. - Test* test = (*maker_)(); + Test* test = factory_->CreateTest(); #endif // GTEST_OS_WINDOWS // Runs the test only if the constructor of the test fixture didn't @@ -3417,23 +3419,25 @@ internal::TestResult* UnitTestImpl::current_test_result() { current_test_info_->impl()->result() : &ad_hoc_test_result_; } -// TestInfoImpl constructor. +// TestInfoImpl constructor. The new instance assumes ownership of the test +// factory opbject. TestInfoImpl::TestInfoImpl(TestInfo* parent, const char* test_case_name, const char* name, TypeId fixture_class_id, - TestMaker maker) : + internal::TestFactoryBase* factory) : parent_(parent), test_case_name_(String(test_case_name)), name_(String(name)), fixture_class_id_(fixture_class_id), should_run_(false), is_disabled_(false), - maker_(maker) { + factory_(factory) { } // TestInfoImpl destructor. TestInfoImpl::~TestInfoImpl() { + delete factory_; } } // namespace internal -- cgit v1.2.3 From 0c5a66245b8c5939b36b2aad6f4d5ab89b724b1a Mon Sep 17 00:00:00 2001 From: vladlosev Date: Mon, 25 Aug 2008 23:11:54 +0000 Subject: Implement wide->UTF-8 string conversion more correctly --- src/gtest-internal-inl.h | 26 +++++++- src/gtest.cc | 163 ++++++++++++++++++++++++++++++++++++----------- 2 files changed, 149 insertions(+), 40 deletions(-) (limited to 'src') diff --git a/src/gtest-internal-inl.h b/src/gtest-internal-inl.h index 77571918..2633d692 100644 --- a/src/gtest-internal-inl.h +++ b/src/gtest-internal-inl.h @@ -133,8 +133,30 @@ class GTestFlagSaver { internal::Int32 repeat_; } GTEST_ATTRIBUTE_UNUSED; -// Converts a Unicode code-point to its UTF-8 encoding. -String ToUtf8String(wchar_t wchar); +// Converts a Unicode code point to a narrow string in UTF-8 encoding. +// code_point parameter is of type UInt32 because wchar_t may not be +// wide enough to contain a code point. +// The output buffer str must containt at least 32 characters. +// The function returns the address of the output buffer. +// If the code_point is not a valid Unicode code point +// (i.e. outside of Unicode range U+0 to U+10FFFF) it will be output +// as '(Invalid Unicode 0xXXXXXXXX)'. +char* CodePointToUtf8(UInt32 code_point, char* str); + +// Converts a wide string to a narrow string in UTF-8 encoding. +// The wide string is assumed to have the following encoding: +// UTF-16 if sizeof(wchar_t) == 2 (on Windows, Cygwin, Symbian OS) +// UTF-32 if sizeof(wchar_t) == 4 (on Linux) +// Parameter str points to a null-terminated wide string. +// Parameter num_chars may additionally limit the number +// of wchar_t characters processed. -1 is used when the entire string +// should be processed. +// If the string contains code points that are not valid Unicode code points +// (i.e. outside of Unicode range U+0 to U+10FFFF) they will be output +// as '(Invalid Unicode 0xXXXXXXXX)'. If the string is in UTF16 encoding +// and contains invalid UTF-16 surrogate pairs, values in those pairs +// will be encoded as individual Unicode characters from Basic Normal Plane. +String WideStringToUtf8(const wchar_t* str, int num_chars); // Returns the number of active threads, or 0 when there is an error. size_t GetThreadCount(); diff --git a/src/gtest.cc b/src/gtest.cc index a0a05208..740eb746 100644 --- a/src/gtest.cc +++ b/src/gtest.cc @@ -784,16 +784,19 @@ bool String::CStringEquals(const char * lhs, const char * rhs) { // encoding, and streams the result to the given Message object. static void StreamWideCharsToMessage(const wchar_t* wstr, size_t len, Message* msg) { - for (size_t i = 0; i != len; i++) { - // TODO(wan): consider allowing a testing::String object to - // contain '\0'. This will make it behave more like std::string, - // and will allow ToUtf8String() to return the correct encoding - // for '\0' s.t. we can get rid of the conditional here (and in - // several other places). - if (wstr[i]) { - *msg << internal::ToUtf8String(wstr[i]); + // TODO(wan): consider allowing a testing::String object to + // contain '\0'. This will make it behave more like std::string, + // and will allow ToUtf8String() to return the correct encoding + // for '\0' s.t. we can get rid of the conditional here (and in + // several other places). + for (size_t i = 0; i != len; ) { // NOLINT + if (wstr[i] != L'\0') { + *msg << WideStringToUtf8(wstr + i, len - i); + while (i != len && wstr[i] != L'\0') + i++; } else { *msg << '\0'; + i++; } } } @@ -852,8 +855,10 @@ String FormatForFailureMessage(wchar_t wchar) { Message msg; // A String object cannot contain '\0', so we print "\\0" when wchar is // L'\0'. - msg << "L'" << (wchar ? ToUtf8String(wchar).c_str() : "\\0") << "' (" - << wchar_as_uint64 << ", 0x" << ::std::setbase(16) + char buffer[32]; // CodePointToUtf8 requires a buffer that big. + msg << "L'" + << (wchar ? CodePointToUtf8(static_cast(wchar), buffer) : "\\0") + << "' (" << wchar_as_uint64 << ", 0x" << ::std::setbase(16) << wchar_as_uint64 << ")"; return msg.GetString(); } @@ -1317,31 +1322,118 @@ inline UInt32 ChopLowBits(UInt32* bits, int n) { return low_bits; } -// Converts a Unicode code-point to its UTF-8 encoding. -String ToUtf8String(wchar_t wchar) { - char str[5] = {}; // Initializes str to all '\0' characters. - - UInt32 code = static_cast(wchar); - if (code <= kMaxCodePoint1) { - str[0] = static_cast(code); // 0xxxxxxx - } else if (code <= kMaxCodePoint2) { - str[1] = static_cast(0x80 | ChopLowBits(&code, 6)); // 10xxxxxx - str[0] = static_cast(0xC0 | code); // 110xxxxx - } else if (code <= kMaxCodePoint3) { - str[2] = static_cast(0x80 | ChopLowBits(&code, 6)); // 10xxxxxx - str[1] = static_cast(0x80 | ChopLowBits(&code, 6)); // 10xxxxxx - str[0] = static_cast(0xE0 | code); // 1110xxxx - } else if (code <= kMaxCodePoint4) { - str[3] = static_cast(0x80 | ChopLowBits(&code, 6)); // 10xxxxxx - str[2] = static_cast(0x80 | ChopLowBits(&code, 6)); // 10xxxxxx - str[1] = static_cast(0x80 | ChopLowBits(&code, 6)); // 10xxxxxx - str[0] = static_cast(0xF0 | code); // 11110xxx +// Converts a Unicode code point to a narrow string in UTF-8 encoding. +// code_point parameter is of type UInt32 because wchar_t may not be +// wide enough to contain a code point. +// The output buffer str must containt at least 32 characters. +// The function returns the address of the output buffer. +// If the code_point is not a valid Unicode code point +// (i.e. outside of Unicode range U+0 to U+10FFFF) it will be output +// as '(Invalid Unicode 0xXXXXXXXX)'. +char* CodePointToUtf8(UInt32 code_point, char* str) { + if (code_point <= kMaxCodePoint1) { + str[1] = '\0'; + str[0] = static_cast(code_point); // 0xxxxxxx + } else if (code_point <= kMaxCodePoint2) { + str[2] = '\0'; + str[1] = static_cast(0x80 | ChopLowBits(&code_point, 6)); // 10xxxxxx + str[0] = static_cast(0xC0 | code_point); // 110xxxxx + } else if (code_point <= kMaxCodePoint3) { + str[3] = '\0'; + str[2] = static_cast(0x80 | ChopLowBits(&code_point, 6)); // 10xxxxxx + str[1] = static_cast(0x80 | ChopLowBits(&code_point, 6)); // 10xxxxxx + str[0] = static_cast(0xE0 | code_point); // 1110xxxx + } else if (code_point <= kMaxCodePoint4) { + str[4] = '\0'; + str[3] = static_cast(0x80 | ChopLowBits(&code_point, 6)); // 10xxxxxx + str[2] = static_cast(0x80 | ChopLowBits(&code_point, 6)); // 10xxxxxx + str[1] = static_cast(0x80 | ChopLowBits(&code_point, 6)); // 10xxxxxx + str[0] = static_cast(0xF0 | code_point); // 11110xxx } else { - return String::Format("(Invalid Unicode 0x%llX)", - static_cast(wchar)); + // The longest string String::Format can produce when invoked + // with these parameters is 28 character long (not including + // the terminating nul character). We are asking for 32 character + // buffer just in case. This is also enough for strncpy to + // null-terminate the destination string. + // MSVC 8 deprecates strncpy(), so we want to suppress warning + // 4996 (deprecated function) there. +#ifdef GTEST_OS_WINDOWS // We are on Windows. +#pragma warning(push) // Saves the current warning state. +#pragma warning(disable:4996) // Temporarily disables warning 4996. +#endif + strncpy(str, String::Format("(Invalid Unicode 0x%X)", code_point).c_str(), + 32); +#ifdef GTEST_OS_WINDOWS // We are on Windows. +#pragma warning(pop) // Restores the warning state. +#endif + str[31] = '\0'; // Makes sure no change in the format to strncpy leaves + // the result unterminated. } + return str; +} + +// The following two functions only make sense if the the system +// uses UTF-16 for wide string encoding. All supported systems +// with 16 bit wchar_t (Windows, Cygwin, Symbian OS) do use UTF-16. - return String(str); +// Determines if the arguments constitute UTF-16 surrogate pair +// and thus should be combined into a single Unicode code point +// using CreateCodePointFromUtf16SurrogatePair. +inline bool IsUtf16SurrogatePair(wchar_t first, wchar_t second) { + if (sizeof(wchar_t) == 2) + return (first & 0xFC00) == 0xD800 && (second & 0xFC00) == 0xDC00; + else + return false; +} + +// Creates a Unicode code point from UTF16 surrogate pair. +inline UInt32 CreateCodePointFromUtf16SurrogatePair(wchar_t first, + wchar_t second) { + if (sizeof(wchar_t) == 2) { + const UInt32 mask = (1 << 10) - 1; + return (((first & mask) << 10) | (second & mask)) + 0x10000; + } else { + // This should not be called, but we provide a sensible default + // in case it is. + return static_cast(first); + } +} + +// Converts a wide string to a narrow string in UTF-8 encoding. +// The wide string is assumed to have the following encoding: +// UTF-16 if sizeof(wchar_t) == 2 (on Windows, Cygwin, Symbian OS) +// UTF-32 if sizeof(wchar_t) == 4 (on Linux) +// Parameter str points to a null-terminated wide string. +// Parameter num_chars may additionally limit the number +// of wchar_t characters processed. -1 is used when the entire string +// should be processed. +// If the string contains code points that are not valid Unicode code points +// (i.e. outside of Unicode range U+0 to U+10FFFF) they will be output +// as '(Invalid Unicode 0xXXXXXXXX)'. If the string is in UTF16 encoding +// and contains invalid UTF-16 surrogate pairs, values in those pairs +// will be encoded as individual Unicode characters from Basic Normal Plane. +String WideStringToUtf8(const wchar_t* str, int num_chars) { + if (num_chars == -1) + num_chars = wcslen(str); + + StrStream stream; + for (int i = 0; i < num_chars; ++i) { + UInt32 unicode_code_point; + + if (str[i] == L'\0') { + break; + } else if (i + 1 < num_chars && IsUtf16SurrogatePair(str[i], str[i + 1])) { + unicode_code_point = CreateCodePointFromUtf16SurrogatePair(str[i], + str[i + 1]); + i++; + } else { + unicode_code_point = static_cast(str[i]); + } + + char buffer[32]; // CodePointToUtf8 requires a buffer this big. + stream << CodePointToUtf8(unicode_code_point, buffer); + } + return StrStreamToString(&stream); } // Converts a wide C string to a String using the UTF-8 encoding. @@ -1349,12 +1441,7 @@ String ToUtf8String(wchar_t wchar) { String String::ShowWideCString(const wchar_t * wide_c_str) { if (wide_c_str == NULL) return String("(null)"); - StrStream ss; - while (*wide_c_str) { - ss << internal::ToUtf8String(*wide_c_str++); - } - - return internal::StrStreamToString(&ss); + return String(internal::WideStringToUtf8(wide_c_str, -1).c_str()); } // Similar to ShowWideCString(), except that this function encloses -- cgit v1.2.3 From a2b1a8556ea64014606d78b09333d9c522430a25 Mon Sep 17 00:00:00 2001 From: shiqian Date: Mon, 8 Sep 2008 17:55:52 +0000 Subject: Adds support for type-parameterized tests (by Zhanyong Wan); also adds case-insensitive wide string comparison to the String class (by Vlad Losev). --- src/gtest-internal-inl.h | 34 +++++++--- src/gtest.cc | 171 +++++++++++++++++++++++++++++++++++------------ 2 files changed, 152 insertions(+), 53 deletions(-) (limited to 'src') diff --git a/src/gtest-internal-inl.h b/src/gtest-internal-inl.h index 2633d692..6aafc7bf 100644 --- a/src/gtest-internal-inl.h +++ b/src/gtest-internal-inl.h @@ -563,7 +563,8 @@ class TestResult { class TestInfoImpl { public: TestInfoImpl(TestInfo* parent, const char* test_case_name, - const char* name, TypeId fixture_class_id, + const char* name, const char* test_case_comment, + const char* comment, TypeId fixture_class_id, internal::TestFactoryBase* factory); ~TestInfoImpl(); @@ -585,6 +586,12 @@ class TestInfoImpl { // Returns the test name. const char* name() const { return name_.c_str(); } + // Returns the test case comment. + const char* test_case_comment() const { return test_case_comment_.c_str(); } + + // Returns the test comment. + const char* comment() const { return comment_.c_str(); } + // Returns the ID of the test fixture class. TypeId fixture_class_id() const { return fixture_class_id_; } @@ -611,12 +618,14 @@ class TestInfoImpl { private: // These fields are immutable properties of the test. - TestInfo* const parent_; // The owner of this object - const String test_case_name_; // Test case name - const String name_; // Test name - const TypeId fixture_class_id_; // ID of the test fixture class - bool should_run_; // True iff this test should run - bool is_disabled_; // True iff this test is disabled + TestInfo* const parent_; // The owner of this object + const String test_case_name_; // Test case name + const String name_; // Test name + const String test_case_comment_; // Test case comment + const String comment_; // Test comment + const TypeId fixture_class_id_; // ID of the test fixture class + bool should_run_; // True iff this test should run + bool is_disabled_; // True iff this test is disabled internal::TestFactoryBase* const factory_; // The factory that creates // the test object @@ -644,7 +653,7 @@ class TestCase { // name: name of the test case // set_up_tc: pointer to the function that sets up the test case // tear_down_tc: pointer to the function that tears down the test case - TestCase(const char* name, + TestCase(const char* name, const char* comment, Test::SetUpTestCaseFunc set_up_tc, Test::TearDownTestCaseFunc tear_down_tc); @@ -654,6 +663,9 @@ class TestCase { // Gets the name of the TestCase. const char* name() const { return name_.c_str(); } + // Returns the test case comment. + const char* comment() const { return comment_.c_str(); } + // Returns true if any test in this test case should run. bool should_run() const { return should_run_; } @@ -739,6 +751,8 @@ class TestCase { private: // Name of the test case. internal::String name_; + // Comment on the test case. + internal::String comment_; // List of TestInfos. internal::List* test_info_list_; // Pointer to the function that sets up the test case. @@ -799,7 +813,7 @@ class UnitTestOptions { // This function is useful as an __except condition. static int GTestShouldProcessSEH(DWORD exception_code); #endif // GTEST_OS_WINDOWS - private: + // Returns true if "name" matches the ':' separated list of glob-style // filters in "filter". static bool MatchesFilter(const String& name, const char* filter); @@ -975,6 +989,7 @@ class UnitTestImpl : public TestPartResultReporterInterface { // set_up_tc: pointer to the function that sets up the test case // tear_down_tc: pointer to the function that tears down the test case TestCase* GetTestCase(const char* test_case_name, + const char* comment, Test::SetUpTestCaseFunc set_up_tc, Test::TearDownTestCaseFunc tear_down_tc); @@ -989,6 +1004,7 @@ class UnitTestImpl : public TestPartResultReporterInterface { Test::TearDownTestCaseFunc tear_down_tc, TestInfo * test_info) { GetTestCase(test_info->test_case_name(), + test_info->test_case_comment(), set_up_tc, tear_down_tc)->AddTestInfo(test_info); } diff --git a/src/gtest.cc b/src/gtest.cc index 740eb746..09f6bae4 100644 --- a/src/gtest.cc +++ b/src/gtest.cc @@ -40,6 +40,8 @@ #include #include #include +#include +#include #ifdef GTEST_OS_LINUX @@ -117,8 +119,14 @@ namespace testing { // Constants. -// A test that matches this pattern is disabled and not run. -static const char kDisableTestPattern[] = "DISABLED_*"; +// A test whose test case name or test name matches this filter is +// disabled and not run. +static const char kDisableTestFilter[] = "DISABLED_*:*/DISABLED_*"; + +// A test case whose name matches this filter is considered a death +// test case and will be run before test cases whose name doesn't +// match this filter. +static const char kDeathTestCaseFilter[] = "*DeathTest:*DeathTest/*"; // A test filter that matches everything. static const char kUniversalFilter[] = "*"; @@ -1516,6 +1524,39 @@ bool String::CaseInsensitiveCStringEquals(const char * lhs, const char * rhs) { #else // GTEST_OS_WINDOWS return strcasecmp(lhs, rhs) == 0; #endif // GTEST_OS_WINDOWS +} + + // Compares two wide C strings, ignoring case. Returns true iff they + // have the same content. + // + // Unlike wcscasecmp(), this function can handle NULL argument(s). + // A NULL C string is considered different to any non-NULL wide C string, + // including the empty string. + // NB: The implementations on different platforms slightly differ. + // On windows, this method uses _wcsicmp which compares according to LC_CTYPE + // environment variable. On GNU platform this method uses wcscasecmp + // which compares according to LC_CTYPE category of the current locale. + // On MacOS X, it uses towlower, which also uses LC_CTYPE category of the + // current locale. +bool String::CaseInsensitiveWideCStringEquals(const wchar_t* lhs, + const wchar_t* rhs) { + if ( lhs == NULL ) return rhs == NULL; + + if ( rhs == NULL ) return false; + +#ifdef GTEST_OS_WINDOWS + return _wcsicmp(lhs, rhs) == 0; +#elif defined(GTEST_OS_MAC) + // Mac OS X doesn't define wcscasecmp. + wint_t left, right; + do { + left = towlower(*lhs++); + right = towlower(*rhs++); + } while (left && left == right); + return left == right; +#else + return wcscasecmp(lhs, rhs) == 0; +#endif // OS selector } // Constructs a String by copying a given number of chars from a @@ -1716,8 +1757,8 @@ void TestResult::RecordProperty(const TestProperty& test_property) { property_with_matching_key.SetValue(test_property.value()); } -// Adds a failure if the key is a reserved attribute of Google Test testcase tags. -// Returns true if the property is valid. +// Adds a failure if the key is a reserved attribute of Google Test +// testcase tags. Returns true if the property is valid. bool TestResult::ValidateTestProperty(const TestProperty& test_property) { String key(test_property.key()); if (key == "name" || key == "status" || key == "time" || key == "classname") { @@ -1973,9 +2014,12 @@ bool Test::HasFatalFailure() { // object via impl_. TestInfo::TestInfo(const char* test_case_name, const char* name, + const char* test_case_comment, + const char* comment, internal::TypeId fixture_class_id, internal::TestFactoryBase* factory) { impl_ = new internal::TestInfoImpl(this, test_case_name, name, + test_case_comment, comment, fixture_class_id, factory); } @@ -1984,30 +2028,41 @@ TestInfo::~TestInfo() { delete impl_; } -// Creates a TestInfo object and registers it with the UnitTest -// singleton; returns the created object. +namespace internal { + +// Creates a new TestInfo object and registers it with Google Test; +// returns the created object. // // Arguments: // -// test_case_name: name of the test case -// name: name of the test -// set_up_tc: pointer to the function that sets up the test case -// tear_down_tc: pointer to the function that tears down the test case -// factory factory object that creates a test object. The new -// TestInfo instance assumes ownership of the factory object. -TestInfo* TestInfo::MakeAndRegisterInstance( - const char* test_case_name, - const char* name, - internal::TypeId fixture_class_id, - Test::SetUpTestCaseFunc set_up_tc, - Test::TearDownTestCaseFunc tear_down_tc, - internal::TestFactoryBase* factory) { +// test_case_name: name of the test case +// name: name of the test +// test_case_comment: a comment on the test case that will be included in +// the test output +// comment: a comment on the test that will be included in the +// test output +// fixture_class_id: ID of the test fixture class +// set_up_tc: pointer to the function that sets up the test case +// tear_down_tc: pointer to the function that tears down the test case +// factory: pointer to the factory that creates a test object. +// The newly created TestInfo instance will assume +// ownership of the factory object. +TestInfo* MakeAndRegisterTestInfo( + const char* test_case_name, const char* name, + const char* test_case_comment, const char* comment, + TypeId fixture_class_id, + SetUpTestCaseFunc set_up_tc, + TearDownTestCaseFunc tear_down_tc, + TestFactoryBase* factory) { TestInfo* const test_info = - new TestInfo(test_case_name, name, fixture_class_id, factory); - internal::GetUnitTestImpl()->AddTestInfo(set_up_tc, tear_down_tc, test_info); + new TestInfo(test_case_name, name, test_case_comment, comment, + fixture_class_id, factory); + GetUnitTestImpl()->AddTestInfo(set_up_tc, tear_down_tc, test_info); return test_info; } +} // namespace internal + // Returns the test case name. const char* TestInfo::test_case_name() const { return impl_->test_case_name(); @@ -2018,6 +2073,16 @@ const char* TestInfo::name() const { return impl_->name(); } +// Returns the test case comment. +const char* TestInfo::test_case_comment() const { + return impl_->test_case_comment(); +} + +// Returns the test comment. +const char* TestInfo::comment() const { + return impl_->comment(); +} + // Returns true if this test should run. bool TestInfo::should_run() const { return impl_->should_run(); } @@ -2170,10 +2235,11 @@ int TestCase::total_test_count() const { // name: name of the test case // set_up_tc: pointer to the function that sets up the test case // tear_down_tc: pointer to the function that tears down the test case -TestCase::TestCase(const char* name, +TestCase::TestCase(const char* name, const char* comment, Test::SetUpTestCaseFunc set_up_tc, Test::TearDownTestCaseFunc tear_down_tc) : name_(name), + comment_(comment), set_up_tc_(set_up_tc), tear_down_tc_(tear_down_tc), should_run_(false), @@ -2283,18 +2349,11 @@ static const char * TestPartResultTypeToString(TestPartResultType type) { // Prints a TestPartResult. static void PrintTestPartResult( const TestPartResult & test_part_result) { - const char * const file_name = test_part_result.file_name(); - - printf("%s", file_name == NULL ? "unknown file" : file_name); - if (test_part_result.line_number() >= 0) { -#ifdef _MSC_VER - printf("(%d)", test_part_result.line_number()); -#else - printf(":%d", test_part_result.line_number()); -#endif - } - printf(": %s", TestPartResultTypeToString(test_part_result.type())); - printf("%s\n", test_part_result.message()); + printf("%s %s%s\n", + internal::FormatFileLocation(test_part_result.file_name(), + test_part_result.line_number()).c_str(), + TestPartResultTypeToString(test_part_result.type()), + test_part_result.message()); fflush(stdout); } @@ -2471,7 +2530,12 @@ void PrettyUnitTestResultPrinter::OnTestCaseStart( const internal::String counts = FormatCountableNoun(test_case->test_to_run_count(), "test", "tests"); ColoredPrintf(COLOR_GREEN, "[----------] "); - printf("%s from %s\n", counts.c_str(), test_case_name_.c_str()); + printf("%s from %s", counts.c_str(), test_case_name_.c_str()); + if (test_case->comment()[0] == '\0') { + printf("\n"); + } else { + printf(", where %s\n", test_case->comment()); + } fflush(stdout); } @@ -2492,7 +2556,11 @@ void PrettyUnitTestResultPrinter::OnTestCaseEnd( void PrettyUnitTestResultPrinter::OnTestStart(const TestInfo * test_info) { ColoredPrintf(COLOR_GREEN, "[ RUN ] "); PrintTestName(test_case_name_.c_str(), test_info->name()); - printf("\n"); + if (test_info->comment()[0] == '\0') { + printf("\n"); + } else { + printf(", where %s\n", test_info->comment()); + } fflush(stdout); } @@ -2553,7 +2621,16 @@ static void PrintFailedTestsPretty(const UnitTestImpl* impl) { continue; } ColoredPrintf(COLOR_RED, "[ FAILED ] "); - printf("%s.%s\n", ti->test_case_name(), ti->name()); + printf("%s.%s", ti->test_case_name(), ti->name()); + if (ti->test_case_comment()[0] != '\0' || + ti->comment()[0] != '\0') { + printf(", where %s", ti->test_case_comment()); + if (ti->test_case_comment()[0] != '\0' && + ti->comment()[0] != '\0') { + printf(" and "); + } + } + printf("%s\n", ti->comment()); } } } @@ -3244,6 +3321,7 @@ class TestCaseNameIs { // set_up_tc: pointer to the function that sets up the test case // tear_down_tc: pointer to the function that tears down the test case TestCase* UnitTestImpl::GetTestCase(const char* test_case_name, + const char* comment, Test::SetUpTestCaseFunc set_up_tc, Test::TearDownTestCaseFunc tear_down_tc) { // Can we find a TestCase with the given name? @@ -3253,10 +3331,11 @@ TestCase* UnitTestImpl::GetTestCase(const char* test_case_name, if (node == NULL) { // No. Let's create one. TestCase* const test_case = - new TestCase(test_case_name, set_up_tc, tear_down_tc); + new TestCase(test_case_name, comment, set_up_tc, tear_down_tc); // Is this a death test case? - if (String(test_case_name).EndsWith("DeathTest")) { + if (internal::UnitTestOptions::MatchesFilter(String(test_case_name), + kDeathTestCaseFilter)) { // Yes. Inserts the test case after the last death test case // defined so far. node = test_cases_.InsertAfter(last_death_test_case_, test_case); @@ -3389,12 +3468,12 @@ int UnitTestImpl::FilterTests() { TestInfo * const test_info = test_info_node->element(); const String test_name(test_info->name()); // A test is disabled if test case name or test name matches - // kDisableTestPattern. + // kDisableTestFilter. const bool is_disabled = - internal::UnitTestOptions::PatternMatchesString(kDisableTestPattern, - test_case_name.c_str()) || - internal::UnitTestOptions::PatternMatchesString(kDisableTestPattern, - test_name.c_str()); + internal::UnitTestOptions::MatchesFilter(test_case_name, + kDisableTestFilter) || + internal::UnitTestOptions::MatchesFilter(test_name, + kDisableTestFilter); test_info->impl()->set_is_disabled(is_disabled); const bool should_run = !is_disabled && @@ -3511,11 +3590,15 @@ internal::TestResult* UnitTestImpl::current_test_result() { TestInfoImpl::TestInfoImpl(TestInfo* parent, const char* test_case_name, const char* name, + const char* test_case_comment, + const char* comment, TypeId fixture_class_id, internal::TestFactoryBase* factory) : parent_(parent), test_case_name_(String(test_case_name)), name_(String(name)), + test_case_comment_(String(test_case_comment)), + comment_(String(comment)), fixture_class_id_(fixture_class_id), should_run_(false), is_disabled_(false), -- cgit v1.2.3 From 29d8235540f1983c3dbd53a23783530017be80e7 Mon Sep 17 00:00:00 2001 From: shiqian Date: Tue, 9 Sep 2008 03:01:38 +0000 Subject: Adds new files for type-parameterized tests, which I forgot to commit in the previous revision. --- src/gtest-typed-test.cc | 97 +++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 97 insertions(+) create mode 100644 src/gtest-typed-test.cc (limited to 'src') diff --git a/src/gtest-typed-test.cc b/src/gtest-typed-test.cc new file mode 100644 index 00000000..d42a1596 --- /dev/null +++ b/src/gtest-typed-test.cc @@ -0,0 +1,97 @@ +// 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. +// +// Author: wan@google.com (Zhanyong Wan) + +#include +#include + +namespace testing { +namespace internal { + +#ifdef GTEST_HAS_TYPED_TEST_P + +// Verifies that registered_tests match the test names in +// defined_test_names_; returns registered_tests if successful, or +// aborts the program otherwise. +const char* TypedTestCasePState::VerifyRegisteredTestNames( + const char* file, int line, const char* registered_tests) { + typedef ::std::set::const_iterator DefinedTestIter; + registered_ = true; + + Message errors; + ::std::set tests; + for (const char* names = registered_tests; names != NULL; + names = SkipComma(names)) { + const String name = GetPrefixUntilComma(names); + if (tests.count(name) != 0) { + errors << "Test " << name << " is listed more than once.\n"; + continue; + } + + bool found = false; + for (DefinedTestIter it = defined_test_names_.begin(); + it != defined_test_names_.end(); + ++it) { + if (name == *it) { + found = true; + break; + } + } + + if (found) { + tests.insert(name); + } else { + errors << "No test named " << name + << " can be found in this test case.\n"; + } + } + + for (DefinedTestIter it = defined_test_names_.begin(); + it != defined_test_names_.end(); + ++it) { + if (tests.count(*it) == 0) { + errors << "You forgot to list test " << *it << ".\n"; + } + } + + const String& errors_str = errors.GetString(); + if (errors_str != "") { + fprintf(stderr, "%s %s", FormatFileLocation(file, line).c_str(), + errors_str.c_str()); + abort(); + } + + return registered_tests; +} + +#endif // GTEST_HAS_TYPED_TEST_P + +} // namespace internal +} // namespace testing -- cgit v1.2.3 From 019d19af978f05b774407e0d46a3bda2c18c67c6 Mon Sep 17 00:00:00 2001 From: shiqian Date: Fri, 12 Sep 2008 04:01:37 +0000 Subject: Improves thread-safe death tests by changing to the original working directory before they are executed; also fixes out-dated comments about death tests. --- src/gtest-death-test.cc | 23 ++++++++++++++++++++++- src/gtest-filepath.cc | 18 ++++++++++++++++++ src/gtest-internal-inl.h | 21 +++++++++++++++++++++ src/gtest.cc | 6 ++++++ 4 files changed, 67 insertions(+), 1 deletion(-) (limited to 'src') diff --git a/src/gtest-death-test.cc b/src/gtest-death-test.cc index cb0d3cd7..971c3005 100644 --- a/src/gtest-death-test.cc +++ b/src/gtest-death-test.cc @@ -546,11 +546,32 @@ struct ExecDeathTestArgs { }; // The main function for a threadsafe-style death test child process. +// This function is called in a clone()-ed process and thus must avoid +// any potentially unsafe operations like malloc or libc functions. static int ExecDeathTestChildMain(void* child_arg) { ExecDeathTestArgs* const args = static_cast(child_arg); GTEST_DEATH_TEST_CHECK_SYSCALL(close(args->close_fd)); + + // 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("chdir(\"%s\") failed: %s", + original_dir, strerror(errno)); + return EXIT_FAILURE; + } + + // We can safely call execve() as it's a direct system call. We + // cannot use execvp() as it's a libc function and thus potentially + // unsafe. Since execve() doesn't search the PATH, the user must + // invoke the test program via a valid path that contains at least + // one path separator. execve(args->argv[0], args->argv, environ); - DeathTestAbort("execve failed: %s", strerror(errno)); + DeathTestAbort("execve(%s, ...) in %s failed: %s", + args->argv[0], original_dir, strerror(errno)); return EXIT_FAILURE; } diff --git a/src/gtest-filepath.cc b/src/gtest-filepath.cc index 3c32c705..2a5be8ce 100644 --- a/src/gtest-filepath.cc +++ b/src/gtest-filepath.cc @@ -32,6 +32,8 @@ #include #include +#include + #ifdef _WIN32_WCE #include #elif defined(_WIN32) @@ -40,6 +42,7 @@ #include #else #include +#include #endif // _WIN32_WCE or _WIN32 #include @@ -66,6 +69,21 @@ const char kPathSeparatorString[] = "/"; const char kCurrentDirectoryString[] = "./"; #endif // GTEST_OS_WINDOWS +// Returns the current working directory, or "" if unsuccessful. +FilePath FilePath::GetCurrentDir() { +#ifdef _WIN32_WCE +// Windows CE doesn't have a current directory, so we just return +// something reasonable. + return FilePath(kCurrentDirectoryString); +#elif defined(GTEST_OS_WINDOWS) + char cwd[_MAX_PATH + 1] = {}; + return FilePath(_getcwd(cwd, sizeof(cwd)) == NULL ? "" : cwd); +#else + char cwd[PATH_MAX + 1] = {}; + return FilePath(getcwd(cwd, sizeof(cwd)) == NULL ? "" : cwd); +#endif +} + // Returns a copy of the FilePath with the case-insensitive extension removed. // Example: FilePath("dir/file.exe").RemoveExtension("EXE") returns // FilePath("dir/file"). If a case-insensitive extension is not diff --git a/src/gtest-internal-inl.h b/src/gtest-internal-inl.h index 6aafc7bf..d4889483 100644 --- a/src/gtest-internal-inl.h +++ b/src/gtest-internal-inl.h @@ -1003,6 +1003,21 @@ class UnitTestImpl : public TestPartResultReporterInterface { void AddTestInfo(Test::SetUpTestCaseFunc set_up_tc, Test::TearDownTestCaseFunc tear_down_tc, TestInfo * test_info) { + // In order to support thread-safe death tests, we need to + // remember the original working directory when the test program + // was first invoked. We cannot do this in RUN_ALL_TESTS(), as + // the user may have changed the current directory before calling + // RUN_ALL_TESTS(). Therefore we capture the current directory in + // AddTestInfo(), which is called to register a TEST or TEST_F + // before main() is reached. + if (original_working_dir_.IsEmpty()) { + original_working_dir_.Set(FilePath::GetCurrentDir()); + if (original_working_dir_.IsEmpty()) { + printf("%s\n", "Failed to get the current working directory."); + abort(); + } + } + GetTestCase(test_info->test_case_name(), test_info->test_case_comment(), set_up_tc, @@ -1083,9 +1098,15 @@ class UnitTestImpl : public TestPartResultReporterInterface { #endif // GTEST_HAS_DEATH_TEST private: + friend class ::testing::UnitTest; + // The UnitTest object that owns this implementation object. UnitTest* const parent_; + // The working directory when the first TEST() or TEST_F() was + // executed. + internal::FilePath original_working_dir_; + // Points to (but doesn't own) the test part result reporter. TestPartResultReporterInterface* test_part_result_reporter_; diff --git a/src/gtest.cc b/src/gtest.cc index 09f6bae4..8ca6ac8e 100644 --- a/src/gtest.cc +++ b/src/gtest.cc @@ -3211,6 +3211,12 @@ int UnitTest::Run() { #endif // GTEST_OS_WINDOWS } +// Returns the working directory when the first TEST() or TEST_F() was +// executed. +const char* UnitTest::original_working_dir() const { + return impl_->original_working_dir_.c_str(); +} + // Returns the TestCase object for the test that's currently running, // or NULL if no test is running. // L < mutex_ -- cgit v1.2.3 From f6b0dc0b408f38bb04079b14198d6bdf703e5e56 Mon Sep 17 00:00:00 2001 From: shiqian Date: Thu, 18 Sep 2008 18:06:35 +0000 Subject: Makes Google Test compile (and all tests pass) on cygwin (possibly on wingw too). --- src/gtest.cc | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) (limited to 'src') diff --git a/src/gtest.cc b/src/gtest.cc index 8ca6ac8e..8d2d2a2a 100644 --- a/src/gtest.cc +++ b/src/gtest.cc @@ -1546,16 +1546,17 @@ bool String::CaseInsensitiveWideCStringEquals(const wchar_t* lhs, #ifdef GTEST_OS_WINDOWS return _wcsicmp(lhs, rhs) == 0; -#elif defined(GTEST_OS_MAC) - // Mac OS X doesn't define wcscasecmp. +#elif defined(GTEST_OS_LINUX) + return wcscasecmp(lhs, rhs) == 0; +#else + // Mac OS X and Cygwin don't define wcscasecmp. Other unknown OSes + // may not define it either. wint_t left, right; do { left = towlower(*lhs++); right = towlower(*rhs++); } while (left && left == right); return left == right; -#else - return wcscasecmp(lhs, rhs) == 0; #endif // OS selector } -- cgit v1.2.3 From 64cdcb69b28fc26e78d95c574187f7dd9830c84c Mon Sep 17 00:00:00 2001 From: shiqian Date: Fri, 26 Sep 2008 16:08:30 +0000 Subject: Lots of changes: * changes the XML report format to match JUnit/Ant's. * improves file path handling. * allows the user to disable RTTI using the GTEST_HAS_RTTI macro. * makes the code compile with -Wswitch-enum. --- src/gtest-death-test.cc | 1 + src/gtest-filepath.cc | 54 ++++++++++++++++++++++++++++++++++++++++++++----- src/gtest.cc | 46 ++++++++++++++++++++++++++++++++--------- 3 files changed, 87 insertions(+), 14 deletions(-) (limited to 'src') diff --git a/src/gtest-death-test.cc b/src/gtest-death-test.cc index 971c3005..fa800879 100644 --- a/src/gtest-death-test.cc +++ b/src/gtest-death-test.cc @@ -416,6 +416,7 @@ bool ForkingDeathTest::Passed(bool status_ok) { << " " << ExitSummary(status_) << "\n"; } break; + case IN_PROGRESS: default: GTEST_LOG(FATAL, "DeathTest::Passed somehow called before conclusion of test"); diff --git a/src/gtest-filepath.cc b/src/gtest-filepath.cc index 2a5be8ce..dc0d78f0 100644 --- a/src/gtest-filepath.cc +++ b/src/gtest-filepath.cc @@ -161,10 +161,13 @@ bool FilePath::FileOrDirectoryExists() const { // that exists. bool FilePath::DirectoryExists() const { bool result = false; -#ifdef _WIN32 - FilePath removed_sep(this->RemoveTrailingPathSeparator()); +#ifdef GTEST_OS_WINDOWS + // Don't strip off trailing separator if path is a root directory on + // Windows (like "C:\\"). + const FilePath& path(IsRootDirectory() ? *this : + RemoveTrailingPathSeparator()); #ifdef _WIN32_WCE - LPCWSTR unicode = String::AnsiToUtf16(removed_sep.c_str()); + LPCWSTR unicode = String::AnsiToUtf16(path.c_str()); const DWORD attributes = GetFileAttributes(unicode); delete [] unicode; if ((attributes != kInvalidFileAttributes) && @@ -173,17 +176,32 @@ bool FilePath::DirectoryExists() const { } #else struct _stat file_stat = {}; - result = _stat(removed_sep.c_str(), &file_stat) == 0 && + result = _stat(path.c_str(), &file_stat) == 0 && (_S_IFDIR & file_stat.st_mode) != 0; #endif // _WIN32_WCE #else struct stat file_stat = {}; result = stat(pathname_.c_str(), &file_stat) == 0 && S_ISDIR(file_stat.st_mode); -#endif // _WIN32 +#endif // GTEST_OS_WINDOWS return result; } +// Returns true if pathname describes a root directory. (Windows has one +// root directory per disk drive.) +bool FilePath::IsRootDirectory() const { +#ifdef GTEST_OS_WINDOWS + const char* const name = pathname_.c_str(); + return pathname_.GetLength() == 3 && + ((name[0] >= 'a' && name[0] <= 'z') || + (name[0] >= 'A' && name[0] <= 'Z')) && + name[1] == ':' && + name[2] == kPathSeparator; +#else + return pathname_ == kPathSeparatorString; +#endif +} + // Returns a pathname for a file that does not currently exist. The pathname // will be directory/base_name.extension or // directory/base_name_.extension if directory/base_name.extension @@ -258,5 +276,31 @@ FilePath FilePath::RemoveTrailingPathSeparator() const { : *this; } +// Normalize removes any redundant separators that might be in the pathname. +// For example, "bar///foo" becomes "bar/foo". Does not eliminate other +// redundancies that might be in a pathname involving "." or "..". +void FilePath::Normalize() { + if (pathname_.c_str() == NULL) { + pathname_ = ""; + return; + } + const char* src = pathname_.c_str(); + char* const dest = new char[pathname_.GetLength() + 1]; + char* dest_ptr = dest; + memset(dest_ptr, 0, pathname_.GetLength() + 1); + + while (*src != '\0') { + *dest_ptr++ = *src; + if (*src != kPathSeparator) + src++; + else + while (*src == kPathSeparator) + src++; + } + *dest_ptr = '\0'; + pathname_ = dest; + delete[] dest; +} + } // namespace internal } // namespace testing diff --git a/src/gtest.cc b/src/gtest.cc index 8d2d2a2a..f8c11997 100644 --- a/src/gtest.cc +++ b/src/gtest.cc @@ -134,6 +134,10 @@ static const char kUniversalFilter[] = "*"; // The default output file for XML output. static const char kDefaultOutputFile[] = "test_detail.xml"; +// The text used in failure messages to indicate the start of the +// stack trace. +static const char kStackTraceMarker[] = "\nStack trace:\n"; + GTEST_DEFINE_bool( break_on_failure, internal::BoolFromGTestEnv("break_on_failure", false), @@ -200,6 +204,14 @@ GTEST_DEFINE_bool( "True iff " GTEST_NAME " should include internal stack frames when " "printing test failure stack traces."); +// Gets the summary of the failure message by omitting the stack trace +// in it. +internal::String TestPartResult::ExtractSummary(const char* message) { + const char* const stack_trace = strstr(message, kStackTraceMarker); + return stack_trace == NULL ? internal::String(message) : + internal::String(message, stack_trace - message); +} + namespace internal { // GTestIsInitialized() returns true iff the user has initialized @@ -2923,13 +2935,28 @@ internal::String XmlUnitTestResultPrinter::EscapeXml(const char* str, // <-- corresponds to a UnitTest object // <-- corresponds to a TestCase object // <-- corresponds to a TestInfo object -// -// <-- individual assertion failures -// +// ... +// ... +// ... +// <-- individual assertion failures // // // +namespace internal { + +// Formats the given time in milliseconds as seconds. The returned +// C-string is owned by this function and cannot be released by the +// caller. Calling the function again invalidates the previous +// result. +const char* FormatTimeInMillisAsSeconds(TimeInMillis ms) { + static String str; + str = (Message() << (ms/1000.0)).GetString(); + return str.c_str(); +} + +} // namespace internal + // Prints an XML representation of a TestInfo object. // TODO(wan): There is also value in printing properties with the plain printer. void XmlUnitTestResultPrinter::PrintXmlTestInfo(FILE* out, @@ -2942,7 +2969,7 @@ void XmlUnitTestResultPrinter::PrintXmlTestInfo(FILE* out, "classname=\"%s\"%s", EscapeXmlAttribute(test_info->name()).c_str(), test_info->should_run() ? "run" : "notrun", - internal::StreamableToString(result->elapsed_time()).c_str(), + internal::FormatTimeInMillisAsSeconds(result->elapsed_time()), EscapeXmlAttribute(test_case_name).c_str(), TestPropertiesAsXmlAttributes(result).c_str()); @@ -2958,8 +2985,9 @@ void XmlUnitTestResultPrinter::PrintXmlTestInfo(FILE* out, if (++failures == 1) fprintf(out, ">\n"); fprintf(out, - " \n", - EscapeXmlAttribute(message.c_str()).c_str()); + " " + "\n", + EscapeXmlAttribute(part.summary()).c_str(), message.c_str()); } } @@ -2981,7 +3009,7 @@ void XmlUnitTestResultPrinter::PrintXmlTestCase(FILE* out, test_case->disabled_test_count()); fprintf(out, "errors=\"0\" time=\"%s\">\n", - internal::StreamableToString(test_case->elapsed_time()).c_str()); + internal::FormatTimeInMillisAsSeconds(test_case->elapsed_time())); for (const internal::ListNode* info_node = test_case->test_info_list().Head(); info_node != NULL; @@ -3002,7 +3030,7 @@ void XmlUnitTestResultPrinter::PrintXmlUnitTest(FILE* out, impl->total_test_count(), impl->failed_test_count(), impl->disabled_test_count(), - internal::StreamableToString(impl->elapsed_time()).c_str()); + internal::FormatTimeInMillisAsSeconds(impl->elapsed_time())); fprintf(out, "name=\"AllTests\">\n"); for (const internal::ListNode* case_node = impl->test_cases()->Head(); @@ -3153,7 +3181,7 @@ void UnitTest::AddTestPartResult(TestPartResultType result_type, } if (os_stack_trace.c_str() != NULL && !os_stack_trace.empty()) { - msg << "\nStack trace:\n" << os_stack_trace; + msg << kStackTraceMarker << os_stack_trace; } const TestPartResult result = -- cgit v1.2.3 From e0865dd9199e8fffd5c2f95a68de6c1851f77c15 Mon Sep 17 00:00:00 2001 From: shiqian Date: Sat, 11 Oct 2008 07:20:02 +0000 Subject: Many changes: - appends "_" to internal macro names (by Markus Heule). - makes Google Test work with newer versions of tools on Symbian and Windows CE (by Mika Raento). - adds the (ASSERT|EXPECT)_NO_FATAL_FAILURE macros (by Markus Heule). - changes EXPECT_(NON|)FATAL_FAILURE to catch failures in the current thread only (by Markus Heule). - adds the EXPECT_(NON|)FATAL_FAILURE_ON_ALL_THREADS macros (by Markus Heule). - adds GTEST_HAS_PTHREAD and GTEST_IS_THREADSAFE to indicate the availability of and Google Test's thread-safety (by Zhanyong Wan). - adds scons/SConscript for building with scons (by Joi Sigurdsson). - adds src/gtest-all.cc for building Google Test from a single file (by Markus Heule). - updates the xcode project to include new tests (by Preston Jackson). --- src/gtest-all.cc | 41 ++++++++ src/gtest-death-test.cc | 68 ++++++------- src/gtest-filepath.cc | 8 +- src/gtest-internal-inl.h | 109 ++++++++++++++------ src/gtest-port.cc | 2 +- src/gtest-test-part.cc | 124 +++++++++++++++++++++++ src/gtest.cc | 256 +++++++++++++++++++++++++---------------------- 7 files changed, 421 insertions(+), 187 deletions(-) create mode 100644 src/gtest-all.cc create mode 100644 src/gtest-test-part.cc (limited to 'src') diff --git a/src/gtest-all.cc b/src/gtest-all.cc new file mode 100644 index 00000000..a67ea0fa --- /dev/null +++ b/src/gtest-all.cc @@ -0,0 +1,41 @@ +// 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. +// +// Author: mheule@google.com (Markus Heule) +// +// Google C++ Testing Framework (Google Test) +// +// Sometimes it's desirable to build Google Test by compiling a single file. +// This file serves this purpose. +#include "src/gtest.cc" +#include "src/gtest-death-test.cc" +#include "src/gtest-filepath.cc" +#include "src/gtest-port.cc" +#include "src/gtest-test-part.cc" +#include "src/gtest-typed-test.cc" diff --git a/src/gtest-death-test.cc b/src/gtest-death-test.cc index fa800879..b667682f 100644 --- a/src/gtest-death-test.cc +++ b/src/gtest-death-test.cc @@ -59,7 +59,7 @@ namespace testing { // The default death test style. static const char kDefaultDeathTestStyle[] = "fast"; -GTEST_DEFINE_string( +GTEST_DEFINE_string_( death_test_style, internal::StringFromGTestEnv("death_test_style", kDefaultDeathTestStyle), "Indicates how to run a death test in a forked child process: " @@ -69,7 +69,7 @@ GTEST_DEFINE_string( "after forking)."); namespace internal { -GTEST_DEFINE_string( +GTEST_DEFINE_string_( internal_run_death_test, "", "Indicates the file, line number, temporal index of " "the single death test to run, and a file descriptor to " @@ -188,7 +188,7 @@ void DeathTestAbort(const char* format, ...) { // A replacement for CHECK that calls DeathTestAbort if the assertion // fails. -#define GTEST_DEATH_TEST_CHECK(expression) \ +#define GTEST_DEATH_TEST_CHECK_(expression) \ do { \ if (!(expression)) { \ DeathTestAbort("CHECK failed: File %s, line %d: %s", \ @@ -196,14 +196,14 @@ void DeathTestAbort(const char* format, ...) { } \ } while (0) -// This macro is similar to GTEST_DEATH_TEST_CHECK, but it is meant for +// This macro is similar to GTEST_DEATH_TEST_CHECK_, but it is meant for // evaluating any system call that fulfills two conditions: it must return // -1 on failure, and set errno to EINTR when it is interrupted and // should be tried again. The macro expands to a loop that repeatedly // evaluates the expression as long as it evaluates to -1 and sets // errno to EINTR. If the expression evaluates to -1 but errno is // something other than EINTR, DeathTestAbort is called. -#define GTEST_DEATH_TEST_CHECK_SYSCALL(expression) \ +#define GTEST_DEATH_TEST_CHECK_SYSCALL_(expression) \ do { \ int retval; \ do { \ @@ -303,11 +303,11 @@ static void FailFromInternalError(int fd) { // TODO(smcafee): Maybe just FAIL the test instead? if (num_read == 0) { - GTEST_LOG(FATAL, error); + GTEST_LOG_(FATAL, error); } else { - GTEST_LOG(FATAL, - Message() << "Error while reading death test internal: " - << strerror(errno) << " [" << errno << "]"); + GTEST_LOG_(FATAL, + Message() << "Error while reading death test internal: " + << strerror(errno) << " [" << errno << "]"); } } @@ -343,19 +343,19 @@ int ForkingDeathTest::Wait() { FailFromInternalError(read_fd_); // Does not return. break; default: - GTEST_LOG(FATAL, - Message() << "Death test child process reported unexpected " - << "status byte (" << static_cast(flag) - << ")"); + GTEST_LOG_(FATAL, + Message() << "Death test child process reported unexpected " + << "status byte (" << static_cast(flag) + << ")"); } } else { - GTEST_LOG(FATAL, - Message() << "Read from death test child process failed: " - << strerror(errno)); + GTEST_LOG_(FATAL, + Message() << "Read from death test child process failed: " + << strerror(errno)); } - GTEST_DEATH_TEST_CHECK_SYSCALL(close(read_fd_)); - GTEST_DEATH_TEST_CHECK_SYSCALL(waitpid(child_pid_, &status_, 0)); + GTEST_DEATH_TEST_CHECK_SYSCALL_(close(read_fd_)); + GTEST_DEATH_TEST_CHECK_SYSCALL_(waitpid(child_pid_, &status_, 0)); return status_; } @@ -418,8 +418,8 @@ bool ForkingDeathTest::Passed(bool status_ok) { break; case IN_PROGRESS: default: - GTEST_LOG(FATAL, - "DeathTest::Passed somehow called before conclusion of test"); + GTEST_LOG_(FATAL, + "DeathTest::Passed somehow called before conclusion of test"); } last_death_test_message = buffer.GetString(); @@ -436,8 +436,8 @@ void ForkingDeathTest::Abort(AbortReason reason) { // to the pipe, then exit. const char flag = reason == TEST_DID_NOT_DIE ? kDeathTestLived : kDeathTestReturned; - GTEST_DEATH_TEST_CHECK_SYSCALL(write(write_fd_, &flag, 1)); - GTEST_DEATH_TEST_CHECK_SYSCALL(close(write_fd_)); + GTEST_DEATH_TEST_CHECK_SYSCALL_(write(write_fd_, &flag, 1)); + GTEST_DEATH_TEST_CHECK_SYSCALL_(close(write_fd_)); _exit(1); // Exits w/o any normal exit hooks (we were supposed to crash) } @@ -455,11 +455,11 @@ class NoExecDeathTest : public ForkingDeathTest { DeathTest::TestRole NoExecDeathTest::AssumeRole() { const size_t thread_count = GetThreadCount(); if (thread_count != 1) { - GTEST_LOG(WARNING, DeathTestThreadWarning(thread_count)); + GTEST_LOG_(WARNING, DeathTestThreadWarning(thread_count)); } int pipe_fd[2]; - GTEST_DEATH_TEST_CHECK(pipe(pipe_fd) != -1); + GTEST_DEATH_TEST_CHECK_(pipe(pipe_fd) != -1); last_death_test_message = ""; CaptureStderr(); @@ -473,10 +473,10 @@ DeathTest::TestRole NoExecDeathTest::AssumeRole() { FlushInfoLog(); const pid_t child_pid = fork(); - GTEST_DEATH_TEST_CHECK(child_pid != -1); + GTEST_DEATH_TEST_CHECK_(child_pid != -1); set_child_pid(child_pid); if (child_pid == 0) { - GTEST_DEATH_TEST_CHECK_SYSCALL(close(pipe_fd[0])); + GTEST_DEATH_TEST_CHECK_SYSCALL_(close(pipe_fd[0])); set_write_fd(pipe_fd[1]); // Redirects all logging to stderr in the child process to prevent // concurrent writes to the log files. We capture stderr in the parent @@ -484,7 +484,7 @@ DeathTest::TestRole NoExecDeathTest::AssumeRole() { LogToStderr(); return EXECUTE_TEST; } else { - GTEST_DEATH_TEST_CHECK_SYSCALL(close(pipe_fd[1])); + GTEST_DEATH_TEST_CHECK_SYSCALL_(close(pipe_fd[1])); set_read_fd(pipe_fd[0]); set_forked(true); return OVERSEE_TEST; @@ -551,7 +551,7 @@ struct ExecDeathTestArgs { // any potentially unsafe operations like malloc or libc functions. static int ExecDeathTestChildMain(void* child_arg) { ExecDeathTestArgs* const args = static_cast(child_arg); - GTEST_DEATH_TEST_CHECK_SYSCALL(close(args->close_fd)); + GTEST_DEATH_TEST_CHECK_SYSCALL_(close(args->close_fd)); // We need to execute the test program in the same environment where // it was originally invoked. Therefore we change to the original @@ -599,14 +599,14 @@ static pid_t ExecDeathTestFork(char* const* argv, int close_fd) { const size_t stack_size = getpagesize(); void* const stack = mmap(NULL, stack_size, PROT_READ | PROT_WRITE, MAP_ANONYMOUS | MAP_PRIVATE, -1, 0); - GTEST_DEATH_TEST_CHECK(stack != MAP_FAILED); + GTEST_DEATH_TEST_CHECK_(stack != MAP_FAILED); void* const stack_top = static_cast(stack) + (stack_grows_down ? stack_size : 0); ExecDeathTestArgs args = { argv, close_fd }; const pid_t child_pid = clone(&ExecDeathTestChildMain, stack_top, SIGCHLD, &args); - GTEST_DEATH_TEST_CHECK(child_pid != -1); - GTEST_DEATH_TEST_CHECK(munmap(stack, stack_size) != -1); + GTEST_DEATH_TEST_CHECK_(child_pid != -1); + GTEST_DEATH_TEST_CHECK_(munmap(stack, stack_size) != -1); return child_pid; } @@ -627,10 +627,10 @@ DeathTest::TestRole ExecDeathTest::AssumeRole() { } int pipe_fd[2]; - GTEST_DEATH_TEST_CHECK(pipe(pipe_fd) != -1); + GTEST_DEATH_TEST_CHECK_(pipe(pipe_fd) != -1); // Clear the close-on-exec flag on the write end of the pipe, lest // it be closed when the child process does an exec: - GTEST_DEATH_TEST_CHECK(fcntl(pipe_fd[1], F_SETFD, 0) != -1); + GTEST_DEATH_TEST_CHECK_(fcntl(pipe_fd[1], F_SETFD, 0) != -1); const String filter_flag = String::Format("--%s%s=%s.%s", @@ -654,7 +654,7 @@ DeathTest::TestRole ExecDeathTest::AssumeRole() { FlushInfoLog(); const pid_t child_pid = ExecDeathTestFork(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_read_fd(pipe_fd[0]); set_forked(true); diff --git a/src/gtest-filepath.cc b/src/gtest-filepath.cc index dc0d78f0..fdb05629 100644 --- a/src/gtest-filepath.cc +++ b/src/gtest-filepath.cc @@ -36,10 +36,14 @@ #ifdef _WIN32_WCE #include -#elif defined(_WIN32) +#elif defined(GTEST_OS_WINDOWS) #include #include #include +#elif defined(GTEST_OS_SYMBIAN) +// Symbian OpenC has PATH_MAX in sys/syslimits.h +#include +#include #else #include #include @@ -249,7 +253,7 @@ bool FilePath::CreateDirectoriesRecursively() const { // directory for any reason, including if the parent directory does not // exist. Not named "CreateDirectory" because that's a macro on Windows. bool FilePath::CreateFolder() const { -#ifdef _WIN32 +#ifdef GTEST_OS_WINDOWS #ifdef _WIN32_WCE FilePath removed_sep(this->RemoveTrailingPathSeparator()); LPCWSTR unicode = String::AnsiToUtf16(removed_sep.c_str()); diff --git a/src/gtest-internal-inl.h b/src/gtest-internal-inl.h index d4889483..ce1d0f4f 100644 --- a/src/gtest-internal-inl.h +++ b/src/gtest-internal-inl.h @@ -64,16 +64,16 @@ namespace testing { // We don't want the users to modify these flags in the code, but want // Google Test's own unit tests to be able to access them. Therefore we // declare them here as opposed to in gtest.h. -GTEST_DECLARE_bool(break_on_failure); -GTEST_DECLARE_bool(catch_exceptions); -GTEST_DECLARE_string(color); -GTEST_DECLARE_string(filter); -GTEST_DECLARE_bool(list_tests); -GTEST_DECLARE_string(output); -GTEST_DECLARE_bool(print_time); -GTEST_DECLARE_int32(repeat); -GTEST_DECLARE_int32(stack_trace_depth); -GTEST_DECLARE_bool(show_internal_stack_frames); +GTEST_DECLARE_bool_(break_on_failure); +GTEST_DECLARE_bool_(catch_exceptions); +GTEST_DECLARE_string_(color); +GTEST_DECLARE_string_(filter); +GTEST_DECLARE_bool_(list_tests); +GTEST_DECLARE_string_(output); +GTEST_DECLARE_bool_(print_time); +GTEST_DECLARE_int32_(repeat); +GTEST_DECLARE_int32_(stack_trace_depth); +GTEST_DECLARE_bool_(show_internal_stack_frames); namespace internal { @@ -131,7 +131,7 @@ class GTestFlagSaver { bool print_time_; bool pretty_; internal::Int32 repeat_; -} GTEST_ATTRIBUTE_UNUSED; +} GTEST_ATTRIBUTE_UNUSED_; // Converts a Unicode code point to a narrow string in UTF-8 encoding. // code_point parameter is of type UInt32 because wchar_t may not be @@ -200,7 +200,7 @@ class ListNode { explicit ListNode(const E & element) : element_(element), next_(NULL) {} // We disallow copying ListNode - GTEST_DISALLOW_COPY_AND_ASSIGN(ListNode); + GTEST_DISALLOW_COPY_AND_ASSIGN_(ListNode); public: @@ -399,7 +399,7 @@ class List { int size_; // The number of elements in the list. // We disallow copying List. - GTEST_DISALLOW_COPY_AND_ASSIGN(List); + GTEST_DISALLOW_COPY_AND_ASSIGN_(List); }; // The virtual destructor of List. @@ -557,7 +557,7 @@ class TestResult { TimeInMillis elapsed_time_; // We disallow copying TestResult. - GTEST_DISALLOW_COPY_AND_ASSIGN(TestResult); + GTEST_DISALLOW_COPY_AND_ASSIGN_(TestResult); }; // class TestResult class TestInfoImpl { @@ -633,7 +633,7 @@ class TestInfoImpl { // test for the second time. internal::TestResult result_; - GTEST_DISALLOW_COPY_AND_ASSIGN(TestInfoImpl); + GTEST_DISALLOW_COPY_AND_ASSIGN_(TestInfoImpl); }; } // namespace internal @@ -765,7 +765,7 @@ class TestCase { internal::TimeInMillis elapsed_time_; // We disallow copying TestCases. - GTEST_DISALLOW_COPY_AND_ASSIGN(TestCase); + GTEST_DISALLOW_COPY_AND_ASSIGN_(TestCase); }; namespace internal { @@ -843,7 +843,7 @@ class OsStackTraceGetterInterface { virtual void UponLeavingGTest() = 0; private: - GTEST_DISALLOW_COPY_AND_ASSIGN(OsStackTraceGetterInterface); + GTEST_DISALLOW_COPY_AND_ASSIGN_(OsStackTraceGetterInterface); }; // A working implemenation of the OsStackTraceGetterInterface interface. @@ -866,7 +866,7 @@ class OsStackTraceGetter : public OsStackTraceGetterInterface { // and any calls to CurrentStackTrace() from within the user code. void* caller_frame_; - GTEST_DISALLOW_COPY_AND_ASSIGN(OsStackTraceGetter); + GTEST_DISALLOW_COPY_AND_ASSIGN_(OsStackTraceGetter); }; // Information about a Google Test trace point. @@ -876,24 +876,63 @@ struct TraceInfo { String message; }; +// This is the default global test part result reporter used in UnitTestImpl. +// This class should only be used by UnitTestImpl. +class DefaultGlobalTestPartResultReporter + : public TestPartResultReporterInterface { + public: + explicit DefaultGlobalTestPartResultReporter(UnitTestImpl* unit_test); + // Implements the TestPartResultReporterInterface. Reports the test part + // result in the current test. + virtual void ReportTestPartResult(const TestPartResult& result); + + private: + UnitTestImpl* const unit_test_; +}; + +// This is the default per thread test part result reporter used in +// UnitTestImpl. This class should only be used by UnitTestImpl. +class DefaultPerThreadTestPartResultReporter + : public TestPartResultReporterInterface { + public: + explicit DefaultPerThreadTestPartResultReporter(UnitTestImpl* unit_test); + // Implements the TestPartResultReporterInterface. The implementation just + // delegates to the current global test part result reporter of *unit_test_. + virtual void ReportTestPartResult(const TestPartResult& result); + + private: + UnitTestImpl* const unit_test_; +}; + // The private implementation of the UnitTest class. We don't protect // the methods under a mutex, as this class is not accessible by a // user and the UnitTest class that delegates work to this class does // proper locking. -class UnitTestImpl : public TestPartResultReporterInterface { +class UnitTestImpl { public: explicit UnitTestImpl(UnitTest* parent); virtual ~UnitTestImpl(); - // Reports a test part result. This method is from the - // TestPartResultReporterInterface interface. - virtual void ReportTestPartResult(const TestPartResult& result); + // There are two different ways to register your own TestPartResultReporter. + // You can register your own repoter to listen either only for test results + // from the current thread or for results from all threads. + // By default, each per-thread test result repoter just passes a new + // TestPartResult to the global test result reporter, which registers the + // test part result for the currently running test. + + // Returns the global test part result reporter. + TestPartResultReporterInterface* GetGlobalTestPartResultReporter(); - // Returns the current test part result reporter. - TestPartResultReporterInterface* test_part_result_reporter(); + // Sets the global test part result reporter. + void SetGlobalTestPartResultReporter( + TestPartResultReporterInterface* reporter); - // Sets the current test part result reporter. - void set_test_part_result_reporter(TestPartResultReporterInterface* reporter); + // Returns the test part result reporter for the current thread. + TestPartResultReporterInterface* GetTestPartResultReporterForCurrentThread(); + + // Sets the test part result reporter for the current thread. + void SetTestPartResultReporterForCurrentThread( + TestPartResultReporterInterface* reporter); // Gets the number of successful test cases. int successful_test_case_count() const; @@ -1107,8 +1146,20 @@ class UnitTestImpl : public TestPartResultReporterInterface { // executed. internal::FilePath original_working_dir_; - // Points to (but doesn't own) the test part result reporter. - TestPartResultReporterInterface* test_part_result_reporter_; + // The default test part result reporters. + DefaultGlobalTestPartResultReporter default_global_test_part_result_reporter_; + DefaultPerThreadTestPartResultReporter + default_per_thread_test_part_result_reporter_; + + // Points to (but doesn't own) the global test part result reporter. + TestPartResultReporterInterface* global_test_part_result_repoter_; + + // Protects read and write access to global_test_part_result_reporter_. + internal::Mutex global_test_part_result_reporter_mutex_; + + // Points to (but doesn't own) the per-thread test part result reporter. + internal::ThreadLocal + per_thread_test_part_result_reporter_; // The list of environments that need to be set-up/torn-down // before/after the tests are run. environments_in_reverse_order_ @@ -1168,7 +1219,7 @@ class UnitTestImpl : public TestPartResultReporterInterface { // A per-thread stack of traces created by the SCOPED_TRACE() macro. internal::ThreadLocal > gtest_trace_stack_; - GTEST_DISALLOW_COPY_AND_ASSIGN(UnitTestImpl); + GTEST_DISALLOW_COPY_AND_ASSIGN_(UnitTestImpl); }; // class UnitTestImpl // Convenience function for accessing the global UnitTest diff --git a/src/gtest-port.cc b/src/gtest-port.cc index b2871b8b..000a4ab1 100644 --- a/src/gtest-port.cc +++ b/src/gtest-port.cc @@ -172,7 +172,7 @@ static ::std::string ReadEntireFile(FILE * file) { // Starts capturing stderr. void CaptureStderr() { if (g_captured_stderr != NULL) { - GTEST_LOG(FATAL, "Only one stderr capturer can exist at one time."); + GTEST_LOG_(FATAL, "Only one stderr capturer can exist at one time."); } g_captured_stderr = new CapturedStderr; } diff --git a/src/gtest-test-part.cc b/src/gtest-test-part.cc new file mode 100644 index 00000000..dcd30b25 --- /dev/null +++ b/src/gtest-test-part.cc @@ -0,0 +1,124 @@ +// 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. +// +// Author: mheule@google.com (Markus Heule) +// +// The Google C++ Testing Framework (Google Test) + +#include + +// 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 +#include "src/gtest-internal-inl.h" +#undef GTEST_IMPLEMENTATION + +namespace testing { + +// Gets the summary of the failure message by omitting the stack trace +// in it. +internal::String TestPartResult::ExtractSummary(const char* message) { + const char* const stack_trace = strstr(message, internal::kStackTraceMarker); + return stack_trace == NULL ? internal::String(message) : + internal::String(message, stack_trace - message); +} + +// Prints a TestPartResult object. +std::ostream& operator<<(std::ostream& os, const TestPartResult& result) { + return os << result.file_name() << ":" + << result.line_number() << ": " + << (result.type() == TPRT_SUCCESS ? "Success" : + result.type() == TPRT_FATAL_FAILURE ? "Fatal failure" : + "Non-fatal failure") << ":\n" + << result.message() << std::endl; +} + +// Constructs an empty TestPartResultArray. +TestPartResultArray::TestPartResultArray() + : list_(new internal::List) { +} + +// Destructs a TestPartResultArray. +TestPartResultArray::~TestPartResultArray() { + delete list_; +} + +// Appends a TestPartResult to the array. +void TestPartResultArray::Append(const TestPartResult& result) { + list_->PushBack(result); +} + +// Returns the TestPartResult at the given index (0-based). +const TestPartResult& TestPartResultArray::GetTestPartResult(int index) const { + if (index < 0 || index >= size()) { + printf("\nInvalid index (%d) into TestPartResultArray.\n", index); + internal::abort(); + } + + const internal::ListNode* p = list_->Head(); + for (int i = 0; i < index; i++) { + p = p->next(); + } + + return p->element(); +} + +// Returns the number of TestPartResult objects in the array. +int TestPartResultArray::size() const { + return list_->size(); +} + +namespace internal { + +HasNewFatalFailureHelper::HasNewFatalFailureHelper() + : has_new_fatal_failure_(false), + original_reporter_(UnitTest::GetInstance()->impl()-> + GetTestPartResultReporterForCurrentThread()) { + UnitTest::GetInstance()->impl()->SetTestPartResultReporterForCurrentThread( + this); +} + +HasNewFatalFailureHelper::~HasNewFatalFailureHelper() { + UnitTest::GetInstance()->impl()->SetTestPartResultReporterForCurrentThread( + original_reporter_); +} + +void HasNewFatalFailureHelper::ReportTestPartResult( + const TestPartResult& result) { + if (result.fatally_failed()) + has_new_fatal_failure_ = true; + original_reporter_->ReportTestPartResult(result); +} + +} // namespace internal + +} // namespace testing diff --git a/src/gtest.cc b/src/gtest.cc index f8c11997..9cc50e05 100644 --- a/src/gtest.cc +++ b/src/gtest.cc @@ -60,11 +60,16 @@ #include #include +#elif defined(GTEST_OS_SYMBIAN) +// No autoconf on Symbian +#define GTEST_HAS_GETTIMEOFDAY +#include // NOLINT + #elif defined(_WIN32_WCE) // We are on Windows CE. #include // NOLINT -#elif defined(_WIN32) // We are on Windows proper. +#elif defined(GTEST_OS_WINDOWS) // We are on Windows proper. #include // NOLINT #include // NOLINT @@ -134,22 +139,26 @@ static const char kUniversalFilter[] = "*"; // The default output file for XML output. static const char kDefaultOutputFile[] = "test_detail.xml"; +namespace internal { + // The text used in failure messages to indicate the start of the // stack trace. -static const char kStackTraceMarker[] = "\nStack trace:\n"; +const char kStackTraceMarker[] = "\nStack trace:\n"; + +} // namespace internal -GTEST_DEFINE_bool( +GTEST_DEFINE_bool_( break_on_failure, internal::BoolFromGTestEnv("break_on_failure", false), "True iff a failed assertion should be a debugger break-point."); -GTEST_DEFINE_bool( +GTEST_DEFINE_bool_( catch_exceptions, internal::BoolFromGTestEnv("catch_exceptions", false), "True iff " GTEST_NAME " should catch exceptions and treat them as test failures."); -GTEST_DEFINE_string( +GTEST_DEFINE_string_( color, internal::StringFromGTestEnv("color", "auto"), "Whether to use colors in the output. Valid values: yes, no, " @@ -157,7 +166,7 @@ GTEST_DEFINE_string( "being sent to a terminal and the TERM environment variable " "is set to xterm or xterm-color."); -GTEST_DEFINE_string( +GTEST_DEFINE_string_( filter, internal::StringFromGTestEnv("filter", kUniversalFilter), "A colon-separated list of glob (not regex) patterns " @@ -166,10 +175,10 @@ GTEST_DEFINE_string( "exclude). A test is run if it matches one of the positive " "patterns and does not match any of the negative patterns."); -GTEST_DEFINE_bool(list_tests, false, - "List all tests without running them."); +GTEST_DEFINE_bool_(list_tests, false, + "List all tests without running them."); -GTEST_DEFINE_string( +GTEST_DEFINE_string_( output, internal::StringFromGTestEnv("output", ""), "A format (currently must be \"xml\"), optionally followed " @@ -181,37 +190,29 @@ GTEST_DEFINE_string( "executable's name and, if necessary, made unique by adding " "digits."); -GTEST_DEFINE_bool( +GTEST_DEFINE_bool_( print_time, internal::BoolFromGTestEnv("print_time", false), "True iff " GTEST_NAME " should display elapsed time in text output."); -GTEST_DEFINE_int32( +GTEST_DEFINE_int32_( repeat, internal::Int32FromGTestEnv("repeat", 1), "How many times to repeat each test. Specify a negative number " "for repeating forever. Useful for shaking out flaky tests."); -GTEST_DEFINE_int32( +GTEST_DEFINE_int32_( stack_trace_depth, internal::Int32FromGTestEnv("stack_trace_depth", kMaxStackTraceDepth), "The maximum number of stack frames to print when an " "assertion fails. The valid range is 0 through 100, inclusive."); -GTEST_DEFINE_bool( +GTEST_DEFINE_bool_( show_internal_stack_frames, false, "True iff " GTEST_NAME " should include internal stack frames when " "printing test failure stack traces."); -// Gets the summary of the failure message by omitting the stack trace -// in it. -internal::String TestPartResult::ExtractSummary(const char* message) { - const char* const stack_trace = strstr(message, kStackTraceMarker); - return stack_trace == NULL ? internal::String(message) : - internal::String(message, stack_trace - message); -} - namespace internal { // GTestIsInitialized() returns true iff the user has initialized @@ -280,11 +281,11 @@ String g_executable_path; FilePath GetCurrentExecutableName() { FilePath result; -#if defined(_WIN32_WCE) || defined(_WIN32) +#if defined(_WIN32_WCE) || defined(GTEST_OS_WINDOWS) result.Set(FilePath(g_executable_path).RemoveExtension("exe")); #else result.Set(FilePath(g_executable_path)); -#endif // _WIN32_WCE || _WIN32 +#endif // _WIN32_WCE || GTEST_OS_WINDOWS return result.RemoveDirectoryName(); } @@ -456,58 +457,46 @@ class UnitTestEventListenerInterface { virtual void OnNewTestPartResult(const TestPartResult*) {} }; -// Constructs an empty TestPartResultArray. -TestPartResultArray::TestPartResultArray() - : list_(new internal::List) { -} - -// Destructs a TestPartResultArray. -TestPartResultArray::~TestPartResultArray() { - delete list_; -} - -// Appends a TestPartResult to the array. -void TestPartResultArray::Append(const TestPartResult& result) { - list_->PushBack(result); -} - -// Returns the TestPartResult at the given index (0-based). -const TestPartResult& TestPartResultArray::GetTestPartResult(int index) const { - if (index < 0 || index >= size()) { - printf("\nInvalid index (%d) into TestPartResultArray.\n", index); - internal::abort(); - } - - const internal::ListNode* p = list_->Head(); - for (int i = 0; i < index; i++) { - p = p->next(); - } - - return p->element(); -} - -// Returns the number of TestPartResult objects in the array. -int TestPartResultArray::size() const { - return list_->size(); +// The c'tor sets this object as the test part result reporter used by +// Google Test. The 'result' parameter specifies where to report the +// results. Intercepts only failures from the current thread. +ScopedFakeTestPartResultReporter::ScopedFakeTestPartResultReporter( + TestPartResultArray* result) + : intercept_mode_(INTERCEPT_ONLY_CURRENT_THREAD), + result_(result) { + Init(); } // The c'tor sets this object as the test part result reporter used by // Google Test. The 'result' parameter specifies where to report the // results. ScopedFakeTestPartResultReporter::ScopedFakeTestPartResultReporter( - TestPartResultArray* result) - : old_reporter_(UnitTest::GetInstance()->impl()-> - test_part_result_reporter()), + InterceptMode intercept_mode, TestPartResultArray* result) + : intercept_mode_(intercept_mode), result_(result) { + Init(); +} + +void ScopedFakeTestPartResultReporter::Init() { internal::UnitTestImpl* const impl = UnitTest::GetInstance()->impl(); - impl->set_test_part_result_reporter(this); + if (intercept_mode_ == INTERCEPT_ALL_THREADS) { + old_reporter_ = impl->GetGlobalTestPartResultReporter(); + impl->SetGlobalTestPartResultReporter(this); + } else { + old_reporter_ = impl->GetTestPartResultReporterForCurrentThread(); + impl->SetTestPartResultReporterForCurrentThread(this); + } } // The d'tor restores the test part result reporter used by Google Test // before. ScopedFakeTestPartResultReporter::~ScopedFakeTestPartResultReporter() { - UnitTest::GetInstance()->impl()-> - set_test_part_result_reporter(old_reporter_); + internal::UnitTestImpl* const impl = UnitTest::GetInstance()->impl(); + if (intercept_mode_ == INTERCEPT_ALL_THREADS) { + impl->SetGlobalTestPartResultReporter(old_reporter_); + } else { + impl->SetTestPartResultReporterForCurrentThread(old_reporter_); + } } // Increments the test part result count and remembers the result. @@ -579,21 +568,47 @@ SingleFailureChecker::~SingleFailureChecker() { EXPECT_PRED_FORMAT3(HasOneFailure, *results_, type_, substr_.c_str()); } -// Reports a test part result. -void UnitTestImpl::ReportTestPartResult(const TestPartResult& result) { - current_test_result()->AddTestPartResult(result); - result_printer()->OnNewTestPartResult(&result); +DefaultGlobalTestPartResultReporter::DefaultGlobalTestPartResultReporter( + UnitTestImpl* unit_test) : unit_test_(unit_test) {} + +void DefaultGlobalTestPartResultReporter::ReportTestPartResult( + const TestPartResult& result) { + unit_test_->current_test_result()->AddTestPartResult(result); + unit_test_->result_printer()->OnNewTestPartResult(&result); +} + +DefaultPerThreadTestPartResultReporter::DefaultPerThreadTestPartResultReporter( + UnitTestImpl* unit_test) : unit_test_(unit_test) {} + +void DefaultPerThreadTestPartResultReporter::ReportTestPartResult( + const TestPartResult& result) { + unit_test_->GetGlobalTestPartResultReporter()->ReportTestPartResult(result); +} + +// Returns the global test part result reporter. +TestPartResultReporterInterface* +UnitTestImpl::GetGlobalTestPartResultReporter() { + internal::MutexLock lock(&global_test_part_result_reporter_mutex_); + return global_test_part_result_repoter_; } -// Returns the current test part result reporter. -TestPartResultReporterInterface* UnitTestImpl::test_part_result_reporter() { - return test_part_result_reporter_; +// Sets the global test part result reporter. +void UnitTestImpl::SetGlobalTestPartResultReporter( + TestPartResultReporterInterface* reporter) { + internal::MutexLock lock(&global_test_part_result_reporter_mutex_); + global_test_part_result_repoter_ = reporter; +} + +// Returns the test part result reporter for the current thread. +TestPartResultReporterInterface* +UnitTestImpl::GetTestPartResultReporterForCurrentThread() { + return per_thread_test_part_result_reporter_.get(); } -// Sets the current test part result reporter. -void UnitTestImpl::set_test_part_result_reporter( +// Sets the test part result reporter for the current thread. +void UnitTestImpl::SetTestPartResultReporterForCurrentThread( TestPartResultReporterInterface* reporter) { - test_part_result_reporter_ = reporter; + per_thread_test_part_result_reporter_.set(reporter); } // Gets the number of successful test cases. @@ -678,7 +693,7 @@ static TimeInMillis GetTimeInMillis() { return now_int64.QuadPart; } return 0; -#elif defined(_WIN32) && !defined(GTEST_HAS_GETTIMEOFDAY) +#elif defined(GTEST_OS_WINDOWS) && !defined(GTEST_HAS_GETTIMEOFDAY) __timeb64 now; #ifdef _MSC_VER // MSVC 8 deprecates _ftime64(), so we want to suppress warning 4996 @@ -1039,7 +1054,7 @@ AssertionResult CmpHelperEQ(const char* expected_expression, // A macro for implementing the helper functions needed to implement // ASSERT_?? and EXPECT_?? with integer or enum arguments. It is here // just to avoid copy-and-paste of similar code. -#define GTEST_IMPL_CMP_HELPER(op_name, op)\ +#define GTEST_IMPL_CMP_HELPER_(op_name, op)\ AssertionResult CmpHelper##op_name(const char* expr1, const char* expr2, \ BiggestInt val1, BiggestInt val2) {\ if (val1 op val2) {\ @@ -1055,21 +1070,21 @@ AssertionResult CmpHelper##op_name(const char* expr1, const char* expr2, \ // Implements the helper function for {ASSERT|EXPECT}_NE with int or // enum arguments. -GTEST_IMPL_CMP_HELPER(NE, !=) +GTEST_IMPL_CMP_HELPER_(NE, !=) // Implements the helper function for {ASSERT|EXPECT}_LE with int or // enum arguments. -GTEST_IMPL_CMP_HELPER(LE, <=) +GTEST_IMPL_CMP_HELPER_(LE, <=) // Implements the helper function for {ASSERT|EXPECT}_LT with int or // enum arguments. -GTEST_IMPL_CMP_HELPER(LT, < ) +GTEST_IMPL_CMP_HELPER_(LT, < ) // Implements the helper function for {ASSERT|EXPECT}_GE with int or // enum arguments. -GTEST_IMPL_CMP_HELPER(GE, >=) +GTEST_IMPL_CMP_HELPER_(GE, >=) // Implements the helper function for {ASSERT|EXPECT}_GT with int or // enum arguments. -GTEST_IMPL_CMP_HELPER(GT, > ) +GTEST_IMPL_CMP_HELPER_(GT, > ) -#undef GTEST_IMPL_CMP_HELPER +#undef GTEST_IMPL_CMP_HELPER_ // The helper function for {ASSERT|EXPECT}_STREQ. AssertionResult CmpHelperSTREQ(const char* expected_expression, @@ -1722,19 +1737,6 @@ String AppendUserMessage(const String& gtest_msg, return msg.GetString(); } -} // namespace internal - -// Prints a TestPartResult object. -std::ostream& operator<<(std::ostream& os, const TestPartResult& result) { - return os << result.file_name() << ":" - << result.line_number() << ": " - << (result.type() == TPRT_SUCCESS ? "Success" : - result.type() == TPRT_FATAL_FAILURE ? "Fatal failure" : - "Non-fatal failure") << ":\n" - << result.message() << std::endl; -} - -namespace internal { // class TestResult // Creates an empty TestResult. @@ -2380,7 +2382,7 @@ enum GTestColor { COLOR_YELLOW }; -#if defined(_WIN32) && !defined(_WIN32_WCE) +#if defined(GTEST_OS_WINDOWS) && !defined(_WIN32_WCE) // Returns the character attribute for the given color. WORD GetColorAttribute(GTestColor color) { @@ -2404,14 +2406,14 @@ const char* GetAnsiColorCode(GTestColor color) { return NULL; } -#endif // _WIN32 && !_WIN32_WCE +#endif // GTEST_OS_WINDOWS && !_WIN32_WCE // Returns true iff Google Test should use colors in the output. bool ShouldUseColor(bool stdout_is_tty) { const char* const gtest_color = GTEST_FLAG(color).c_str(); if (String::CaseInsensitiveCStringEquals(gtest_color, "auto")) { -#ifdef _WIN32 +#ifdef GTEST_OS_WINDOWS // On Windows the TERM variable is usually not set, but the // console there does support colors. return stdout_is_tty; @@ -2423,7 +2425,7 @@ bool ShouldUseColor(bool stdout_is_tty) { String::CStringEquals(term, "xterm-color") || String::CStringEquals(term, "cygwin"); return stdout_is_tty && term_supports_color; -#endif // _WIN32 +#endif // GTEST_OS_WINDOWS } return String::CaseInsensitiveCStringEquals(gtest_color, "yes") || @@ -2443,7 +2445,7 @@ void ColoredPrintf(GTestColor color, const char* fmt, ...) { va_list args; va_start(args, fmt); -#ifdef _WIN32_WCE +#if defined(_WIN32_WCE) || defined(GTEST_OS_SYMBIAN) static const bool use_color = false; #else static const bool use_color = ShouldUseColor(isatty(fileno(stdout)) != 0); @@ -2456,7 +2458,7 @@ void ColoredPrintf(GTestColor color, const char* fmt, ...) { return; } -#if defined(_WIN32) && !defined(_WIN32_WCE) +#if defined(GTEST_OS_WINDOWS) && !defined(_WIN32_WCE) const HANDLE stdout_handle = GetStdHandle(STD_OUTPUT_HANDLE); // Gets the current text color. @@ -2474,7 +2476,7 @@ void ColoredPrintf(GTestColor color, const char* fmt, ...) { printf("\033[0;3%sm", GetAnsiColorCode(color)); vprintf(fmt, args); printf("\033[m"); // Resets the terminal to default. -#endif // _WIN32 && !_WIN32_WCE +#endif // GTEST_OS_WINDOWS && !_WIN32_WCE va_end(args); } @@ -2718,7 +2720,7 @@ class UnitTestEventsRepeater : public UnitTestEventListenerInterface { private: Listeners listeners_; - GTEST_DISALLOW_COPY_AND_ASSIGN(UnitTestEventsRepeater); + GTEST_DISALLOW_COPY_AND_ASSIGN_(UnitTestEventsRepeater); }; UnitTestEventsRepeater::~UnitTestEventsRepeater() { @@ -2736,7 +2738,7 @@ void UnitTestEventsRepeater::AddListener( // Since the methods are identical, use a macro to reduce boilerplate. // This defines a member that repeats the call to all listeners. -#define GTEST_REPEATER_METHOD(Name, Type) \ +#define GTEST_REPEATER_METHOD_(Name, Type) \ void UnitTestEventsRepeater::Name(const Type* parameter) { \ for (ListenersNode* listener = listeners_.Head(); \ listener != NULL; \ @@ -2745,19 +2747,19 @@ void UnitTestEventsRepeater::Name(const Type* parameter) { \ } \ } -GTEST_REPEATER_METHOD(OnUnitTestStart, UnitTest) -GTEST_REPEATER_METHOD(OnUnitTestEnd, UnitTest) -GTEST_REPEATER_METHOD(OnGlobalSetUpStart, UnitTest) -GTEST_REPEATER_METHOD(OnGlobalSetUpEnd, UnitTest) -GTEST_REPEATER_METHOD(OnGlobalTearDownStart, UnitTest) -GTEST_REPEATER_METHOD(OnGlobalTearDownEnd, UnitTest) -GTEST_REPEATER_METHOD(OnTestCaseStart, TestCase) -GTEST_REPEATER_METHOD(OnTestCaseEnd, TestCase) -GTEST_REPEATER_METHOD(OnTestStart, TestInfo) -GTEST_REPEATER_METHOD(OnTestEnd, TestInfo) -GTEST_REPEATER_METHOD(OnNewTestPartResult, TestPartResult) +GTEST_REPEATER_METHOD_(OnUnitTestStart, UnitTest) +GTEST_REPEATER_METHOD_(OnUnitTestEnd, UnitTest) +GTEST_REPEATER_METHOD_(OnGlobalSetUpStart, UnitTest) +GTEST_REPEATER_METHOD_(OnGlobalSetUpEnd, UnitTest) +GTEST_REPEATER_METHOD_(OnGlobalTearDownStart, UnitTest) +GTEST_REPEATER_METHOD_(OnGlobalTearDownEnd, UnitTest) +GTEST_REPEATER_METHOD_(OnTestCaseStart, TestCase) +GTEST_REPEATER_METHOD_(OnTestCaseEnd, TestCase) +GTEST_REPEATER_METHOD_(OnTestStart, TestInfo) +GTEST_REPEATER_METHOD_(OnTestEnd, TestInfo) +GTEST_REPEATER_METHOD_(OnNewTestPartResult, TestPartResult) -#undef GTEST_REPEATER_METHOD +#undef GTEST_REPEATER_METHOD_ // End PrettyUnitTestResultPrinter @@ -2818,7 +2820,7 @@ class XmlUnitTestResultPrinter : public UnitTestEventListenerInterface { // The output file. const internal::String output_file_; - GTEST_DISALLOW_COPY_AND_ASSIGN(XmlUnitTestResultPrinter); + GTEST_DISALLOW_COPY_AND_ASSIGN_(XmlUnitTestResultPrinter); }; // Creates a new XmlUnitTestResultPrinter. @@ -3181,13 +3183,14 @@ void UnitTest::AddTestPartResult(TestPartResultType result_type, } if (os_stack_trace.c_str() != NULL && !os_stack_trace.empty()) { - msg << kStackTraceMarker << os_stack_trace; + msg << internal::kStackTraceMarker << os_stack_trace; } const TestPartResult result = TestPartResult(result_type, file_name, line_number, msg.GetString().c_str()); - impl_->test_part_result_reporter()->ReportTestPartResult(result); + impl_->GetTestPartResultReporterForCurrentThread()-> + ReportTestPartResult(result); // If this is a failure and the user wants the debugger to break on // failures ... @@ -3291,6 +3294,21 @@ namespace internal { UnitTestImpl::UnitTestImpl(UnitTest* parent) : parent_(parent), +#ifdef _MSC_VER +#pragma warning(push) // Saves the current warning state. +#pragma warning(disable:4355) // Temporarily disables warning 4355 + // (using this in initializer). + default_global_test_part_result_reporter_(this), + default_per_thread_test_part_result_reporter_(this), +#pragma warning(pop) // Restores the warning state again. +#else + default_global_test_part_result_reporter_(this), + default_per_thread_test_part_result_reporter_(this), +#endif // _MSC_VER + global_test_part_result_repoter_( + &default_global_test_part_result_reporter_), + per_thread_test_part_result_reporter_( + &default_per_thread_test_part_result_reporter_), test_cases_(), last_death_test_case_(NULL), current_test_case_(NULL), @@ -3305,10 +3323,6 @@ UnitTestImpl::UnitTestImpl(UnitTest* parent) #else elapsed_time_(0) { #endif // GTEST_HAS_DEATH_TEST - // We do the assignment here instead of in the initializer list, as - // doing that latter causes MSVC to issue a warning about using - // 'this' in initializers. - test_part_result_reporter_ = this; } UnitTestImpl::~UnitTestImpl() { -- cgit v1.2.3 From 66179b1fb5b6943166d4209182ce869e984cf388 Mon Sep 17 00:00:00 2001 From: chandlerc Date: Tue, 21 Oct 2008 05:05:14 +0000 Subject: On some Linux distros, you need to explicitly #include to get the definition of PATH_MAX. This patch adds it in the appropriate place. --- src/gtest-filepath.cc | 1 + 1 file changed, 1 insertion(+) (limited to 'src') diff --git a/src/gtest-filepath.cc b/src/gtest-filepath.cc index fdb05629..fc4b7873 100644 --- a/src/gtest-filepath.cc +++ b/src/gtest-filepath.cc @@ -45,6 +45,7 @@ #include #include #else +#include #include #include #endif // _WIN32_WCE or _WIN32 -- cgit v1.2.3 From d2849f573052ba8431a887e0034b1be353a0d9b4 Mon Sep 17 00:00:00 2001 From: shiqian Date: Mon, 10 Nov 2008 18:27:46 +0000 Subject: Makes Google Test compile on Solaris and z/OS. By Rainer Klaffenboeck. --- src/gtest-filepath.cc | 16 +++++++++++++--- src/gtest.cc | 6 +++++- 2 files changed, 18 insertions(+), 4 deletions(-) (limited to 'src') diff --git a/src/gtest-filepath.cc b/src/gtest-filepath.cc index fc4b7873..640c27c3 100644 --- a/src/gtest-filepath.cc +++ b/src/gtest-filepath.cc @@ -48,7 +48,17 @@ #include #include #include -#endif // _WIN32_WCE or _WIN32 +#endif // _WIN32_WCE or _WIN32 + +#ifdef GTEST_OS_WINDOWS +#define GTEST_PATH_MAX_ _MAX_PATH +#elif defined(PATH_MAX) +#define GTEST_PATH_MAX_ PATH_MAX +#elif defined(_XOPEN_PATH_MAX) +#define GTEST_PATH_MAX_ _XOPEN_PATH_MAX +#else +#define GTEST_PATH_MAX_ _POSIX_PATH_MAX +#endif // GTEST_OS_WINDOWS #include @@ -81,10 +91,10 @@ FilePath FilePath::GetCurrentDir() { // something reasonable. return FilePath(kCurrentDirectoryString); #elif defined(GTEST_OS_WINDOWS) - char cwd[_MAX_PATH + 1] = {}; + char cwd[GTEST_PATH_MAX_ + 1] = {}; return FilePath(_getcwd(cwd, sizeof(cwd)) == NULL ? "" : cwd); #else - char cwd[PATH_MAX + 1] = {}; + char cwd[GTEST_PATH_MAX_ + 1] = {}; return FilePath(getcwd(cwd, sizeof(cwd)) == NULL ? "" : cwd); #endif } diff --git a/src/gtest.cc b/src/gtest.cc index 9cc50e05..b5c3d077 100644 --- a/src/gtest.cc +++ b/src/gtest.cc @@ -65,6 +65,10 @@ #define GTEST_HAS_GETTIMEOFDAY #include // NOLINT +#elif defined(GTEST_OS_ZOS) +// On z/OS we additionally need strings.h for strcasecmp. +#include + #elif defined(_WIN32_WCE) // We are on Windows CE. #include // NOLINT @@ -2445,7 +2449,7 @@ void ColoredPrintf(GTestColor color, const char* fmt, ...) { va_list args; va_start(args, fmt); -#if defined(_WIN32_WCE) || defined(GTEST_OS_SYMBIAN) +#if defined(_WIN32_WCE) || defined(GTEST_OS_SYMBIAN) || defined(GTEST_OS_ZOS) static const bool use_color = false; #else static const bool use_color = ShouldUseColor(isatty(fileno(stdout)) != 0); -- cgit v1.2.3 From 3d7042176307f0d7700a3640f3b3bcc8790b8fcd Mon Sep 17 00:00:00 2001 From: vladlosev Date: Thu, 20 Nov 2008 01:40:35 +0000 Subject: Value-parameterized tests and many bugfixes --- src/gtest-internal-inl.h | 28 ++++++++++++++-- src/gtest-port.cc | 32 +++++++++++++++--- src/gtest.cc | 85 ++++++++++++++++++++++++++++++++++++++++++++---- 3 files changed, 132 insertions(+), 13 deletions(-) (limited to 'src') diff --git a/src/gtest-internal-inl.h b/src/gtest-internal-inl.h index ce1d0f4f..0f2bcfba 100644 --- a/src/gtest-internal-inl.h +++ b/src/gtest-internal-inl.h @@ -53,7 +53,6 @@ #include // NOLINT #endif // GTEST_OS_WINDOWS -#include // NOLINT #include #include @@ -846,7 +845,7 @@ class OsStackTraceGetterInterface { GTEST_DISALLOW_COPY_AND_ASSIGN_(OsStackTraceGetterInterface); }; -// A working implemenation of the OsStackTraceGetterInterface interface. +// A working implementation of the OsStackTraceGetterInterface interface. class OsStackTraceGetter : public OsStackTraceGetterInterface { public: OsStackTraceGetter() {} @@ -1063,6 +1062,14 @@ class UnitTestImpl { tear_down_tc)->AddTestInfo(test_info); } +#ifdef GTEST_HAS_PARAM_TEST + // Returns ParameterizedTestCaseRegistry object used to keep track of + // value-parameterized tests and instantiate and register them. + internal::ParameterizedTestCaseRegistry& parameterized_test_registry() { + return parameterized_test_registry_; + } +#endif // GTEST_HAS_PARAM_TEST + // Sets the TestCase object for the test that's currently running. void set_current_test_case(TestCase* current_test_case) { current_test_case_ = current_test_case; @@ -1075,6 +1082,14 @@ class UnitTestImpl { current_test_info_ = current_test_info; } + // Registers all parameterized tests defined using TEST_P and + // INSTANTIATE_TEST_P, creating regular tests for each test/parameter + // combination. This method can be called more then once; it has + // guards protecting from registering the tests more then once. + // If value-parameterized tests are disabled, RegisterParameterizedTests + // is present but does nothing. + void RegisterParameterizedTests(); + // Runs all tests in this UnitTest object, prints the result, and // returns 0 if all tests are successful, or 1 otherwise. If any // exception is thrown during a test on Windows, this test is @@ -1169,6 +1184,15 @@ class UnitTestImpl { internal::List test_cases_; // The list of TestCases. +#ifdef GTEST_HAS_PARAM_TEST + // ParameterizedTestRegistry object used to register value-parameterized + // tests. + internal::ParameterizedTestCaseRegistry parameterized_test_registry_; + + // Indicates whether RegisterParameterizedTests() has been called already. + bool parameterized_tests_registered_; +#endif // GTEST_HAS_PARAM_TEST + // Points to the last death test case registered. Initially NULL. internal::ListNode* last_death_test_case_; diff --git a/src/gtest-port.cc b/src/gtest-port.cc index 000a4ab1..9878cae0 100644 --- a/src/gtest-port.cc +++ b/src/gtest-port.cc @@ -56,25 +56,49 @@ namespace internal { // Implements RE. Currently only needed for death tests. RE::~RE() { - regfree(®ex_); + regfree(&partial_regex_); + regfree(&full_regex_); free(const_cast(pattern_)); } -// Returns true iff str contains regular expression re. +// Returns true iff regular expression re matches the entire str. +bool RE::FullMatch(const char* str, const RE& re) { + if (!re.is_valid_) return false; + + regmatch_t match; + return regexec(&re.full_regex_, str, 1, &match, 0) == 0; +} + +// Returns true iff regular expression re matches a substring of str +// (including str itself). bool RE::PartialMatch(const char* str, const RE& re) { if (!re.is_valid_) return false; regmatch_t match; - return regexec(&re.regex_, str, 1, &match, 0) == 0; + return regexec(&re.partial_regex_, str, 1, &match, 0) == 0; } // Initializes an RE from its string representation. void RE::Init(const char* regex) { pattern_ = strdup(regex); - is_valid_ = regcomp(®ex_, regex, REG_EXTENDED) == 0; + + // Reserves enough bytes to hold the regular expression used for a + // full match. + const size_t full_regex_len = strlen(regex) + 10; + char* const full_pattern = new char[full_regex_len]; + + snprintf(full_pattern, full_regex_len, "^(%s)$", regex); + is_valid_ = regcomp(&full_regex_, full_pattern, REG_EXTENDED) == 0; + // We want to call regcomp(&partial_regex_, ...) even if the + // previous expression returns false. Otherwise partial_regex_ may + // not be properly initialized can may cause trouble when it's + // freed. + is_valid_ = (regcomp(&partial_regex_, regex, REG_EXTENDED) == 0) && is_valid_; EXPECT_TRUE(is_valid_) << "Regular expression \"" << regex << "\" is not a valid POSIX Extended regular expression."; + + delete[] full_pattern; } #endif // GTEST_HAS_DEATH_TEST diff --git a/src/gtest.cc b/src/gtest.cc index b5c3d077..83708300 100644 --- a/src/gtest.cc +++ b/src/gtest.cc @@ -277,6 +277,9 @@ void AssertHelper::operator=(const Message& message) const { ); // NOLINT } +// Mutex for linked pointers. +Mutex g_linked_ptr_mutex(Mutex::NO_CONSTRUCTOR_NEEDED_FOR_STATIC_MUTEX); + // Application pathname gotten in InitGoogleTest. String g_executable_path; @@ -830,7 +833,7 @@ static void StreamWideCharsToMessage(const wchar_t* wstr, size_t len, // several other places). for (size_t i = 0; i != len; ) { // NOLINT if (wstr[i] != L'\0') { - *msg << WideStringToUtf8(wstr + i, len - i); + *msg << WideStringToUtf8(wstr + i, static_cast(len - i)); while (i != len && wstr[i] != L'\0') i++; } else { @@ -1453,7 +1456,7 @@ inline UInt32 CreateCodePointFromUtf16SurrogatePair(wchar_t first, // will be encoded as individual Unicode characters from Basic Normal Plane. String WideStringToUtf8(const wchar_t* str, int num_chars) { if (num_chars == -1) - num_chars = wcslen(str); + num_chars = static_cast(wcslen(str)); StrStream stream; for (int i = 0; i < num_chars; ++i) { @@ -2080,6 +2083,25 @@ TestInfo* MakeAndRegisterTestInfo( return test_info; } +#ifdef GTEST_HAS_PARAM_TEST +void ReportInvalidTestCaseType(const char* test_case_name, + const char* file, int line) { + Message errors; + errors + << "Attempted redefinition of test case " << test_case_name << ".\n" + << "All tests in the same test case must use the same test fixture\n" + << "class. However, in test case " << test_case_name << ", you tried\n" + << "to define a test using a fixture class different from the one\n" + << "used earlier. This can happen if the two fixture classes are\n" + << "from different namespaces and have the same name. You should\n" + << "probably rename one of the classes to put the tests into different\n" + << "test cases."; + + fprintf(stderr, "%s %s", FormatFileLocation(file, line).c_str(), + errors.GetString().c_str()); +} +#endif // GTEST_HAS_PARAM_TEST + } // namespace internal // Returns the test case name. @@ -2156,6 +2178,18 @@ TestInfo * TestCase::GetTestInfo(const char* test_name) { namespace internal { +// This method expands all parameterized tests registered with macros TEST_P +// and INSTANTIATE_TEST_CASE_P into regular tests and registers those. +// This will be done just once during the program runtime. +void UnitTestImpl::RegisterParameterizedTests() { +#ifdef GTEST_HAS_PARAM_TEST + if (!parameterized_tests_registered_) { + parameterized_test_registry_.RegisterTests(); + parameterized_tests_registered_ = true; + } +#endif +} + // Creates the test object, runs it, records its result, and then // deletes it. void TestInfoImpl::Run() { @@ -3269,6 +3303,16 @@ const TestInfo* UnitTest::current_test_info() const { return impl_->current_test_info(); } +#ifdef GTEST_HAS_PARAM_TEST +// Returns ParameterizedTestCaseRegistry object used to keep track of +// value-parameterized tests and instantiate and register them. +// L < mutex_ +internal::ParameterizedTestCaseRegistry& + UnitTest::parameterized_test_registry() { + return impl_->parameterized_test_registry(); +} +#endif // GTEST_HAS_PARAM_TEST + // Creates an empty UnitTest. UnitTest::UnitTest() { impl_ = new internal::UnitTestImpl(this); @@ -3314,6 +3358,10 @@ UnitTestImpl::UnitTestImpl(UnitTest* parent) per_thread_test_part_result_reporter_( &default_per_thread_test_part_result_reporter_), test_cases_(), +#ifdef GTEST_HAS_PARAM_TEST + parameterized_test_registry_(), + parameterized_tests_registered_(false), +#endif // GTEST_HAS_PARAM_TEST last_death_test_case_(NULL), current_test_case_(NULL), current_test_info_(NULL), @@ -3415,6 +3463,10 @@ static void TearDownEnvironment(Environment* env) { env->TearDown(); } // considered to be failed, but the rest of the tests will still be // run. (We disable exceptions on Linux and Mac OS X, so the issue // doesn't apply there.) +// When parameterized tests are enabled, it explands and registers +// parameterized tests first in RegisterParameterizedTests(). +// All other functions called from RunAllTests() may safely assume that +// parameterized tests are ready to be counted and run. int UnitTestImpl::RunAllTests() { // Makes sure InitGoogleTest() was called. if (!GTestIsInitialized()) { @@ -3424,6 +3476,8 @@ int UnitTestImpl::RunAllTests() { return 1; } + RegisterParameterizedTests(); + // Lists all the tests and exits if the --gtest_list_tests // flag was specified. if (GTEST_FLAG(list_tests)) { @@ -3639,7 +3693,7 @@ internal::TestResult* UnitTestImpl::current_test_result() { } // TestInfoImpl constructor. The new instance assumes ownership of the test -// factory opbject. +// factory object. TestInfoImpl::TestInfoImpl(TestInfo* parent, const char* test_case_name, const char* name, @@ -3663,10 +3717,6 @@ TestInfoImpl::~TestInfoImpl() { delete factory_; } -} // namespace internal - -namespace internal { - // Parses a string as a command line flag. The string should have // the format "--flag=value". When def_optional is true, the "=value" // part can be omitted. @@ -3814,6 +3864,27 @@ void InitGoogleTestImpl(int* argc, CharType** argv) { } } +// Returns the current OS stack trace as a String. +// +// The maximum number of stack frames to be included is specified by +// the gtest_stack_trace_depth flag. The skip_count parameter +// specifies the number of top frames to be skipped, which doesn't +// count against the number of frames to be included. +// +// For example, if Foo() calls Bar(), which in turn calls +// GetCurrentOsStackTraceExceptTop(..., 1), Foo() will be included in +// the trace but Bar() and GetCurrentOsStackTraceExceptTop() won't. +String GetCurrentOsStackTraceExceptTop(UnitTest* unit_test, int skip_count) { + // We pass skip_count + 1 to skip this wrapper function in addition + // to what the user really wants to skip. + return unit_test->impl()->CurrentOsStackTraceExceptTop(skip_count + 1); +} + +// Returns the number of failed test parts in the given test result object. +int GetFailedPartCount(const TestResult* result) { + return result->failed_part_count(); +} + } // namespace internal // Initializes Google Test. This must be called before calling -- cgit v1.2.3 From 38e1f9ab9cb0308f435c9a27bb084046783aaeb4 Mon Sep 17 00:00:00 2001 From: shiqian Date: Thu, 20 Nov 2008 04:56:21 +0000 Subject: Moves a code block in gtest.cc to mirror the change in the Google internal version of gtest. --- src/gtest.cc | 42 +++++++++++++++++++++--------------------- 1 file changed, 21 insertions(+), 21 deletions(-) (limited to 'src') diff --git a/src/gtest.cc b/src/gtest.cc index 83708300..4a67b7a2 100644 --- a/src/gtest.cc +++ b/src/gtest.cc @@ -3717,6 +3717,27 @@ TestInfoImpl::~TestInfoImpl() { delete factory_; } +// Returns the current OS stack trace as a String. +// +// The maximum number of stack frames to be included is specified by +// the gtest_stack_trace_depth flag. The skip_count parameter +// specifies the number of top frames to be skipped, which doesn't +// count against the number of frames to be included. +// +// For example, if Foo() calls Bar(), which in turn calls +// GetCurrentOsStackTraceExceptTop(..., 1), Foo() will be included in +// the trace but Bar() and GetCurrentOsStackTraceExceptTop() won't. +String GetCurrentOsStackTraceExceptTop(UnitTest* unit_test, int skip_count) { + // We pass skip_count + 1 to skip this wrapper function in addition + // to what the user really wants to skip. + return unit_test->impl()->CurrentOsStackTraceExceptTop(skip_count + 1); +} + +// Returns the number of failed test parts in the given test result object. +int GetFailedPartCount(const TestResult* result) { + return result->failed_part_count(); +} + // Parses a string as a command line flag. The string should have // the format "--flag=value". When def_optional is true, the "=value" // part can be omitted. @@ -3864,27 +3885,6 @@ void InitGoogleTestImpl(int* argc, CharType** argv) { } } -// Returns the current OS stack trace as a String. -// -// The maximum number of stack frames to be included is specified by -// the gtest_stack_trace_depth flag. The skip_count parameter -// specifies the number of top frames to be skipped, which doesn't -// count against the number of frames to be included. -// -// For example, if Foo() calls Bar(), which in turn calls -// GetCurrentOsStackTraceExceptTop(..., 1), Foo() will be included in -// the trace but Bar() and GetCurrentOsStackTraceExceptTop() won't. -String GetCurrentOsStackTraceExceptTop(UnitTest* unit_test, int skip_count) { - // We pass skip_count + 1 to skip this wrapper function in addition - // to what the user really wants to skip. - return unit_test->impl()->CurrentOsStackTraceExceptTop(skip_count + 1); -} - -// Returns the number of failed test parts in the given test result object. -int GetFailedPartCount(const TestResult* result) { - return result->failed_part_count(); -} - } // namespace internal // Initializes Google Test. This must be called before calling -- cgit v1.2.3 From c440a6923aa65d5be64134a6f430a5867a63df3f Mon Sep 17 00:00:00 2001 From: shiqian Date: Mon, 24 Nov 2008 20:13:22 +0000 Subject: Enables the Python tests to run with 2.3 (necessary for testing on Mac OS X Tiger); also fixes gtest_output_test when built with xcode. --- src/gtest-internal-inl.h | 4 ++++ src/gtest.cc | 21 +++++++++++++++++++-- 2 files changed, 23 insertions(+), 2 deletions(-) (limited to 'src') diff --git a/src/gtest-internal-inl.h b/src/gtest-internal-inl.h index 0f2bcfba..faf9464d 100644 --- a/src/gtest-internal-inl.h +++ b/src/gtest-internal-inl.h @@ -76,6 +76,10 @@ GTEST_DECLARE_bool_(show_internal_stack_frames); namespace internal { +// The value of GetTestTypeId() as seen from within the Google Test +// library. This is solely for testing GetTestTypeId(). +extern const TypeId kTestTypeIdInGoogleTest; + // Names of the flags (needed for parsing Google Test flags). const char kBreakOnFailureFlag[] = "break_on_failure"; const char kCatchExceptionsFlag[] = "catch_exceptions"; diff --git a/src/gtest.cc b/src/gtest.cc index 4a67b7a2..968efb22 100644 --- a/src/gtest.cc +++ b/src/gtest.cc @@ -515,6 +515,23 @@ void ScopedFakeTestPartResultReporter::ReportTestPartResult( namespace internal { +// Returns the type ID of ::testing::Test. We should always call this +// instead of GetTypeId< ::testing::Test>() to get the type ID of +// testing::Test. This is to work around a suspected linker bug when +// using Google Test as a framework on Mac OS X. The bug causes +// GetTypeId< ::testing::Test>() to return different values depending +// on whether the call is from the Google Test framework itself or +// from user test code. GetTestTypeId() is guaranteed to always +// return the same value, as it always calls GetTypeId<>() from the +// gtest.cc, which is within the Google Test framework. +TypeId GetTestTypeId() { + return GetTypeId(); +} + +// The value of GetTestTypeId() as seen from within the Google Test +// library. This is solely for testing GetTestTypeId(). +extern const TypeId kTestTypeIdInGoogleTest = GetTestTypeId(); + // This predicate-formatter checks that 'results' contains a test part // failure of the given type and that the failure message contains the // given substring. @@ -1924,9 +1941,9 @@ bool Test::HasSameFixtureClass() { if (this_fixture_id != first_fixture_id) { // Is the first test defined using TEST? - const bool first_is_TEST = first_fixture_id == internal::GetTypeId(); + const bool first_is_TEST = first_fixture_id == internal::GetTestTypeId(); // Is this test defined using TEST? - const bool this_is_TEST = this_fixture_id == internal::GetTypeId(); + const bool this_is_TEST = this_fixture_id == internal::GetTestTypeId(); if (first_is_TEST || this_is_TEST) { // The user mixed TEST and TEST_F in this test case - we'll tell -- cgit v1.2.3 From 1998cf5d32a19aaffe8652545802744d9133022d Mon Sep 17 00:00:00 2001 From: vladlosev Date: Wed, 26 Nov 2008 20:48:45 +0000 Subject: Allow Google Mock to initialize Google Test --- src/gtest-internal-inl.h | 5 ++++ src/gtest.cc | 71 ++++++++++++++++++++++++++++++------------------ 2 files changed, 50 insertions(+), 26 deletions(-) (limited to 'src') diff --git a/src/gtest-internal-inl.h b/src/gtest-internal-inl.h index faf9464d..b8f67c18 100644 --- a/src/gtest-internal-inl.h +++ b/src/gtest-internal-inl.h @@ -1256,6 +1256,11 @@ inline UnitTestImpl* GetUnitTestImpl() { return UnitTest::GetInstance()->impl(); } +// Parses the command line for Google Test flags, without initializing +// other parts of Google Test. +void ParseGoogleTestFlagsOnly(int* argc, char** argv); +void ParseGoogleTestFlagsOnly(int* argc, wchar_t** argv); + } // namespace internal } // namespace testing diff --git a/src/gtest.cc b/src/gtest.cc index 968efb22..b8363912 100644 --- a/src/gtest.cc +++ b/src/gtest.cc @@ -222,13 +222,13 @@ namespace internal { // GTestIsInitialized() returns true iff the user has initialized // Google Test. Useful for catching the user mistake of not initializing // Google Test before calling RUN_ALL_TESTS(). - +// // A user must call testing::InitGoogleTest() to initialize Google -// Test. g_parse_gtest_flags_called is set to true iff +// Test. g_init_gtest_count is set to the number of times // InitGoogleTest() has been called. We don't protect this variable // under a mutex as it is only accessed in the main thread. -static bool g_parse_gtest_flags_called = false; -static bool GTestIsInitialized() { return g_parse_gtest_flags_called; } +int g_init_gtest_count = 0; +static bool GTestIsInitialized() { return g_init_gtest_count != 0; } // Iterates over a list of TestCases, keeping a running sum of the // results of calling a given int-returning method on each. @@ -3844,23 +3844,12 @@ bool ParseStringFlag(const char* str, const char* flag, String* value) { return true; } -// The internal implementation of InitGoogleTest(). -// -// The type parameter CharType can be instantiated to either char or -// wchar_t. +// Parses the command line for Google Test flags, without initializing +// other parts of Google Test. The type parameter CharType can be +// instantiated to either char or wchar_t. template -void InitGoogleTestImpl(int* argc, CharType** argv) { - g_parse_gtest_flags_called = true; - if (*argc <= 0) return; - -#ifdef GTEST_HAS_DEATH_TEST - g_argvs.clear(); - for (int i = 0; i != *argc; i++) { - g_argvs.push_back(StreamableToString(argv[i])); - } -#endif // GTEST_HAS_DEATH_TEST - - for (int i = 1; i != *argc; i++) { +void ParseGoogleTestFlagsOnlyImpl(int* argc, CharType** argv) { + for (int i = 1; i < *argc; i++) { const String arg_string = StreamableToString(argv[i]); const char* const arg = arg_string.c_str(); @@ -3902,6 +3891,40 @@ void InitGoogleTestImpl(int* argc, CharType** argv) { } } +// Parses the command line for Google Test flags, without initializing +// other parts of Google Test. +void ParseGoogleTestFlagsOnly(int* argc, char** argv) { + ParseGoogleTestFlagsOnlyImpl(argc, argv); +} +void ParseGoogleTestFlagsOnly(int* argc, wchar_t** argv) { + ParseGoogleTestFlagsOnlyImpl(argc, argv); +} + +// The internal implementation of InitGoogleTest(). +// +// The type parameter CharType can be instantiated to either char or +// wchar_t. +template +void InitGoogleTestImpl(int* argc, CharType** argv) { + g_init_gtest_count++; + + // We don't want to run the initialization code twice. + if (g_init_gtest_count != 1) return; + + if (*argc <= 0) return; + + internal::g_executable_path = internal::StreamableToString(argv[0]); + +#ifdef GTEST_HAS_DEATH_TEST + g_argvs.clear(); + for (int i = 0; i != *argc; i++) { + g_argvs.push_back(StreamableToString(argv[i])); + } +#endif // GTEST_HAS_DEATH_TEST + + ParseGoogleTestFlagsOnly(argc, argv); +} + } // namespace internal // Initializes Google Test. This must be called before calling @@ -3911,20 +3934,16 @@ void InitGoogleTestImpl(int* argc, CharType** argv) { // // No value is returned. Instead, the Google Test flag variables are // updated. +// +// Calling the function for the second time has no user-visible effect. void InitGoogleTest(int* argc, char** argv) { - internal::g_executable_path = argv[0]; internal::InitGoogleTestImpl(argc, argv); } // This overloaded version can be used in Windows programs compiled in // UNICODE mode. -#ifdef GTEST_OS_WINDOWS void InitGoogleTest(int* argc, wchar_t** argv) { - // g_executable_path uses normal characters rather than wide chars, so call - // StreamableToString to convert argv[0] to normal characters (utf8 encoding). - internal::g_executable_path = internal::StreamableToString(argv[0]); internal::InitGoogleTestImpl(argc, argv); } -#endif // GTEST_OS_WINDOWS } // namespace testing -- cgit v1.2.3 From 0fb58d70eb91f047e45794e1967a82fc18081af3 Mon Sep 17 00:00:00 2001 From: shiqian Date: Tue, 2 Dec 2008 23:41:01 +0000 Subject: Fixes compatibility with IBM z/OS. By Rainer Klaffenboeck. --- src/gtest.cc | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'src') diff --git a/src/gtest.cc b/src/gtest.cc index b8363912..a9ca334a 100644 --- a/src/gtest.cc +++ b/src/gtest.cc @@ -61,11 +61,13 @@ #include #elif defined(GTEST_OS_SYMBIAN) -// No autoconf on Symbian #define GTEST_HAS_GETTIMEOFDAY #include // NOLINT #elif defined(GTEST_OS_ZOS) +#define GTEST_HAS_GETTIMEOFDAY +#include // NOLINT + // On z/OS we additionally need strings.h for strcasecmp. #include -- cgit v1.2.3 From 53e0dc4041f660b6517b15b08b496e164be614f1 Mon Sep 17 00:00:00 2001 From: shiqian Date: Thu, 8 Jan 2009 01:10:31 +0000 Subject: Implements the --gtest_death_test_use_fork flag and StaticAssertTypeEq. --- src/gtest-death-test.cc | 25 +++++++++++++++++++++++-- src/gtest-internal-inl.h | 4 ++++ src/gtest.cc | 2 ++ 3 files changed, 29 insertions(+), 2 deletions(-) (limited to 'src') diff --git a/src/gtest-death-test.cc b/src/gtest-death-test.cc index b667682f..6499842c 100644 --- a/src/gtest-death-test.cc +++ b/src/gtest-death-test.cc @@ -68,6 +68,17 @@ GTEST_DEFINE_string_( "\"fast\" (child process runs the death test immediately " "after forking)."); +GTEST_DEFINE_bool_( + death_test_use_fork, + internal::BoolFromGTestEnv("death_test_use_fork", false), + "Instructs to use fork()/_exit() instead of clone() in death tests. " + "Useful when running under valgrind or similar tools if those " + "do not support clone(). Valgrind 3.3.1 will just fail if " + "it sees an unsupported combination of clone() flags. " + "It is not recommended to use this flag w/o valgrind though it will " + "work in 99% of the cases. Once valgrind is fixed, this flag will " + "most likely be removed."); + namespace internal { GTEST_DEFINE_string_( internal_run_death_test, "", @@ -603,8 +614,18 @@ static pid_t ExecDeathTestFork(char* const* argv, int close_fd) { void* const stack_top = static_cast(stack) + (stack_grows_down ? stack_size : 0); ExecDeathTestArgs args = { argv, close_fd }; - const pid_t child_pid = clone(&ExecDeathTestChildMain, stack_top, - SIGCHLD, &args); + pid_t child_pid; + if (GTEST_FLAG(death_test_use_fork)) { + // Valgrind-friendly version. As of valgrind 3.3.1 the clone() call below + // is not supported (valgrind will fail with an error message). + if ((child_pid = fork()) == 0) { + ExecDeathTestChildMain(&args); + _exit(0); + } + } else { + child_pid = clone(&ExecDeathTestChildMain, stack_top, + SIGCHLD, &args); + } GTEST_DEATH_TEST_CHECK_(child_pid != -1); GTEST_DEATH_TEST_CHECK_(munmap(stack, stack_size) != -1); return child_pid; diff --git a/src/gtest-internal-inl.h b/src/gtest-internal-inl.h index b8f67c18..353c40a6 100644 --- a/src/gtest-internal-inl.h +++ b/src/gtest-internal-inl.h @@ -66,6 +66,7 @@ namespace testing { GTEST_DECLARE_bool_(break_on_failure); GTEST_DECLARE_bool_(catch_exceptions); GTEST_DECLARE_string_(color); +GTEST_DECLARE_bool_(death_test_use_fork); GTEST_DECLARE_string_(filter); GTEST_DECLARE_bool_(list_tests); GTEST_DECLARE_string_(output); @@ -100,6 +101,7 @@ class GTestFlagSaver { catch_exceptions_ = GTEST_FLAG(catch_exceptions); color_ = GTEST_FLAG(color); death_test_style_ = GTEST_FLAG(death_test_style); + death_test_use_fork_ = GTEST_FLAG(death_test_use_fork); filter_ = GTEST_FLAG(filter); internal_run_death_test_ = GTEST_FLAG(internal_run_death_test); list_tests_ = GTEST_FLAG(list_tests); @@ -114,6 +116,7 @@ class GTestFlagSaver { GTEST_FLAG(catch_exceptions) = catch_exceptions_; GTEST_FLAG(color) = color_; GTEST_FLAG(death_test_style) = death_test_style_; + GTEST_FLAG(death_test_use_fork) = death_test_use_fork_; GTEST_FLAG(filter) = filter_; GTEST_FLAG(internal_run_death_test) = internal_run_death_test_; GTEST_FLAG(list_tests) = list_tests_; @@ -127,6 +130,7 @@ class GTestFlagSaver { bool catch_exceptions_; String color_; String death_test_style_; + bool death_test_use_fork_; String filter_; String internal_run_death_test_; bool list_tests_; diff --git a/src/gtest.cc b/src/gtest.cc index a9ca334a..ae20d874 100644 --- a/src/gtest.cc +++ b/src/gtest.cc @@ -3867,6 +3867,8 @@ void ParseGoogleTestFlagsOnlyImpl(int* argc, CharType** argv) { ParseStringFlag(arg, kColorFlag, >EST_FLAG(color)) || ParseStringFlag(arg, kDeathTestStyleFlag, >EST_FLAG(death_test_style)) || + ParseBoolFlag(arg, kDeathTestUseFork, + >EST_FLAG(death_test_use_fork)) || ParseStringFlag(arg, kFilterFlag, >EST_FLAG(filter)) || ParseStringFlag(arg, kInternalRunDeathTestFlag, >EST_FLAG(internal_run_death_test)) || -- cgit v1.2.3 From fe186c382905dcf57014985ccea8e067275e9f5f Mon Sep 17 00:00:00 2001 From: shiqian Date: Sat, 10 Jan 2009 01:16:33 +0000 Subject: Implements --gtest_also_run_disabled_tests. By Eric Roman. --- src/gtest-internal-inl.h | 7 ++++++- src/gtest.cc | 16 ++++++++++++---- 2 files changed, 18 insertions(+), 5 deletions(-) (limited to 'src') diff --git a/src/gtest-internal-inl.h b/src/gtest-internal-inl.h index 353c40a6..5808a50c 100644 --- a/src/gtest-internal-inl.h +++ b/src/gtest-internal-inl.h @@ -63,6 +63,7 @@ namespace testing { // We don't want the users to modify these flags in the code, but want // Google Test's own unit tests to be able to access them. Therefore we // declare them here as opposed to in gtest.h. +GTEST_DECLARE_bool_(also_run_disabled_tests); GTEST_DECLARE_bool_(break_on_failure); GTEST_DECLARE_bool_(catch_exceptions); GTEST_DECLARE_string_(color); @@ -72,8 +73,8 @@ GTEST_DECLARE_bool_(list_tests); GTEST_DECLARE_string_(output); GTEST_DECLARE_bool_(print_time); GTEST_DECLARE_int32_(repeat); -GTEST_DECLARE_int32_(stack_trace_depth); GTEST_DECLARE_bool_(show_internal_stack_frames); +GTEST_DECLARE_int32_(stack_trace_depth); namespace internal { @@ -82,6 +83,7 @@ namespace internal { extern const TypeId kTestTypeIdInGoogleTest; // Names of the flags (needed for parsing Google Test flags). +const char kAlsoRunDisabledTestsFlag[] = "also_run_disabled_tests"; const char kBreakOnFailureFlag[] = "break_on_failure"; const char kCatchExceptionsFlag[] = "catch_exceptions"; const char kColorFlag[] = "color"; @@ -97,6 +99,7 @@ class GTestFlagSaver { public: // The c'tor. GTestFlagSaver() { + also_run_disabled_tests_ = GTEST_FLAG(also_run_disabled_tests); break_on_failure_ = GTEST_FLAG(break_on_failure); catch_exceptions_ = GTEST_FLAG(catch_exceptions); color_ = GTEST_FLAG(color); @@ -112,6 +115,7 @@ class GTestFlagSaver { // The d'tor is not virtual. DO NOT INHERIT FROM THIS CLASS. ~GTestFlagSaver() { + GTEST_FLAG(also_run_disabled_tests) = also_run_disabled_tests_; GTEST_FLAG(break_on_failure) = break_on_failure_; GTEST_FLAG(catch_exceptions) = catch_exceptions_; GTEST_FLAG(color) = color_; @@ -126,6 +130,7 @@ class GTestFlagSaver { } private: // Fields for saving the original values of flags. + bool also_run_disabled_tests_; bool break_on_failure_; bool catch_exceptions_; String color_; diff --git a/src/gtest.cc b/src/gtest.cc index ae20d874..0e3115ba 100644 --- a/src/gtest.cc +++ b/src/gtest.cc @@ -153,6 +153,11 @@ const char kStackTraceMarker[] = "\nStack trace:\n"; } // namespace internal +GTEST_DEFINE_bool_( + also_run_disabled_tests, + internal::BoolFromGTestEnv("also_run_disabled_tests", false), + "Run disabled tests too, in addition to the tests normally being run."); + GTEST_DEFINE_bool_( break_on_failure, internal::BoolFromGTestEnv("break_on_failure", false), @@ -1610,7 +1615,7 @@ bool String::CaseInsensitiveWideCStringEquals(const wchar_t* lhs, right = towlower(*rhs++); } while (left && left == right); return left == right; -#endif // OS selector +#endif // OS selector } // Constructs a String by copying a given number of chars from a @@ -2736,7 +2741,7 @@ void PrettyUnitTestResultPrinter::OnUnitTestEnd( } int num_disabled = impl->disabled_test_count(); - if (num_disabled) { + if (num_disabled && !GTEST_FLAG(also_run_disabled_tests)) { if (!num_failures) { printf("\n"); // Add a spacer if no FAILURE banner is displayed. } @@ -3602,7 +3607,8 @@ int UnitTestImpl::FilterTests() { kDisableTestFilter); test_info->impl()->set_is_disabled(is_disabled); - const bool should_run = !is_disabled && + const bool should_run = + (GTEST_FLAG(also_run_disabled_tests) || !is_disabled) && internal::UnitTestOptions::FilterMatchesTest(test_case_name, test_name); test_info->impl()->set_should_run(should_run); @@ -3860,7 +3866,9 @@ void ParseGoogleTestFlagsOnlyImpl(int* argc, CharType** argv) { using internal::ParseStringFlag; // Do we see a Google Test flag? - if (ParseBoolFlag(arg, kBreakOnFailureFlag, + if (ParseBoolFlag(arg, kAlsoRunDisabledTestsFlag, + >EST_FLAG(also_run_disabled_tests)) || + ParseBoolFlag(arg, kBreakOnFailureFlag, >EST_FLAG(break_on_failure)) || ParseBoolFlag(arg, kCatchExceptionsFlag, >EST_FLAG(catch_exceptions)) || -- cgit v1.2.3 From 650d5bf3ba200ecbeccbfcec6e7b6cc6f40a1f60 Mon Sep 17 00:00:00 2001 From: "zhanyong.wan" Date: Mon, 26 Jan 2009 19:21:32 +0000 Subject: Fixes the bug where the XML output path is affected by test changing the current directory. By Stefan Weigand. --- src/gtest-filepath.cc | 44 +++++++++++++++++++++++++++++++++----------- src/gtest-internal-inl.h | 7 ++++--- src/gtest.cc | 22 ++++++++++++++++++---- 3 files changed, 55 insertions(+), 18 deletions(-) (limited to 'src') diff --git a/src/gtest-filepath.cc b/src/gtest-filepath.cc index 640c27c3..b21b7091 100644 --- a/src/gtest-filepath.cc +++ b/src/gtest-filepath.cc @@ -46,8 +46,8 @@ #include #else #include -#include -#include +#include // NOLINT +#include // NOLINT #endif // _WIN32_WCE or _WIN32 #ifdef GTEST_OS_WINDOWS @@ -144,13 +144,22 @@ FilePath FilePath::MakeFileName(const FilePath& directory, const FilePath& base_name, int number, const char* extension) { - FilePath dir(directory.RemoveTrailingPathSeparator()); - if (number == 0) { - return FilePath(String::Format("%s%c%s.%s", dir.c_str(), kPathSeparator, - base_name.c_str(), extension)); - } - return FilePath(String::Format("%s%c%s_%d.%s", dir.c_str(), kPathSeparator, - base_name.c_str(), number, extension)); + const FilePath file_name( + (number == 0) ? + String::Format("%s.%s", base_name.c_str(), extension) : + String::Format("%s_%d.%s", base_name.c_str(), number, extension)); + return ConcatPaths(directory, file_name); +} + +// Given directory = "dir", relative_path = "test.xml", returns "dir/test.xml". +// On Windows, uses \ as the separator rather than /. +FilePath FilePath::ConcatPaths(const FilePath& directory, + const FilePath& relative_path) { + if (directory.IsEmpty()) + return relative_path; + const FilePath dir(directory.RemoveTrailingPathSeparator()); + return FilePath(String::Format("%s%c%s", dir.c_str(), kPathSeparator, + relative_path.c_str())); } // Returns true if pathname describes something findable in the file-system, @@ -207,13 +216,26 @@ bool FilePath::DirectoryExists() const { bool FilePath::IsRootDirectory() const { #ifdef GTEST_OS_WINDOWS const char* const name = pathname_.c_str(); - return pathname_.GetLength() == 3 && + // TODO(wan@google.com): on Windows a network share like + // \\server\share can be a root directory, although it cannot be the + // current directory. Handle this properly. + return pathname_.GetLength() == 3 && IsAbsolutePath(); +#else + return pathname_ == kPathSeparatorString; +#endif +} + +// Returns true if pathname describes an absolute path. +bool FilePath::IsAbsolutePath() const { + const char* const name = pathname_.c_str(); +#ifdef GTEST_OS_WINDOWS + return pathname_.GetLength() >= 3 && ((name[0] >= 'a' && name[0] <= 'z') || (name[0] >= 'A' && name[0] <= 'Z')) && name[1] == ':' && name[2] == kPathSeparator; #else - return pathname_ == kPathSeparatorString; + return name[0] == kPathSeparator; #endif } diff --git a/src/gtest-internal-inl.h b/src/gtest-internal-inl.h index 5808a50c..28006a2f 100644 --- a/src/gtest-internal-inl.h +++ b/src/gtest-internal-inl.h @@ -799,9 +799,10 @@ class UnitTestOptions { // Returns the output format, or "" for normal printed output. static String GetOutputFormat(); - // Returns the name of the requested output file, or the default if none - // was explicitly specified. - static String GetOutputFile(); + // Returns the absolute path of the requested output file, or the + // default (test_detail.xml in the original working directory) if + // none was explicitly specified. + static String GetAbsolutePathToOutputFile(); // Functions for processing the gtest_filter flag. diff --git a/src/gtest.cc b/src/gtest.cc index 0e3115ba..d6be608a 100644 --- a/src/gtest.cc +++ b/src/gtest.cc @@ -69,7 +69,7 @@ #include // NOLINT // On z/OS we additionally need strings.h for strcasecmp. -#include +#include // NOLINT #elif defined(_WIN32_WCE) // We are on Windows CE. @@ -289,6 +289,7 @@ Mutex g_linked_ptr_mutex(Mutex::NO_CONSTRUCTOR_NEEDED_FOR_STATIC_MUTEX); // Application pathname gotten in InitGoogleTest. String g_executable_path; +String g_original_working_dir; // Returns the current application's name, removing directory path if that // is present. @@ -319,16 +320,27 @@ String UnitTestOptions::GetOutputFormat() { // Returns the name of the requested output file, or the default if none // was explicitly specified. -String UnitTestOptions::GetOutputFile() { +String UnitTestOptions::GetAbsolutePathToOutputFile() { const char* const gtest_output_flag = GTEST_FLAG(output).c_str(); if (gtest_output_flag == NULL) return String(""); const char* const colon = strchr(gtest_output_flag, ':'); if (colon == NULL) - return String(kDefaultOutputFile); + return String(internal::FilePath::ConcatPaths( + internal::FilePath(g_original_working_dir), + internal::FilePath(kDefaultOutputFile)).ToString() ); internal::FilePath output_name(colon + 1); + if (!output_name.IsAbsolutePath()) + // TODO(wan@google.com): on Windows \some\path is not an absolute + // path (as its meaning depends on the current drive), yet the + // following logic for turning it into an absolute path is wrong. + // Fix it. + output_name = internal::FilePath::ConcatPaths( + internal::FilePath(g_original_working_dir), + internal::FilePath(colon + 1)); + if (!output_name.IsDirectory()) return output_name.ToString(); @@ -3675,7 +3687,7 @@ UnitTestEventListenerInterface* UnitTestImpl::result_printer() { const String& output_format = internal::UnitTestOptions::GetOutputFormat(); if (output_format == "xml") { repeater->AddListener(new XmlUnitTestResultPrinter( - internal::UnitTestOptions::GetOutputFile().c_str())); + internal::UnitTestOptions::GetAbsolutePathToOutputFile().c_str())); } else if (output_format != "") { printf("WARNING: unrecognized output format \"%s\" ignored.\n", output_format.c_str()); @@ -3926,6 +3938,8 @@ void InitGoogleTestImpl(int* argc, CharType** argv) { if (*argc <= 0) return; internal::g_executable_path = internal::StreamableToString(argv[0]); + internal::g_original_working_dir = + internal::FilePath::GetCurrentDir().ToString(); #ifdef GTEST_HAS_DEATH_TEST g_argvs.clear(); -- cgit v1.2.3 From a32fc79c9af648cd500f9850975d04ae49ebda3f Mon Sep 17 00:00:00 2001 From: "zhanyong.wan" Date: Mon, 26 Jan 2009 21:04:36 +0000 Subject: Simplifies gtest's implementation by using an existing API to get the original working directory. --- src/gtest.cc | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) (limited to 'src') diff --git a/src/gtest.cc b/src/gtest.cc index d6be608a..903dcd94 100644 --- a/src/gtest.cc +++ b/src/gtest.cc @@ -289,7 +289,6 @@ Mutex g_linked_ptr_mutex(Mutex::NO_CONSTRUCTOR_NEEDED_FOR_STATIC_MUTEX); // Application pathname gotten in InitGoogleTest. String g_executable_path; -String g_original_working_dir; // Returns the current application's name, removing directory path if that // is present. @@ -328,7 +327,8 @@ String UnitTestOptions::GetAbsolutePathToOutputFile() { const char* const colon = strchr(gtest_output_flag, ':'); if (colon == NULL) return String(internal::FilePath::ConcatPaths( - internal::FilePath(g_original_working_dir), + internal::FilePath( + UnitTest::GetInstance()->original_working_dir()), internal::FilePath(kDefaultOutputFile)).ToString() ); internal::FilePath output_name(colon + 1); @@ -338,8 +338,8 @@ String UnitTestOptions::GetAbsolutePathToOutputFile() { // following logic for turning it into an absolute path is wrong. // Fix it. output_name = internal::FilePath::ConcatPaths( - internal::FilePath(g_original_working_dir), - internal::FilePath(colon + 1)); + internal::FilePath(UnitTest::GetInstance()->original_working_dir()), + internal::FilePath(colon + 1)); if (!output_name.IsDirectory()) return output_name.ToString(); @@ -3938,8 +3938,6 @@ void InitGoogleTestImpl(int* argc, CharType** argv) { if (*argc <= 0) return; internal::g_executable_path = internal::StreamableToString(argv[0]); - internal::g_original_working_dir = - internal::FilePath::GetCurrentDir().ToString(); #ifdef GTEST_HAS_DEATH_TEST g_argvs.clear(); -- cgit v1.2.3 From c946ae60194727ede9d3ef44754839f48541a981 Mon Sep 17 00:00:00 2001 From: "zhanyong.wan" Date: Thu, 29 Jan 2009 01:28:52 +0000 Subject: Implements a simple regex matcher (to be used by death tests on Windows). --- src/gtest-filepath.cc | 1 - src/gtest-internal-inl.h | 16 +++ src/gtest-port.cc | 271 ++++++++++++++++++++++++++++++++++++++++++++++- 3 files changed, 285 insertions(+), 3 deletions(-) (limited to 'src') diff --git a/src/gtest-filepath.cc b/src/gtest-filepath.cc index b21b7091..ebf7cf93 100644 --- a/src/gtest-filepath.cc +++ b/src/gtest-filepath.cc @@ -215,7 +215,6 @@ bool FilePath::DirectoryExists() const { // root directory per disk drive.) bool FilePath::IsRootDirectory() const { #ifdef GTEST_OS_WINDOWS - const char* const name = pathname_.c_str(); // TODO(wan@google.com): on Windows a network share like // \\server\share can be a root directory, although it cannot be the // current directory. Handle this properly. diff --git a/src/gtest-internal-inl.h b/src/gtest-internal-inl.h index 28006a2f..caa0877c 100644 --- a/src/gtest-internal-inl.h +++ b/src/gtest-internal-inl.h @@ -1266,6 +1266,22 @@ inline UnitTestImpl* GetUnitTestImpl() { return UnitTest::GetInstance()->impl(); } +// Internal helper functions for implementing the simple regular +// expression matcher. +bool IsInSet(char ch, const char* str); +bool IsDigit(char ch); +bool IsPunct(char ch); +bool IsRepeat(char ch); +bool IsWhiteSpace(char ch); +bool IsWordChar(char ch); +bool IsValidEscape(char ch); +bool AtomMatchesChar(bool escaped, char pattern, char ch); +bool ValidateRegex(const char* regex); +bool MatchRegexAtHead(const char* regex, const char* str); +bool MatchRepetitionAndRegexAtHead( + bool escaped, char ch, char repeat, const char* regex, const char* str); +bool MatchRegexAnywhere(const char* regex, const char* str); + // Parses the command line for Google Test flags, without initializing // other parts of Google Test. void ParseGoogleTestFlagsOnly(int* argc, char** argv); diff --git a/src/gtest-port.cc b/src/gtest-port.cc index 9878cae0..3c9ec4bb 100644 --- a/src/gtest-port.cc +++ b/src/gtest-port.cc @@ -39,6 +39,10 @@ #include #endif // GTEST_HAS_DEATH_TEST +#if GTEST_USES_SIMPLE_RE +#include +#endif + #ifdef _WIN32_WCE #include // For TerminateProcess() #endif // _WIN32_WCE @@ -47,11 +51,19 @@ #include #include +// 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 +#include "src/gtest-internal-inl.h" +#undef GTEST_IMPLEMENTATION namespace testing { namespace internal { -#ifdef GTEST_HAS_DEATH_TEST +#if GTEST_USES_POSIX_RE // Implements RE. Currently only needed for death tests. @@ -101,7 +113,262 @@ void RE::Init(const char* regex) { delete[] full_pattern; } -#endif // GTEST_HAS_DEATH_TEST +#elif GTEST_USES_SIMPLE_RE + +// Returns true iff ch appears anywhere in str (excluding the +// terminating '\0' character). +bool IsInSet(char ch, const char* str) { + return ch != '\0' && strchr(str, ch) != NULL; +} + +// Returns true iff ch belongs to the given classification. Unlike +// similar functions in , these aren't affected by the +// current locale. +bool IsDigit(char ch) { return '0' <= ch && ch <= '9'; } +bool IsPunct(char ch) { + return IsInSet(ch, "^-!\"#$%&'()*+,./:;<=>?@[\\]_`{|}~"); +} +bool IsRepeat(char ch) { return IsInSet(ch, "?*+"); } +bool IsWhiteSpace(char ch) { return IsInSet(ch, " \f\n\r\t\v"); } +bool IsWordChar(char ch) { + return ('a' <= ch && ch <= 'z') || ('A' <= ch && ch <= 'Z') || + ('0' <= ch && ch <= '9') || ch == '_'; +} + +// Returns true iff "\\c" is a supported escape sequence. +bool IsValidEscape(char c) { + return (IsPunct(c) || IsInSet(c, "dDfnrsStvwW")); +} + +// Returns true iff the given atom (specified by escaped and pattern) +// matches ch. The result is undefined if the atom is invalid. +bool AtomMatchesChar(bool escaped, char pattern_char, char ch) { + if (escaped) { // "\\p" where p is pattern_char. + switch (pattern_char) { + case 'd': return IsDigit(ch); + case 'D': return !IsDigit(ch); + case 'f': return ch == '\f'; + case 'n': return ch == '\n'; + case 'r': return ch == '\r'; + case 's': return IsWhiteSpace(ch); + case 'S': return !IsWhiteSpace(ch); + case 't': return ch == '\t'; + case 'v': return ch == '\v'; + case 'w': return IsWordChar(ch); + case 'W': return !IsWordChar(ch); + } + return IsPunct(pattern_char) && pattern_char == ch; + } + + return (pattern_char == '.' && ch != '\n') || pattern_char == ch; +} + +// Helper function used by ValidateRegex() to format error messages. +String FormatRegexSyntaxError(const char* regex, int index) { + return (Message() << "Syntax error at index " << index + << " in simple regular expression \"" << regex << "\": ").GetString(); +} + +// Generates non-fatal failures and returns false if regex is invalid; +// otherwise returns true. +bool ValidateRegex(const char* regex) { + if (regex == NULL) { + // TODO(wan@google.com): fix the source file location in the + // assertion failures to match where the regex is used in user + // code. + ADD_FAILURE() << "NULL is not a valid simple regular expression."; + return false; + } + + bool is_valid = true; + + // True iff ?, *, or + can follow the previous atom. + bool prev_repeatable = false; + for (int i = 0; regex[i]; i++) { + if (regex[i] == '\\') { // An escape sequence + i++; + if (regex[i] == '\0') { + ADD_FAILURE() << FormatRegexSyntaxError(regex, i - 1) + << "'\\' cannot appear at the end."; + return false; + } + + if (!IsValidEscape(regex[i])) { + ADD_FAILURE() << FormatRegexSyntaxError(regex, i - 1) + << "invalid escape sequence \"\\" << regex[i] << "\"."; + is_valid = false; + } + prev_repeatable = true; + } else { // Not an escape sequence. + const char ch = regex[i]; + + if (ch == '^' && i > 0) { + ADD_FAILURE() << FormatRegexSyntaxError(regex, i) + << "'^' can only appear at the beginning."; + is_valid = false; + } else if (ch == '$' && regex[i + 1] != '\0') { + ADD_FAILURE() << FormatRegexSyntaxError(regex, i) + << "'$' can only appear at the end."; + is_valid = false; + } else if (IsInSet(ch, "()[]{}|")) { + ADD_FAILURE() << FormatRegexSyntaxError(regex, i) + << "'" << ch << "' is unsupported."; + is_valid = false; + } else if (IsRepeat(ch) && !prev_repeatable) { + ADD_FAILURE() << FormatRegexSyntaxError(regex, i) + << "'" << ch << "' can only follow a repeatable token."; + is_valid = false; + } + + prev_repeatable = !IsInSet(ch, "^$?*+"); + } + } + + return is_valid; +} + +// Matches a repeated regex atom followed by a valid simple regular +// expression. The regex atom is defined as c if escaped is false, +// or \c otherwise. repeat is the repetition meta character (?, *, +// or +). The behavior is undefined if str contains too many +// characters to be indexable by size_t, in which case the test will +// probably time out anyway. We are fine with this limitation as +// std::string has it too. +bool MatchRepetitionAndRegexAtHead( + bool escaped, char c, char repeat, const char* regex, + const char* str) { + const size_t min_count = (repeat == '+') ? 1 : 0; + const size_t max_count = (repeat == '?') ? 1 : + static_cast(-1) - 1; + // We cannot call numeric_limits::max() as it conflicts with the + // max() macro on Windows. + + for (size_t i = 0; i <= max_count; ++i) { + // We know that the atom matches each of the first i characters in str. + if (i >= min_count && MatchRegexAtHead(regex, str + i)) { + // We have enough matches at the head, and the tail matches too. + // Since we only care about *whether* the pattern matches str + // (as opposed to *how* it matches), there is no need to find a + // greedy match. + return true; + } + if (str[i] == '\0' || !AtomMatchesChar(escaped, c, str[i])) + return false; + } + return false; +} + +// Returns true iff regex matches a prefix of str. regex must be a +// valid simple regular expression and not start with "^", or the +// result is undefined. +bool MatchRegexAtHead(const char* regex, const char* str) { + if (*regex == '\0') // An empty regex matches a prefix of anything. + return true; + + // "$" only matches the end of a string. Note that regex being + // valid guarantees that there's nothing after "$" in it. + if (*regex == '$') + return *str == '\0'; + + // Is the first thing in regex an escape sequence? + const bool escaped = *regex == '\\'; + if (escaped) + ++regex; + if (IsRepeat(regex[1])) { + // MatchRepetitionAndRegexAtHead() calls MatchRegexAtHead(), so + // here's an indirect recursion. It terminates as the regex gets + // shorter in each recursion. + return MatchRepetitionAndRegexAtHead( + escaped, regex[0], regex[1], regex + 2, str); + } else { + // regex isn't empty, isn't "$", and doesn't start with a + // repetition. We match the first atom of regex with the first + // character of str and recurse. + return (*str != '\0') && AtomMatchesChar(escaped, *regex, *str) && + MatchRegexAtHead(regex + 1, str + 1); + } +} + +// Returns true iff regex matches any substring of str. regex must be +// a valid simple regular expression, or the result is undefined. +// +// The algorithm is recursive, but the recursion depth doesn't exceed +// the regex length, so we won't need to worry about running out of +// stack space normally. In rare cases the time complexity can be +// exponential with respect to the regex length + the string length, +// but usually it's must faster (often close to linear). +bool MatchRegexAnywhere(const char* regex, const char* str) { + if (regex == NULL || str == NULL) + return false; + + if (*regex == '^') + return MatchRegexAtHead(regex + 1, str); + + // A successful match can be anywhere in str. + do { + if (MatchRegexAtHead(regex, str)) + return true; + } while (*str++ != '\0'); + return false; +} + +// Implements the RE class. + +RE::~RE() { + free(const_cast(pattern_)); + free(const_cast(full_pattern_)); +} + +// Returns true iff regular expression re matches the entire str. +bool RE::FullMatch(const char* str, const RE& re) { + return re.is_valid_ && MatchRegexAnywhere(re.full_pattern_, str); +} + +// Returns true iff regular expression re matches a substring of str +// (including str itself). +bool RE::PartialMatch(const char* str, const RE& re) { + return re.is_valid_ && MatchRegexAnywhere(re.pattern_, str); +} + +// Initializes an RE from its string representation. +void RE::Init(const char* regex) { + pattern_ = full_pattern_ = NULL; + if (regex != NULL) { +#ifdef GTEST_OS_WINDOWS + pattern_ = _strdup(regex); +#else + pattern_ = strdup(regex); +#endif + } + + is_valid_ = ValidateRegex(regex); + if (!is_valid_) { + // No need to calculate the full pattern when the regex is invalid. + return; + } + + const size_t len = strlen(regex); + // Reserves enough bytes to hold the regular expression used for a + // full match: we need space to prepend a '^', append a '$', and + // terminate the string with '\0'. + char* buffer = static_cast(malloc(len + 3)); + full_pattern_ = buffer; + + if (*regex != '^') + *buffer++ = '^'; // Makes sure full_pattern_ starts with '^'. + + // We don't use snprintf or strncpy, as they trigger a warning when + // compiled with VC++ 8.0. + memcpy(buffer, regex, len); + buffer += len; + + if (len == 0 || regex[len - 1] != '$') + *buffer++ = '$'; // Makes sure full_pattern_ ends with '$'. + + *buffer = '\0'; +} + +#endif // GTEST_USES_POSIX_RE // Logs a message at the given severity level. void GTestLog(GTestLogSeverity severity, const char* file, -- cgit v1.2.3 From 4b83461e9772cce62e84310060fe84172e9bf4ba Mon Sep 17 00:00:00 2001 From: "zhanyong.wan" Date: Thu, 29 Jan 2009 06:49:00 +0000 Subject: Fixes some warnings when compiled with MSVC at warning level 4. --- src/gtest-internal-inl.h | 4 ++++ src/gtest.cc | 22 +++++++++------------- 2 files changed, 13 insertions(+), 13 deletions(-) (limited to 'src') diff --git a/src/gtest-internal-inl.h b/src/gtest-internal-inl.h index caa0877c..ef3fe98d 100644 --- a/src/gtest-internal-inl.h +++ b/src/gtest-internal-inl.h @@ -901,6 +901,8 @@ class DefaultGlobalTestPartResultReporter private: UnitTestImpl* const unit_test_; + + GTEST_DISALLOW_COPY_AND_ASSIGN_(DefaultGlobalTestPartResultReporter); }; // This is the default per thread test part result reporter used in @@ -915,6 +917,8 @@ class DefaultPerThreadTestPartResultReporter private: UnitTestImpl* const unit_test_; + + GTEST_DISALLOW_COPY_AND_ASSIGN_(DefaultPerThreadTestPartResultReporter); }; // The private implementation of the UnitTest class. We don't protect diff --git a/src/gtest.cc b/src/gtest.cc index 903dcd94..26077673 100644 --- a/src/gtest.cc +++ b/src/gtest.cc @@ -374,7 +374,7 @@ bool UnitTestOptions::PatternMatchesString(const char *pattern, bool UnitTestOptions::MatchesFilter(const String& name, const char* filter) { const char *cur_pattern = filter; - while (true) { + for (;;) { if (PatternMatchesString(cur_pattern, name.c_str())) { return true; } @@ -1458,23 +1458,19 @@ char* CodePointToUtf8(UInt32 code_point, char* str) { // and thus should be combined into a single Unicode code point // using CreateCodePointFromUtf16SurrogatePair. inline bool IsUtf16SurrogatePair(wchar_t first, wchar_t second) { - if (sizeof(wchar_t) == 2) - return (first & 0xFC00) == 0xD800 && (second & 0xFC00) == 0xDC00; - else - return false; + return sizeof(wchar_t) == 2 && + (first & 0xFC00) == 0xD800 && (second & 0xFC00) == 0xDC00; } // Creates a Unicode code point from UTF16 surrogate pair. inline UInt32 CreateCodePointFromUtf16SurrogatePair(wchar_t first, wchar_t second) { - if (sizeof(wchar_t) == 2) { - const UInt32 mask = (1 << 10) - 1; - return (((first & mask) << 10) | (second & mask)) + 0x10000; - } else { - // This should not be called, but we provide a sensible default - // in case it is. - return static_cast(first); - } + const UInt32 mask = (1 << 10) - 1; + return (sizeof(wchar_t) == 2) ? + (((first & mask) << 10) | (second & mask)) + 0x10000 : + // This function should not be called when the condition is + // false, but we provide a sensible default in case it is. + static_cast(first); } // Converts a wide string to a narrow string in UTF-8 encoding. -- cgit v1.2.3 From ad99ca14461f0e929d835d29518e11c05e8d41f0 Mon Sep 17 00:00:00 2001 From: "zhanyong.wan" Date: Mon, 2 Feb 2009 06:37:03 +0000 Subject: Exposes gtest flags to user code access. By Alexander Demin. --- src/gtest-internal-inl.h | 17 +++-------------- 1 file changed, 3 insertions(+), 14 deletions(-) (limited to 'src') diff --git a/src/gtest-internal-inl.h b/src/gtest-internal-inl.h index ef3fe98d..cefed209 100644 --- a/src/gtest-internal-inl.h +++ b/src/gtest-internal-inl.h @@ -60,21 +60,10 @@ namespace testing { // Declares the flags. // -// We don't want the users to modify these flags in the code, but want -// Google Test's own unit tests to be able to access them. Therefore we -// declare them here as opposed to in gtest.h. -GTEST_DECLARE_bool_(also_run_disabled_tests); -GTEST_DECLARE_bool_(break_on_failure); -GTEST_DECLARE_bool_(catch_exceptions); -GTEST_DECLARE_string_(color); +// We don't want the users to modify this flag in the code, but want +// Google Test's own unit tests to be able to access it. Therefore we +// declare it here as opposed to in gtest.h. GTEST_DECLARE_bool_(death_test_use_fork); -GTEST_DECLARE_string_(filter); -GTEST_DECLARE_bool_(list_tests); -GTEST_DECLARE_string_(output); -GTEST_DECLARE_bool_(print_time); -GTEST_DECLARE_int32_(repeat); -GTEST_DECLARE_bool_(show_internal_stack_frames); -GTEST_DECLARE_int32_(stack_trace_depth); namespace internal { -- cgit v1.2.3 From 37504994338c114247519331237831f88a9a7c40 Mon Sep 17 00:00:00 2001 From: "zhanyong.wan" Date: Fri, 6 Feb 2009 00:47:20 +0000 Subject: Adds tests for EXPECT_FATAL_FAILURE and reduces the golden file bloat (by Zhanyong Wan). Fixes more warnings on Windows (by Vlad Losev). --- src/gtest.cc | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) (limited to 'src') diff --git a/src/gtest.cc b/src/gtest.cc index 26077673..8e8238a9 100644 --- a/src/gtest.cc +++ b/src/gtest.cc @@ -3771,6 +3771,22 @@ int GetFailedPartCount(const TestResult* result) { return result->failed_part_count(); } +// Used by the GTEST_HIDE_UNREACHABLE_CODE_ macro to suppress unreachable +// code warnings. +namespace { +class ClassUniqueToAlwaysTrue {}; +} + +bool AlwaysTrue() { +#if GTEST_HAS_EXCEPTIONS + // This condition is always false so AlwaysTrue() never actually throws, + // but it makes the compiler think that it may throw. + if (atoi("42") == 36) // NOLINT + throw ClassUniqueToAlwaysTrue(); +#endif // GTEST_HAS_EXCEPTIONS + return true; +} + // Parses a string as a command line flag. The string should have // the format "--flag=value". When def_optional is true, the "=value" // part can be omitted. -- cgit v1.2.3 From cd3e4016ea451c9ee5cb7925329f2611098cbcf9 Mon Sep 17 00:00:00 2001 From: "zhanyong.wan" Date: Mon, 9 Feb 2009 18:05:21 +0000 Subject: Implements the test sharding protocol. By Eric Fellheimer. --- src/gtest-internal-inl.h | 35 +++++++++- src/gtest-port.cc | 22 +++---- src/gtest.cc | 163 ++++++++++++++++++++++++++++++++++++++++++++--- 3 files changed, 199 insertions(+), 21 deletions(-) (limited to 'src') diff --git a/src/gtest-internal-inl.h b/src/gtest-internal-inl.h index cefed209..07d0c5b4 100644 --- a/src/gtest-internal-inl.h +++ b/src/gtest-internal-inl.h @@ -162,6 +162,32 @@ String WideStringToUtf8(const wchar_t* str, int num_chars); // Returns the number of active threads, or 0 when there is an error. size_t GetThreadCount(); +// Reads the GTEST_SHARD_STATUS_FILE environment variable, and creates the file +// if the variable is present. If a file already exists at this location, this +// function will write over it. If the variable is present, but the file cannot +// be created, prints an error and exits. +void WriteToShardStatusFileIfNeeded(); + +// Checks whether sharding is enabled by examining the relevant +// environment variable values. If the variables are present, +// but inconsistent (e.g., shard_index >= total_shards), prints +// an error and exits. If in_subprocess_for_death_test, sharding is +// disabled because it must only be applied to the original test +// process. Otherwise, we could filter out death tests we intended to execute. +bool ShouldShard(const char* total_shards_str, const char* shard_index_str, + bool in_subprocess_for_death_test); + +// Parses the environment variable var as an Int32. If it is unset, +// returns default_val. If it is not an Int32, prints an error and +// and aborts. +Int32 Int32FromEnvOrDie(const char* env_var, Int32 default_val); + +// Given the total number of shards, the shard index, and the test id, +// returns true iff the test should be run on this shard. The test id is +// some arbitrary but unique non-negative integer assigned to each test +// method. Assumes that 0 <= shard_index < total_shards. +bool ShouldRunTestOnShard(int total_shards, int shard_index, int test_id); + // List is a simple singly-linked list container. // // We cannot use std::list as Microsoft's implementation of STL has @@ -1111,11 +1137,18 @@ class UnitTestImpl { ad_hoc_test_result_.Clear(); } + enum ReactionToSharding { + HONOR_SHARDING_PROTOCOL, + IGNORE_SHARDING_PROTOCOL + }; + // Matches the full name of each test against the user-specified // filter to decide whether the test should run, then records the // result in each TestCase and TestInfo object. + // If shard_tests == HONOR_SHARDING_PROTOCOL, further filters tests + // based on sharding variables in the environment. // Returns the number of tests that should run. - int FilterTests(); + int FilterTests(ReactionToSharding shard_tests); // Lists all the tests by name. void ListAllTests(); diff --git a/src/gtest-port.cc b/src/gtest-port.cc index 3c9ec4bb..9348f55c 100644 --- a/src/gtest-port.cc +++ b/src/gtest-port.cc @@ -512,17 +512,6 @@ static String FlagToEnvVar(const char* flag) { return env_var.GetString(); } -// Reads and returns the Boolean environment variable corresponding to -// the given flag; if it's not set, returns default_value. -// -// The value is considered true iff it's not "0". -bool BoolFromGTestEnv(const char* flag, bool default_value) { - const String env_var = FlagToEnvVar(flag); - const char* const string_value = GetEnv(env_var.c_str()); - return string_value == NULL ? - default_value : strcmp(string_value, "0") != 0; -} - // Parses 'str' for a 32-bit signed integer. If successful, writes // the result to *value and returns true; otherwise leaves *value // unchanged and returns false. @@ -564,6 +553,17 @@ bool ParseInt32(const Message& src_text, const char* str, Int32* value) { return true; } +// Reads and returns the Boolean environment variable corresponding to +// the given flag; if it's not set, returns default_value. +// +// The value is considered true iff it's not "0". +bool BoolFromGTestEnv(const char* flag, bool default_value) { + const String env_var = FlagToEnvVar(flag); + const char* const string_value = GetEnv(env_var.c_str()); + return string_value == NULL ? + default_value : strcmp(string_value, "0") != 0; +} + // Reads and returns a 32-bit integer stored in the environment // variable corresponding to the given flag; if it isn't set or // doesn't represent a valid 32-bit integer, returns default_value. diff --git a/src/gtest.cc b/src/gtest.cc index 8e8238a9..0d161e0e 100644 --- a/src/gtest.cc +++ b/src/gtest.cc @@ -145,6 +145,13 @@ static const char kUniversalFilter[] = "*"; // The default output file for XML output. static const char kDefaultOutputFile[] = "test_detail.xml"; +// The environment variable name for the test shard index. +static const char kTestShardIndex[] = "GTEST_SHARD_INDEX"; +// The environment variable name for the total number of test shards. +static const char kTestTotalShards[] = "GTEST_TOTAL_SHARDS"; +// The environment variable name for the test shard status file. +static const char kTestShardStatusFile[] = "GTEST_SHARD_STATUS_FILE"; + namespace internal { // The text used in failure messages to indicate the start of the @@ -2595,6 +2602,13 @@ void PrettyUnitTestResultPrinter::OnUnitTestStart( "Note: %s filter = %s\n", GTEST_NAME, filter); } + if (internal::ShouldShard(kTestTotalShards, kTestShardIndex, false)) { + ColoredPrintf(COLOR_YELLOW, + "Note: This is test shard %s of %s.\n", + internal::GetEnv(kTestShardIndex), + internal::GetEnv(kTestTotalShards)); + } + const internal::UnitTestImpl* const impl = unit_test->impl(); ColoredPrintf(COLOR_GREEN, "[==========] "); printf("Running %s from %s.\n", @@ -3510,6 +3524,11 @@ int UnitTestImpl::RunAllTests() { RegisterParameterizedTests(); + // Even if sharding is not on, test runners may want to use the + // GTEST_SHARD_STATUS_FILE to query whether the test supports the sharding + // protocol. + internal::WriteToShardStatusFileIfNeeded(); + // Lists all the tests and exits if the --gtest_list_tests // flag was specified. if (GTEST_FLAG(list_tests)) { @@ -3528,9 +3547,15 @@ int UnitTestImpl::RunAllTests() { UnitTestEventListenerInterface * const printer = result_printer(); + const bool should_shard = ShouldShard(kTestTotalShards, kTestShardIndex, + in_subprocess_for_death_test); + // Compares the full test names with the filter to decide which // tests to run. - const bool has_tests_to_run = FilterTests() > 0; + const bool has_tests_to_run = FilterTests(should_shard + ? HONOR_SHARDING_PROTOCOL + : IGNORE_SHARDING_PROTOCOL) > 0; + // True iff at least one test has failed. bool failed = false; @@ -3586,12 +3611,126 @@ int UnitTestImpl::RunAllTests() { return failed ? 1 : 0; } +// Reads the GTEST_SHARD_STATUS_FILE environment variable, and creates the file +// if the variable is present. If a file already exists at this location, this +// function will write over it. If the variable is present, but the file cannot +// be created, prints an error and exits. +void WriteToShardStatusFileIfNeeded() { + const char* const test_shard_file = GetEnv(kTestShardStatusFile); + if (test_shard_file != NULL) { +#ifdef _MSC_VER // MSVC 8 deprecates fopen(). +#pragma warning(push) // Saves the current warning state. +#pragma warning(disable:4996) // Temporarily disables warning on + // deprecated functions. +#endif + FILE* const file = fopen(test_shard_file, "w"); +#ifdef _MSC_VER +#pragma warning(pop) // Restores the warning state. +#endif + if (file == NULL) { + ColoredPrintf(COLOR_RED, + "Could not write to the test shard status file \"%s\" " + "specified by the %s environment variable.\n", + test_shard_file, kTestShardStatusFile); + fflush(stdout); + exit(EXIT_FAILURE); + } + fclose(file); + } +} + +// Checks whether sharding is enabled by examining the relevant +// environment variable values. If the variables are present, +// but inconsistent (i.e., shard_index >= total_shards), prints +// an error and exits. If in_subprocess_for_death_test, sharding is +// disabled because it must only be applied to the original test +// process. Otherwise, we could filter out death tests we intended to execute. +bool ShouldShard(const char* total_shards_env, + const char* shard_index_env, + bool in_subprocess_for_death_test) { + if (in_subprocess_for_death_test) { + return false; + } + + const Int32 total_shards = Int32FromEnvOrDie(total_shards_env, -1); + const Int32 shard_index = Int32FromEnvOrDie(shard_index_env, -1); + + if (total_shards == -1 && shard_index == -1) { + return false; + } else if (total_shards == -1 && shard_index != -1) { + const Message msg = Message() + << "Invalid environment variables: you have " + << kTestShardIndex << " = " << shard_index + << ", but have left " << kTestTotalShards << " unset.\n"; + ColoredPrintf(COLOR_RED, msg.GetString().c_str()); + fflush(stdout); + exit(EXIT_FAILURE); + } else if (total_shards != -1 && shard_index == -1) { + const Message msg = Message() + << "Invalid environment variables: you have " + << kTestTotalShards << " = " << total_shards + << ", but have left " << kTestShardIndex << " unset.\n"; + ColoredPrintf(COLOR_RED, msg.GetString().c_str()); + fflush(stdout); + exit(EXIT_FAILURE); + } else if (shard_index < 0 || shard_index >= total_shards) { + const Message msg = Message() + << "Invalid environment variables: we require 0 <= " + << kTestShardIndex << " < " << kTestTotalShards + << ", but you have " << kTestShardIndex << "=" << shard_index + << ", " << kTestTotalShards << "=" << total_shards << ".\n"; + ColoredPrintf(COLOR_RED, msg.GetString().c_str()); + fflush(stdout); + exit(EXIT_FAILURE); + } + + return total_shards > 1; +} + +// Parses the environment variable var as an Int32. If it is unset, +// returns default_val. If it is not an Int32, prints an error +// and aborts. +Int32 Int32FromEnvOrDie(const char* const var, Int32 default_val) { + const char* str_val = GetEnv(var); + if (str_val == NULL) { + return default_val; + } + + Int32 result; + if (!ParseInt32(Message() << "The value of environment variable " << var, + str_val, &result)) { + exit(EXIT_FAILURE); + } + return result; +} + +// Given the total number of shards, the shard index, and the test id, +// returns true iff the test should be run on this shard. The test id is +// some arbitrary but unique non-negative integer assigned to each test +// method. Assumes that 0 <= shard_index < total_shards. +bool ShouldRunTestOnShard(int total_shards, int shard_index, int test_id) { + return (test_id % total_shards) == shard_index; +} + // Compares the name of each test with the user-specified filter to // decide whether the test should be run, then records the result in // each TestCase and TestInfo object. +// If shard_tests == true, further filters tests based on sharding +// variables in the environment - see +// http://code.google.com/p/googletest/wiki/GoogleTestAdvancedGuide. // Returns the number of tests that should run. -int UnitTestImpl::FilterTests() { +int UnitTestImpl::FilterTests(ReactionToSharding shard_tests) { + const Int32 total_shards = shard_tests == HONOR_SHARDING_PROTOCOL ? + Int32FromEnvOrDie(kTestTotalShards, -1) : -1; + const Int32 shard_index = shard_tests == HONOR_SHARDING_PROTOCOL ? + Int32FromEnvOrDie(kTestShardIndex, -1) : -1; + + // num_runnable_tests are the number of tests that will + // run across all shards (i.e., match filter and are not disabled). + // num_selected_tests are the number of tests to be run on + // this shard. int num_runnable_tests = 0; + int num_selected_tests = 0; for (const internal::ListNode *test_case_node = test_cases_.Head(); test_case_node != NULL; @@ -3615,18 +3754,24 @@ int UnitTestImpl::FilterTests() { kDisableTestFilter); test_info->impl()->set_is_disabled(is_disabled); - const bool should_run = + const bool is_runnable = (GTEST_FLAG(also_run_disabled_tests) || !is_disabled) && internal::UnitTestOptions::FilterMatchesTest(test_case_name, test_name); - test_info->impl()->set_should_run(should_run); - test_case->set_should_run(test_case->should_run() || should_run); - if (should_run) { - num_runnable_tests++; - } + + const bool is_selected = is_runnable && + (shard_tests == IGNORE_SHARDING_PROTOCOL || + ShouldRunTestOnShard(total_shards, shard_index, + num_runnable_tests)); + + num_runnable_tests += is_runnable; + num_selected_tests += is_selected; + + test_info->impl()->set_should_run(is_selected); + test_case->set_should_run(test_case->should_run() || is_selected); } } - return num_runnable_tests; + return num_selected_tests; } // Lists all tests by name. -- cgit v1.2.3 From 0af0709b02899f9177db55eba7929e65e5834b29 Mon Sep 17 00:00:00 2001 From: "zhanyong.wan" Date: Mon, 23 Feb 2009 23:21:55 +0000 Subject: Cleans up macro definitions. --- src/gtest-death-test.cc | 14 +++--- src/gtest-filepath.cc | 20 ++++----- src/gtest-internal-inl.h | 20 ++++----- src/gtest-port.cc | 13 +++--- src/gtest-test-part.cc | 4 +- src/gtest-typed-test.cc | 2 +- src/gtest.cc | 110 +++++++++++++++++++++++------------------------ 7 files changed, 92 insertions(+), 91 deletions(-) (limited to 'src') diff --git a/src/gtest-death-test.cc b/src/gtest-death-test.cc index 6499842c..7bb36490 100644 --- a/src/gtest-death-test.cc +++ b/src/gtest-death-test.cc @@ -34,7 +34,7 @@ #include #include -#ifdef GTEST_HAS_DEATH_TEST +#if GTEST_HAS_DEATH_TEST #include #include #include @@ -48,9 +48,9 @@ // 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 +#define GTEST_IMPLEMENTATION_ 1 #include "src/gtest-internal-inl.h" -#undef GTEST_IMPLEMENTATION +#undef GTEST_IMPLEMENTATION_ namespace testing { @@ -90,7 +90,7 @@ GTEST_DEFINE_string_( "death test. FOR INTERNAL USE ONLY."); } // namespace internal -#ifdef GTEST_HAS_DEATH_TEST +#if GTEST_HAS_DEATH_TEST // ExitedWithCode constructor. ExitedWithCode::ExitedWithCode(int exit_code) : exit_code_(exit_code) { @@ -144,7 +144,7 @@ bool ExitedUnsuccessfully(int exit_status) { static String DeathTestThreadWarning(size_t thread_count) { Message msg; msg << "Death tests use fork(), which is unsafe particularly" - << " in a threaded context. For this test, " << GTEST_NAME << " "; + << " in a threaded context. For this test, " << GTEST_NAME_ << " "; if (thread_count == 0) msg << "couldn't detect the number of threads."; else @@ -655,11 +655,11 @@ DeathTest::TestRole ExecDeathTest::AssumeRole() { const String filter_flag = String::Format("--%s%s=%s.%s", - GTEST_FLAG_PREFIX, kFilterFlag, + GTEST_FLAG_PREFIX_, kFilterFlag, info->test_case_name(), info->name()); const String internal_flag = String::Format("--%s%s=%s:%d:%d:%d", - GTEST_FLAG_PREFIX, kInternalRunDeathTestFlag, file_, line_, + GTEST_FLAG_PREFIX_, kInternalRunDeathTestFlag, file_, line_, death_test_index, pipe_fd[1]); Arguments args; args.AddArguments(GetArgvs()); diff --git a/src/gtest-filepath.cc b/src/gtest-filepath.cc index ebf7cf93..e5908012 100644 --- a/src/gtest-filepath.cc +++ b/src/gtest-filepath.cc @@ -36,11 +36,11 @@ #ifdef _WIN32_WCE #include -#elif defined(GTEST_OS_WINDOWS) +#elif GTEST_OS_WINDOWS #include #include #include -#elif defined(GTEST_OS_SYMBIAN) +#elif GTEST_OS_SYMBIAN // Symbian OpenC has PATH_MAX in sys/syslimits.h #include #include @@ -50,7 +50,7 @@ #include // NOLINT #endif // _WIN32_WCE or _WIN32 -#ifdef GTEST_OS_WINDOWS +#if GTEST_OS_WINDOWS #define GTEST_PATH_MAX_ _MAX_PATH #elif defined(PATH_MAX) #define GTEST_PATH_MAX_ PATH_MAX @@ -65,7 +65,7 @@ namespace testing { namespace internal { -#ifdef GTEST_OS_WINDOWS +#if GTEST_OS_WINDOWS const char kPathSeparator = '\\'; const char kPathSeparatorString[] = "\\"; #ifdef _WIN32_WCE @@ -90,7 +90,7 @@ FilePath FilePath::GetCurrentDir() { // Windows CE doesn't have a current directory, so we just return // something reasonable. return FilePath(kCurrentDirectoryString); -#elif defined(GTEST_OS_WINDOWS) +#elif GTEST_OS_WINDOWS char cwd[GTEST_PATH_MAX_ + 1] = {}; return FilePath(_getcwd(cwd, sizeof(cwd)) == NULL ? "" : cwd); #else @@ -165,7 +165,7 @@ FilePath FilePath::ConcatPaths(const FilePath& directory, // Returns true if pathname describes something findable in the file-system, // either a file, directory, or whatever. bool FilePath::FileOrDirectoryExists() const { -#ifdef GTEST_OS_WINDOWS +#if GTEST_OS_WINDOWS #ifdef _WIN32_WCE LPCWSTR unicode = String::AnsiToUtf16(pathname_.c_str()); const DWORD attributes = GetFileAttributes(unicode); @@ -185,7 +185,7 @@ bool FilePath::FileOrDirectoryExists() const { // that exists. bool FilePath::DirectoryExists() const { bool result = false; -#ifdef GTEST_OS_WINDOWS +#if GTEST_OS_WINDOWS // Don't strip off trailing separator if path is a root directory on // Windows (like "C:\\"). const FilePath& path(IsRootDirectory() ? *this : @@ -214,7 +214,7 @@ bool FilePath::DirectoryExists() const { // Returns true if pathname describes a root directory. (Windows has one // root directory per disk drive.) bool FilePath::IsRootDirectory() const { -#ifdef GTEST_OS_WINDOWS +#if GTEST_OS_WINDOWS // TODO(wan@google.com): on Windows a network share like // \\server\share can be a root directory, although it cannot be the // current directory. Handle this properly. @@ -227,7 +227,7 @@ bool FilePath::IsRootDirectory() const { // Returns true if pathname describes an absolute path. bool FilePath::IsAbsolutePath() const { const char* const name = pathname_.c_str(); -#ifdef GTEST_OS_WINDOWS +#if GTEST_OS_WINDOWS return pathname_.GetLength() >= 3 && ((name[0] >= 'a' && name[0] <= 'z') || (name[0] >= 'A' && name[0] <= 'Z')) && @@ -285,7 +285,7 @@ bool FilePath::CreateDirectoriesRecursively() const { // directory for any reason, including if the parent directory does not // exist. Not named "CreateDirectory" because that's a macro on Windows. bool FilePath::CreateFolder() const { -#ifdef GTEST_OS_WINDOWS +#if GTEST_OS_WINDOWS #ifdef _WIN32_WCE FilePath removed_sep(this->RemoveTrailingPathSeparator()); LPCWSTR unicode = String::AnsiToUtf16(removed_sep.c_str()); diff --git a/src/gtest-internal-inl.h b/src/gtest-internal-inl.h index 07d0c5b4..b1a5dbb1 100644 --- a/src/gtest-internal-inl.h +++ b/src/gtest-internal-inl.h @@ -37,19 +37,19 @@ #ifndef GTEST_SRC_GTEST_INTERNAL_INL_H_ #define GTEST_SRC_GTEST_INTERNAL_INL_H_ -// GTEST_IMPLEMENTATION is defined iff the current translation unit is -// part of Google Test's implementation. -#ifndef GTEST_IMPLEMENTATION +// GTEST_IMPLEMENTATION_ is defined to 1 iff the current translation unit is +// part of Google Test's implementation; otherwise it's undefined. +#if !GTEST_IMPLEMENTATION_ // A user is trying to include this from his code - just say no. #error "gtest-internal-inl.h is part of Google Test's internal implementation." #error "It must not be included except by Google Test itself." -#endif // GTEST_IMPLEMENTATION +#endif // GTEST_IMPLEMENTATION_ #include #include -#ifdef GTEST_OS_WINDOWS +#if GTEST_OS_WINDOWS #include // NOLINT #endif // GTEST_OS_WINDOWS @@ -833,7 +833,7 @@ class UnitTestOptions { static bool FilterMatchesTest(const String &test_case_name, const String &test_name); -#ifdef GTEST_OS_WINDOWS +#if GTEST_OS_WINDOWS // Function for supporting the gtest_catch_exception flag. // Returns EXCEPTION_EXECUTE_HANDLER if Google Test should handle the @@ -1095,7 +1095,7 @@ class UnitTestImpl { tear_down_tc)->AddTestInfo(test_info); } -#ifdef GTEST_HAS_PARAM_TEST +#if GTEST_HAS_PARAM_TEST // Returns ParameterizedTestCaseRegistry object used to keep track of // value-parameterized tests and instantiate and register them. internal::ParameterizedTestCaseRegistry& parameterized_test_registry() { @@ -1175,7 +1175,7 @@ class UnitTestImpl { return gtest_trace_stack_.pointer(); } -#ifdef GTEST_HAS_DEATH_TEST +#if GTEST_HAS_DEATH_TEST // Returns a pointer to the parsed --gtest_internal_run_death_test // flag, or NULL if that flag was not specified. // This information is useful only in a death test child process. @@ -1224,7 +1224,7 @@ class UnitTestImpl { internal::List test_cases_; // The list of TestCases. -#ifdef GTEST_HAS_PARAM_TEST +#if GTEST_HAS_PARAM_TEST // ParameterizedTestRegistry object used to register value-parameterized // tests. internal::ParameterizedTestCaseRegistry parameterized_test_registry_; @@ -1273,7 +1273,7 @@ class UnitTestImpl { // How long the test took to run, in milliseconds. TimeInMillis elapsed_time_; -#ifdef GTEST_HAS_DEATH_TEST +#if GTEST_HAS_DEATH_TEST // The decomposed components of the gtest_internal_run_death_test flag, // parsed when RUN_ALL_TESTS is called. internal::scoped_ptr internal_run_death_test_flag_; diff --git a/src/gtest-port.cc b/src/gtest-port.cc index 9348f55c..59a22308 100644 --- a/src/gtest-port.cc +++ b/src/gtest-port.cc @@ -35,7 +35,7 @@ #include #include -#ifdef GTEST_HAS_DEATH_TEST +#if GTEST_HAS_DEATH_TEST #include #endif // GTEST_HAS_DEATH_TEST @@ -56,9 +56,9 @@ // 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 +#define GTEST_IMPLEMENTATION_ 1 #include "src/gtest-internal-inl.h" -#undef GTEST_IMPLEMENTATION +#undef GTEST_IMPLEMENTATION_ namespace testing { namespace internal { @@ -334,7 +334,7 @@ bool RE::PartialMatch(const char* str, const RE& re) { void RE::Init(const char* regex) { pattern_ = full_pattern_ = NULL; if (regex != NULL) { -#ifdef GTEST_OS_WINDOWS +#if GTEST_OS_WINDOWS pattern_ = _strdup(regex); #else pattern_ = strdup(regex); @@ -383,7 +383,7 @@ void GTestLog(GTestLogSeverity severity, const char* file, } } -#ifdef GTEST_HAS_DEATH_TEST +#if GTEST_HAS_DEATH_TEST // Defines the stderr capturer. @@ -502,7 +502,8 @@ void abort() { // given flag. For example, FlagToEnvVar("foo") will return // "GTEST_FOO" in the open-source version. static String FlagToEnvVar(const char* flag) { - const String full_flag = (Message() << GTEST_FLAG_PREFIX << flag).GetString(); + const String full_flag = + (Message() << GTEST_FLAG_PREFIX_ << flag).GetString(); Message env_var; for (int i = 0; i != full_flag.GetLength(); i++) { diff --git a/src/gtest-test-part.cc b/src/gtest-test-part.cc index dcd30b25..2cb55856 100644 --- a/src/gtest-test-part.cc +++ b/src/gtest-test-part.cc @@ -38,9 +38,9 @@ // 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 +#define GTEST_IMPLEMENTATION_ 1 #include "src/gtest-internal-inl.h" -#undef GTEST_IMPLEMENTATION +#undef GTEST_IMPLEMENTATION_ namespace testing { diff --git a/src/gtest-typed-test.cc b/src/gtest-typed-test.cc index d42a1596..cb91f2b2 100644 --- a/src/gtest-typed-test.cc +++ b/src/gtest-typed-test.cc @@ -35,7 +35,7 @@ namespace testing { namespace internal { -#ifdef GTEST_HAS_TYPED_TEST_P +#if GTEST_HAS_TYPED_TEST_P // Verifies that registered_tests match the test names in // defined_test_names_; returns registered_tests if successful, or diff --git a/src/gtest.cc b/src/gtest.cc index 0d161e0e..e4f9d0f3 100644 --- a/src/gtest.cc +++ b/src/gtest.cc @@ -43,11 +43,11 @@ #include #include -#ifdef GTEST_OS_LINUX +#if GTEST_OS_LINUX // TODO(kenton@google.com): Use autoconf to detect availability of // gettimeofday(). -#define GTEST_HAS_GETTIMEOFDAY +#define GTEST_HAS_GETTIMEOFDAY_ 1 #include #include @@ -60,12 +60,12 @@ #include #include -#elif defined(GTEST_OS_SYMBIAN) -#define GTEST_HAS_GETTIMEOFDAY +#elif GTEST_OS_SYMBIAN +#define GTEST_HAS_GETTIMEOFDAY_ 1 #include // NOLINT -#elif defined(GTEST_OS_ZOS) -#define GTEST_HAS_GETTIMEOFDAY +#elif GTEST_OS_ZOS +#define GTEST_HAS_GETTIMEOFDAY_ 1 #include // NOLINT // On z/OS we additionally need strings.h for strcasecmp. @@ -75,7 +75,7 @@ #include // NOLINT -#elif defined(GTEST_OS_WINDOWS) // We are on Windows proper. +#elif GTEST_OS_WINDOWS // We are on Windows proper. #include // NOLINT #include // NOLINT @@ -89,9 +89,9 @@ // TODO(kenton@google.com): There are other ways to get the time on // Windows, like GetTickCount() or GetSystemTimeAsFileTime(). MinGW // supports these. consider using them instead. -#define GTEST_HAS_GETTIMEOFDAY +#define GTEST_HAS_GETTIMEOFDAY_ 1 #include // NOLINT -#endif +#endif // defined(__MINGW__) || defined(__MINGW32__) // cpplint thinks that the header is already included, so we want to // silence it. @@ -102,25 +102,25 @@ // Assume other platforms have gettimeofday(). // TODO(kenton@google.com): Use autoconf to detect availability of // gettimeofday(). -#define GTEST_HAS_GETTIMEOFDAY +#define GTEST_HAS_GETTIMEOFDAY_ 1 // cpplint thinks that the header is already included, so we want to // silence it. #include // NOLINT #include // NOLINT -#endif +#endif // GTEST_OS_LINUX // 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 +#define GTEST_IMPLEMENTATION_ 1 #include "src/gtest-internal-inl.h" -#undef GTEST_IMPLEMENTATION +#undef GTEST_IMPLEMENTATION_ -#ifdef GTEST_OS_WINDOWS +#if GTEST_OS_WINDOWS #define fileno _fileno #define isatty _isatty #define vsnprintf _vsnprintf @@ -173,7 +173,7 @@ GTEST_DEFINE_bool_( GTEST_DEFINE_bool_( catch_exceptions, internal::BoolFromGTestEnv("catch_exceptions", false), - "True iff " GTEST_NAME + "True iff " GTEST_NAME_ " should catch exceptions and treat them as test failures."); GTEST_DEFINE_string_( @@ -211,7 +211,7 @@ GTEST_DEFINE_string_( GTEST_DEFINE_bool_( print_time, internal::BoolFromGTestEnv("print_time", false), - "True iff " GTEST_NAME + "True iff " GTEST_NAME_ " should display elapsed time in text output."); GTEST_DEFINE_int32_( @@ -228,7 +228,7 @@ GTEST_DEFINE_int32_( GTEST_DEFINE_bool_( show_internal_stack_frames, false, - "True iff " GTEST_NAME " should include internal stack frames when " + "True iff " GTEST_NAME_ " should include internal stack frames when " "printing test failure stack traces."); namespace internal { @@ -302,7 +302,7 @@ String g_executable_path; FilePath GetCurrentExecutableName() { FilePath result; -#if defined(_WIN32_WCE) || defined(GTEST_OS_WINDOWS) +#if defined(_WIN32_WCE) || GTEST_OS_WINDOWS result.Set(FilePath(g_executable_path).RemoveExtension("exe")); #else result.Set(FilePath(g_executable_path)); @@ -433,7 +433,7 @@ bool UnitTestOptions::FilterMatchesTest(const String &test_case_name, !MatchesFilter(full_name, negative.c_str())); } -#ifdef GTEST_OS_WINDOWS +#if GTEST_OS_WINDOWS // Returns EXCEPTION_EXECUTE_HANDLER if Google Test should handle the // given SEH exception, or EXCEPTION_CONTINUE_SEARCH otherwise. // This function is useful as an __except condition. @@ -743,7 +743,7 @@ static TimeInMillis GetTimeInMillis() { return now_int64.QuadPart; } return 0; -#elif defined(GTEST_OS_WINDOWS) && !defined(GTEST_HAS_GETTIMEOFDAY) +#elif GTEST_OS_WINDOWS && !GTEST_HAS_GETTIMEOFDAY_ __timeb64 now; #ifdef _MSC_VER // MSVC 8 deprecates _ftime64(), so we want to suppress warning 4996 @@ -758,7 +758,7 @@ static TimeInMillis GetTimeInMillis() { _ftime64(&now); #endif // _MSC_VER return static_cast(now.time) * 1000 + now.millitm; -#elif defined(GTEST_HAS_GETTIMEOFDAY) +#elif GTEST_HAS_GETTIMEOFDAY_ struct timeval now; gettimeofday(&now, NULL); return static_cast(now.tv_sec) * 1000 + now.tv_usec / 1000; @@ -793,7 +793,7 @@ static char* CloneString(const char* str, size_t length) { char* const clone = new char[length + 1]; // MSVC 8 deprecates strncpy(), so we want to suppress warning // 4996 (deprecated function) there. -#ifdef GTEST_OS_WINDOWS // We are on Windows. +#if GTEST_OS_WINDOWS // We are on Windows. #pragma warning(push) // Saves the current warning state. #pragma warning(disable:4996) // Temporarily disables warning 4996. strncpy(clone, str, length); @@ -1314,7 +1314,7 @@ AssertionResult IsNotSubstring( namespace internal { -#ifdef GTEST_OS_WINDOWS +#if GTEST_OS_WINDOWS namespace { @@ -1442,14 +1442,14 @@ char* CodePointToUtf8(UInt32 code_point, char* str) { // null-terminate the destination string. // MSVC 8 deprecates strncpy(), so we want to suppress warning // 4996 (deprecated function) there. -#ifdef GTEST_OS_WINDOWS // We are on Windows. +#if GTEST_OS_WINDOWS // We are on Windows. #pragma warning(push) // Saves the current warning state. #pragma warning(disable:4996) // Temporarily disables warning 4996. #endif strncpy(str, String::Format("(Invalid Unicode 0x%X)", code_point).c_str(), 32); -#ifdef GTEST_OS_WINDOWS // We are on Windows. -#pragma warning(pop) // Restores the warning state. +#if GTEST_OS_WINDOWS // We are on Windows. +#pragma warning(pop) // Restores the warning state. #endif str[31] = '\0'; // Makes sure no change in the format to strncpy leaves // the result unterminated. @@ -1592,7 +1592,7 @@ bool String::CaseInsensitiveCStringEquals(const char * lhs, const char * rhs) { if ( rhs == NULL ) return false; -#ifdef GTEST_OS_WINDOWS +#if GTEST_OS_WINDOWS return _stricmp(lhs, rhs) == 0; #else // GTEST_OS_WINDOWS return strcasecmp(lhs, rhs) == 0; @@ -1617,9 +1617,9 @@ bool String::CaseInsensitiveWideCStringEquals(const wchar_t* lhs, if ( rhs == NULL ) return false; -#ifdef GTEST_OS_WINDOWS +#if GTEST_OS_WINDOWS return _wcsicmp(lhs, rhs) == 0; -#elif defined(GTEST_OS_LINUX) +#elif GTEST_OS_LINUX return wcscasecmp(lhs, rhs) == 0; #else // Mac OS X and Cygwin don't define wcscasecmp. Other unknown OSes @@ -1720,7 +1720,7 @@ String String::Format(const char * format, ...) { char buffer[4096]; // MSVC 8 deprecates vsnprintf(), so we want to suppress warning // 4996 (deprecated function) there. -#ifdef GTEST_OS_WINDOWS // We are on Windows. +#if GTEST_OS_WINDOWS // We are on Windows. #pragma warning(push) // Saves the current warning state. #pragma warning(disable:4996) // Temporarily disables warning 4996. const int size = @@ -1827,7 +1827,7 @@ bool TestResult::ValidateTestProperty(const TestProperty& test_property) { << "Reserved key used in RecordProperty(): " << key << " ('name', 'status', 'time', and 'classname' are reserved by " - << GTEST_NAME << ")"; + << GTEST_NAME_ << ")"; return false; } return true; @@ -1917,7 +1917,7 @@ void Test::RecordProperty(const char* key, int value) { RecordProperty(key, value_message.GetString().c_str()); } -#ifdef GTEST_OS_WINDOWS +#if GTEST_OS_WINDOWS // We are on Windows. // Adds an "exception thrown" fatal failure to the current test. @@ -2013,7 +2013,7 @@ void Test::Run() { if (!HasSameFixtureClass()) return; internal::UnitTestImpl* const impl = internal::GetUnitTestImpl(); -#ifdef GTEST_OS_WINDOWS +#if GTEST_OS_WINDOWS // We are on Windows. impl->os_stack_trace_getter()->UponLeavingGTest(); __try { @@ -2122,7 +2122,7 @@ TestInfo* MakeAndRegisterTestInfo( return test_info; } -#ifdef GTEST_HAS_PARAM_TEST +#if GTEST_HAS_PARAM_TEST void ReportInvalidTestCaseType(const char* test_case_name, const char* file, int line) { Message errors; @@ -2221,7 +2221,7 @@ namespace internal { // and INSTANTIATE_TEST_CASE_P into regular tests and registers those. // This will be done just once during the program runtime. void UnitTestImpl::RegisterParameterizedTests() { -#ifdef GTEST_HAS_PARAM_TEST +#if GTEST_HAS_PARAM_TEST if (!parameterized_tests_registered_) { parameterized_test_registry_.RegisterTests(); parameterized_tests_registered_ = true; @@ -2247,7 +2247,7 @@ void TestInfoImpl::Run() { const TimeInMillis start = GetTimeInMillis(); impl->os_stack_trace_getter()->UponLeavingGTest(); -#ifdef GTEST_OS_WINDOWS +#if GTEST_OS_WINDOWS // We are on Windows. Test* test = NULL; @@ -2459,7 +2459,7 @@ enum GTestColor { COLOR_YELLOW }; -#if defined(GTEST_OS_WINDOWS) && !defined(_WIN32_WCE) +#if GTEST_OS_WINDOWS && !defined(_WIN32_WCE) // Returns the character attribute for the given color. WORD GetColorAttribute(GTestColor color) { @@ -2490,7 +2490,7 @@ bool ShouldUseColor(bool stdout_is_tty) { const char* const gtest_color = GTEST_FLAG(color).c_str(); if (String::CaseInsensitiveCStringEquals(gtest_color, "auto")) { -#ifdef GTEST_OS_WINDOWS +#if GTEST_OS_WINDOWS // On Windows the TERM variable is usually not set, but the // console there does support colors. return stdout_is_tty; @@ -2522,11 +2522,11 @@ void ColoredPrintf(GTestColor color, const char* fmt, ...) { va_list args; va_start(args, fmt); -#if defined(_WIN32_WCE) || defined(GTEST_OS_SYMBIAN) || defined(GTEST_OS_ZOS) +#if defined(_WIN32_WCE) || GTEST_OS_SYMBIAN || GTEST_OS_ZOS static const bool use_color = false; #else static const bool use_color = ShouldUseColor(isatty(fileno(stdout)) != 0); -#endif // !_WIN32_WCE +#endif // defined(_WIN32_WCE) || GTEST_OS_SYMBIAN || GTEST_OS_ZOS // The '!= 0' comparison is necessary to satisfy MSVC 7.1. if (!use_color) { @@ -2535,7 +2535,7 @@ void ColoredPrintf(GTestColor color, const char* fmt, ...) { return; } -#if defined(GTEST_OS_WINDOWS) && !defined(_WIN32_WCE) +#if GTEST_OS_WINDOWS && !defined(_WIN32_WCE) const HANDLE stdout_handle = GetStdHandle(STD_OUTPUT_HANDLE); // Gets the current text color. @@ -2553,7 +2553,7 @@ void ColoredPrintf(GTestColor color, const char* fmt, ...) { printf("\033[0;3%sm", GetAnsiColorCode(color)); vprintf(fmt, args); printf("\033[m"); // Resets the terminal to default. -#endif // GTEST_OS_WINDOWS && !_WIN32_WCE +#endif // GTEST_OS_WINDOWS && !defined(_WIN32_WCE) va_end(args); } @@ -2599,7 +2599,7 @@ void PrettyUnitTestResultPrinter::OnUnitTestStart( // tests may be skipped. if (!internal::String::CStringEquals(filter, kUniversalFilter)) { ColoredPrintf(COLOR_YELLOW, - "Note: %s filter = %s\n", GTEST_NAME, filter); + "Note: %s filter = %s\n", GTEST_NAME_, filter); } if (internal::ShouldShard(kTestTotalShards, kTestShardIndex, false)) { @@ -2926,7 +2926,7 @@ void XmlUnitTestResultPrinter::OnUnitTestEnd(const UnitTest* unit_test) { if (output_dir.CreateDirectoriesRecursively()) { // MSVC 8 deprecates fopen(), so we want to suppress warning 4996 // (deprecated function) there. -#ifdef GTEST_OS_WINDOWS +#if GTEST_OS_WINDOWS // We are on Windows. #pragma warning(push) // Saves the current warning state. #pragma warning(disable:4996) // Temporarily disables warning 4996. @@ -3191,7 +3191,7 @@ void OsStackTraceGetter::UponLeavingGTest() { const char* const OsStackTraceGetter::kElidedFramesMarker = - "... " GTEST_NAME " internal frames ..."; + "... " GTEST_NAME_ " internal frames ..."; } // namespace internal @@ -3255,7 +3255,7 @@ void UnitTest::AddTestPartResult(TestPartResultType result_type, internal::MutexLock lock(&mutex_); if (impl_->gtest_trace_stack()->size() > 0) { - msg << "\n" << GTEST_NAME << " trace:"; + msg << "\n" << GTEST_NAME_ << " trace:"; for (internal::ListNode* node = impl_->gtest_trace_stack()->Head(); @@ -3298,7 +3298,7 @@ void UnitTest::RecordPropertyForCurrentTest(const char* key, // We don't protect this under mutex_, as we only support calling it // from the main thread. int UnitTest::Run() { -#ifdef GTEST_OS_WINDOWS +#if GTEST_OS_WINDOWS #if !defined(_WIN32_WCE) // SetErrorMode doesn't exist on CE. @@ -3349,7 +3349,7 @@ const TestInfo* UnitTest::current_test_info() const { return impl_->current_test_info(); } -#ifdef GTEST_HAS_PARAM_TEST +#if GTEST_HAS_PARAM_TEST // Returns ParameterizedTestCaseRegistry object used to keep track of // value-parameterized tests and instantiate and register them. // L < mutex_ @@ -3404,7 +3404,7 @@ UnitTestImpl::UnitTestImpl(UnitTest* parent) per_thread_test_part_result_reporter_( &default_per_thread_test_part_result_reporter_), test_cases_(), -#ifdef GTEST_HAS_PARAM_TEST +#if GTEST_HAS_PARAM_TEST parameterized_test_registry_(), parameterized_tests_registered_(false), #endif // GTEST_HAS_PARAM_TEST @@ -3414,7 +3414,7 @@ UnitTestImpl::UnitTestImpl(UnitTest* parent) ad_hoc_test_result_(), result_printer_(NULL), os_stack_trace_getter_(NULL), -#ifdef GTEST_HAS_DEATH_TEST +#if GTEST_HAS_DEATH_TEST elapsed_time_(0), internal_run_death_test_flag_(NULL), death_test_factory_(new DefaultDeathTestFactory) { @@ -3540,7 +3540,7 @@ int UnitTestImpl::RunAllTests() { // death test. bool in_subprocess_for_death_test = false; -#ifdef GTEST_HAS_DEATH_TEST +#if GTEST_HAS_DEATH_TEST internal_run_death_test_flag_.reset(ParseInternalRunDeathTestFlag()); in_subprocess_for_death_test = (internal_run_death_test_flag_.get() != NULL); #endif // GTEST_HAS_DEATH_TEST @@ -3817,7 +3817,7 @@ UnitTestEventListenerInterface* UnitTestImpl::result_printer() { return result_printer_; } -#ifdef GTEST_HAS_DEATH_TEST +#if GTEST_HAS_DEATH_TEST if (internal_run_death_test_flag_.get() != NULL) { result_printer_ = new NullUnitTestResultPrinter; return result_printer_; @@ -3943,8 +3943,8 @@ const char* ParseFlagValue(const char* str, // str and flag must not be NULL. if (str == NULL || flag == NULL) return NULL; - // The flag must start with "--" followed by GTEST_FLAG_PREFIX. - const String flag_str = String::Format("--%s%s", GTEST_FLAG_PREFIX, flag); + // The flag must start with "--" followed by GTEST_FLAG_PREFIX_. + const String flag_str = String::Format("--%s%s", GTEST_FLAG_PREFIX_, flag); const size_t flag_len = flag_str.GetLength(); if (strncmp(str, flag_str.c_str(), flag_len) != 0) return NULL; @@ -4096,7 +4096,7 @@ void InitGoogleTestImpl(int* argc, CharType** argv) { internal::g_executable_path = internal::StreamableToString(argv[0]); -#ifdef GTEST_HAS_DEATH_TEST +#if GTEST_HAS_DEATH_TEST g_argvs.clear(); for (int i = 0; i != *argc; i++) { g_argvs.push_back(StreamableToString(argv[i])); -- cgit v1.2.3 From 4984c93490eeeb7d3d1979b30a39a21cad07cba5 Mon Sep 17 00:00:00 2001 From: "zhanyong.wan" Date: Fri, 6 Mar 2009 01:20:15 +0000 Subject: Implements death tests on Windows (by Vlad Losev); enables POSIX regex on Mac and Cygwin; fixes build issue on some Linux versions due to PATH_MAX. --- src/gtest-death-test.cc | 742 +++++++++++++++++++++++++++++++++++++++-------- src/gtest-filepath.cc | 1 + src/gtest-internal-inl.h | 80 ++++- src/gtest-port.cc | 66 ++++- src/gtest.cc | 38 ++- 5 files changed, 781 insertions(+), 146 deletions(-) (limited to 'src') diff --git a/src/gtest-death-test.cc b/src/gtest-death-test.cc index 7bb36490..71b749b9 100644 --- a/src/gtest-death-test.cc +++ b/src/gtest-death-test.cc @@ -27,7 +27,7 @@ // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. // -// Author: wan@google.com (Zhanyong Wan) +// Author: wan@google.com (Zhanyong Wan), vladl@losev.com (Vlad Losev) // // This file implements death tests. @@ -36,8 +36,16 @@ #if GTEST_HAS_DEATH_TEST #include +#include #include #include + +#if GTEST_OS_WINDOWS +#include +#else +#include +#endif // GTEST_OS_WINDOWS + #endif // GTEST_HAS_DEATH_TEST #include @@ -98,9 +106,14 @@ ExitedWithCode::ExitedWithCode(int exit_code) : exit_code_(exit_code) { // ExitedWithCode function-call operator. bool ExitedWithCode::operator()(int exit_status) const { +#if GTEST_OS_WINDOWS + return exit_status == exit_code_; +#else return WIFEXITED(exit_status) && WEXITSTATUS(exit_status) == exit_code_; +#endif // GTEST_OS_WINDOWS } +#if !GTEST_OS_WINDOWS // KilledBySignal constructor. KilledBySignal::KilledBySignal(int signum) : signum_(signum) { } @@ -109,6 +122,7 @@ KilledBySignal::KilledBySignal(int signum) : signum_(signum) { bool KilledBySignal::operator()(int exit_status) const { return WIFSIGNALED(exit_status) && WTERMSIG(exit_status) == signum_; } +#endif // !GTEST_OS_WINDOWS namespace internal { @@ -118,6 +132,9 @@ namespace internal { // specified by wait(2). static String ExitSummary(int exit_code) { Message m; +#if GTEST_OS_WINDOWS + m << "Exited with exit status " << exit_code; +#else if (WIFEXITED(exit_code)) { m << "Exited with exit status " << WEXITSTATUS(exit_code); } else if (WIFSIGNALED(exit_code)) { @@ -128,6 +145,7 @@ static String ExitSummary(int exit_code) { m << " (core dumped)"; } #endif +#endif // GTEST_OS_WINDOWS return m.GetString(); } @@ -137,6 +155,7 @@ bool ExitedUnsuccessfully(int exit_status) { return !ExitedWithCode(0)(exit_status); } +#if !GTEST_OS_WINDOWS // Generates a textual failure message when a death test finds more than // one thread running, or cannot determine the number of threads, prior // to executing the given statement. It is the responsibility of the @@ -151,10 +170,7 @@ static String DeathTestThreadWarning(size_t thread_count) { msg << "detected " << thread_count << " threads."; return msg.GetString(); } - -// Static string containing a description of the outcome of the -// last death test. -static String last_death_test_message; +#endif // !GTEST_OS_WINDOWS // Flag characters for reporting a death test that did not die. static const char kDeathTestLived = 'L'; @@ -170,29 +186,33 @@ static const char kDeathTestInternalError = 'I'; enum DeathTestOutcome { IN_PROGRESS, DIED, LIVED, RETURNED }; // Routine for aborting the program which is safe to call from an -// exec-style death test child process, in which case the the error +// exec-style death test child process, in which case the error // message is propagated back to the parent process. Otherwise, the // message is simply printed to stderr. In either case, the program // then exits with status 1. -void DeathTestAbort(const char* format, ...) { - // This function may be called from a threadsafe-style death test - // child process, which operates on a very small stack. Use the - // heap for any additional non-miniscule memory requirements. +void DeathTestAbort(const String& message) { + // On a POSIX system, this function may be called from a threadsafe-style + // death test child process, which operates on a very small stack. Use + // the heap for any additional non-minuscule memory requirements. const InternalRunDeathTestFlag* const flag = GetUnitTestImpl()->internal_run_death_test_flag(); - va_list args; - va_start(args, format); - if (flag != NULL) { - FILE* parent = fdopen(flag->status_fd, "w"); +// Suppress MSVC complaints about POSIX functions. +#ifdef _MSC_VER +#pragma warning(push) +#pragma warning(disable: 4996) +#endif // _MSC_VER + FILE* parent = fdopen(flag->status_fd(), "w"); +#ifdef _MSC_VER +#pragma warning(pop) +#endif // _MSC_VER fputc(kDeathTestInternalError, parent); - vfprintf(parent, format, args); - fclose(parent); - va_end(args); + fprintf(parent, "%s", message.c_str()); + fflush(parent); _exit(1); } else { - vfprintf(stderr, format, args); - va_end(args); + fprintf(stderr, "%s", message.c_str()); + fflush(stderr); abort(); } } @@ -202,8 +222,9 @@ void DeathTestAbort(const char* format, ...) { #define GTEST_DEATH_TEST_CHECK_(expression) \ do { \ if (!(expression)) { \ - DeathTestAbort("CHECK failed: File %s, line %d: %s", \ - __FILE__, __LINE__, #expression); \ + DeathTestAbort(::testing::internal::String::Format(\ + "CHECK failed: File %s, line %d: %s", \ + __FILE__, __LINE__, #expression)); \ } \ } while (0) @@ -216,16 +237,59 @@ void DeathTestAbort(const char* format, ...) { // something other than EINTR, DeathTestAbort is called. #define GTEST_DEATH_TEST_CHECK_SYSCALL_(expression) \ do { \ - int retval; \ + int gtest_retval; \ do { \ - retval = (expression); \ - } while (retval == -1 && errno == EINTR); \ - if (retval == -1) { \ - DeathTestAbort("CHECK failed: File %s, line %d: %s != -1", \ - __FILE__, __LINE__, #expression); \ + gtest_retval = (expression); \ + } while (gtest_retval == -1 && errno == EINTR); \ + if (gtest_retval == -1) { \ + DeathTestAbort(::testing::internal::String::Format(\ + "CHECK failed: File %s, line %d: %s != -1", \ + __FILE__, __LINE__, #expression)); \ } \ } while (0) +// Returns the message describing the last system error, regardless of the +// platform. +String GetLastSystemErrorMessage() { +#if GTEST_OS_WINDOWS + const DWORD error_num = ::GetLastError(); + + if (error_num == NULL) + return String(""); + + char* message_ptr; + + ::FormatMessageA( + // The caller does not provide a buffer. The function will allocate one. + FORMAT_MESSAGE_ALLOCATE_BUFFER | + // The function must look up an error message in its system error + // message table. + FORMAT_MESSAGE_FROM_SYSTEM | + // Do not expand insert sequences in the message definition. + FORMAT_MESSAGE_IGNORE_INSERTS, + NULL, // Message source. Ignored in this call. + error_num, + 0x0, // Use system-default language. + reinterpret_cast(&message_ptr), + 0, // Buffer size. Ignored in this call. + NULL); // Message arguments. Ignored in this call. + + const String message = message_ptr; + ::LocalFree(message_ptr); + return message; +#else + return errno == 0 ? String("") : String(strerror(errno)); +#endif // GTEST_OS_WINDOWS +} + +// TODO(vladl@google.com): Move the definition of FailFromInternalError +// here. +#if GTEST_OS_WINDOWS +static void FailFromInternalError(HANDLE handle); +#else +static void FailFromInternalError(int fd); +#endif // GTEST_OS_WINDOWS + // Death test constructor. Increments the running death test count // for the current test. DeathTest::DeathTest() { @@ -245,61 +309,393 @@ bool DeathTest::Create(const char* statement, const RE* regex, } const char* DeathTest::LastMessage() { - return last_death_test_message.c_str(); + return last_death_test_message_.c_str(); +} + +void DeathTest::set_last_death_test_message(const String& message) { + last_death_test_message_ = message; } +String DeathTest::last_death_test_message_; + +// Provides cross platform implementation for some death functionality. +// TODO(vladl@google.com): Merge this class with DeathTest in +// gtest-death-test-internal.h. +class DeathTestImpl : public DeathTest { + protected: + DeathTestImpl(const char* statement, const RE* regex) + : statement_(statement), + regex_(regex), + spawned_(false), + status_(-1), + outcome_(IN_PROGRESS) {} + + virtual bool Passed(bool status_ok); + + const char* statement() const { return statement_; } + const RE* regex() const { return regex_; } + bool spawned() const { return spawned_; } + void set_spawned(bool spawned) { spawned_ = spawned; } + int status() const { return status_; } + void set_status(int status) { status_ = status; } + DeathTestOutcome outcome() const { return outcome_; } + void set_outcome(DeathTestOutcome outcome) { outcome_ = outcome; } + + private: + // The textual content of the code this object is testing. This class + // doesn't own this string and should not attempt to delete it. + const char* const statement_; + // The regular expression which test output must match. DeathTestImpl + // doesn't own this object and should not attempt to delete it. + const RE* const regex_; + // True if the death test child process has been successfully spawned. + bool spawned_; + // The exit status of the child process. + int status_; + // How the death test concluded. + DeathTestOutcome outcome_; +}; + +// TODO(vladl@google.com): Move definition of DeathTestImpl::Passed() here. + +#if GTEST_OS_WINDOWS +// WindowsDeathTest implements death tests on Windows. Due to the +// specifics of starting new processes on Windows, death tests there are +// always threadsafe, and Google Test considers the +// --gtest_death_test_style=fast setting to be equivalent to +// --gtest_death_test_style=threadsafe there. +// +// A few implementation notes: Like the Linux version, the Windows +// implementation uses pipes for child-to-parent communication. But due to +// the specifics of pipes on Windows, some extra steps are required: +// +// 1. The parent creates a communication pipe and stores handles to both +// ends of it. +// 2. The parent starts the child and provides it with the information +// necessary to acquire the handle to the write end of the pipe. +// 3. The child acquires the write end of the pipe and signals the parent +// using a Windows event. +// 4. Now the parent can release the write end of the pipe on its side. If +// this is done before step 3, the object's reference count goes down to +// 0 and it is destroyed, preventing the child from acquiring it. The +// parent now has to release it, or read operations on the read end of +// the pipe will not return when the child terminates. +// 5. The parent reads child's output through the pipe (outcome code and +// any possible error messages) from the pipe, and its stderr and then +// determines whether to fail the test. +// +// Note: to distinguish Win32 API calls from the local method and function +// calls, the former are explicitly resolved in the global namespace. +// +class WindowsDeathTest : public DeathTestImpl { + public: + WindowsDeathTest(const char* statement, + const RE* regex, + const char* file, + int line) + : DeathTestImpl(statement, regex), file_(file), line_(line) {} + + // All of these virtual functions are inherited from DeathTest. + virtual int Wait(); + virtual void Abort(AbortReason reason); + virtual TestRole AssumeRole(); + + private: + // The name of the file in which the death test is located. + const char* const file_; + // The line number on which the death test is located. + const int line_; + // Handle to the read end of the pipe to the child process. + // The child keeps its write end of the pipe in the status_handle_ + // field of its InternalRunDeathTestFlag class. + AutoHandle read_handle_; + // Handle to the write end of the pipe to the child process. + AutoHandle write_handle_; + // Child process handle. + AutoHandle child_handle_; + // Event the child process uses to signal the parent that it has + // acquired the handle to the write end of the pipe. After seeing this + // event the parent can release its own handles to make sure its + // ReadFile() calls return when the child terminates. + AutoHandle event_handle_; +}; + +// Waits for the child in a death test to exit, returning its exit +// status, or 0 if no child process exists. As a side effect, sets the +// outcome data member. +// TODO(vladl@google.com): Outcome classification logic is common with +// ForkingDeathTes::Wait(). Refactor it into a +// common function. +int WindowsDeathTest::Wait() { + if (!spawned()) + return 0; + + // Wait until the child either signals that it has acquired the write end + // of the pipe or it dies. + const HANDLE wait_handles[2] = { child_handle_.Get(), event_handle_.Get() }; + switch (::WaitForMultipleObjects(2, + wait_handles, + FALSE, // Waits for any of the handles. + INFINITE)) { + case WAIT_OBJECT_0: + case WAIT_OBJECT_0 + 1: + break; + default: + GTEST_DEATH_TEST_CHECK_(false); // Should not get here. + } + + // The child has acquired the write end of the pipe or exited. + // We release the handle on our side and continue. + write_handle_.Reset(); + event_handle_.Reset(); + + // ReadFile() blocks until data is available (signifying the + // failure of the death test) or until the pipe is closed (signifying + // its success), so it's okay to call this in the parent before or + // after the child process has exited. + char flag; + DWORD bytes_read; + GTEST_DEATH_TEST_CHECK_(::ReadFile(read_handle_.Get(), + &flag, + 1, + &bytes_read, + NULL) || + ::GetLastError() == ERROR_BROKEN_PIPE); + + if (bytes_read == 0) { + set_outcome(DIED); + } else if (bytes_read == 1) { + switch (flag) { + case kDeathTestReturned: + set_outcome(RETURNED); + break; + case kDeathTestLived: + set_outcome(LIVED); + break; + case kDeathTestInternalError: + FailFromInternalError(read_handle_.Get()); // Does not return. + break; + default: + GTEST_LOG_(FATAL, + Message() << "Death test child process reported " + << " unexpected status byte (" + << static_cast(flag) << ")"); + } + } else { + GTEST_LOG_(FATAL, + Message() << "Read from death test child process failed: " + << GetLastSystemErrorMessage()); + } + read_handle_.Reset(); // Done with reading. + + // Waits for the child process to exit if it haven't already. This + // returns immediately if the child has already exited, regardless of + // whether previous calls to WaitForMultipleObjects synchronized on this + // handle or not. + GTEST_DEATH_TEST_CHECK_( + WAIT_OBJECT_0 == ::WaitForSingleObject(child_handle_.Get(), + INFINITE)); + DWORD status; + GTEST_DEATH_TEST_CHECK_(::GetExitCodeProcess(child_handle_.Get(), + &status)); + child_handle_.Reset(); + set_status(static_cast(status)); + return this->status(); +} + +// TODO(vladl@google.com): define a cross-platform way to write to +// status_fd to be used both here and in ForkingDeathTest::Abort(). +// +// Signals that the death test did not die as expected. This is called +// from the child process only. +void WindowsDeathTest::Abort(AbortReason reason) { + const InternalRunDeathTestFlag* const internal_flag = + GetUnitTestImpl()->internal_run_death_test_flag(); + // The parent process considers the death test to be a failure if + // it finds any data in our pipe. So, here we write a single flag byte + // to the pipe, then exit. + const char status_ch = + reason == TEST_DID_NOT_DIE ? kDeathTestLived : kDeathTestReturned; + +#ifdef _MSC_VER +#pragma warning(push) +#pragma warning(disable: 4996) +#endif // _MSC_VER + GTEST_DEATH_TEST_CHECK_SYSCALL_(write(internal_flag->status_fd(), + &status_ch, 1)); +#ifdef _MSC_VER +#pragma warning(pop) +#endif // _MSC_VER + + // The write handle will be closed when the child terminates in _exit(). + _exit(1); // Exits w/o any normal exit hooks (we were supposed to crash) +} + +// The AssumeRole process for a Windows death test. It creates a child +// process with the same executable as the current process to run the +// death test. The child process is given the --gtest_filter and +// --gtest_internal_run_death_test flags such that it knows to run the +// current death test only. +DeathTest::TestRole WindowsDeathTest::AssumeRole() { + const UnitTestImpl* const impl = GetUnitTestImpl(); + const InternalRunDeathTestFlag* const flag = + impl->internal_run_death_test_flag(); + const TestInfo* const info = impl->current_test_info(); + const int death_test_index = info->result()->death_test_count(); + + if (flag != NULL) { + // ParseInternalRunDeathTestFlag() has performed all the necessary + // processing. + return EXECUTE_TEST; + } + + // WindowsDeathTest uses an anonymous pipe to communicate results of + // a death test. + SECURITY_ATTRIBUTES handles_are_inheritable = { + sizeof(SECURITY_ATTRIBUTES), NULL, TRUE }; + HANDLE read_handle, write_handle; + GTEST_DEATH_TEST_CHECK_(::CreatePipe(&read_handle, &write_handle, + &handles_are_inheritable, + 0)); // Default buffer size. + read_handle_.Reset(read_handle); + write_handle_.Reset(write_handle); + event_handle_.Reset(::CreateEvent( + &handles_are_inheritable, + TRUE, // The event will automatically reset to non-signaled state. + FALSE, // The initial state is non-signalled. + NULL)); // The even is unnamed. + GTEST_DEATH_TEST_CHECK_(event_handle_.Get() != NULL); + const String filter_flag = String::Format("--%s%s=%s.%s", + GTEST_FLAG_PREFIX_, kFilterFlag, + info->test_case_name(), + info->name()); + const String internal_flag = String::Format( + "--%s%s=%s|%d|%d|%u|%Iu|%Iu", + GTEST_FLAG_PREFIX_, + kInternalRunDeathTestFlag, + file_, line_, + death_test_index, + static_cast(::GetCurrentProcessId()), + // size_t has the same with as pointers on both 32-bit and 64-bit + // Windows platforms. + // See http://msdn.microsoft.com/en-us/library/tcxf1dw6.aspx. + reinterpret_cast(write_handle), + reinterpret_cast(event_handle_.Get())); + + char executable_path[_MAX_PATH + 1]; // NOLINT + GTEST_DEATH_TEST_CHECK_( + _MAX_PATH + 1 != ::GetModuleFileNameA(NULL, + executable_path, + _MAX_PATH)); + + String command_line = String::Format("%s %s \"%s\"", + ::GetCommandLineA(), + filter_flag.c_str(), + internal_flag.c_str()); + + DeathTest::set_last_death_test_message(""); + + CaptureStderr(); + // Flush the log buffers since the log streams are shared with the child. + FlushInfoLog(); + + // The child process will share the standard handles with the parent. + STARTUPINFOA startup_info; + memset(&startup_info, 0, sizeof(STARTUPINFO)); + startup_info.dwFlags = STARTF_USESTDHANDLES; + startup_info.hStdInput = ::GetStdHandle(STD_INPUT_HANDLE); + startup_info.hStdOutput = ::GetStdHandle(STD_OUTPUT_HANDLE); + startup_info.hStdError = ::GetStdHandle(STD_ERROR_HANDLE); + + PROCESS_INFORMATION process_info; + GTEST_DEATH_TEST_CHECK_(::CreateProcessA( + executable_path, + const_cast(command_line.c_str()), + NULL, // Retuned process handle is not inheritable. + NULL, // Retuned thread handle is not inheritable. + TRUE, // Child inherits all inheritable handles (for write_handle_). + 0x0, // Default creation flags. + NULL, // Inherit the parent's environment. + UnitTest::GetInstance()->original_working_dir(), + &startup_info, + &process_info)); + child_handle_.Reset(process_info.hProcess); + ::CloseHandle(process_info.hThread); + set_spawned(true); + return OVERSEE_TEST; +} +#else // We are not on Windows. + // ForkingDeathTest provides implementations for most of the abstract // methods of the DeathTest interface. Only the AssumeRole method is // left undefined. -class ForkingDeathTest : public DeathTest { +class ForkingDeathTest : public DeathTestImpl { public: ForkingDeathTest(const char* statement, const RE* regex); // All of these virtual functions are inherited from DeathTest. virtual int Wait(); - virtual bool Passed(bool status_ok); virtual void Abort(AbortReason reason); protected: - void set_forked(bool forked) { forked_ = forked; } void set_child_pid(pid_t child_pid) { child_pid_ = child_pid; } void set_read_fd(int fd) { read_fd_ = fd; } void set_write_fd(int fd) { write_fd_ = fd; } private: - // The textual content of the code this object is testing. - const char* const statement_; - // The regular expression which test output must match. - const RE* const regex_; - // True if the death test successfully forked. - bool forked_; // PID of child process during death test; 0 in the child process itself. pid_t child_pid_; // File descriptors for communicating the death test's status byte. int read_fd_; // Always -1 in the child process. int write_fd_; // Always -1 in the parent process. - // The exit status of the child process. - int status_; - // How the death test concluded. - DeathTestOutcome outcome_; }; // Constructs a ForkingDeathTest. ForkingDeathTest::ForkingDeathTest(const char* statement, const RE* regex) - : DeathTest(), - statement_(statement), - regex_(regex), - forked_(false), + : DeathTestImpl(statement, regex), child_pid_(-1), read_fd_(-1), - write_fd_(-1), - status_(-1), - outcome_(IN_PROGRESS) { + write_fd_(-1) { } +#endif // GTEST_OS_WINDOWS + +// This is called from a death test parent process to read a failure +// message from the death test child process and log it with the FATAL +// severity. On Windows, the message is read from a pipe handle. On other +// platforms, it is read from a file descriptor. +// TODO(vladl@google.com): Re-factor the code to merge common parts after +// the reading code is abstracted. +#if GTEST_OS_WINDOWS +static void FailFromInternalError(HANDLE handle) { + Message error; + char buffer[256]; -// Reads an internal failure message from a file descriptor, then calls -// LOG(FATAL) with that message. Called from a death test parent process -// to read a failure message from the death test child process. + bool read_succeeded = true; + DWORD bytes_read; + do { + // ERROR_BROKEN_PIPE arises when the other end of the pipe has been + // closed. This is a normal condition for us. + bytes_read = 0; + read_succeeded = ::ReadFile(handle, + buffer, + sizeof(buffer) - 1, + &bytes_read, + NULL) || ::GetLastError() == ERROR_BROKEN_PIPE; + buffer[bytes_read] = 0; + error << buffer; + } while (read_succeeded && bytes_read > 0); + + if (read_succeeded) { + GTEST_LOG_(FATAL, error); + } else { + const DWORD last_error = ::GetLastError(); + const String message = GetLastSystemErrorMessage(); + GTEST_LOG_(FATAL, + Message() << "Error while reading death test internal: " + << message << " [" << last_error << "]"); + } +} +#else static void FailFromInternalError(int fd) { Message error; char buffer[256]; @@ -312,21 +708,24 @@ static void FailFromInternalError(int fd) { } } while (num_read == -1 && errno == EINTR); - // TODO(smcafee): Maybe just FAIL the test instead? if (num_read == 0) { GTEST_LOG_(FATAL, error); } else { + const int last_error = errno; + const String message = GetLastSystemErrorMessage(); GTEST_LOG_(FATAL, Message() << "Error while reading death test internal: " - << strerror(errno) << " [" << errno << "]"); + << message << " [" << last_error << "]"); } } +#endif // GTEST_OS_WINDOWS +#if !GTEST_OS_WINDOWS // Waits for the child in a death test to exit, returning its exit // status, or 0 if no child process exists. As a side effect, sets the // outcome data member. int ForkingDeathTest::Wait() { - if (!forked_) + if (!spawned()) return 0; // The read() here blocks until data is available (signifying the @@ -341,14 +740,14 @@ int ForkingDeathTest::Wait() { } while (bytes_read == -1 && errno == EINTR); if (bytes_read == 0) { - outcome_ = DIED; + set_outcome(DIED); } else if (bytes_read == 1) { switch (flag) { case kDeathTestReturned: - outcome_ = RETURNED; + set_outcome(RETURNED); break; case kDeathTestLived: - outcome_ = LIVED; + set_outcome(LIVED); break; case kDeathTestInternalError: FailFromInternalError(read_fd_); // Does not return. @@ -360,28 +759,34 @@ int ForkingDeathTest::Wait() { << ")"); } } else { + const String error_message = GetLastSystemErrorMessage(); GTEST_LOG_(FATAL, Message() << "Read from death test child process failed: " - << strerror(errno)); + << error_message); } GTEST_DEATH_TEST_CHECK_SYSCALL_(close(read_fd_)); - GTEST_DEATH_TEST_CHECK_SYSCALL_(waitpid(child_pid_, &status_, 0)); - return status_; + int status; + GTEST_DEATH_TEST_CHECK_SYSCALL_(waitpid(child_pid_, &status, 0)); + set_status(status); + return status; } +#endif // !GTEST_OS_WINDOWS // Assesses the success or failure of a death test, using both private // members which have previously been set, and one argument: // // Private data members: -// outcome: an enumeration describing how the death test +// outcome: An enumeration describing how the death test // concluded: DIED, LIVED, or RETURNED. The death test fails -// in the latter two cases -// status: the exit status of the child process, in the format -// specified by wait(2) -// regex: a regular expression object to be applied to +// in the latter two cases. +// status: The exit status of the child process. On *nix, it is in the +// in the format specified by wait(2). On Windows, this is the +// value supplied to the ExitProcess() API or a numeric code +// of the exception that terminated the program. +// regex: A regular expression object to be applied to // the test's captured standard error output; the death test -// fails if it does not match +// fails if it does not match. // // Argument: // status_ok: true if exit_status is acceptable in the context of @@ -389,9 +794,9 @@ int ForkingDeathTest::Wait() { // // Returns true iff all of the above conditions are met. Otherwise, the // first failing condition, in the order given above, is the one that is -// reported. Also sets the static variable last_death_test_message. -bool ForkingDeathTest::Passed(bool status_ok) { - if (!forked_) +// reported. Also sets the last death test message string. +bool DeathTestImpl::Passed(bool status_ok) { + if (!spawned()) return false; #if GTEST_HAS_GLOBAL_STRING @@ -403,8 +808,8 @@ bool ForkingDeathTest::Passed(bool status_ok) { bool success = false; Message buffer; - buffer << "Death test: " << statement_ << "\n"; - switch (outcome_) { + buffer << "Death test: " << statement() << "\n"; + switch (outcome()) { case LIVED: buffer << " Result: failed to die.\n" << " Error msg: " << error_message; @@ -415,16 +820,16 @@ bool ForkingDeathTest::Passed(bool status_ok) { break; case DIED: if (status_ok) { - if (RE::PartialMatch(error_message, *regex_)) { + if (RE::PartialMatch(error_message, *regex())) { success = true; } else { buffer << " Result: died but not with expected error.\n" - << " Expected: " << regex_->pattern() << "\n" + << " Expected: " << regex()->pattern() << "\n" << "Actual msg: " << error_message; } } else { buffer << " Result: died but not with expected exit code:\n" - << " " << ExitSummary(status_) << "\n"; + << " " << ExitSummary(status()) << "\n"; } break; case IN_PROGRESS: @@ -433,13 +838,14 @@ bool ForkingDeathTest::Passed(bool status_ok) { "DeathTest::Passed somehow called before conclusion of test"); } - last_death_test_message = buffer.GetString(); + DeathTest::set_last_death_test_message(buffer.GetString()); return success; } +#if !GTEST_OS_WINDOWS // Signals that the death test code which should have exited, didn't. // Should be called only in a death test child process. -// Writes a status byte to the child's status file desriptor, then +// Writes a status byte to the child's status file descriptor, then // calls _exit(1). void ForkingDeathTest::Abort(AbortReason reason) { // The parent process considers the death test to be a failure if @@ -472,7 +878,7 @@ DeathTest::TestRole NoExecDeathTest::AssumeRole() { int pipe_fd[2]; GTEST_DEATH_TEST_CHECK_(pipe(pipe_fd) != -1); - last_death_test_message = ""; + DeathTest::set_last_death_test_message(""); CaptureStderr(); // When we fork the process below, the log file buffers are copied, but the // file descriptors are shared. We flush all log files here so that closing @@ -497,7 +903,7 @@ DeathTest::TestRole NoExecDeathTest::AssumeRole() { } else { GTEST_DEATH_TEST_CHECK_SYSCALL_(close(pipe_fd[1])); set_read_fd(pipe_fd[0]); - set_forked(true); + set_spawned(true); return OVERSEE_TEST; } } @@ -524,9 +930,9 @@ class Arguments { Arguments() { args_.push_back(NULL); } + ~Arguments() { - for (std::vector::iterator i = args_.begin(); - i + 1 != args_.end(); + for (std::vector::iterator i = args_.begin(); i != args_.end(); ++i) { free(*i); } @@ -571,8 +977,9 @@ static int ExecDeathTestChildMain(void* child_arg) { UnitTest::GetInstance()->original_working_dir(); // We can safely call chdir() as it's a direct system call. if (chdir(original_dir) != 0) { - DeathTestAbort("chdir(\"%s\") failed: %s", - original_dir, strerror(errno)); + DeathTestAbort(String::Format("chdir(\"%s\") failed: %s", + original_dir, + GetLastSystemErrorMessage().c_str())); return EXIT_FAILURE; } @@ -582,8 +989,10 @@ static int ExecDeathTestChildMain(void* child_arg) { // invoke the test program via a valid path that contains at least // one path separator. execve(args->argv[0], args->argv, environ); - DeathTestAbort("execve(%s, ...) in %s failed: %s", - args->argv[0], original_dir, strerror(errno)); + DeathTestAbort(String::Format("execve(%s, ...) in %s failed: %s", + args->argv[0], + original_dir, + GetLastSystemErrorMessage().c_str())); return EXIT_FAILURE; } @@ -643,7 +1052,7 @@ DeathTest::TestRole ExecDeathTest::AssumeRole() { const int death_test_index = info->result()->death_test_count(); if (flag != NULL) { - set_write_fd(flag->status_fd); + set_write_fd(flag->status_fd()); return EXECUTE_TEST; } @@ -658,16 +1067,15 @@ DeathTest::TestRole ExecDeathTest::AssumeRole() { GTEST_FLAG_PREFIX_, kFilterFlag, info->test_case_name(), info->name()); const String internal_flag = - String::Format("--%s%s=%s:%d:%d:%d", - GTEST_FLAG_PREFIX_, kInternalRunDeathTestFlag, file_, line_, - death_test_index, pipe_fd[1]); + String::Format("--%s%s=%s|%d|%d|%d", + GTEST_FLAG_PREFIX_, kInternalRunDeathTestFlag, + file_, line_, death_test_index, pipe_fd[1]); Arguments args; args.AddArguments(GetArgvs()); - args.AddArgument("--logtostderr"); args.AddArgument(filter_flag.c_str()); args.AddArgument(internal_flag.c_str()); - last_death_test_message = ""; + DeathTest::set_last_death_test_message(""); CaptureStderr(); // See the comment in NoExecDeathTest::AssumeRole for why the next line @@ -678,10 +1086,12 @@ DeathTest::TestRole ExecDeathTest::AssumeRole() { GTEST_DEATH_TEST_CHECK_SYSCALL_(close(pipe_fd[1])); set_child_pid(child_pid); set_read_fd(pipe_fd[0]); - set_forked(true); + set_spawned(true); return OVERSEE_TEST; } +#endif // !GTEST_OS_WINDOWS + // Creates a concrete DeathTest-derived class that depends on the // --gtest_death_test_style flag, and sets the pointer pointed to // by the "test" argument to its address. If the test should be @@ -697,28 +1107,36 @@ bool DefaultDeathTestFactory::Create(const char* statement, const RE* regex, ->increment_death_test_count(); if (flag != NULL) { - if (death_test_index > flag->index) { - last_death_test_message = String::Format( + if (death_test_index > flag->index()) { + DeathTest::set_last_death_test_message(String::Format( "Death test count (%d) somehow exceeded expected maximum (%d)", - death_test_index, flag->index); + death_test_index, flag->index())); return false; } - if (!(flag->file == file && flag->line == line && - flag->index == death_test_index)) { + if (!(flag->file() == file && flag->line() == line && + flag->index() == death_test_index)) { *test = NULL; return true; } } +#if GTEST_OS_WINDOWS + if (GTEST_FLAG(death_test_style) == "threadsafe" || + GTEST_FLAG(death_test_style) == "fast") { + *test = new WindowsDeathTest(statement, regex, file, line); + } +#else if (GTEST_FLAG(death_test_style) == "threadsafe") { *test = new ExecDeathTest(statement, regex, file, line); } else if (GTEST_FLAG(death_test_style) == "fast") { *test = new NoExecDeathTest(statement, regex); - } else { - last_death_test_message = String::Format( + } +#endif // GTEST_OS_WINDOWS + else { // NOLINT - this is more readable than unbalanced brackets inside #if. + DeathTest::set_last_death_test_message(String::Format( "Unknown death test style \"%s\" encountered", - GTEST_FLAG(death_test_style).c_str()); + GTEST_FLAG(death_test_style).c_str())); return false; } @@ -728,6 +1146,8 @@ bool DefaultDeathTestFactory::Create(const char* statement, const RE* regex, // Splits a given string on a given delimiter, populating a given // vector with the fields. GTEST_HAS_DEATH_TEST implies that we have // ::std::string, so we can use it here. +// TODO(vladl@google.com): Get rid of std::vector to be able to build on +// Visual C++ 7.1 with exceptions disabled. static void SplitString(const ::std::string& str, char delimiter, ::std::vector< ::std::string>* dest) { ::std::vector< ::std::string> parsed; @@ -745,25 +1165,72 @@ static void SplitString(const ::std::string& str, char delimiter, dest->swap(parsed); } -// Attempts to parse a string into a positive integer. Returns true -// if that is possible. GTEST_HAS_DEATH_TEST implies that we have -// ::std::string, so we can use it here. -static bool ParsePositiveInt(const ::std::string& str, int* number) { - // Fail fast if the given string does not begin with a digit; - // this bypasses strtol's "optional leading whitespace and plus - // or minus sign" semantics, which are undesirable here. - if (str.empty() || !isdigit(str[0])) { - return false; +#if GTEST_OS_WINDOWS +// Recreates the pipe and event handles from the provided parameters, +// signals the event, and returns a file descriptor wrapped around the pipe +// handle. This function is called in the child process only. +int GetStatusFileDescriptor(unsigned int parent_process_id, + size_t status_handle_as_size_t, + size_t event_handle_as_size_t) { + AutoHandle parent_process_handle(::OpenProcess(PROCESS_DUP_HANDLE, + FALSE, // Non-inheritable. + parent_process_id)); + if (parent_process_handle.Get() == INVALID_HANDLE_VALUE) { + DeathTestAbort(String::Format("Unable to open parent process %u", + parent_process_id)); } - char* endptr; - const long parsed = strtol(str.c_str(), &endptr, 10); // NOLINT - if (*endptr == '\0' && parsed <= INT_MAX) { - *number = static_cast(parsed); - return true; - } else { - return false; + + // TODO(vladl@google.com): Replace the following check with a + // compile-time assertion when available. + GTEST_CHECK_(sizeof(HANDLE) <= sizeof(size_t)); + + const HANDLE status_handle = + reinterpret_cast(status_handle_as_size_t); + HANDLE dup_status_handle; + + // The newly initialized handle is accessible only in in the parent + // process. To obtain one accessible within the child, we need to use + // DuplicateHandle. + if (!::DuplicateHandle(parent_process_handle.Get(), status_handle, + ::GetCurrentProcess(), &dup_status_handle, + 0x0, // Requested privileges ignored since + // DUPLICATE_SAME_ACCESS is used. + FALSE, // Request non-inheritable handler. + DUPLICATE_SAME_ACCESS)) { + DeathTestAbort(String::Format( + "Unable to duplicate the pipe handle %Iu from the parent process %u", + status_handle_as_size_t, parent_process_id)); } + + const HANDLE event_handle = reinterpret_cast(event_handle_as_size_t); + HANDLE dup_event_handle; + + if (!::DuplicateHandle(parent_process_handle.Get(), event_handle, + ::GetCurrentProcess(), &dup_event_handle, + 0x0, + FALSE, + DUPLICATE_SAME_ACCESS)) { + DeathTestAbort(String::Format( + "Unable to duplicate the event handle %Iu from the parent process %u", + event_handle_as_size_t, parent_process_id)); + } + + const int status_fd = + ::_open_osfhandle(reinterpret_cast(dup_status_handle), + O_APPEND | O_TEXT); + if (status_fd == -1) { + DeathTestAbort(String::Format( + "Unable to convert pipe handle %Iu to a file descriptor", + status_handle_as_size_t)); + } + + // Signals the parent that the write end of the pipe has been acquired + // so the parent can release its own write end. + ::SetEvent(dup_event_handle); + + return status_fd; } +#endif // GTEST_OS_WINDOWS // Returns a newly created InternalRunDeathTestFlag object with fields // initialized from the GTEST_FLAG(internal_run_death_test) flag if @@ -771,22 +1238,43 @@ static bool ParsePositiveInt(const ::std::string& str, int* number) { InternalRunDeathTestFlag* ParseInternalRunDeathTestFlag() { if (GTEST_FLAG(internal_run_death_test) == "") return NULL; - InternalRunDeathTestFlag* const internal_run_death_test_flag = - new InternalRunDeathTestFlag; // GTEST_HAS_DEATH_TEST implies that we have ::std::string, so we // can use it here. + int line = -1; + int index = -1; ::std::vector< ::std::string> fields; - SplitString(GTEST_FLAG(internal_run_death_test).c_str(), ':', &fields); + SplitString(GTEST_FLAG(internal_run_death_test).c_str(), '|', &fields); + int status_fd = -1; + +#if GTEST_OS_WINDOWS + unsigned int parent_process_id = 0; + size_t status_handle_as_size_t = 0; + size_t event_handle_as_size_t = 0; + + if (fields.size() != 6 + || !ParseNaturalNumber(fields[1], &line) + || !ParseNaturalNumber(fields[2], &index) + || !ParseNaturalNumber(fields[3], &parent_process_id) + || !ParseNaturalNumber(fields[4], &status_handle_as_size_t) + || !ParseNaturalNumber(fields[5], &event_handle_as_size_t)) { + DeathTestAbort(String::Format( + "Bad --gtest_internal_run_death_test flag: %s", + GTEST_FLAG(internal_run_death_test).c_str())); + } + status_fd = GetStatusFileDescriptor(parent_process_id, + status_handle_as_size_t, + event_handle_as_size_t); +#else if (fields.size() != 4 - || !ParsePositiveInt(fields[1], &internal_run_death_test_flag->line) - || !ParsePositiveInt(fields[2], &internal_run_death_test_flag->index) - || !ParsePositiveInt(fields[3], - &internal_run_death_test_flag->status_fd)) { - DeathTestAbort("Bad --gtest_internal_run_death_test flag: %s", - GTEST_FLAG(internal_run_death_test).c_str()); - } - internal_run_death_test_flag->file = fields[0].c_str(); - return internal_run_death_test_flag; + || !ParseNaturalNumber(fields[1], &line) + || !ParseNaturalNumber(fields[2], &index) + || !ParseNaturalNumber(fields[3], &status_fd)) { + DeathTestAbort(String::Format( + "Bad --gtest_internal_run_death_test flag: %s", + GTEST_FLAG(internal_run_death_test).c_str())); + } +#endif // GTEST_OS_WINDOWS + return new InternalRunDeathTestFlag(fields[0], line, index, status_fd); } } // namespace internal diff --git a/src/gtest-filepath.cc b/src/gtest-filepath.cc index e5908012..32fd3bcb 100644 --- a/src/gtest-filepath.cc +++ b/src/gtest-filepath.cc @@ -48,6 +48,7 @@ #include #include // NOLINT #include // NOLINT +#include // Some Linux distributions define PATH_MAX here. #endif // _WIN32_WCE or _WIN32 #if GTEST_OS_WINDOWS diff --git a/src/gtest-internal-inl.h b/src/gtest-internal-inl.h index b1a5dbb1..eadcf95e 100644 --- a/src/gtest-internal-inl.h +++ b/src/gtest-internal-inl.h @@ -45,17 +45,20 @@ #error "It must not be included except by Google Test itself." #endif // GTEST_IMPLEMENTATION_ +#include #include - -#include +#include // For strtoll/_strtoul64. #if GTEST_OS_WINDOWS -#include // NOLINT +#include // For DWORD. #endif // GTEST_OS_WINDOWS +#include #include #include +#include + namespace testing { // Declares the flags. @@ -1313,6 +1316,77 @@ bool MatchRegexAnywhere(const char* regex, const char* str); void ParseGoogleTestFlagsOnly(int* argc, char** argv); void ParseGoogleTestFlagsOnly(int* argc, wchar_t** argv); +#if GTEST_HAS_DEATH_TEST + +// Returns the message describing the last system error, regardless of the +// platform. +String GetLastSystemErrorMessage(); + +#if GTEST_OS_WINDOWS +// Provides leak-safe Windows kernel handle ownership. +class AutoHandle { + public: + AutoHandle() : handle_(INVALID_HANDLE_VALUE) {} + explicit AutoHandle(HANDLE handle) : handle_(handle) {} + + ~AutoHandle() { Reset(); } + + HANDLE Get() const { return handle_; } + void Reset() { Reset(INVALID_HANDLE_VALUE); } + void Reset(HANDLE handle) { + if (handle != handle_) { + if (handle_ != INVALID_HANDLE_VALUE) + ::CloseHandle(handle_); + handle_ = handle; + } + } + + private: + HANDLE handle_; + + GTEST_DISALLOW_COPY_AND_ASSIGN_(AutoHandle); +}; +#endif // GTEST_OS_WINDOWS + +// Attempts to parse a string into a positive integer pointed to by the +// number parameter. Returns true if that is possible. +// GTEST_HAS_DEATH_TEST implies that we have ::std::string, so we can use +// it here. +template +bool ParseNaturalNumber(const ::std::string& str, Integer* number) { + // Fail fast if the given string does not begin with a digit; + // this bypasses strtoXXX's "optional leading whitespace and plus + // or minus sign" semantics, which are undesirable here. + if (str.empty() || !isdigit(str[0])) { + return false; + } + errno = 0; + + char* end; + // BiggestConvertible is the largest integer type that system-provided + // string-to-number conversion routines can return. +#if GTEST_OS_WINDOWS + typedef unsigned __int64 BiggestConvertible; + const BiggestConvertible parsed = _strtoui64(str.c_str(), &end, 10); +#else + typedef unsigned long long BiggestConvertible; // NOLINT + const BiggestConvertible parsed = strtoull(str.c_str(), &end, 10); +#endif // GTEST_OS_WINDOWS + const bool parse_success = *end == '\0' && errno == 0; + + // TODO(vladl@google.com): Convert this to compile time assertion when it is + // available. + GTEST_CHECK_(sizeof(Integer) <= sizeof(parsed)); + + const Integer result = static_cast(parsed); + if (parse_success && static_cast(result) == parsed) { + *number = result; + return true; + } + return false; +} +#endif // GTEST_HAS_DEATH_TEST + } // namespace internal } // namespace testing diff --git a/src/gtest-port.cc b/src/gtest-port.cc index 59a22308..aacb5e72 100644 --- a/src/gtest-port.cc +++ b/src/gtest-port.cc @@ -35,9 +35,9 @@ #include #include -#if GTEST_HAS_DEATH_TEST -#include -#endif // GTEST_HAS_DEATH_TEST +#if !GTEST_OS_WINDOWS +#include +#endif // GTEST_OS_WINDOWS #if GTEST_USES_SIMPLE_RE #include @@ -63,6 +63,13 @@ namespace testing { namespace internal { +#if GTEST_OS_WINDOWS +// Microsoft does not provide a definition of STDERR_FILENO. +const int kStdErrFileno = 2; +#else +const int kStdErrFileno = STDERR_FILENO; +#endif // GTEST_OS_WINDOWS + #if GTEST_USES_POSIX_RE // Implements RE. Currently only needed for death tests. @@ -105,7 +112,13 @@ void RE::Init(const char* regex) { // previous expression returns false. Otherwise partial_regex_ may // not be properly initialized can may cause trouble when it's // freed. - is_valid_ = (regcomp(&partial_regex_, regex, REG_EXTENDED) == 0) && is_valid_; + // + // Some implementation of POSIX regex (e.g. on at least some + // versions of Cygwin) doesn't accept the empty string as a valid + // regex. We change it to an equivalent form "()" to be safe. + const char* const partial_regex = (*regex == '\0') ? "()" : regex; + is_valid_ = (regcomp(&partial_regex_, partial_regex, REG_EXTENDED) == 0) + && is_valid_; EXPECT_TRUE(is_valid_) << "Regular expression \"" << regex << "\" is not a valid POSIX Extended regular expression."; @@ -379,11 +392,19 @@ void GTestLog(GTestLogSeverity severity, const char* file, severity == GTEST_ERROR ? "[ ERROR ]" : "[ FATAL ]"; fprintf(stderr, "\n%s %s:%d: %s\n", marker, file, line, msg); if (severity == GTEST_FATAL) { + fflush(NULL); // abort() is not guaranteed to flush open file streams. abort(); } } -#if GTEST_HAS_DEATH_TEST +#if GTEST_HAS_STD_STRING + +// Disable Microsoft deprecation warnings for POSIX functions called from +// this class (creat, dup, dup2, and close) +#ifdef _MSC_VER +#pragma warning(push) +#pragma warning(disable: 4996) +#endif // _MSC_VER // Defines the stderr capturer. @@ -391,16 +412,26 @@ class CapturedStderr { public: // The ctor redirects stderr to a temporary file. CapturedStderr() { - uncaptured_fd_ = dup(STDERR_FILENO); + uncaptured_fd_ = dup(kStdErrFileno); + +#if GTEST_OS_WINDOWS + char temp_dir_path[MAX_PATH + 1] = { '\0' }; // NOLINT + char temp_file_path[MAX_PATH + 1] = { '\0' }; // NOLINT + ::GetTempPathA(sizeof(temp_dir_path), temp_dir_path); + ::GetTempFileNameA(temp_dir_path, "gtest_redir", 0, temp_file_path); + const int captured_fd = creat(temp_file_path, _S_IREAD | _S_IWRITE); + filename_ = temp_file_path; +#else // There's no guarantee that a test has write access to the // current directory, so we create the temporary file in the /tmp // directory instead. char name_template[] = "/tmp/captured_stderr.XXXXXX"; const int captured_fd = mkstemp(name_template); filename_ = name_template; +#endif // GTEST_OS_WINDOWS fflush(NULL); - dup2(captured_fd, STDERR_FILENO); + dup2(captured_fd, kStdErrFileno); close(captured_fd); } @@ -412,7 +443,7 @@ class CapturedStderr { void StopCapture() { // Restores the original stream. fflush(NULL); - dup2(uncaptured_fd_, STDERR_FILENO); + dup2(uncaptured_fd_, kStdErrFileno); close(uncaptured_fd_); uncaptured_fd_ = -1; } @@ -427,6 +458,10 @@ class CapturedStderr { ::std::string filename_; }; +#ifdef _MSC_VER +#pragma warning(pop) +#endif // _MSC_VER + static CapturedStderr* g_captured_stderr = NULL; // Returns the size (in bytes) of a file. @@ -436,8 +471,6 @@ static size_t GetFileSize(FILE * file) { } // Reads the entire content of a file as a string. -// GTEST_HAS_DEATH_TEST implies that we have ::std::string, so we can -// use it here. static ::std::string ReadEntireFile(FILE * file) { const size_t file_size = GetFileSize(file); char* const buffer = new char[file_size]; @@ -473,9 +506,18 @@ void CaptureStderr() { // use it here. ::std::string GetCapturedStderr() { g_captured_stderr->StopCapture(); + +// Disables Microsoft deprecation warning for fopen and fclose. +#ifdef _MSC_VER +#pragma warning(push) +#pragma warning(disable: 4996) +#endif // _MSC_VER FILE* const file = fopen(g_captured_stderr->filename().c_str(), "r"); const ::std::string content = ReadEntireFile(file); fclose(file); +#ifdef _MSC_VER +#pragma warning(pop) +#endif // _MSC_VER delete g_captured_stderr; g_captured_stderr = NULL; @@ -483,6 +525,10 @@ void CaptureStderr() { return content; } +#endif // GTEST_HAS_STD_STRING + +#if GTEST_HAS_DEATH_TEST + // A copy of all command line arguments. Set by InitGoogleTest(). ::std::vector g_argvs; diff --git a/src/gtest.cc b/src/gtest.cc index e4f9d0f3..f86a2a35 100644 --- a/src/gtest.cc +++ b/src/gtest.cc @@ -3300,17 +3300,43 @@ void UnitTest::RecordPropertyForCurrentTest(const char* key, int UnitTest::Run() { #if GTEST_OS_WINDOWS + const bool in_death_test_child_process = + internal::GTEST_FLAG(internal_run_death_test).GetLength() > 0; + + // Either the user wants Google Test to catch exceptions thrown by the + // tests or this is executing in the context of death test child + // process. In either case the user does not want to see pop-up dialogs + // about crashes - they are expected.. + if (GTEST_FLAG(catch_exceptions) || in_death_test_child_process) { #if !defined(_WIN32_WCE) - // SetErrorMode doesn't exist on CE. - if (GTEST_FLAG(catch_exceptions)) { - // The user wants Google Test to catch exceptions thrown by the tests. - - // This lets fatal errors be handled by us, instead of causing pop-ups. + // SetErrorMode doesn't exist on CE. SetErrorMode(SEM_FAILCRITICALERRORS | SEM_NOALIGNMENTFAULTEXCEPT | SEM_NOGPFAULTERRORBOX | SEM_NOOPENFILEERRORBOX); - } #endif // _WIN32_WCE + // Death test children can be terminated with _abort(). On Windows, + // _abort() can show a dialog with a warning message. This forces the + // abort message to go to stderr instead. + _set_error_mode(_OUT_TO_STDERR); + + // In the debug version, Visual Studio pops up a separate dialog + // offering a choice to debug the aborted program. We need to suppress + // this dialog or it will pop up for every EXPECT/ASSERT_DEATH statement + // executed. Google Test will notify the user of any unexpected + // failure via stderr. +#if _MSC_VER >= 1400 + // VC++ doesn't define _set_abort_behavior() prior to the version 8.0. + // Users of prior VC versions shall suffer the agony and pain of + // clicking through the countless debug dialogs. + // TODO(vladl@google.com): find a way to suppress the abort dialog() in the + // debug mode when compiled with VC 7.1 or lower. + if (!GTEST_FLAG(break_on_failure)) + _set_abort_behavior( + 0x0, // Clear the following flags: + _WRITE_ABORT_MSG | _CALL_REPORTFAULT); // pop-up window, core dump. +#endif // _MSC_VER >= 1400 + } + __try { return impl_->RunAllTests(); } __except(internal::UnitTestOptions::GTestShouldProcessSEH( -- cgit v1.2.3 From 40e72a8a837b47cbfe2e695068c1845073ab2630 Mon Sep 17 00:00:00 2001 From: "zhanyong.wan" Date: Fri, 6 Mar 2009 20:05:23 +0000 Subject: Implements --gtest_throw_on_failure for using gtest with other testing frameworks. --- src/gtest-internal-inl.h | 4 +++ src/gtest.cc | 67 +++++++++++++++++++++++++++++++++++++++--------- 2 files changed, 59 insertions(+), 12 deletions(-) (limited to 'src') diff --git a/src/gtest-internal-inl.h b/src/gtest-internal-inl.h index eadcf95e..de5124d7 100644 --- a/src/gtest-internal-inl.h +++ b/src/gtest-internal-inl.h @@ -84,6 +84,7 @@ const char kListTestsFlag[] = "list_tests"; const char kOutputFlag[] = "output"; const char kPrintTimeFlag[] = "print_time"; const char kRepeatFlag[] = "repeat"; +const char kThrowOnFailureFlag[] = "throw_on_failure"; // This class saves the values of all Google Test flags in its c'tor, and // restores them in its d'tor. @@ -103,6 +104,7 @@ class GTestFlagSaver { output_ = GTEST_FLAG(output); print_time_ = GTEST_FLAG(print_time); repeat_ = GTEST_FLAG(repeat); + throw_on_failure_ = GTEST_FLAG(throw_on_failure); } // The d'tor is not virtual. DO NOT INHERIT FROM THIS CLASS. @@ -119,6 +121,7 @@ class GTestFlagSaver { GTEST_FLAG(output) = output_; GTEST_FLAG(print_time) = print_time_; GTEST_FLAG(repeat) = repeat_; + GTEST_FLAG(throw_on_failure) = throw_on_failure_; } private: // Fields for saving the original values of flags. @@ -135,6 +138,7 @@ class GTestFlagSaver { bool print_time_; bool pretty_; internal::Int32 repeat_; + bool throw_on_failure_; } GTEST_ATTRIBUTE_UNUSED_; // Converts a Unicode code point to a narrow string in UTF-8 encoding. diff --git a/src/gtest.cc b/src/gtest.cc index f86a2a35..61a34845 100644 --- a/src/gtest.cc +++ b/src/gtest.cc @@ -111,6 +111,10 @@ #endif // GTEST_OS_LINUX +#if GTEST_HAS_EXCEPTIONS +#include +#endif + // 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 @@ -231,6 +235,13 @@ GTEST_DEFINE_bool_( "True iff " GTEST_NAME_ " should include internal stack frames when " "printing test failure stack traces."); +GTEST_DEFINE_bool_( + throw_on_failure, + internal::BoolFromGTestEnv("throw_on_failure", false), + "When this flag is specified, a failed assertion will throw an exception " + "if exceptions are enabled or exit the program with a non-zero code " + "otherwise."); + namespace internal { // GTestIsInitialized() returns true iff the user has initialized @@ -2438,14 +2449,20 @@ static const char * TestPartResultTypeToString(TestPartResultType type) { return "Unknown result type"; } +// Prints a TestPartResult to a String. +static internal::String PrintTestPartResultToString( + const TestPartResult& test_part_result) { + return (Message() + << internal::FormatFileLocation(test_part_result.file_name(), + test_part_result.line_number()) + << " " << TestPartResultTypeToString(test_part_result.type()) + << test_part_result.message()).GetString(); +} + // Prints a TestPartResult. static void PrintTestPartResult( - const TestPartResult & test_part_result) { - printf("%s %s%s\n", - internal::FormatFileLocation(test_part_result.file_name(), - test_part_result.line_number()).c_str(), - TestPartResultTypeToString(test_part_result.type()), - test_part_result.message()); + const TestPartResult& test_part_result) { + printf("%s\n", PrintTestPartResultToString(test_part_result).c_str()); fflush(stdout); } @@ -3240,6 +3257,19 @@ Environment* UnitTest::AddEnvironment(Environment* env) { return env; } +#if GTEST_HAS_EXCEPTIONS +// A failed Google Test assertion will throw an exception of this type +// when exceptions are enabled. We derive it from std::runtime_error, +// which is for errors presumably detectable only at run time. Since +// std::runtime_error inherits from std::exception, many testing +// frameworks know how to extract and print the message inside it. +class GoogleTestFailureException : public ::std::runtime_error { + public: + explicit GoogleTestFailureException(const TestPartResult& failure) + : runtime_error(PrintTestPartResultToString(failure).c_str()) {} +}; +#endif + // Adds a TestPartResult to the current TestResult object. All Google Test // assertion macros (e.g. ASSERT_TRUE, EXPECT_EQ, etc) eventually call // this to report their results. The user code should use the @@ -3276,11 +3306,23 @@ void UnitTest::AddTestPartResult(TestPartResultType result_type, impl_->GetTestPartResultReporterForCurrentThread()-> ReportTestPartResult(result); - // If this is a failure and the user wants the debugger to break on - // failures ... - if (result_type != TPRT_SUCCESS && GTEST_FLAG(break_on_failure)) { - // ... then we generate a seg fault. - *static_cast(NULL) = 1; + if (result_type != TPRT_SUCCESS) { + // gunit_break_on_failure takes precedence over + // gunit_throw_on_failure. This allows a user to set the latter + // in the code (perhaps in order to use Google Test assertions + // with another testing framework) and specify the former on the + // command line for debugging. + if (GTEST_FLAG(break_on_failure)) { + *static_cast(NULL) = 1; + } else if (GTEST_FLAG(throw_on_failure)) { +#if GTEST_HAS_EXCEPTIONS + throw GoogleTestFailureException(result); +#else + // We cannot call abort() as it generates a pop-up in debug mode + // that cannot be suppressed in VC 7.1 or below. + exit(1); +#endif + } } } @@ -4078,7 +4120,8 @@ void ParseGoogleTestFlagsOnlyImpl(int* argc, CharType** argv) { ParseBoolFlag(arg, kListTestsFlag, >EST_FLAG(list_tests)) || ParseStringFlag(arg, kOutputFlag, >EST_FLAG(output)) || ParseBoolFlag(arg, kPrintTimeFlag, >EST_FLAG(print_time)) || - ParseInt32Flag(arg, kRepeatFlag, >EST_FLAG(repeat)) + ParseInt32Flag(arg, kRepeatFlag, >EST_FLAG(repeat)) || + ParseBoolFlag(arg, kThrowOnFailureFlag, >EST_FLAG(throw_on_failure)) ) { // Yes. Shift the remainder of the argv list left by one. Note // that argv has (*argc + 1) elements, the last one always being -- cgit v1.2.3 From 44a041b711ff4a5b5f341f21127aed46dbfe38ad Mon Sep 17 00:00:00 2001 From: "zhanyong.wan" Date: Wed, 11 Mar 2009 18:31:26 +0000 Subject: Fixes death-test-related tests on Windows, by Vlad Losev. --- src/gtest-internal-inl.h | 7 ++++--- src/gtest-typed-test.cc | 1 + 2 files changed, 5 insertions(+), 3 deletions(-) (limited to 'src') diff --git a/src/gtest-internal-inl.h b/src/gtest-internal-inl.h index de5124d7..d079a3e1 100644 --- a/src/gtest-internal-inl.h +++ b/src/gtest-internal-inl.h @@ -49,16 +49,17 @@ #include #include // For strtoll/_strtoul64. +#include + +#include + #if GTEST_OS_WINDOWS #include // For DWORD. #endif // GTEST_OS_WINDOWS -#include #include #include -#include - namespace testing { // Declares the flags. diff --git a/src/gtest-typed-test.cc b/src/gtest-typed-test.cc index cb91f2b2..e45e2abb 100644 --- a/src/gtest-typed-test.cc +++ b/src/gtest-typed-test.cc @@ -85,6 +85,7 @@ const char* TypedTestCasePState::VerifyRegisteredTestNames( if (errors_str != "") { fprintf(stderr, "%s %s", FormatFileLocation(file, line).c_str(), errors_str.c_str()); + fflush(stderr); abort(); } -- cgit v1.2.3 From 3d8064999c838978bd271fcf78185f4e6f042f12 Mon Sep 17 00:00:00 2001 From: "zhanyong.wan" Date: Wed, 11 Mar 2009 20:25:25 +0000 Subject: Fixes build failure on Windows, by Rainer Klaffenboeck. --- src/gtest-port.cc | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) (limited to 'src') diff --git a/src/gtest-port.cc b/src/gtest-port.cc index aacb5e72..e41ab9f5 100644 --- a/src/gtest-port.cc +++ b/src/gtest-port.cc @@ -35,7 +35,10 @@ #include #include -#if !GTEST_OS_WINDOWS +#if GTEST_OS_WINDOWS +#include +#include +#else #include #endif // GTEST_OS_WINDOWS -- cgit v1.2.3 From 87d23e45f096c91c9e722b20bf15b733dbab0f80 Mon Sep 17 00:00:00 2001 From: "zhanyong.wan" Date: Wed, 11 Mar 2009 22:18:52 +0000 Subject: Implements the --help flag; fixes tests on Windows. --- src/gtest.cc | 145 +++++++++++++++++++++++++++++++++++++++++++++++++++++------ 1 file changed, 132 insertions(+), 13 deletions(-) (limited to 'src') diff --git a/src/gtest.cc b/src/gtest.cc index 61a34845..a66b78fd 100644 --- a/src/gtest.cc +++ b/src/gtest.cc @@ -244,6 +244,10 @@ GTEST_DEFINE_bool_( namespace internal { +// g_help_flag is true iff the --help flag or an equivalent form is +// specified on the command line. +static bool g_help_flag = false; + // GTestIsInitialized() returns true iff the user has initialized // Google Test. Useful for catching the user mistake of not initializing // Google Test before calling RUN_ALL_TESTS(). @@ -2471,6 +2475,7 @@ static void PrintTestPartResult( namespace internal { enum GTestColor { + COLOR_DEFAULT, COLOR_RED, COLOR_GREEN, COLOR_YELLOW @@ -2484,20 +2489,21 @@ WORD GetColorAttribute(GTestColor color) { case COLOR_RED: return FOREGROUND_RED; case COLOR_GREEN: return FOREGROUND_GREEN; case COLOR_YELLOW: return FOREGROUND_RED | FOREGROUND_GREEN; + default: return 0; } - return 0; } #else -// Returns the ANSI color code for the given color. +// Returns the ANSI color code for the given color. COLOR_DEFAULT is +// an invalid input. const char* GetAnsiColorCode(GTestColor color) { switch (color) { case COLOR_RED: return "1"; case COLOR_GREEN: return "2"; case COLOR_YELLOW: return "3"; + default: return NULL; }; - return NULL; } #endif // GTEST_OS_WINDOWS && !_WIN32_WCE @@ -2540,9 +2546,11 @@ void ColoredPrintf(GTestColor color, const char* fmt, ...) { va_start(args, fmt); #if defined(_WIN32_WCE) || GTEST_OS_SYMBIAN || GTEST_OS_ZOS - static const bool use_color = false; + const bool use_color = false; #else - static const bool use_color = ShouldUseColor(isatty(fileno(stdout)) != 0); + static const bool in_color_mode = + ShouldUseColor(isatty(fileno(stdout)) != 0); + const bool use_color = in_color_mode && (color != COLOR_DEFAULT); #endif // defined(_WIN32_WCE) || GTEST_OS_SYMBIAN || GTEST_OS_ZOS // The '!= 0' comparison is necessary to satisfy MSVC 7.1. @@ -2577,6 +2585,7 @@ void ColoredPrintf(GTestColor color, const char* fmt, ...) { } // namespace internal using internal::ColoredPrintf; +using internal::COLOR_DEFAULT; using internal::COLOR_RED; using internal::COLOR_GREEN; using internal::COLOR_YELLOW; @@ -3590,6 +3599,10 @@ int UnitTestImpl::RunAllTests() { return 1; } + // Do not run any test if the --help flag was specified. + if (g_help_flag) + return 0; + RegisterParameterizedTests(); // Even if sharding is not on, test runners may want to use the @@ -3789,9 +3802,9 @@ bool ShouldRunTestOnShard(int total_shards, int shard_index, int test_id) { // Returns the number of tests that should run. int UnitTestImpl::FilterTests(ReactionToSharding shard_tests) { const Int32 total_shards = shard_tests == HONOR_SHARDING_PROTOCOL ? - Int32FromEnvOrDie(kTestTotalShards, -1) : -1; + Int32FromEnvOrDie(kTestTotalShards, -1) : -1; const Int32 shard_index = shard_tests == HONOR_SHARDING_PROTOCOL ? - Int32FromEnvOrDie(kTestShardIndex, -1) : -1; + Int32FromEnvOrDie(kTestShardIndex, -1) : -1; // num_runnable_tests are the number of tests that will // run across all shards (i.e., match filter and are not disabled). @@ -3800,7 +3813,7 @@ int UnitTestImpl::FilterTests(ReactionToSharding shard_tests) { int num_runnable_tests = 0; int num_selected_tests = 0; for (const internal::ListNode *test_case_node = - test_cases_.Head(); + test_cases_.Head(); test_case_node != NULL; test_case_node = test_case_node->next()) { TestCase * const test_case = test_case_node->element(); @@ -3808,7 +3821,7 @@ int UnitTestImpl::FilterTests(ReactionToSharding shard_tests) { test_case->set_should_run(false); for (const internal::ListNode *test_info_node = - test_case->test_info_list().Head(); + test_case->test_info_list().Head(); test_info_node != NULL; test_info_node = test_info_node->next()) { TestInfo * const test_info = test_info_node->element(); @@ -3816,10 +3829,10 @@ int UnitTestImpl::FilterTests(ReactionToSharding shard_tests) { // A test is disabled if test case name or test name matches // kDisableTestFilter. const bool is_disabled = - internal::UnitTestOptions::MatchesFilter(test_case_name, - kDisableTestFilter) || - internal::UnitTestOptions::MatchesFilter(test_name, - kDisableTestFilter); + internal::UnitTestOptions::MatchesFilter(test_case_name, + kDisableTestFilter) || + internal::UnitTestOptions::MatchesFilter(test_name, + kDisableTestFilter); test_info->impl()->set_is_disabled(is_disabled); const bool is_runnable = @@ -4089,6 +4102,102 @@ bool ParseStringFlag(const char* str, const char* flag, String* value) { return true; } +// Prints a string containing code-encoded text. The following escape +// sequences can be used in the string to control the text color: +// +// @@ prints a single '@' character. +// @R changes the color to red. +// @G changes the color to green. +// @Y changes the color to yellow. +// @D changes to the default terminal text color. +// +// TODO(wan@google.com): Write tests for this once we add stdout +// capturing to Google Test. +static void PrintColorEncoded(const char* str) { + GTestColor color = COLOR_DEFAULT; // The current color. + + // Conceptually, we split the string into segments divided by escape + // sequences. Then we print one segment at a time. At the end of + // each iteration, the str pointer advances to the beginning of the + // next segment. + for (;;) { + const char* p = strchr(str, '@'); + if (p == NULL) { + ColoredPrintf(color, "%s", str); + return; + } + + ColoredPrintf(color, "%s", String(str, p - str).c_str()); + + const char ch = p[1]; + str = p + 2; + if (ch == '@') { + ColoredPrintf(color, "@"); + } else if (ch == 'D') { + color = COLOR_DEFAULT; + } else if (ch == 'R') { + color = COLOR_RED; + } else if (ch == 'G') { + color = COLOR_GREEN; + } else if (ch == 'Y') { + color = COLOR_YELLOW; + } else { + --str; + } + } +} + +static const char kColorEncodedHelpMessage[] = +"This program contains tests written using " GTEST_NAME_ ". You can use the\n" +"following command line flags to control its behavior:\n" +"\n" +"Test Selection:\n" +" @G--" GTEST_FLAG_PREFIX_ "list_tests@D\n" +" List the names of all tests instead of running them. The name of\n" +" TEST(Foo, Bar) is \"Foo.Bar\".\n" +" @G--" GTEST_FLAG_PREFIX_ "filter=@YPOSTIVE_PATTERNS" + "[@G-@YNEGATIVE_PATTERNS]@D\n" +" Run only the tests whose name matches one of the positive patterns but\n" +" none of the negative patterns. '?' matches any single character; '*'\n" +" matches any substring; ':' separates two patterns.\n" +" @G--" GTEST_FLAG_PREFIX_ "also_run_disabled_tests@D\n" +" Run all disabled tests too.\n" +" @G--" GTEST_FLAG_PREFIX_ "repeat=@Y[COUNT]@D\n" +" Run the tests repeatedly; use a negative count to repeat forever.\n" +"\n" +"Test Output:\n" +" @G--" GTEST_FLAG_PREFIX_ "color=@Y(@Gyes@Y|@Gno@Y|@Gauto@Y)@D\n" +" Enable/disable colored output. The default is @Gauto@D.\n" +" -@G-" GTEST_FLAG_PREFIX_ "print_time@D\n" +" Print the elapsed time of each test.\n" +" @G--" GTEST_FLAG_PREFIX_ "output=xml@Y[@G:@YDIRECTORY_PATH@G" + GTEST_PATH_SEP_ "@Y|@G:@YFILE_PATH]@D\n" +" Generate an XML report in the given directory or with the given file\n" +" name. @YFILE_PATH@D defaults to @Gtest_details.xml@D.\n" +"\n" +"Failure Behavior:\n" +" @G--" GTEST_FLAG_PREFIX_ "break_on_failure@D\n" +" Turn assertion failures into debugger break-points.\n" +" @G--" GTEST_FLAG_PREFIX_ "throw_on_failure@D\n" +" Turn assertion failures into C++ exceptions.\n" +#if GTEST_OS_WINDOWS +" @G--" GTEST_FLAG_PREFIX_ "catch_exceptions@D\n" +" Suppress pop-ups caused by exceptions.\n" +#endif // GTEST_OS_WINDOWS +"\n" +"Except for @G--" GTEST_FLAG_PREFIX_ "list_tests@D, you can alternatively set " + "the corresponding\n" +"environment variable of a flag (all letters in upper-case). For example, to\n" +"print the elapsed time, you can either specify @G--" GTEST_FLAG_PREFIX_ + "print_time@D or set the\n" +"@G" GTEST_FLAG_PREFIX_UPPER_ "PRINT_TIME@D environment variable to a " + "non-zero value.\n" +"\n" +"For more information, please read the " GTEST_NAME_ " documentation at\n" +"@G" GTEST_PROJECT_URL_ "@D. If you find a bug in " GTEST_NAME_ "\n" +"(not one in your own code or tests), please report it to\n" +"@G<" GTEST_DEV_EMAIL_ ">@D.\n"; + // Parses the command line for Google Test flags, without initializing // other parts of Google Test. The type parameter CharType can be // instantiated to either char or wchar_t. @@ -4137,8 +4246,18 @@ void ParseGoogleTestFlagsOnlyImpl(int* argc, CharType** argv) { // We also need to decrement the iterator as we just removed // an element. i--; + } else if (arg_string == "--help" || arg_string == "-h" || + arg_string == "-?" || arg_string == "/?") { + g_help_flag = true; } } + + if (g_help_flag) { + // We print the help here instead of in RUN_ALL_TESTS(), as the + // latter may not be called at all if the user is using Google + // Test with another testing framework. + PrintColorEncoded(kColorEncodedHelpMessage); + } } // Parses the command line for Google Test flags, without initializing -- cgit v1.2.3 From 62f8d28c0bd5cb057013fdf5b366db7b7981ec4c Mon Sep 17 00:00:00 2001 From: "zhanyong.wan" Date: Wed, 11 Mar 2009 23:35:32 +0000 Subject: Fixes a typo in Vlad's email address. --- src/gtest-death-test.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src') diff --git a/src/gtest-death-test.cc b/src/gtest-death-test.cc index 71b749b9..d9695864 100644 --- a/src/gtest-death-test.cc +++ b/src/gtest-death-test.cc @@ -27,7 +27,7 @@ // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. // -// Author: wan@google.com (Zhanyong Wan), vladl@losev.com (Vlad Losev) +// Author: wan@google.com (Zhanyong Wan), vladl@google.com (Vlad Losev) // // This file implements death tests. -- cgit v1.2.3 From 9623aed82cf3e0dcd2fb2fb7442a5a9507ac55a5 Mon Sep 17 00:00:00 2001 From: "zhanyong.wan" Date: Tue, 17 Mar 2009 21:03:35 +0000 Subject: Enables death tests on Cygwin and Mac (by Vlad Losev); fixes a python test on Mac. --- src/gtest-death-test.cc | 73 +++++++++++++++++++++++++++++++++++-------------- 1 file changed, 52 insertions(+), 21 deletions(-) (limited to 'src') diff --git a/src/gtest-death-test.cc b/src/gtest-death-test.cc index d9695864..7e7dd608 100644 --- a/src/gtest-death-test.cc +++ b/src/gtest-death-test.cc @@ -35,6 +35,11 @@ #include #if GTEST_HAS_DEATH_TEST + +#if GTEST_OS_MAC +#include +#endif // GTEST_OS_MAC + #include #include #include @@ -44,6 +49,7 @@ #include #else #include +#include #endif // GTEST_OS_WINDOWS #endif // GTEST_HAS_DEATH_TEST @@ -80,8 +86,9 @@ GTEST_DEFINE_bool_( death_test_use_fork, internal::BoolFromGTestEnv("death_test_use_fork", false), "Instructs to use fork()/_exit() instead of clone() in death tests. " - "Useful when running under valgrind or similar tools if those " - "do not support clone(). Valgrind 3.3.1 will just fail if " + "Ignored and always uses fork() on POSIX systems where clone() is not " + "implemented. Useful when running under valgrind or similar tools if " + "those do not support clone(). Valgrind 3.3.1 will just fail if " "it sees an unsupported combination of clone() flags. " "It is not recommended to use this flag w/o valgrind though it will " "work in 99% of the cases. Once valgrind is fixed, this flag will " @@ -963,6 +970,22 @@ struct ExecDeathTestArgs { int close_fd; // File descriptor to close; the read end of a pipe }; +#if GTEST_OS_MAC +inline char** GetEnviron() { + // When Google Test is built as a framework on MacOS X, the environ variable + // is unavailable. Apple's documentation (man environ) recommends using + // _NSGetEnviron() instead. + return *_NSGetEnviron(); +} +#else +extern "C" char** environ; // Some POSIX platforms expect you + // to declare environ. extern "C" makes + // it reside in the global namespace. +inline char** GetEnviron() { + return environ; +} +#endif // GTEST_OS_MAC + // The main function for a threadsafe-style death test child process. // This function is called in a clone()-ed process and thus must avoid // any potentially unsafe operations like malloc or libc functions. @@ -988,7 +1011,7 @@ static int ExecDeathTestChildMain(void* child_arg) { // unsafe. Since execve() doesn't search the PATH, the user must // invoke the test program via a valid path that contains at least // one path separator. - execve(args->argv[0], args->argv, environ); + execve(args->argv[0], args->argv, GetEnviron()); DeathTestAbort(String::Format("execve(%s, ...) in %s failed: %s", args->argv[0], original_dir, @@ -1001,12 +1024,12 @@ static int ExecDeathTestChildMain(void* child_arg) { // This could be accomplished more elegantly by a single recursive // function, but we want to guard against the unlikely possibility of // a smart compiler optimizing the recursion away. -static bool StackLowerThanAddress(const void* ptr) { +bool StackLowerThanAddress(const void* ptr) { int dummy; return &dummy < ptr; } -static bool StackGrowsDown() { +bool StackGrowsDown() { int dummy; return StackLowerThanAddress(&dummy); } @@ -1015,28 +1038,36 @@ static bool StackGrowsDown() { // that uses clone(2). It dies with an error message if anything goes // wrong. static pid_t ExecDeathTestFork(char* const* argv, int close_fd) { - static const bool stack_grows_down = StackGrowsDown(); - const size_t stack_size = getpagesize(); - void* const stack = mmap(NULL, stack_size, PROT_READ | PROT_WRITE, - MAP_ANONYMOUS | MAP_PRIVATE, -1, 0); - GTEST_DEATH_TEST_CHECK_(stack != MAP_FAILED); - void* const stack_top = - static_cast(stack) + (stack_grows_down ? stack_size : 0); ExecDeathTestArgs args = { argv, close_fd }; pid_t child_pid; - if (GTEST_FLAG(death_test_use_fork)) { - // Valgrind-friendly version. As of valgrind 3.3.1 the clone() call below - // is not supported (valgrind will fail with an error message). - if ((child_pid = fork()) == 0) { + +#if GTEST_HAS_CLONE + const bool use_fork = GTEST_FLAG(death_test_use_fork); + + if (!use_fork) { + static const bool stack_grows_down = StackGrowsDown(); + const size_t stack_size = getpagesize(); + // MMAP_ANONYMOUS is not defined on Mac, so we use MAP_ANON instead. + void* const stack = mmap(NULL, stack_size, PROT_READ | PROT_WRITE, + MAP_ANON | MAP_PRIVATE, -1, 0); + GTEST_DEATH_TEST_CHECK_(stack != MAP_FAILED); + void* const stack_top = + static_cast(stack) + (stack_grows_down ? stack_size : 0); + + child_pid = clone(&ExecDeathTestChildMain, stack_top, SIGCHLD, &args); + + GTEST_DEATH_TEST_CHECK_(munmap(stack, stack_size) != -1); + } +#else + const bool use_fork = true; +#endif // GTEST_HAS_CLONE + + if (use_fork && (child_pid = fork()) == 0) { ExecDeathTestChildMain(&args); _exit(0); - } - } else { - child_pid = clone(&ExecDeathTestChildMain, stack_top, - SIGCHLD, &args); } + GTEST_DEATH_TEST_CHECK_(child_pid != -1); - GTEST_DEATH_TEST_CHECK_(munmap(stack, stack_size) != -1); return child_pid; } -- cgit v1.2.3 From 2c0fc6d415343b732a4ae39cce1458be1170b9f6 Mon Sep 17 00:00:00 2001 From: "zhanyong.wan" Date: Tue, 24 Mar 2009 20:39:44 +0000 Subject: Cleans up death test implementation (by Vlad Losev); changes the XML format to be closer to junitreport (by Zhanyong Wan). --- src/gtest-death-test.cc | 599 ++++++++++++++++++++--------------------------- src/gtest-internal-inl.h | 2 +- src/gtest.cc | 8 +- 3 files changed, 257 insertions(+), 352 deletions(-) (limited to 'src') diff --git a/src/gtest-death-test.cc b/src/gtest-death-test.cc index 7e7dd608..18eaaeca 100644 --- a/src/gtest-death-test.cc +++ b/src/gtest-death-test.cc @@ -48,6 +48,7 @@ #if GTEST_OS_WINDOWS #include #else +#include #include #include #endif // GTEST_OS_WINDOWS @@ -204,12 +205,12 @@ void DeathTestAbort(const String& message) { const InternalRunDeathTestFlag* const flag = GetUnitTestImpl()->internal_run_death_test_flag(); if (flag != NULL) { -// Suppress MSVC complaints about POSIX functions. #ifdef _MSC_VER #pragma warning(push) -#pragma warning(disable: 4996) +#pragma warning(disable: 4996) // Suppresses deprecation warning + // about POSIX functions in MSVC. #endif // _MSC_VER - FILE* parent = fdopen(flag->status_fd(), "w"); + FILE* parent = fdopen(flag->write_fd(), "w"); #ifdef _MSC_VER #pragma warning(pop) #endif // _MSC_VER @@ -255,47 +256,53 @@ void DeathTestAbort(const String& message) { } \ } while (0) -// Returns the message describing the last system error, regardless of the -// platform. -String GetLastSystemErrorMessage() { -#if GTEST_OS_WINDOWS - const DWORD error_num = ::GetLastError(); - - if (error_num == NULL) - return String(""); - - char* message_ptr; - - ::FormatMessageA( - // The caller does not provide a buffer. The function will allocate one. - FORMAT_MESSAGE_ALLOCATE_BUFFER | - // The function must look up an error message in its system error - // message table. - FORMAT_MESSAGE_FROM_SYSTEM | - // Do not expand insert sequences in the message definition. - FORMAT_MESSAGE_IGNORE_INSERTS, - NULL, // Message source. Ignored in this call. - error_num, - 0x0, // Use system-default language. - reinterpret_cast(&message_ptr), - 0, // Buffer size. Ignored in this call. - NULL); // Message arguments. Ignored in this call. - - const String message = message_ptr; - ::LocalFree(message_ptr); - return message; -#else - return errno == 0 ? String("") : String(strerror(errno)); -#endif // GTEST_OS_WINDOWS +// Returns the message describing the last system error in errno. +String GetLastErrnoDescription() { +#ifdef _MSC_VER +#pragma warning(push) +#pragma warning(disable: 4996) // Suppresses deprecation warning + // about POSIX functions in MSVC. +#endif // _MSC_VER + return String(errno == 0 ? "" : strerror(errno)); +#ifdef _MSC_VER +#pragma warning(pop) +#endif // _MSC_VER } -// TODO(vladl@google.com): Move the definition of FailFromInternalError -// here. -#if GTEST_OS_WINDOWS -static void FailFromInternalError(HANDLE handle); -#else -static void FailFromInternalError(int fd); -#endif // GTEST_OS_WINDOWS +// This is called from a death test parent process to read a failure +// message from the death test child process and log it with the FATAL +// severity. On Windows, the message is read from a pipe handle. On other +// platforms, it is read from a file descriptor. +static void FailFromInternalError(int fd) { + Message error; + char buffer[256]; + int num_read; + + do { +#ifdef _MSC_VER +#pragma warning(push) +#pragma warning(disable: 4996) // Suppresses deprecation warning + // about POSIX functions in MSVC. +#endif // _MSC_VER + while ((num_read = static_cast(read(fd, buffer, 255))) > 0) { +#ifdef _MSC_VER +#pragma warning(pop) +#endif // _MSC_VER + buffer[num_read] = '\0'; + error << buffer; + } + } while (num_read == -1 && errno == EINTR); + + if (num_read == 0) { + GTEST_LOG_(FATAL, error); + } else { + const int last_error = errno; + const String message = GetLastErrnoDescription(); + GTEST_LOG_(FATAL, + Message() << "Error while reading death test internal: " + << message << " [" << last_error << "]"); + } +} // Death test constructor. Increments the running death test count // for the current test. @@ -326,8 +333,6 @@ void DeathTest::set_last_death_test_message(const String& message) { String DeathTest::last_death_test_message_; // Provides cross platform implementation for some death functionality. -// TODO(vladl@google.com): Merge this class with DeathTest in -// gtest-death-test-internal.h. class DeathTestImpl : public DeathTest { protected: DeathTestImpl(const char* statement, const RE* regex) @@ -335,8 +340,14 @@ class DeathTestImpl : public DeathTest { regex_(regex), spawned_(false), status_(-1), - outcome_(IN_PROGRESS) {} + outcome_(IN_PROGRESS), + read_fd_(-1), + write_fd_(-1) {} + // read_fd_ is expected to be closed and cleared by a derived class. + ~DeathTestImpl() { GTEST_DEATH_TEST_CHECK_(read_fd_ == -1); } + + void Abort(AbortReason reason); virtual bool Passed(bool status_ok); const char* statement() const { return statement_; } @@ -347,6 +358,16 @@ class DeathTestImpl : public DeathTest { void set_status(int status) { status_ = status; } DeathTestOutcome outcome() const { return outcome_; } void set_outcome(DeathTestOutcome outcome) { outcome_ = outcome; } + int read_fd() const { return read_fd_; } + void set_read_fd(int fd) { read_fd_ = fd; } + int write_fd() const { return write_fd_; } + void set_write_fd(int fd) { write_fd_ = fd; } + + // Called in the parent process only. Reads the result code of the death + // test child process via a pipe, interprets it to set the outcome_ + // member, and closes read_fd_. Outputs diagnostics and terminates in + // case of unexpected codes. + void ReadAndInterpretStatusByte(); private: // The textual content of the code this object is testing. This class @@ -361,9 +382,161 @@ class DeathTestImpl : public DeathTest { int status_; // How the death test concluded. DeathTestOutcome outcome_; + // Descriptor to the read end of the pipe to the child process. It is + // always -1 in the child process. The child keeps its write end of the + // pipe in write_fd_. + int read_fd_; + // Descriptor to the child's write end of the pipe to the parent process. + // It is always -1 in the parent process. The parent keeps its end of the + // pipe in read_fd_. + int write_fd_; }; -// TODO(vladl@google.com): Move definition of DeathTestImpl::Passed() here. +// Called in the parent process only. Reads the result code of the death +// test child process via a pipe, interprets it to set the outcome_ +// member, and closes read_fd_. Outputs diagnostics and terminates in +// case of unexpected codes. +void DeathTestImpl::ReadAndInterpretStatusByte() { +#ifdef _MSC_VER +#pragma warning(push) +#pragma warning(disable: 4996) // Suppresses deprecation warning + // about POSIX functions in MSVC. +#endif // _MSC_VER + char flag; + int bytes_read; + + // The read() here blocks until data is available (signifying the + // failure of the death test) or until the pipe is closed (signifying + // its success), so it's okay to call this in the parent before + // the child process has exited. + do { + bytes_read = static_cast(read(read_fd(), &flag, 1)); + } while (bytes_read == -1 && errno == EINTR); + + if (bytes_read == 0) { + set_outcome(DIED); + } else if (bytes_read == 1) { + switch (flag) { + case kDeathTestReturned: + set_outcome(RETURNED); + break; + case kDeathTestLived: + set_outcome(LIVED); + break; + case kDeathTestInternalError: + FailFromInternalError(read_fd()); // Does not return. + break; + default: + GTEST_LOG_(FATAL, + Message() << "Death test child process reported " + << "unexpected status byte (" + << static_cast(flag) << ")"); + } + } else { + GTEST_LOG_(FATAL, + Message() << "Read from death test child process failed: " + << GetLastErrnoDescription()); + } + GTEST_DEATH_TEST_CHECK_SYSCALL_(close(read_fd())); + set_read_fd(-1); +#ifdef _MSC_VER +#pragma warning(pop) +#endif // _MSC_VER +} + +// Signals that the death test code which should have exited, didn't. +// Should be called only in a death test child process. +// Writes a status byte to the child's status file descriptor, then +// calls _exit(1). +void DeathTestImpl::Abort(AbortReason reason) { + // The parent process considers the death test to be a failure if + // it finds any data in our pipe. So, here we write a single flag byte + // to the pipe, then exit. + const char status_ch = + reason == TEST_DID_NOT_DIE ? kDeathTestLived : kDeathTestReturned; + +#ifdef _MSC_VER +#pragma warning(push) +#pragma warning(disable: 4996) // Suppresses deprecation warning + // about POSIX functions. +#endif // _MSC_VER + GTEST_DEATH_TEST_CHECK_SYSCALL_(write(write_fd(), &status_ch, 1)); + GTEST_DEATH_TEST_CHECK_SYSCALL_(close(write_fd())); +#ifdef _MSC_VER +#pragma warning(pop) +#endif // _MSC_VER + + _exit(1); // Exits w/o any normal exit hooks (we were supposed to crash) +} + +// Assesses the success or failure of a death test, using both private +// members which have previously been set, and one argument: +// +// Private data members: +// outcome: An enumeration describing how the death test +// concluded: DIED, LIVED, or RETURNED. The death test fails +// in the latter two cases. +// status: The exit status of the child process. On *nix, it is in the +// in the format specified by wait(2). On Windows, this is the +// value supplied to the ExitProcess() API or a numeric code +// of the exception that terminated the program. +// regex: A regular expression object to be applied to +// the test's captured standard error output; the death test +// fails if it does not match. +// +// Argument: +// status_ok: true if exit_status is acceptable in the context of +// this particular death test, which fails if it is false +// +// Returns true iff all of the above conditions are met. Otherwise, the +// first failing condition, in the order given above, is the one that is +// reported. Also sets the last death test message string. +bool DeathTestImpl::Passed(bool status_ok) { + if (!spawned()) + return false; + +#if GTEST_HAS_GLOBAL_STRING + const ::string error_message = GetCapturedStderr(); +#else + const ::std::string error_message = GetCapturedStderr(); +#endif // GTEST_HAS_GLOBAL_STRING + + bool success = false; + Message buffer; + + buffer << "Death test: " << statement() << "\n"; + switch (outcome()) { + case LIVED: + buffer << " Result: failed to die.\n" + << " Error msg: " << error_message; + break; + case RETURNED: + buffer << " Result: illegal return in test statement.\n" + << " Error msg: " << error_message; + break; + case DIED: + if (status_ok) { + if (RE::PartialMatch(error_message, *regex())) { + success = true; + } else { + buffer << " Result: died but not with expected error.\n" + << " Expected: " << regex()->pattern() << "\n" + << "Actual msg: " << error_message; + } + } else { + buffer << " Result: died but not with expected exit code:\n" + << " " << ExitSummary(status()) << "\n"; + } + break; + case IN_PROGRESS: + default: + GTEST_LOG_(FATAL, + "DeathTest::Passed somehow called before conclusion of test"); + } + + DeathTest::set_last_death_test_message(buffer.GetString()); + return success; +} #if GTEST_OS_WINDOWS // WindowsDeathTest implements death tests on Windows. Due to the @@ -404,7 +577,6 @@ class WindowsDeathTest : public DeathTestImpl { // All of these virtual functions are inherited from DeathTest. virtual int Wait(); - virtual void Abort(AbortReason reason); virtual TestRole AssumeRole(); private: @@ -412,10 +584,6 @@ class WindowsDeathTest : public DeathTestImpl { const char* const file_; // The line number on which the death test is located. const int line_; - // Handle to the read end of the pipe to the child process. - // The child keeps its write end of the pipe in the status_handle_ - // field of its InternalRunDeathTestFlag class. - AutoHandle read_handle_; // Handle to the write end of the pipe to the child process. AutoHandle write_handle_; // Child process handle. @@ -430,9 +598,6 @@ class WindowsDeathTest : public DeathTestImpl { // Waits for the child in a death test to exit, returning its exit // status, or 0 if no child process exists. As a side effect, sets the // outcome data member. -// TODO(vladl@google.com): Outcome classification logic is common with -// ForkingDeathTes::Wait(). Refactor it into a -// common function. int WindowsDeathTest::Wait() { if (!spawned()) return 0; @@ -456,44 +621,7 @@ int WindowsDeathTest::Wait() { write_handle_.Reset(); event_handle_.Reset(); - // ReadFile() blocks until data is available (signifying the - // failure of the death test) or until the pipe is closed (signifying - // its success), so it's okay to call this in the parent before or - // after the child process has exited. - char flag; - DWORD bytes_read; - GTEST_DEATH_TEST_CHECK_(::ReadFile(read_handle_.Get(), - &flag, - 1, - &bytes_read, - NULL) || - ::GetLastError() == ERROR_BROKEN_PIPE); - - if (bytes_read == 0) { - set_outcome(DIED); - } else if (bytes_read == 1) { - switch (flag) { - case kDeathTestReturned: - set_outcome(RETURNED); - break; - case kDeathTestLived: - set_outcome(LIVED); - break; - case kDeathTestInternalError: - FailFromInternalError(read_handle_.Get()); // Does not return. - break; - default: - GTEST_LOG_(FATAL, - Message() << "Death test child process reported " - << " unexpected status byte (" - << static_cast(flag) << ")"); - } - } else { - GTEST_LOG_(FATAL, - Message() << "Read from death test child process failed: " - << GetLastSystemErrorMessage()); - } - read_handle_.Reset(); // Done with reading. + ReadAndInterpretStatusByte(); // Waits for the child process to exit if it haven't already. This // returns immediately if the child has already exited, regardless of @@ -510,34 +638,6 @@ int WindowsDeathTest::Wait() { return this->status(); } -// TODO(vladl@google.com): define a cross-platform way to write to -// status_fd to be used both here and in ForkingDeathTest::Abort(). -// -// Signals that the death test did not die as expected. This is called -// from the child process only. -void WindowsDeathTest::Abort(AbortReason reason) { - const InternalRunDeathTestFlag* const internal_flag = - GetUnitTestImpl()->internal_run_death_test_flag(); - // The parent process considers the death test to be a failure if - // it finds any data in our pipe. So, here we write a single flag byte - // to the pipe, then exit. - const char status_ch = - reason == TEST_DID_NOT_DIE ? kDeathTestLived : kDeathTestReturned; - -#ifdef _MSC_VER -#pragma warning(push) -#pragma warning(disable: 4996) -#endif // _MSC_VER - GTEST_DEATH_TEST_CHECK_SYSCALL_(write(internal_flag->status_fd(), - &status_ch, 1)); -#ifdef _MSC_VER -#pragma warning(pop) -#endif // _MSC_VER - - // The write handle will be closed when the child terminates in _exit(). - _exit(1); // Exits w/o any normal exit hooks (we were supposed to crash) -} - // The AssumeRole process for a Windows death test. It creates a child // process with the same executable as the current process to run the // death test. The child process is given the --gtest_filter and @@ -553,6 +653,7 @@ DeathTest::TestRole WindowsDeathTest::AssumeRole() { if (flag != NULL) { // ParseInternalRunDeathTestFlag() has performed all the necessary // processing. + set_write_fd(flag->write_fd()); return EXECUTE_TEST; } @@ -564,7 +665,8 @@ DeathTest::TestRole WindowsDeathTest::AssumeRole() { GTEST_DEATH_TEST_CHECK_(::CreatePipe(&read_handle, &write_handle, &handles_are_inheritable, 0)); // Default buffer size. - read_handle_.Reset(read_handle); + set_read_fd(::_open_osfhandle(reinterpret_cast(read_handle), + O_RDONLY)); write_handle_.Reset(write_handle); event_handle_.Reset(::CreateEvent( &handles_are_inheritable, @@ -642,92 +744,20 @@ class ForkingDeathTest : public DeathTestImpl { // All of these virtual functions are inherited from DeathTest. virtual int Wait(); - virtual void Abort(AbortReason reason); protected: void set_child_pid(pid_t child_pid) { child_pid_ = child_pid; } - void set_read_fd(int fd) { read_fd_ = fd; } - void set_write_fd(int fd) { write_fd_ = fd; } private: // PID of child process during death test; 0 in the child process itself. pid_t child_pid_; - // File descriptors for communicating the death test's status byte. - int read_fd_; // Always -1 in the child process. - int write_fd_; // Always -1 in the parent process. }; // Constructs a ForkingDeathTest. ForkingDeathTest::ForkingDeathTest(const char* statement, const RE* regex) : DeathTestImpl(statement, regex), - child_pid_(-1), - read_fd_(-1), - write_fd_(-1) { -} -#endif // GTEST_OS_WINDOWS - -// This is called from a death test parent process to read a failure -// message from the death test child process and log it with the FATAL -// severity. On Windows, the message is read from a pipe handle. On other -// platforms, it is read from a file descriptor. -// TODO(vladl@google.com): Re-factor the code to merge common parts after -// the reading code is abstracted. -#if GTEST_OS_WINDOWS -static void FailFromInternalError(HANDLE handle) { - Message error; - char buffer[256]; - - bool read_succeeded = true; - DWORD bytes_read; - do { - // ERROR_BROKEN_PIPE arises when the other end of the pipe has been - // closed. This is a normal condition for us. - bytes_read = 0; - read_succeeded = ::ReadFile(handle, - buffer, - sizeof(buffer) - 1, - &bytes_read, - NULL) || ::GetLastError() == ERROR_BROKEN_PIPE; - buffer[bytes_read] = 0; - error << buffer; - } while (read_succeeded && bytes_read > 0); - - if (read_succeeded) { - GTEST_LOG_(FATAL, error); - } else { - const DWORD last_error = ::GetLastError(); - const String message = GetLastSystemErrorMessage(); - GTEST_LOG_(FATAL, - Message() << "Error while reading death test internal: " - << message << " [" << last_error << "]"); - } -} -#else -static void FailFromInternalError(int fd) { - Message error; - char buffer[256]; - ssize_t num_read; - - do { - while ((num_read = read(fd, buffer, 255)) > 0) { - buffer[num_read] = '\0'; - error << buffer; - } - } while (num_read == -1 && errno == EINTR); - - if (num_read == 0) { - GTEST_LOG_(FATAL, error); - } else { - const int last_error = errno; - const String message = GetLastSystemErrorMessage(); - GTEST_LOG_(FATAL, - Message() << "Error while reading death test internal: " - << message << " [" << last_error << "]"); - } -} -#endif // GTEST_OS_WINDOWS + child_pid_(-1) {} -#if !GTEST_OS_WINDOWS // Waits for the child in a death test to exit, returning its exit // status, or 0 if no child process exists. As a side effect, sets the // outcome data member. @@ -735,135 +765,13 @@ int ForkingDeathTest::Wait() { if (!spawned()) return 0; - // The read() here blocks until data is available (signifying the - // failure of the death test) or until the pipe is closed (signifying - // its success), so it's okay to call this in the parent before - // the child process has exited. - char flag; - ssize_t bytes_read; - - do { - bytes_read = read(read_fd_, &flag, 1); - } while (bytes_read == -1 && errno == EINTR); - - if (bytes_read == 0) { - set_outcome(DIED); - } else if (bytes_read == 1) { - switch (flag) { - case kDeathTestReturned: - set_outcome(RETURNED); - break; - case kDeathTestLived: - set_outcome(LIVED); - break; - case kDeathTestInternalError: - FailFromInternalError(read_fd_); // Does not return. - break; - default: - GTEST_LOG_(FATAL, - Message() << "Death test child process reported unexpected " - << "status byte (" << static_cast(flag) - << ")"); - } - } else { - const String error_message = GetLastSystemErrorMessage(); - GTEST_LOG_(FATAL, - Message() << "Read from death test child process failed: " - << error_message); - } + ReadAndInterpretStatusByte(); - GTEST_DEATH_TEST_CHECK_SYSCALL_(close(read_fd_)); int status; GTEST_DEATH_TEST_CHECK_SYSCALL_(waitpid(child_pid_, &status, 0)); set_status(status); return status; } -#endif // !GTEST_OS_WINDOWS - -// Assesses the success or failure of a death test, using both private -// members which have previously been set, and one argument: -// -// Private data members: -// outcome: An enumeration describing how the death test -// concluded: DIED, LIVED, or RETURNED. The death test fails -// in the latter two cases. -// status: The exit status of the child process. On *nix, it is in the -// in the format specified by wait(2). On Windows, this is the -// value supplied to the ExitProcess() API or a numeric code -// of the exception that terminated the program. -// regex: A regular expression object to be applied to -// the test's captured standard error output; the death test -// fails if it does not match. -// -// Argument: -// status_ok: true if exit_status is acceptable in the context of -// this particular death test, which fails if it is false -// -// Returns true iff all of the above conditions are met. Otherwise, the -// first failing condition, in the order given above, is the one that is -// reported. Also sets the last death test message string. -bool DeathTestImpl::Passed(bool status_ok) { - if (!spawned()) - return false; - -#if GTEST_HAS_GLOBAL_STRING - const ::string error_message = GetCapturedStderr(); -#else - const ::std::string error_message = GetCapturedStderr(); -#endif // GTEST_HAS_GLOBAL_STRING - - bool success = false; - Message buffer; - - buffer << "Death test: " << statement() << "\n"; - switch (outcome()) { - case LIVED: - buffer << " Result: failed to die.\n" - << " Error msg: " << error_message; - break; - case RETURNED: - buffer << " Result: illegal return in test statement.\n" - << " Error msg: " << error_message; - break; - case DIED: - if (status_ok) { - if (RE::PartialMatch(error_message, *regex())) { - success = true; - } else { - buffer << " Result: died but not with expected error.\n" - << " Expected: " << regex()->pattern() << "\n" - << "Actual msg: " << error_message; - } - } else { - buffer << " Result: died but not with expected exit code:\n" - << " " << ExitSummary(status()) << "\n"; - } - break; - case IN_PROGRESS: - default: - GTEST_LOG_(FATAL, - "DeathTest::Passed somehow called before conclusion of test"); - } - - DeathTest::set_last_death_test_message(buffer.GetString()); - return success; -} - -#if !GTEST_OS_WINDOWS -// Signals that the death test code which should have exited, didn't. -// Should be called only in a death test child process. -// Writes a status byte to the child's status file descriptor, then -// calls _exit(1). -void ForkingDeathTest::Abort(AbortReason reason) { - // The parent process considers the death test to be a failure if - // it finds any data in our pipe. So, here we write a single flag byte - // to the pipe, then exit. - const char flag = - reason == TEST_DID_NOT_DIE ? kDeathTestLived : kDeathTestReturned; - GTEST_DEATH_TEST_CHECK_SYSCALL_(write(write_fd_, &flag, 1)); - GTEST_DEATH_TEST_CHECK_SYSCALL_(close(write_fd_)); - _exit(1); // Exits w/o any normal exit hooks (we were supposed to crash) -} // A concrete death test class that forks, then immediately runs the test // in the child process. @@ -978,12 +886,10 @@ inline char** GetEnviron() { return *_NSGetEnviron(); } #else -extern "C" char** environ; // Some POSIX platforms expect you - // to declare environ. extern "C" makes - // it reside in the global namespace. -inline char** GetEnviron() { - return environ; -} +// Some POSIX platforms expect you to declare environ. extern "C" makes +// it reside in the global namespace. +extern "C" char** environ; +inline char** GetEnviron() { return environ; } #endif // GTEST_OS_MAC // The main function for a threadsafe-style death test child process. @@ -1002,7 +908,7 @@ static int ExecDeathTestChildMain(void* child_arg) { if (chdir(original_dir) != 0) { DeathTestAbort(String::Format("chdir(\"%s\") failed: %s", original_dir, - GetLastSystemErrorMessage().c_str())); + GetLastErrnoDescription().c_str())); return EXIT_FAILURE; } @@ -1015,7 +921,7 @@ static int ExecDeathTestChildMain(void* child_arg) { DeathTestAbort(String::Format("execve(%s, ...) in %s failed: %s", args->argv[0], original_dir, - GetLastSystemErrorMessage().c_str())); + GetLastErrnoDescription().c_str())); return EXIT_FAILURE; } @@ -1083,7 +989,7 @@ DeathTest::TestRole ExecDeathTest::AssumeRole() { const int death_test_index = info->result()->death_test_count(); if (flag != NULL) { - set_write_fd(flag->status_fd()); + set_write_fd(flag->write_fd()); return EXECUTE_TEST; } @@ -1201,7 +1107,7 @@ static void SplitString(const ::std::string& str, char delimiter, // signals the event, and returns a file descriptor wrapped around the pipe // handle. This function is called in the child process only. int GetStatusFileDescriptor(unsigned int parent_process_id, - size_t status_handle_as_size_t, + size_t write_handle_as_size_t, size_t event_handle_as_size_t) { AutoHandle parent_process_handle(::OpenProcess(PROCESS_DUP_HANDLE, FALSE, // Non-inheritable. @@ -1215,22 +1121,22 @@ int GetStatusFileDescriptor(unsigned int parent_process_id, // compile-time assertion when available. GTEST_CHECK_(sizeof(HANDLE) <= sizeof(size_t)); - const HANDLE status_handle = - reinterpret_cast(status_handle_as_size_t); - HANDLE dup_status_handle; + const HANDLE write_handle = + reinterpret_cast(write_handle_as_size_t); + HANDLE dup_write_handle; // The newly initialized handle is accessible only in in the parent // process. To obtain one accessible within the child, we need to use // DuplicateHandle. - if (!::DuplicateHandle(parent_process_handle.Get(), status_handle, - ::GetCurrentProcess(), &dup_status_handle, + if (!::DuplicateHandle(parent_process_handle.Get(), write_handle, + ::GetCurrentProcess(), &dup_write_handle, 0x0, // Requested privileges ignored since // DUPLICATE_SAME_ACCESS is used. FALSE, // Request non-inheritable handler. DUPLICATE_SAME_ACCESS)) { DeathTestAbort(String::Format( "Unable to duplicate the pipe handle %Iu from the parent process %u", - status_handle_as_size_t, parent_process_id)); + write_handle_as_size_t, parent_process_id)); } const HANDLE event_handle = reinterpret_cast(event_handle_as_size_t); @@ -1246,20 +1152,19 @@ int GetStatusFileDescriptor(unsigned int parent_process_id, event_handle_as_size_t, parent_process_id)); } - const int status_fd = - ::_open_osfhandle(reinterpret_cast(dup_status_handle), - O_APPEND | O_TEXT); - if (status_fd == -1) { + const int write_fd = + ::_open_osfhandle(reinterpret_cast(dup_write_handle), O_APPEND); + if (write_fd == -1) { DeathTestAbort(String::Format( "Unable to convert pipe handle %Iu to a file descriptor", - status_handle_as_size_t)); + write_handle_as_size_t)); } // Signals the parent that the write end of the pipe has been acquired // so the parent can release its own write end. ::SetEvent(dup_event_handle); - return status_fd; + return write_fd; } #endif // GTEST_OS_WINDOWS @@ -1275,37 +1180,37 @@ InternalRunDeathTestFlag* ParseInternalRunDeathTestFlag() { int index = -1; ::std::vector< ::std::string> fields; SplitString(GTEST_FLAG(internal_run_death_test).c_str(), '|', &fields); - int status_fd = -1; + int write_fd = -1; #if GTEST_OS_WINDOWS unsigned int parent_process_id = 0; - size_t status_handle_as_size_t = 0; + size_t write_handle_as_size_t = 0; size_t event_handle_as_size_t = 0; if (fields.size() != 6 || !ParseNaturalNumber(fields[1], &line) || !ParseNaturalNumber(fields[2], &index) || !ParseNaturalNumber(fields[3], &parent_process_id) - || !ParseNaturalNumber(fields[4], &status_handle_as_size_t) + || !ParseNaturalNumber(fields[4], &write_handle_as_size_t) || !ParseNaturalNumber(fields[5], &event_handle_as_size_t)) { DeathTestAbort(String::Format( "Bad --gtest_internal_run_death_test flag: %s", GTEST_FLAG(internal_run_death_test).c_str())); } - status_fd = GetStatusFileDescriptor(parent_process_id, - status_handle_as_size_t, - event_handle_as_size_t); + write_fd = GetStatusFileDescriptor(parent_process_id, + write_handle_as_size_t, + event_handle_as_size_t); #else if (fields.size() != 4 || !ParseNaturalNumber(fields[1], &line) || !ParseNaturalNumber(fields[2], &index) - || !ParseNaturalNumber(fields[3], &status_fd)) { + || !ParseNaturalNumber(fields[3], &write_fd)) { DeathTestAbort(String::Format( "Bad --gtest_internal_run_death_test flag: %s", GTEST_FLAG(internal_run_death_test).c_str())); } #endif // GTEST_OS_WINDOWS - return new InternalRunDeathTestFlag(fields[0], line, index, status_fd); + return new InternalRunDeathTestFlag(fields[0], line, index, write_fd); } } // namespace internal diff --git a/src/gtest-internal-inl.h b/src/gtest-internal-inl.h index d079a3e1..dfc1e958 100644 --- a/src/gtest-internal-inl.h +++ b/src/gtest-internal-inl.h @@ -1325,7 +1325,7 @@ void ParseGoogleTestFlagsOnly(int* argc, wchar_t** argv); // Returns the message describing the last system error, regardless of the // platform. -String GetLastSystemErrorMessage(); +String GetLastErrnoDescription(); #if GTEST_OS_WINDOWS // Provides leak-safe Windows kernel handle ownership. diff --git a/src/gtest.cc b/src/gtest.cc index a66b78fd..adec6c79 100644 --- a/src/gtest.cc +++ b/src/gtest.cc @@ -3044,7 +3044,7 @@ internal::String XmlUnitTestResultPrinter::EscapeXml(const char* str, // // This is how Google Test concepts map to the DTD: // -// <-- corresponds to a UnitTest object +// <-- corresponds to a UnitTest object // <-- corresponds to a TestCase object // <-- corresponds to a TestInfo object // ... @@ -3053,7 +3053,7 @@ internal::String XmlUnitTestResultPrinter::EscapeXml(const char* str, // <-- individual assertion failures // // -// +// namespace internal { @@ -3137,7 +3137,7 @@ void XmlUnitTestResultPrinter::PrintXmlUnitTest(FILE* out, const internal::UnitTestImpl* const impl = unit_test->impl(); fprintf(out, "\n"); fprintf(out, - "total_test_count(), impl->failed_test_count(), @@ -3150,7 +3150,7 @@ void XmlUnitTestResultPrinter::PrintXmlUnitTest(FILE* out, case_node = case_node->next()) { PrintXmlTestCase(out, case_node->element()); } - fprintf(out, "\n"); + fprintf(out, "\n"); } // Produces a string representing the test properties in a result as space -- cgit v1.2.3 From f3c6efd8d78f96a9a500b3ba7e024de122b9afa1 Mon Sep 17 00:00:00 2001 From: "zhanyong.wan" Date: Wed, 25 Mar 2009 03:55:18 +0000 Subject: Makes gtest compile without warning with gcc 4.0.3 and -Wall -Wextra. --- src/gtest-death-test.cc | 2 +- src/gtest-filepath.cc | 13 +++++++------ 2 files changed, 8 insertions(+), 7 deletions(-) (limited to 'src') diff --git a/src/gtest-death-test.cc b/src/gtest-death-test.cc index 18eaaeca..5e7eca0d 100644 --- a/src/gtest-death-test.cc +++ b/src/gtest-death-test.cc @@ -945,7 +945,7 @@ bool StackGrowsDown() { // wrong. static pid_t ExecDeathTestFork(char* const* argv, int close_fd) { ExecDeathTestArgs args = { argv, close_fd }; - pid_t child_pid; + pid_t child_pid = -1; #if GTEST_HAS_CLONE const bool use_fork = GTEST_FLAG(death_test_use_fork); diff --git a/src/gtest-filepath.cc b/src/gtest-filepath.cc index 32fd3bcb..d0cc5ffa 100644 --- a/src/gtest-filepath.cc +++ b/src/gtest-filepath.cc @@ -33,6 +33,7 @@ #include #include +#include #ifdef _WIN32_WCE #include @@ -166,20 +167,19 @@ FilePath FilePath::ConcatPaths(const FilePath& directory, // Returns true if pathname describes something findable in the file-system, // either a file, directory, or whatever. bool FilePath::FileOrDirectoryExists() const { -#if GTEST_OS_WINDOWS #ifdef _WIN32_WCE LPCWSTR unicode = String::AnsiToUtf16(pathname_.c_str()); const DWORD attributes = GetFileAttributes(unicode); delete [] unicode; return attributes != kInvalidFileAttributes; -#else +#elif GTEST_OS_WINDOWS struct _stat file_stat = {}; return _stat(pathname_.c_str(), &file_stat) == 0; -#endif // _WIN32_WCE #else - struct stat file_stat = {}; + struct stat file_stat; + memset(&file_stat, 0, sizeof(file_stat)); return stat(pathname_.c_str(), &file_stat) == 0; -#endif // GTEST_OS_WINDOWS +#endif // _WIN32_WCE } // Returns true if pathname describes a directory in the file-system @@ -205,7 +205,8 @@ bool FilePath::DirectoryExists() const { (_S_IFDIR & file_stat.st_mode) != 0; #endif // _WIN32_WCE #else - struct stat file_stat = {}; + struct stat file_stat; + memset(&file_stat, 0, sizeof(file_stat)); result = stat(pathname_.c_str(), &file_stat) == 0 && S_ISDIR(file_stat.st_mode); #endif // GTEST_OS_WINDOWS -- cgit v1.2.3 From 3c7bbf5b46679aea4e0ac7d3ad241cb036146751 Mon Sep 17 00:00:00 2001 From: "zhanyong.wan" Date: Thu, 26 Mar 2009 19:03:47 +0000 Subject: Simplifies implementation by defining a POSIX portability layer; adds the death test style flag to --help. --- src/gtest-death-test.cc | 57 +++++----------------------------- src/gtest-filepath.cc | 30 ++++++------------ src/gtest-port.cc | 30 +++++------------- src/gtest-test-part.cc | 2 +- src/gtest.cc | 81 +++++++++++++------------------------------------ 5 files changed, 47 insertions(+), 153 deletions(-) (limited to 'src') diff --git a/src/gtest-death-test.cc b/src/gtest-death-test.cc index 5e7eca0d..1ad2d6d5 100644 --- a/src/gtest-death-test.cc +++ b/src/gtest-death-test.cc @@ -48,7 +48,6 @@ #if GTEST_OS_WINDOWS #include #else -#include #include #include #endif // GTEST_OS_WINDOWS @@ -205,15 +204,7 @@ void DeathTestAbort(const String& message) { const InternalRunDeathTestFlag* const flag = GetUnitTestImpl()->internal_run_death_test_flag(); if (flag != NULL) { -#ifdef _MSC_VER -#pragma warning(push) -#pragma warning(disable: 4996) // Suppresses deprecation warning - // about POSIX functions in MSVC. -#endif // _MSC_VER - FILE* parent = fdopen(flag->write_fd(), "w"); -#ifdef _MSC_VER -#pragma warning(pop) -#endif // _MSC_VER + FILE* parent = posix::fdopen(flag->write_fd(), "w"); fputc(kDeathTestInternalError, parent); fprintf(parent, "%s", message.c_str()); fflush(parent); @@ -258,15 +249,7 @@ void DeathTestAbort(const String& message) { // Returns the message describing the last system error in errno. String GetLastErrnoDescription() { -#ifdef _MSC_VER -#pragma warning(push) -#pragma warning(disable: 4996) // Suppresses deprecation warning - // about POSIX functions in MSVC. -#endif // _MSC_VER - return String(errno == 0 ? "" : strerror(errno)); -#ifdef _MSC_VER -#pragma warning(pop) -#endif // _MSC_VER + return String(errno == 0 ? "" : posix::strerror(errno)); } // This is called from a death test parent process to read a failure @@ -279,15 +262,7 @@ static void FailFromInternalError(int fd) { int num_read; do { -#ifdef _MSC_VER -#pragma warning(push) -#pragma warning(disable: 4996) // Suppresses deprecation warning - // about POSIX functions in MSVC. -#endif // _MSC_VER - while ((num_read = static_cast(read(fd, buffer, 255))) > 0) { -#ifdef _MSC_VER -#pragma warning(pop) -#endif // _MSC_VER + while ((num_read = posix::read(fd, buffer, 255)) > 0) { buffer[num_read] = '\0'; error << buffer; } @@ -397,11 +372,6 @@ class DeathTestImpl : public DeathTest { // member, and closes read_fd_. Outputs diagnostics and terminates in // case of unexpected codes. void DeathTestImpl::ReadAndInterpretStatusByte() { -#ifdef _MSC_VER -#pragma warning(push) -#pragma warning(disable: 4996) // Suppresses deprecation warning - // about POSIX functions in MSVC. -#endif // _MSC_VER char flag; int bytes_read; @@ -410,7 +380,7 @@ void DeathTestImpl::ReadAndInterpretStatusByte() { // its success), so it's okay to call this in the parent before // the child process has exited. do { - bytes_read = static_cast(read(read_fd(), &flag, 1)); + bytes_read = posix::read(read_fd(), &flag, 1); } while (bytes_read == -1 && errno == EINTR); if (bytes_read == 0) { @@ -437,11 +407,8 @@ void DeathTestImpl::ReadAndInterpretStatusByte() { Message() << "Read from death test child process failed: " << GetLastErrnoDescription()); } - GTEST_DEATH_TEST_CHECK_SYSCALL_(close(read_fd())); + GTEST_DEATH_TEST_CHECK_SYSCALL_(posix::close(read_fd())); set_read_fd(-1); -#ifdef _MSC_VER -#pragma warning(pop) -#endif // _MSC_VER } // Signals that the death test code which should have exited, didn't. @@ -454,18 +421,8 @@ void DeathTestImpl::Abort(AbortReason reason) { // to the pipe, then exit. const char status_ch = reason == TEST_DID_NOT_DIE ? kDeathTestLived : kDeathTestReturned; - -#ifdef _MSC_VER -#pragma warning(push) -#pragma warning(disable: 4996) // Suppresses deprecation warning - // about POSIX functions. -#endif // _MSC_VER - GTEST_DEATH_TEST_CHECK_SYSCALL_(write(write_fd(), &status_ch, 1)); - GTEST_DEATH_TEST_CHECK_SYSCALL_(close(write_fd())); -#ifdef _MSC_VER -#pragma warning(pop) -#endif // _MSC_VER - + GTEST_DEATH_TEST_CHECK_SYSCALL_(posix::write(write_fd(), &status_ch, 1)); + GTEST_DEATH_TEST_CHECK_SYSCALL_(posix::close(write_fd())); _exit(1); // Exits w/o any normal exit hooks (we were supposed to crash) } diff --git a/src/gtest-filepath.cc b/src/gtest-filepath.cc index d0cc5ffa..7ba6a6b7 100644 --- a/src/gtest-filepath.cc +++ b/src/gtest-filepath.cc @@ -33,22 +33,17 @@ #include #include -#include #ifdef _WIN32_WCE #include #elif GTEST_OS_WINDOWS #include #include -#include #elif GTEST_OS_SYMBIAN // Symbian OpenC has PATH_MAX in sys/syslimits.h #include -#include #else #include -#include // NOLINT -#include // NOLINT #include // Some Linux distributions define PATH_MAX here. #endif // _WIN32_WCE or _WIN32 @@ -172,13 +167,9 @@ bool FilePath::FileOrDirectoryExists() const { const DWORD attributes = GetFileAttributes(unicode); delete [] unicode; return attributes != kInvalidFileAttributes; -#elif GTEST_OS_WINDOWS - struct _stat file_stat = {}; - return _stat(pathname_.c_str(), &file_stat) == 0; #else - struct stat file_stat; - memset(&file_stat, 0, sizeof(file_stat)); - return stat(pathname_.c_str(), &file_stat) == 0; + posix::stat_struct file_stat; + return posix::stat(pathname_.c_str(), &file_stat) == 0; #endif // _WIN32_WCE } @@ -191,6 +182,10 @@ bool FilePath::DirectoryExists() const { // Windows (like "C:\\"). const FilePath& path(IsRootDirectory() ? *this : RemoveTrailingPathSeparator()); +#else + const FilePath& path(*this); +#endif + #ifdef _WIN32_WCE LPCWSTR unicode = String::AnsiToUtf16(path.c_str()); const DWORD attributes = GetFileAttributes(unicode); @@ -200,16 +195,11 @@ bool FilePath::DirectoryExists() const { result = true; } #else - struct _stat file_stat = {}; - result = _stat(path.c_str(), &file_stat) == 0 && - (_S_IFDIR & file_stat.st_mode) != 0; + posix::stat_struct file_stat; + result = posix::stat(path.c_str(), &file_stat) == 0 && + posix::IsDir(file_stat); #endif // _WIN32_WCE -#else - struct stat file_stat; - memset(&file_stat, 0, sizeof(file_stat)); - result = stat(pathname_.c_str(), &file_stat) == 0 && - S_ISDIR(file_stat.st_mode); -#endif // GTEST_OS_WINDOWS + return result; } diff --git a/src/gtest-port.cc b/src/gtest-port.cc index e41ab9f5..02998424 100644 --- a/src/gtest-port.cc +++ b/src/gtest-port.cc @@ -42,10 +42,6 @@ #include #endif // GTEST_OS_WINDOWS -#if GTEST_USES_SIMPLE_RE -#include -#endif - #ifdef _WIN32_WCE #include // For TerminateProcess() #endif // _WIN32_WCE @@ -350,11 +346,7 @@ bool RE::PartialMatch(const char* str, const RE& re) { void RE::Init(const char* regex) { pattern_ = full_pattern_ = NULL; if (regex != NULL) { -#if GTEST_OS_WINDOWS - pattern_ = _strdup(regex); -#else - pattern_ = strdup(regex); -#endif + pattern_ = posix::strdup(regex); } is_valid_ = ValidateRegex(regex); @@ -510,17 +502,9 @@ void CaptureStderr() { ::std::string GetCapturedStderr() { g_captured_stderr->StopCapture(); -// Disables Microsoft deprecation warning for fopen and fclose. -#ifdef _MSC_VER -#pragma warning(push) -#pragma warning(disable: 4996) -#endif // _MSC_VER - FILE* const file = fopen(g_captured_stderr->filename().c_str(), "r"); + FILE* const file = posix::fopen(g_captured_stderr->filename().c_str(), "r"); const ::std::string content = ReadEntireFile(file); - fclose(file); -#ifdef _MSC_VER -#pragma warning(pop) -#endif // _MSC_VER + posix::fclose(file); delete g_captured_stderr; g_captured_stderr = NULL; @@ -541,10 +525,12 @@ const ::std::vector& GetArgvs() { return g_argvs; } #endif // GTEST_HAS_DEATH_TEST #ifdef _WIN32_WCE +namespace posix { void abort() { DebugBreak(); TerminateProcess(GetCurrentProcess(), 1); } +} // namespace posix #endif // _WIN32_WCE // Returns the name of the environment variable corresponding to the @@ -609,7 +595,7 @@ bool ParseInt32(const Message& src_text, const char* str, Int32* value) { // The value is considered true iff it's not "0". bool BoolFromGTestEnv(const char* flag, bool default_value) { const String env_var = FlagToEnvVar(flag); - const char* const string_value = GetEnv(env_var.c_str()); + const char* const string_value = posix::getenv(env_var.c_str()); return string_value == NULL ? default_value : strcmp(string_value, "0") != 0; } @@ -619,7 +605,7 @@ bool BoolFromGTestEnv(const char* flag, bool default_value) { // doesn't represent a valid 32-bit integer, returns default_value. Int32 Int32FromGTestEnv(const char* flag, Int32 default_value) { const String env_var = FlagToEnvVar(flag); - const char* const string_value = GetEnv(env_var.c_str()); + const char* const string_value = posix::getenv(env_var.c_str()); if (string_value == NULL) { // The environment variable is not set. return default_value; @@ -641,7 +627,7 @@ Int32 Int32FromGTestEnv(const char* flag, Int32 default_value) { // the given flag; if it's not set, returns default_value. const char* StringFromGTestEnv(const char* flag, const char* default_value) { const String env_var = FlagToEnvVar(flag); - const char* const value = GetEnv(env_var.c_str()); + const char* const value = posix::getenv(env_var.c_str()); return value == NULL ? default_value : value; } diff --git a/src/gtest-test-part.cc b/src/gtest-test-part.cc index 2cb55856..b9ca6b73 100644 --- a/src/gtest-test-part.cc +++ b/src/gtest-test-part.cc @@ -81,7 +81,7 @@ void TestPartResultArray::Append(const TestPartResult& result) { const TestPartResult& TestPartResultArray::GetTestPartResult(int index) const { if (index < 0 || index >= size()) { printf("\nInvalid index (%d) into TestPartResultArray.\n", index); - internal::abort(); + internal::posix::abort(); } const internal::ListNode* p = list_->Head(); diff --git a/src/gtest.cc b/src/gtest.cc index adec6c79..e98f63fa 100644 --- a/src/gtest.cc +++ b/src/gtest.cc @@ -39,7 +39,6 @@ #include #include #include -#include #include #include @@ -125,8 +124,6 @@ #undef GTEST_IMPLEMENTATION_ #if GTEST_OS_WINDOWS -#define fileno _fileno -#define isatty _isatty #define vsnprintf _vsnprintf #endif // GTEST_OS_WINDOWS @@ -806,16 +803,7 @@ static char* CloneString(const char* str, size_t length) { return NULL; } else { char* const clone = new char[length + 1]; - // MSVC 8 deprecates strncpy(), so we want to suppress warning - // 4996 (deprecated function) there. -#if GTEST_OS_WINDOWS // We are on Windows. -#pragma warning(push) // Saves the current warning state. -#pragma warning(disable:4996) // Temporarily disables warning 4996. - strncpy(clone, str, length); -#pragma warning(pop) // Restores the warning state. -#else // We are on Linux or Mac OS. - strncpy(clone, str, length); -#endif // GTEST_OS_WINDOWS + posix::strncpy(clone, str, length); clone[length] = '\0'; return clone; } @@ -1455,17 +1443,8 @@ char* CodePointToUtf8(UInt32 code_point, char* str) { // the terminating nul character). We are asking for 32 character // buffer just in case. This is also enough for strncpy to // null-terminate the destination string. - // MSVC 8 deprecates strncpy(), so we want to suppress warning - // 4996 (deprecated function) there. -#if GTEST_OS_WINDOWS // We are on Windows. -#pragma warning(push) // Saves the current warning state. -#pragma warning(disable:4996) // Temporarily disables warning 4996. -#endif - strncpy(str, String::Format("(Invalid Unicode 0x%X)", code_point).c_str(), - 32); -#if GTEST_OS_WINDOWS // We are on Windows. -#pragma warning(pop) // Restores the warning state. -#endif + posix::strncpy( + str, String::Format("(Invalid Unicode 0x%X)", code_point).c_str(), 32); str[31] = '\0'; // Makes sure no change in the format to strncpy leaves // the result unterminated. } @@ -1603,15 +1582,11 @@ AssertionResult CmpHelperSTRNE(const char* s1_expression, // NULL C string is considered different to any non-NULL C string, // including the empty string. bool String::CaseInsensitiveCStringEquals(const char * lhs, const char * rhs) { - if ( lhs == NULL ) return rhs == NULL; - - if ( rhs == NULL ) return false; - -#if GTEST_OS_WINDOWS - return _stricmp(lhs, rhs) == 0; -#else // GTEST_OS_WINDOWS - return strcasecmp(lhs, rhs) == 0; -#endif // GTEST_OS_WINDOWS + if (lhs == NULL) + return rhs == NULL; + if (rhs == NULL) + return false; + return posix::strcasecmp(lhs, rhs) == 0; } // Compares two wide C strings, ignoring case. Returns true iff they @@ -2519,7 +2494,7 @@ bool ShouldUseColor(bool stdout_is_tty) { return stdout_is_tty; #else // On non-Windows platforms, we rely on the TERM variable. - const char* const term = GetEnv("TERM"); + const char* const term = posix::getenv("TERM"); const bool term_supports_color = String::CStringEquals(term, "xterm") || String::CStringEquals(term, "xterm-color") || @@ -2549,7 +2524,7 @@ void ColoredPrintf(GTestColor color, const char* fmt, ...) { const bool use_color = false; #else static const bool in_color_mode = - ShouldUseColor(isatty(fileno(stdout)) != 0); + ShouldUseColor(posix::isatty(posix::fileno(stdout)) != 0); const bool use_color = in_color_mode && (color != COLOR_DEFAULT); #endif // defined(_WIN32_WCE) || GTEST_OS_SYMBIAN || GTEST_OS_ZOS // The '!= 0' comparison is necessary to satisfy MSVC 7.1. @@ -2631,8 +2606,8 @@ void PrettyUnitTestResultPrinter::OnUnitTestStart( if (internal::ShouldShard(kTestTotalShards, kTestShardIndex, false)) { ColoredPrintf(COLOR_YELLOW, "Note: This is test shard %s of %s.\n", - internal::GetEnv(kTestShardIndex), - internal::GetEnv(kTestTotalShards)); + internal::posix::getenv(kTestShardIndex), + internal::posix::getenv(kTestTotalShards)); } const internal::UnitTestImpl* const impl = unit_test->impl(); @@ -2950,17 +2925,7 @@ void XmlUnitTestResultPrinter::OnUnitTestEnd(const UnitTest* unit_test) { internal::FilePath output_dir(output_file.RemoveFileName()); if (output_dir.CreateDirectoriesRecursively()) { - // MSVC 8 deprecates fopen(), so we want to suppress warning 4996 - // (deprecated function) there. -#if GTEST_OS_WINDOWS - // We are on Windows. -#pragma warning(push) // Saves the current warning state. -#pragma warning(disable:4996) // Temporarily disables warning 4996. - xmlout = fopen(output_file_.c_str(), "w"); -#pragma warning(pop) // Restores the warning state. -#else // We are on Linux or Mac OS. - xmlout = fopen(output_file_.c_str(), "w"); -#endif // GTEST_OS_WINDOWS + xmlout = internal::posix::fopen(output_file_.c_str(), "w"); } if (xmlout == NULL) { // TODO(wan): report the reason of the failure. @@ -3697,17 +3662,9 @@ int UnitTestImpl::RunAllTests() { // function will write over it. If the variable is present, but the file cannot // be created, prints an error and exits. void WriteToShardStatusFileIfNeeded() { - const char* const test_shard_file = GetEnv(kTestShardStatusFile); + const char* const test_shard_file = posix::getenv(kTestShardStatusFile); if (test_shard_file != NULL) { -#ifdef _MSC_VER // MSVC 8 deprecates fopen(). -#pragma warning(push) // Saves the current warning state. -#pragma warning(disable:4996) // Temporarily disables warning on - // deprecated functions. -#endif - FILE* const file = fopen(test_shard_file, "w"); -#ifdef _MSC_VER -#pragma warning(pop) // Restores the warning state. -#endif + FILE* const file = posix::fopen(test_shard_file, "w"); if (file == NULL) { ColoredPrintf(COLOR_RED, "Could not write to the test shard status file \"%s\" " @@ -3772,7 +3729,7 @@ bool ShouldShard(const char* total_shards_env, // returns default_val. If it is not an Int32, prints an error // and aborts. Int32 Int32FromEnvOrDie(const char* const var, Int32 default_val) { - const char* str_val = GetEnv(var); + const char* str_val = posix::getenv(var); if (str_val == NULL) { return default_val; } @@ -4175,7 +4132,11 @@ static const char kColorEncodedHelpMessage[] = " Generate an XML report in the given directory or with the given file\n" " name. @YFILE_PATH@D defaults to @Gtest_details.xml@D.\n" "\n" -"Failure Behavior:\n" +"Assertion Behavior:\n" +#if GTEST_HAS_DEATH_TEST && !GTEST_OS_WINDOWS +" @G--" GTEST_FLAG_PREFIX_ "death_test_style=@Y(@Gfast@Y|@Gthreadsafe@Y)@D\n" +" Set the default death test style.\n" +#endif // GTEST_HAS_DEATH_TEST && !GTEST_OS_WINDOWS " @G--" GTEST_FLAG_PREFIX_ "break_on_failure@D\n" " Turn assertion failures into debugger break-points.\n" " @G--" GTEST_FLAG_PREFIX_ "throw_on_failure@D\n" -- cgit v1.2.3 From e120fc58906cd7ca6492ba634bb7e082167bd5bf Mon Sep 17 00:00:00 2001 From: "zhanyong.wan" Date: Thu, 26 Mar 2009 21:11:22 +0000 Subject: Works around a VC bug by avoiding defining a function named strdup(). --- src/gtest-death-test.cc | 4 ++-- src/gtest-port.cc | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) (limited to 'src') diff --git a/src/gtest-death-test.cc b/src/gtest-death-test.cc index 1ad2d6d5..517495b5 100644 --- a/src/gtest-death-test.cc +++ b/src/gtest-death-test.cc @@ -810,7 +810,7 @@ class Arguments { } } void AddArgument(const char* argument) { - args_.insert(args_.end() - 1, strdup(argument)); + args_.insert(args_.end() - 1, posix::StrDup(argument)); } template @@ -818,7 +818,7 @@ class Arguments { for (typename ::std::vector::const_iterator i = arguments.begin(); i != arguments.end(); ++i) { - args_.insert(args_.end() - 1, strdup(i->c_str())); + args_.insert(args_.end() - 1, posix::StrDup(i->c_str())); } } char* const* Argv() { diff --git a/src/gtest-port.cc b/src/gtest-port.cc index 02998424..ef213892 100644 --- a/src/gtest-port.cc +++ b/src/gtest-port.cc @@ -98,7 +98,7 @@ bool RE::PartialMatch(const char* str, const RE& re) { // Initializes an RE from its string representation. void RE::Init(const char* regex) { - pattern_ = strdup(regex); + pattern_ = posix::StrDup(regex); // Reserves enough bytes to hold the regular expression used for a // full match. @@ -346,7 +346,7 @@ bool RE::PartialMatch(const char* str, const RE& re) { void RE::Init(const char* regex) { pattern_ = full_pattern_ = NULL; if (regex != NULL) { - pattern_ = posix::strdup(regex); + pattern_ = posix::StrDup(regex); } is_valid_ = ValidateRegex(regex); -- cgit v1.2.3 From 6a26383e31cf79dd0acf89bf3a53c7a805decf1d Mon Sep 17 00:00:00 2001 From: "zhanyong.wan" Date: Tue, 31 Mar 2009 16:27:55 +0000 Subject: Cleans up the use of GTEST_OS_WINDOWS and _MSC_VER. --- src/gtest-port.cc | 6 +++--- src/gtest.cc | 6 +++--- 2 files changed, 6 insertions(+), 6 deletions(-) (limited to 'src') diff --git a/src/gtest-port.cc b/src/gtest-port.cc index ef213892..166ff414 100644 --- a/src/gtest-port.cc +++ b/src/gtest-port.cc @@ -62,12 +62,12 @@ namespace testing { namespace internal { -#if GTEST_OS_WINDOWS -// Microsoft does not provide a definition of STDERR_FILENO. +#ifdef _MSC_VER +// MSVC does not provide a definition of STDERR_FILENO. const int kStdErrFileno = 2; #else const int kStdErrFileno = STDERR_FILENO; -#endif // GTEST_OS_WINDOWS +#endif // _MSC_VER #if GTEST_USES_POSIX_RE diff --git a/src/gtest.cc b/src/gtest.cc index e98f63fa..ac5ed9d5 100644 --- a/src/gtest.cc +++ b/src/gtest.cc @@ -1710,16 +1710,16 @@ String String::Format(const char * format, ...) { char buffer[4096]; // MSVC 8 deprecates vsnprintf(), so we want to suppress warning // 4996 (deprecated function) there. -#if GTEST_OS_WINDOWS // We are on Windows. +#ifdef _MSC_VER // We are using MSVC. #pragma warning(push) // Saves the current warning state. #pragma warning(disable:4996) // Temporarily disables warning 4996. const int size = vsnprintf(buffer, sizeof(buffer)/sizeof(buffer[0]) - 1, format, args); #pragma warning(pop) // Restores the warning state. -#else // We are on Linux or Mac OS. +#else // We are not using MSVC. const int size = vsnprintf(buffer, sizeof(buffer)/sizeof(buffer[0]) - 1, format, args); -#endif // GTEST_OS_WINDOWS +#endif // _MSC_VER va_end(args); return String(size >= 0 ? buffer : ""); -- cgit v1.2.3 From c12f63214e9b7761d27e68353e4aaf1761c9cf88 Mon Sep 17 00:00:00 2001 From: "zhanyong.wan" Date: Tue, 7 Apr 2009 21:03:22 +0000 Subject: Adds sample4_unittest to scons (by Vlad Losev); adds logic for getting the thread count on Mac (by Vlad Losev); adds HasFailure() and HasNonfatalFailure() (by Zhanyong Wan). --- src/gtest-internal-inl.h | 11 +++++++++++ src/gtest-port.cc | 21 +++++++++++++++++++++ src/gtest.cc | 18 +++++++++++++++++- 3 files changed, 49 insertions(+), 1 deletion(-) (limited to 'src') diff --git a/src/gtest-internal-inl.h b/src/gtest-internal-inl.h index dfc1e958..2a90edac 100644 --- a/src/gtest-internal-inl.h +++ b/src/gtest-internal-inl.h @@ -548,6 +548,9 @@ class TestResult { // Returns true iff the test fatally failed. bool HasFatalFailure() const; + // Returns true iff the test has a non-fatal failure. + bool HasNonfatalFailure() const; + // Returns the elapsed time, in milliseconds. TimeInMillis elapsed_time() const { return elapsed_time_; } @@ -575,6 +578,9 @@ class TestResult { // Increments the death test count, returning the new count. int increment_death_test_count() { return ++death_test_count_; } + // Clears the test part results. + void ClearTestPartResults() { test_part_results_.Clear(); } + // Clears the object. void Clear(); private: @@ -1300,6 +1306,11 @@ inline UnitTestImpl* GetUnitTestImpl() { return UnitTest::GetInstance()->impl(); } +// Clears all test part results of the current test. +inline void ClearCurrentTestPartResults() { + GetUnitTestImpl()->current_test_result()->ClearTestPartResults(); +} + // Internal helper functions for implementing the simple regular // expression matcher. bool IsInSet(char ch, const char* str); diff --git a/src/gtest-port.cc b/src/gtest-port.cc index 166ff414..193f5323 100644 --- a/src/gtest-port.cc +++ b/src/gtest-port.cc @@ -42,6 +42,11 @@ #include #endif // GTEST_OS_WINDOWS +#if GTEST_OS_MAC +#include +#include +#endif // GTEST_OS_MAC + #ifdef _WIN32_WCE #include // For TerminateProcess() #endif // _WIN32_WCE @@ -69,6 +74,22 @@ const int kStdErrFileno = 2; const int kStdErrFileno = STDERR_FILENO; #endif // _MSC_VER +// Returns the number of threads running in the process, or 0 to indicate that +// we cannot detect it. +size_t GetThreadCount() { +#if GTEST_OS_MAC + mach_msg_type_number_t thread_count; + thread_act_port_array_t thread_list; + kern_return_t status = task_threads(mach_task_self(), + &thread_list, &thread_count); + return status == KERN_SUCCESS ? static_cast(thread_count) : 0; +#else + // There's no portable way to detect the number of threads, so we just + // return 0 to indicate that we cannot detect it. + return 0; +#endif // GTEST_OS_MAC +} + #if GTEST_USES_POSIX_RE // Implements RE. Currently only needed for death tests. diff --git a/src/gtest.cc b/src/gtest.cc index ac5ed9d5..5903f2ae 100644 --- a/src/gtest.cc +++ b/src/gtest.cc @@ -1852,7 +1852,7 @@ int TestResult::failed_part_count() const { } // Returns true iff the test part fatally failed. -static bool TestPartFatallyFailed(const TestPartResult & result) { +static bool TestPartFatallyFailed(const TestPartResult& result) { return result.fatally_failed(); } @@ -1861,6 +1861,16 @@ bool TestResult::HasFatalFailure() const { return test_part_results_.CountIf(TestPartFatallyFailed) > 0; } +// Returns true iff the test part non-fatally failed. +static bool TestPartNonfatallyFailed(const TestPartResult& result) { + return result.nonfatally_failed(); +} + +// Returns true iff the test has a non-fatal failure. +bool TestResult::HasNonfatalFailure() const { + return test_part_results_.CountIf(TestPartNonfatallyFailed) > 0; +} + // Gets the number of all test parts. This is the sum of the number // of successful test parts and the number of failed test parts. int TestResult::total_part_count() const { @@ -2059,6 +2069,12 @@ bool Test::HasFatalFailure() { return internal::GetUnitTestImpl()->current_test_result()->HasFatalFailure(); } +// Returns true iff the current test has a non-fatal failure. +bool Test::HasNonfatalFailure() { + return internal::GetUnitTestImpl()->current_test_result()-> + HasNonfatalFailure(); +} + // class TestInfo // Constructs a TestInfo object. It assumes ownership of the test factory -- cgit v1.2.3 From 7fa242a44b47ce74d7246440b14571f7a5dd1b17 Mon Sep 17 00:00:00 2001 From: "zhanyong.wan" Date: Thu, 9 Apr 2009 02:57:38 +0000 Subject: Makes the Python tests more stable (by Vlad Losev); fixes a memory leak in GetThreadCount() on Mac (by Vlad Losev); improves fuse_gtest_files.py to support fusing Google Mock files (by Zhanyong Wan). --- src/gtest-port.cc | 28 ++++++++++++++++++++++------ 1 file changed, 22 insertions(+), 6 deletions(-) (limited to 'src') diff --git a/src/gtest-port.cc b/src/gtest-port.cc index 193f5323..3c1e80c2 100644 --- a/src/gtest-port.cc +++ b/src/gtest-port.cc @@ -45,6 +45,7 @@ #if GTEST_OS_MAC #include #include +#include #endif // GTEST_OS_MAC #ifdef _WIN32_WCE @@ -74,22 +75,37 @@ const int kStdErrFileno = 2; const int kStdErrFileno = STDERR_FILENO; #endif // _MSC_VER +#if GTEST_OS_MAC + // Returns the number of threads running in the process, or 0 to indicate that // we cannot detect it. size_t GetThreadCount() { -#if GTEST_OS_MAC + const task_t task = mach_task_self(); mach_msg_type_number_t thread_count; - thread_act_port_array_t thread_list; - kern_return_t status = task_threads(mach_task_self(), - &thread_list, &thread_count); - return status == KERN_SUCCESS ? static_cast(thread_count) : 0; + thread_act_array_t thread_list; + const kern_return_t status = task_threads(task, &thread_list, &thread_count); + if (status == KERN_SUCCESS) { + // task_threads allocates resources in thread_list and we need to free them + // to avoid leaks. + vm_deallocate(task, + reinterpret_cast(thread_list), + sizeof(thread_t) * thread_count); + return static_cast(thread_count); + } else { + return 0; + } +} + #else + +size_t GetThreadCount() { // There's no portable way to detect the number of threads, so we just // return 0 to indicate that we cannot detect it. return 0; -#endif // GTEST_OS_MAC } +#endif // GTEST_OS_MAC + #if GTEST_USES_POSIX_RE // Implements RE. Currently only needed for death tests. -- cgit v1.2.3 From f204cd89e591e8cda022f4b471962c8556e19b8c Mon Sep 17 00:00:00 2001 From: "zhanyong.wan" Date: Tue, 14 Apr 2009 23:19:22 +0000 Subject: Makes gtest print elapsed time by default. --- src/gtest.cc | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) (limited to 'src') diff --git a/src/gtest.cc b/src/gtest.cc index 5903f2ae..b77f62e7 100644 --- a/src/gtest.cc +++ b/src/gtest.cc @@ -211,7 +211,7 @@ GTEST_DEFINE_string_( GTEST_DEFINE_bool_( print_time, - internal::BoolFromGTestEnv("print_time", false), + internal::BoolFromGTestEnv("print_time", true), "True iff " GTEST_NAME_ " should display elapsed time in text output."); @@ -4141,8 +4141,8 @@ static const char kColorEncodedHelpMessage[] = "Test Output:\n" " @G--" GTEST_FLAG_PREFIX_ "color=@Y(@Gyes@Y|@Gno@Y|@Gauto@Y)@D\n" " Enable/disable colored output. The default is @Gauto@D.\n" -" -@G-" GTEST_FLAG_PREFIX_ "print_time@D\n" -" Print the elapsed time of each test.\n" +" -@G-" GTEST_FLAG_PREFIX_ "print_time=0@D\n" +" Don't print the elapsed time of each test.\n" " @G--" GTEST_FLAG_PREFIX_ "output=xml@Y[@G:@YDIRECTORY_PATH@G" GTEST_PATH_SEP_ "@Y|@G:@YFILE_PATH]@D\n" " Generate an XML report in the given directory or with the given file\n" @@ -4165,10 +4165,9 @@ static const char kColorEncodedHelpMessage[] = "Except for @G--" GTEST_FLAG_PREFIX_ "list_tests@D, you can alternatively set " "the corresponding\n" "environment variable of a flag (all letters in upper-case). For example, to\n" -"print the elapsed time, you can either specify @G--" GTEST_FLAG_PREFIX_ - "print_time@D or set the\n" -"@G" GTEST_FLAG_PREFIX_UPPER_ "PRINT_TIME@D environment variable to a " - "non-zero value.\n" +"disable colored text output, you can either specify @G--" GTEST_FLAG_PREFIX_ + "color=no@D or set\n" +"the @G" GTEST_FLAG_PREFIX_UPPER_ "COLOR@D environment variable to @Gno@D.\n" "\n" "For more information, please read the " GTEST_NAME_ " documentation at\n" "@G" GTEST_PROJECT_URL_ "@D. If you find a bug in " GTEST_NAME_ "\n" -- cgit v1.2.3 From f2d0d0e3d56794855d1e9a1f157457b7225e8c88 Mon Sep 17 00:00:00 2001 From: "zhanyong.wan" Date: Fri, 24 Apr 2009 00:26:25 +0000 Subject: Renames the POSIX wrappers (by Zhanyong Wan) and adds more targets to SConscript (by Vlad Losev). --- src/gtest-death-test.cc | 14 +++++++------- src/gtest-filepath.cc | 8 ++++---- src/gtest-port.cc | 12 ++++++------ src/gtest-test-part.cc | 2 +- src/gtest.cc | 22 +++++++++++----------- 5 files changed, 29 insertions(+), 29 deletions(-) (limited to 'src') diff --git a/src/gtest-death-test.cc b/src/gtest-death-test.cc index 517495b5..0d4110bd 100644 --- a/src/gtest-death-test.cc +++ b/src/gtest-death-test.cc @@ -204,7 +204,7 @@ void DeathTestAbort(const String& message) { const InternalRunDeathTestFlag* const flag = GetUnitTestImpl()->internal_run_death_test_flag(); if (flag != NULL) { - FILE* parent = posix::fdopen(flag->write_fd(), "w"); + FILE* parent = posix::FDOpen(flag->write_fd(), "w"); fputc(kDeathTestInternalError, parent); fprintf(parent, "%s", message.c_str()); fflush(parent); @@ -249,7 +249,7 @@ void DeathTestAbort(const String& message) { // Returns the message describing the last system error in errno. String GetLastErrnoDescription() { - return String(errno == 0 ? "" : posix::strerror(errno)); + return String(errno == 0 ? "" : posix::StrError(errno)); } // This is called from a death test parent process to read a failure @@ -262,7 +262,7 @@ static void FailFromInternalError(int fd) { int num_read; do { - while ((num_read = posix::read(fd, buffer, 255)) > 0) { + while ((num_read = posix::Read(fd, buffer, 255)) > 0) { buffer[num_read] = '\0'; error << buffer; } @@ -380,7 +380,7 @@ void DeathTestImpl::ReadAndInterpretStatusByte() { // its success), so it's okay to call this in the parent before // the child process has exited. do { - bytes_read = posix::read(read_fd(), &flag, 1); + bytes_read = posix::Read(read_fd(), &flag, 1); } while (bytes_read == -1 && errno == EINTR); if (bytes_read == 0) { @@ -407,7 +407,7 @@ void DeathTestImpl::ReadAndInterpretStatusByte() { Message() << "Read from death test child process failed: " << GetLastErrnoDescription()); } - GTEST_DEATH_TEST_CHECK_SYSCALL_(posix::close(read_fd())); + GTEST_DEATH_TEST_CHECK_SYSCALL_(posix::Close(read_fd())); set_read_fd(-1); } @@ -421,8 +421,8 @@ void DeathTestImpl::Abort(AbortReason reason) { // to the pipe, then exit. const char status_ch = reason == TEST_DID_NOT_DIE ? kDeathTestLived : kDeathTestReturned; - GTEST_DEATH_TEST_CHECK_SYSCALL_(posix::write(write_fd(), &status_ch, 1)); - GTEST_DEATH_TEST_CHECK_SYSCALL_(posix::close(write_fd())); + GTEST_DEATH_TEST_CHECK_SYSCALL_(posix::Write(write_fd(), &status_ch, 1)); + GTEST_DEATH_TEST_CHECK_SYSCALL_(posix::Close(write_fd())); _exit(1); // Exits w/o any normal exit hooks (we were supposed to crash) } diff --git a/src/gtest-filepath.cc b/src/gtest-filepath.cc index 7ba6a6b7..3180d0d5 100644 --- a/src/gtest-filepath.cc +++ b/src/gtest-filepath.cc @@ -168,8 +168,8 @@ bool FilePath::FileOrDirectoryExists() const { delete [] unicode; return attributes != kInvalidFileAttributes; #else - posix::stat_struct file_stat; - return posix::stat(pathname_.c_str(), &file_stat) == 0; + posix::StatStruct file_stat; + return posix::Stat(pathname_.c_str(), &file_stat) == 0; #endif // _WIN32_WCE } @@ -195,8 +195,8 @@ bool FilePath::DirectoryExists() const { result = true; } #else - posix::stat_struct file_stat; - result = posix::stat(path.c_str(), &file_stat) == 0 && + posix::StatStruct file_stat; + result = posix::Stat(path.c_str(), &file_stat) == 0 && posix::IsDir(file_stat); #endif // _WIN32_WCE diff --git a/src/gtest-port.cc b/src/gtest-port.cc index 3c1e80c2..e5c793f8 100644 --- a/src/gtest-port.cc +++ b/src/gtest-port.cc @@ -539,9 +539,9 @@ void CaptureStderr() { ::std::string GetCapturedStderr() { g_captured_stderr->StopCapture(); - FILE* const file = posix::fopen(g_captured_stderr->filename().c_str(), "r"); + FILE* const file = posix::FOpen(g_captured_stderr->filename().c_str(), "r"); const ::std::string content = ReadEntireFile(file); - posix::fclose(file); + posix::FClose(file); delete g_captured_stderr; g_captured_stderr = NULL; @@ -563,7 +563,7 @@ const ::std::vector& GetArgvs() { return g_argvs; } #ifdef _WIN32_WCE namespace posix { -void abort() { +void Abort() { DebugBreak(); TerminateProcess(GetCurrentProcess(), 1); } @@ -632,7 +632,7 @@ bool ParseInt32(const Message& src_text, const char* str, Int32* value) { // The value is considered true iff it's not "0". bool BoolFromGTestEnv(const char* flag, bool default_value) { const String env_var = FlagToEnvVar(flag); - const char* const string_value = posix::getenv(env_var.c_str()); + const char* const string_value = posix::GetEnv(env_var.c_str()); return string_value == NULL ? default_value : strcmp(string_value, "0") != 0; } @@ -642,7 +642,7 @@ bool BoolFromGTestEnv(const char* flag, bool default_value) { // doesn't represent a valid 32-bit integer, returns default_value. Int32 Int32FromGTestEnv(const char* flag, Int32 default_value) { const String env_var = FlagToEnvVar(flag); - const char* const string_value = posix::getenv(env_var.c_str()); + const char* const string_value = posix::GetEnv(env_var.c_str()); if (string_value == NULL) { // The environment variable is not set. return default_value; @@ -664,7 +664,7 @@ Int32 Int32FromGTestEnv(const char* flag, Int32 default_value) { // the given flag; if it's not set, returns default_value. const char* StringFromGTestEnv(const char* flag, const char* default_value) { const String env_var = FlagToEnvVar(flag); - const char* const value = posix::getenv(env_var.c_str()); + const char* const value = posix::GetEnv(env_var.c_str()); return value == NULL ? default_value : value; } diff --git a/src/gtest-test-part.cc b/src/gtest-test-part.cc index b9ca6b73..9aacd2be 100644 --- a/src/gtest-test-part.cc +++ b/src/gtest-test-part.cc @@ -81,7 +81,7 @@ void TestPartResultArray::Append(const TestPartResult& result) { const TestPartResult& TestPartResultArray::GetTestPartResult(int index) const { if (index < 0 || index >= size()) { printf("\nInvalid index (%d) into TestPartResultArray.\n", index); - internal::posix::abort(); + internal::posix::Abort(); } const internal::ListNode* p = list_->Head(); diff --git a/src/gtest.cc b/src/gtest.cc index b77f62e7..6e01c1be 100644 --- a/src/gtest.cc +++ b/src/gtest.cc @@ -803,7 +803,7 @@ static char* CloneString(const char* str, size_t length) { return NULL; } else { char* const clone = new char[length + 1]; - posix::strncpy(clone, str, length); + posix::StrNCpy(clone, str, length); clone[length] = '\0'; return clone; } @@ -1443,7 +1443,7 @@ char* CodePointToUtf8(UInt32 code_point, char* str) { // the terminating nul character). We are asking for 32 character // buffer just in case. This is also enough for strncpy to // null-terminate the destination string. - posix::strncpy( + posix::StrNCpy( str, String::Format("(Invalid Unicode 0x%X)", code_point).c_str(), 32); str[31] = '\0'; // Makes sure no change in the format to strncpy leaves // the result unterminated. @@ -1586,7 +1586,7 @@ bool String::CaseInsensitiveCStringEquals(const char * lhs, const char * rhs) { return rhs == NULL; if (rhs == NULL) return false; - return posix::strcasecmp(lhs, rhs) == 0; + return posix::StrCaseCmp(lhs, rhs) == 0; } // Compares two wide C strings, ignoring case. Returns true iff they @@ -2510,7 +2510,7 @@ bool ShouldUseColor(bool stdout_is_tty) { return stdout_is_tty; #else // On non-Windows platforms, we rely on the TERM variable. - const char* const term = posix::getenv("TERM"); + const char* const term = posix::GetEnv("TERM"); const bool term_supports_color = String::CStringEquals(term, "xterm") || String::CStringEquals(term, "xterm-color") || @@ -2540,7 +2540,7 @@ void ColoredPrintf(GTestColor color, const char* fmt, ...) { const bool use_color = false; #else static const bool in_color_mode = - ShouldUseColor(posix::isatty(posix::fileno(stdout)) != 0); + ShouldUseColor(posix::IsATTY(posix::FileNo(stdout)) != 0); const bool use_color = in_color_mode && (color != COLOR_DEFAULT); #endif // defined(_WIN32_WCE) || GTEST_OS_SYMBIAN || GTEST_OS_ZOS // The '!= 0' comparison is necessary to satisfy MSVC 7.1. @@ -2622,8 +2622,8 @@ void PrettyUnitTestResultPrinter::OnUnitTestStart( if (internal::ShouldShard(kTestTotalShards, kTestShardIndex, false)) { ColoredPrintf(COLOR_YELLOW, "Note: This is test shard %s of %s.\n", - internal::posix::getenv(kTestShardIndex), - internal::posix::getenv(kTestTotalShards)); + internal::posix::GetEnv(kTestShardIndex), + internal::posix::GetEnv(kTestTotalShards)); } const internal::UnitTestImpl* const impl = unit_test->impl(); @@ -2941,7 +2941,7 @@ void XmlUnitTestResultPrinter::OnUnitTestEnd(const UnitTest* unit_test) { internal::FilePath output_dir(output_file.RemoveFileName()); if (output_dir.CreateDirectoriesRecursively()) { - xmlout = internal::posix::fopen(output_file_.c_str(), "w"); + xmlout = internal::posix::FOpen(output_file_.c_str(), "w"); } if (xmlout == NULL) { // TODO(wan): report the reason of the failure. @@ -3678,9 +3678,9 @@ int UnitTestImpl::RunAllTests() { // function will write over it. If the variable is present, but the file cannot // be created, prints an error and exits. void WriteToShardStatusFileIfNeeded() { - const char* const test_shard_file = posix::getenv(kTestShardStatusFile); + const char* const test_shard_file = posix::GetEnv(kTestShardStatusFile); if (test_shard_file != NULL) { - FILE* const file = posix::fopen(test_shard_file, "w"); + FILE* const file = posix::FOpen(test_shard_file, "w"); if (file == NULL) { ColoredPrintf(COLOR_RED, "Could not write to the test shard status file \"%s\" " @@ -3745,7 +3745,7 @@ bool ShouldShard(const char* total_shards_env, // returns default_val. If it is not an Int32, prints an error // and aborts. Int32 Int32FromEnvOrDie(const char* const var, Int32 default_val) { - const char* str_val = posix::getenv(var); + const char* str_val = posix::GetEnv(var); if (str_val == NULL) { return default_val; } -- cgit v1.2.3 From fa2b06c52fa3ffb1909ed8b928e106292609cfcb Mon Sep 17 00:00:00 2001 From: "zhanyong.wan" Date: Fri, 24 Apr 2009 20:27:29 +0000 Subject: Makes --gtest_list_tests honor the test filter (by Jay Campan). --- src/gtest-internal-inl.h | 12 ++++++++++-- src/gtest.cc | 47 +++++++++++++++++++++++++++++------------------ 2 files changed, 39 insertions(+), 20 deletions(-) (limited to 'src') diff --git a/src/gtest-internal-inl.h b/src/gtest-internal-inl.h index 2a90edac..26d1bd1d 100644 --- a/src/gtest-internal-inl.h +++ b/src/gtest-internal-inl.h @@ -621,6 +621,12 @@ class TestInfoImpl { // Sets the is_disabled member. void set_is_disabled(bool is) { is_disabled_ = is; } + // Returns true if this test matches the filter specified by the user. + bool matches_filter() const { return matches_filter_; } + + // Sets the matches_filter member. + void set_matches_filter(bool matches) { matches_filter_ = matches; } + // Returns the test case name. const char* test_case_name() const { return test_case_name_.c_str(); } @@ -667,6 +673,8 @@ class TestInfoImpl { const TypeId fixture_class_id_; // ID of the test fixture class bool should_run_; // True iff this test should run bool is_disabled_; // True iff this test is disabled + bool matches_filter_; // True if this test matches the + // user-specified filter. internal::TestFactoryBase* const factory_; // The factory that creates // the test object @@ -1164,8 +1172,8 @@ class UnitTestImpl { // Returns the number of tests that should run. int FilterTests(ReactionToSharding shard_tests); - // Lists all the tests by name. - void ListAllTests(); + // Prints the names of the tests matching the user-specified filter flag. + void ListTestsMatchingFilter(); const TestCase* current_test_case() const { return current_test_case_; } TestInfo* current_test_info() { return current_test_info_; } diff --git a/src/gtest.cc b/src/gtest.cc index 6e01c1be..4a1b21f9 100644 --- a/src/gtest.cc +++ b/src/gtest.cc @@ -2172,6 +2172,9 @@ const char* TestInfo::comment() const { // Returns true if this test should run. bool TestInfo::should_run() const { return impl_->should_run(); } +// Returns true if this test matches the user-specified filter. +bool TestInfo::matches_filter() const { return impl_->matches_filter(); } + // Returns the result of the test. const internal::TestResult* TestInfo::result() const { return impl_->result(); } @@ -3297,8 +3300,8 @@ void UnitTest::AddTestPartResult(TestPartResultType result_type, ReportTestPartResult(result); if (result_type != TPRT_SUCCESS) { - // gunit_break_on_failure takes precedence over - // gunit_throw_on_failure. This allows a user to set the latter + // gtest_break_on_failure takes precedence over + // gtest_throw_on_failure. This allows a user to set the latter // in the code (perhaps in order to use Google Test assertions // with another testing framework) and specify the former on the // command line for debugging. @@ -3591,13 +3594,6 @@ int UnitTestImpl::RunAllTests() { // protocol. internal::WriteToShardStatusFileIfNeeded(); - // Lists all the tests and exits if the --gtest_list_tests - // flag was specified. - if (GTEST_FLAG(list_tests)) { - ListAllTests(); - return 0; - } - // True iff we are in a subprocess for running a thread-safe-style // death test. bool in_subprocess_for_death_test = false; @@ -3618,6 +3614,13 @@ int UnitTestImpl::RunAllTests() { ? HONOR_SHARDING_PROTOCOL : IGNORE_SHARDING_PROTOCOL) > 0; + // List the tests and exit if the --gtest_list_tests flag was specified. + if (GTEST_FLAG(list_tests)) { + // This must be called *after* FilterTests() has been called. + ListTestsMatchingFilter(); + return 0; + } + // True iff at least one test has failed. bool failed = false; @@ -3808,10 +3811,14 @@ int UnitTestImpl::FilterTests(ReactionToSharding shard_tests) { kDisableTestFilter); test_info->impl()->set_is_disabled(is_disabled); - const bool is_runnable = - (GTEST_FLAG(also_run_disabled_tests) || !is_disabled) && + const bool matches_filter = internal::UnitTestOptions::FilterMatchesTest(test_case_name, test_name); + test_info->impl()->set_matches_filter(matches_filter); + + const bool is_runnable = + (GTEST_FLAG(also_run_disabled_tests) || !is_disabled) && + matches_filter; const bool is_selected = is_runnable && (shard_tests == IGNORE_SHARDING_PROTOCOL || @@ -3828,23 +3835,26 @@ int UnitTestImpl::FilterTests(ReactionToSharding shard_tests) { return num_selected_tests; } -// Lists all tests by name. -void UnitTestImpl::ListAllTests() { +// Prints the names of the tests matching the user-specified filter flag. +void UnitTestImpl::ListTestsMatchingFilter() { for (const internal::ListNode* test_case_node = test_cases_.Head(); test_case_node != NULL; test_case_node = test_case_node->next()) { const TestCase* const test_case = test_case_node->element(); - - // Prints the test case name following by an indented list of test nodes. - printf("%s.\n", test_case->name()); + bool printed_test_case_name = false; for (const internal::ListNode* test_info_node = test_case->test_info_list().Head(); test_info_node != NULL; test_info_node = test_info_node->next()) { const TestInfo* const test_info = test_info_node->element(); - - printf(" %s\n", test_info->name()); + if (test_info->matches_filter()) { + if (!printed_test_case_name) { + printed_test_case_name = true; + printf("%s.\n", test_case->name()); + } + printf(" %s\n", test_info->name()); + } } } fflush(stdout); @@ -3941,6 +3951,7 @@ TestInfoImpl::TestInfoImpl(TestInfo* parent, fixture_class_id_(fixture_class_id), should_run_(false), is_disabled_(false), + matches_filter_(false), factory_(factory) { } -- cgit v1.2.3 From f2334aa19555063791ec16fe2b476ec00195bbb8 Mon Sep 17 00:00:00 2001 From: "zhanyong.wan" Date: Sat, 25 Apr 2009 04:42:30 +0000 Subject: Ports gtest to minGW (by Kenton Varda). --- src/gtest.cc | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) (limited to 'src') diff --git a/src/gtest.cc b/src/gtest.cc index 4a1b21f9..a7118055 100644 --- a/src/gtest.cc +++ b/src/gtest.cc @@ -2013,8 +2013,8 @@ void Test::Run() { if (!HasSameFixtureClass()) return; internal::UnitTestImpl* const impl = internal::GetUnitTestImpl(); -#if GTEST_OS_WINDOWS - // We are on Windows. +#if GTEST_HAS_SEH + // Catch SEH-style exceptions. impl->os_stack_trace_getter()->UponLeavingGTest(); __try { SetUp(); @@ -2045,7 +2045,7 @@ void Test::Run() { AddExceptionThrownFailure(GetExceptionCode(), "TearDown()"); } -#else // We are on Linux or Mac - exceptions are disabled. +#else // We are on a compiler or platform that doesn't support SEH. impl->os_stack_trace_getter()->UponLeavingGTest(); SetUp(); @@ -2060,7 +2060,7 @@ void Test::Run() { // failed. impl->os_stack_trace_getter()->UponLeavingGTest(); TearDown(); -#endif // GTEST_OS_WINDOWS +#endif // GTEST_HAS_SEH } @@ -2256,8 +2256,8 @@ void TestInfoImpl::Run() { const TimeInMillis start = GetTimeInMillis(); impl->os_stack_trace_getter()->UponLeavingGTest(); -#if GTEST_OS_WINDOWS - // We are on Windows. +#if GTEST_HAS_SEH + // Catch SEH-style exceptions. Test* test = NULL; __try { @@ -2269,7 +2269,7 @@ void TestInfoImpl::Run() { "the test fixture's constructor"); return; } -#else // We are on Linux or Mac OS - exceptions are disabled. +#else // We are on a compiler or platform that doesn't support SEH. // TODO(wan): If test->Run() throws, test won't be deleted. This is // not a problem now as we don't use exceptions. If we were to @@ -2278,7 +2278,7 @@ void TestInfoImpl::Run() { // Creates the test object. Test* test = factory_->CreateTest(); -#endif // GTEST_OS_WINDOWS +#endif // GTEST_HAS_SEH // Runs the test only if the constructor of the test fixture didn't // generate a fatal failure. @@ -3333,7 +3333,8 @@ void UnitTest::RecordPropertyForCurrentTest(const char* key, // We don't protect this under mutex_, as we only support calling it // from the main thread. int UnitTest::Run() { -#if GTEST_OS_WINDOWS +#if GTEST_HAS_SEH + // Catch SEH-style exceptions. const bool in_death_test_child_process = internal::GTEST_FLAG(internal_run_death_test).GetLength() > 0; @@ -3381,11 +3382,10 @@ int UnitTest::Run() { return 1; } -#else - // We are on Linux or Mac OS. There is no exception of any kind. +#else // We are on a compiler or platform that doesn't support SEH. return impl_->RunAllTests(); -#endif // GTEST_OS_WINDOWS +#endif // GTEST_HAS_SEH } // Returns the working directory when the first TEST() or TEST_F() was -- cgit v1.2.3 From c78ae6196dc9c24380b5cf86f8fd75a4d3edc704 Mon Sep 17 00:00:00 2001 From: "zhanyong.wan" Date: Tue, 28 Apr 2009 00:28:09 +0000 Subject: Ports gtest to C++Builder, by Josh Kelley. --- src/gtest-filepath.cc | 25 ++++++++++++++++--------- src/gtest-port.cc | 4 ++-- src/gtest.cc | 21 +++++++++++++++------ 3 files changed, 33 insertions(+), 17 deletions(-) (limited to 'src') diff --git a/src/gtest-filepath.cc b/src/gtest-filepath.cc index 3180d0d5..f966352b 100644 --- a/src/gtest-filepath.cc +++ b/src/gtest-filepath.cc @@ -88,10 +88,10 @@ FilePath FilePath::GetCurrentDir() { // something reasonable. return FilePath(kCurrentDirectoryString); #elif GTEST_OS_WINDOWS - char cwd[GTEST_PATH_MAX_ + 1] = {}; + char cwd[GTEST_PATH_MAX_ + 1] = { '\0' }; return FilePath(_getcwd(cwd, sizeof(cwd)) == NULL ? "" : cwd); #else - char cwd[GTEST_PATH_MAX_ + 1] = {}; + char cwd[GTEST_PATH_MAX_ + 1] = { '\0' }; return FilePath(getcwd(cwd, sizeof(cwd)) == NULL ? "" : cwd); #endif } @@ -127,8 +127,13 @@ FilePath FilePath::RemoveDirectoryName() const { // On Windows platform, '\' is the path separator, otherwise it is '/'. FilePath FilePath::RemoveFileName() const { const char* const last_sep = strrchr(c_str(), kPathSeparator); - return FilePath(last_sep ? String(c_str(), last_sep + 1 - c_str()) - : String(kCurrentDirectoryString)); + String dir; + if (last_sep) { + dir = String(c_str(), last_sep + 1 - c_str()); + } else { + dir = kCurrentDirectoryString; + } + return FilePath(dir); } // Helper functions for naming files in a directory for xml output. @@ -141,11 +146,13 @@ FilePath FilePath::MakeFileName(const FilePath& directory, const FilePath& base_name, int number, const char* extension) { - const FilePath file_name( - (number == 0) ? - String::Format("%s.%s", base_name.c_str(), extension) : - String::Format("%s_%d.%s", base_name.c_str(), number, extension)); - return ConcatPaths(directory, file_name); + String file; + if (number == 0) { + file = String::Format("%s.%s", base_name.c_str(), extension); + } else { + file = String::Format("%s_%d.%s", base_name.c_str(), number, extension); + } + return ConcatPaths(directory, FilePath(file)); } // Given directory = "dir", relative_path = "test.xml", returns "dir/test.xml". diff --git a/src/gtest-port.cc b/src/gtest-port.cc index e5c793f8..7f6db79f 100644 --- a/src/gtest-port.cc +++ b/src/gtest-port.cc @@ -68,8 +68,8 @@ namespace testing { namespace internal { -#ifdef _MSC_VER -// MSVC does not provide a definition of STDERR_FILENO. +#if defined(_MSC_VER) || defined(__BORLANDC__) +// MSVC and C++Builder do not provide a definition of STDERR_FILENO. const int kStdErrFileno = 2; #else const int kStdErrFileno = STDERR_FILENO; diff --git a/src/gtest.cc b/src/gtest.cc index a7118055..48807671 100644 --- a/src/gtest.cc +++ b/src/gtest.cc @@ -735,10 +735,11 @@ String UnitTestImpl::CurrentOsStackTraceExceptTop(int skip_count) { } static TimeInMillis GetTimeInMillis() { -#ifdef _WIN32_WCE // We are on Windows CE +#if defined(_WIN32_WCE) || defined(__BORLANDC__) // Difference between 1970-01-01 and 1601-01-01 in miliseconds. // http://analogous.blogspot.com/2005/04/epoch.html - const TimeInMillis kJavaEpochToWinFileTimeDelta = 11644473600000UL; + const TimeInMillis kJavaEpochToWinFileTimeDelta = + static_cast(116444736UL) * 100000UL; const DWORD kTenthMicrosInMilliSecond = 10000; SYSTEMTIME now_systime; @@ -3221,13 +3222,18 @@ UnitTest * UnitTest::GetInstance() { // different implementation in this case to bypass the compiler bug. // This implementation makes the compiler happy, at the cost of // leaking the UnitTest object. -#if _MSC_VER == 1310 && !defined(_DEBUG) // MSVC 7.1 and optimized build. + + // CodeGear C++Builder insists on a public destructor for the + // default implementation. Use this implementation to keep good OO + // design with private destructor. + +#if (_MSC_VER == 1310 && !defined(_DEBUG)) || defined(__BORLANDC__) static UnitTest* const instance = new UnitTest; return instance; #else static UnitTest instance; return &instance; -#endif // _MSC_VER==1310 && !defined(_DEBUG) +#endif // (_MSC_VER == 1310 && !defined(_DEBUG)) || defined(__BORLANDC__) } // Registers and returns a global test environment. When a test @@ -3259,7 +3265,7 @@ Environment* UnitTest::AddEnvironment(Environment* env) { class GoogleTestFailureException : public ::std::runtime_error { public: explicit GoogleTestFailureException(const TestPartResult& failure) - : runtime_error(PrintTestPartResultToString(failure).c_str()) {} + : ::std::runtime_error(PrintTestPartResultToString(failure).c_str()) {} }; #endif @@ -3350,17 +3356,20 @@ int UnitTest::Run() { SEM_NOGPFAULTERRORBOX | SEM_NOOPENFILEERRORBOX); #endif // _WIN32_WCE +#if defined(_MSC_VER) || defined(__MINGW32__) // Death test children can be terminated with _abort(). On Windows, // _abort() can show a dialog with a warning message. This forces the // abort message to go to stderr instead. _set_error_mode(_OUT_TO_STDERR); +#endif +#if _MSC_VER >= 1400 // In the debug version, Visual Studio pops up a separate dialog // offering a choice to debug the aborted program. We need to suppress // this dialog or it will pop up for every EXPECT/ASSERT_DEATH statement // executed. Google Test will notify the user of any unexpected // failure via stderr. -#if _MSC_VER >= 1400 + // // VC++ doesn't define _set_abort_behavior() prior to the version 8.0. // Users of prior VC versions shall suffer the agony and pain of // clicking through the countless debug dialogs. -- cgit v1.2.3 From 42abea350d4f26a006f760fae0d1f9882deb9221 Mon Sep 17 00:00:00 2001 From: "zhanyong.wan" Date: Tue, 5 May 2009 23:13:43 +0000 Subject: Uses DebugBreak() to properly break on Windows (by Vlad Losev). --- src/gtest.cc | 7 +++++++ 1 file changed, 7 insertions(+) (limited to 'src') diff --git a/src/gtest.cc b/src/gtest.cc index 48807671..6fc4044d 100644 --- a/src/gtest.cc +++ b/src/gtest.cc @@ -3312,7 +3312,14 @@ void UnitTest::AddTestPartResult(TestPartResultType result_type, // with another testing framework) and specify the former on the // command line for debugging. if (GTEST_FLAG(break_on_failure)) { +#if GTEST_OS_WINDOWS + // Using DebugBreak on Windows allows gtest to still break into a debugger + // when a failure happens and both the --gtest_break_on_failure and + // the --gtest_catch_exceptions flags are specified. + DebugBreak(); +#else *static_cast(NULL) = 1; +#endif // GTEST_OS_WINDOWS } else if (GTEST_FLAG(throw_on_failure)) { #if GTEST_HAS_EXCEPTIONS throw GoogleTestFailureException(result); -- cgit v1.2.3 From fd36c200f446aaada1a1f0b026f2d742d4b2fa5a Mon Sep 17 00:00:00 2001 From: "zhanyong.wan" Date: Tue, 9 Jun 2009 05:38:14 +0000 Subject: Adds support for xterm-256color (by Michihiro Kuramochi). --- src/gtest.cc | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'src') diff --git a/src/gtest.cc b/src/gtest.cc index 6fc4044d..c093bce9 100644 --- a/src/gtest.cc +++ b/src/gtest.cc @@ -183,7 +183,7 @@ GTEST_DEFINE_string_( "Whether to use colors in the output. Valid values: yes, no, " "and auto. 'auto' means to use colors if the output is " "being sent to a terminal and the TERM environment variable " - "is set to xterm or xterm-color."); + "is set to xterm, xterm-color, xterm-256color or cygwin."); GTEST_DEFINE_string_( filter, @@ -2518,6 +2518,7 @@ bool ShouldUseColor(bool stdout_is_tty) { const bool term_supports_color = String::CStringEquals(term, "xterm") || String::CStringEquals(term, "xterm-color") || + String::CStringEquals(term, "xterm-256color") || String::CStringEquals(term, "cygwin"); return stdout_is_tty && term_supports_color; #endif // GTEST_OS_WINDOWS -- cgit v1.2.3 From ae3247986bbbafcc913b5fe6132090ad6f1c3f36 Mon Sep 17 00:00:00 2001 From: "zhanyong.wan" Date: Fri, 19 Jun 2009 00:24:28 +0000 Subject: Fixes broken gtest_unittest on Cygwin and cleans it up (by Vlad Losev); fixes the wrong usage of os.environ.clear() in gtest_output_test.py (by Vlad Losev); fixes the logic for detecting Symbian (by Zhanyong Wan); moves TestProperty for event listener (by Vlad Losev). --- src/gtest-internal-inl.h | 35 ----------------------------------- 1 file changed, 35 deletions(-) (limited to 'src') diff --git a/src/gtest-internal-inl.h b/src/gtest-internal-inl.h index 26d1bd1d..94c9d7ee 100644 --- a/src/gtest-internal-inl.h +++ b/src/gtest-internal-inl.h @@ -450,41 +450,6 @@ static void Delete(T * x) { delete x; } -// A copyable object representing a user specified test property which can be -// output as a key/value string pair. -// -// Don't inherit from TestProperty as its destructor is not virtual. -class TestProperty { - public: - // C'tor. TestProperty does NOT have a default constructor. - // Always use this constructor (with parameters) to create a - // TestProperty object. - TestProperty(const char* key, const char* value) : - key_(key), value_(value) { - } - - // Gets the user supplied key. - const char* key() const { - return key_.c_str(); - } - - // Gets the user supplied value. - const char* value() const { - return value_.c_str(); - } - - // Sets a new value, overriding the one supplied in the constructor. - void SetValue(const char* new_value) { - value_ = new_value; - } - - private: - // The key supplied by the user. - String key_; - // The value supplied by the user. - String value_; -}; - // A predicate that checks the key of a TestProperty against a known key. // // TestPropertyKeyIs is copyable. -- cgit v1.2.3 From 4853a503371f39aa22e14adcdecea71c09841e34 Mon Sep 17 00:00:00 2001 From: "zhanyong.wan" Date: Fri, 19 Jun 2009 17:23:54 +0000 Subject: Fixes compatibility with Windows CE and Symbian (By Tim Baverstock and Mika). --- src/gtest-internal-inl.h | 4 +++- src/gtest-port.cc | 13 ++++++++++++- src/gtest-typed-test.cc | 2 +- src/gtest.cc | 6 +++--- 4 files changed, 19 insertions(+), 6 deletions(-) (limited to 'src') diff --git a/src/gtest-internal-inl.h b/src/gtest-internal-inl.h index 94c9d7ee..f909a0ac 100644 --- a/src/gtest-internal-inl.h +++ b/src/gtest-internal-inl.h @@ -45,7 +45,9 @@ #error "It must not be included except by Google Test itself." #endif // GTEST_IMPLEMENTATION_ +#ifndef _WIN32_WCE #include +#endif // !_WIN32_WCE #include #include // For strtoll/_strtoul64. @@ -1072,7 +1074,7 @@ class UnitTestImpl { original_working_dir_.Set(FilePath::GetCurrentDir()); if (original_working_dir_.IsEmpty()) { printf("%s\n", "Failed to get the current working directory."); - abort(); + posix::Abort(); } } diff --git a/src/gtest-port.cc b/src/gtest-port.cc index 7f6db79f..bc6d8f80 100644 --- a/src/gtest-port.cc +++ b/src/gtest-port.cc @@ -36,8 +36,10 @@ #include #if GTEST_OS_WINDOWS +#ifndef _WIN32_WCE #include #include +#endif // _WIN32_WCE #else #include #endif // GTEST_OS_WINDOWS @@ -425,7 +427,7 @@ void GTestLog(GTestLogSeverity severity, const char* file, fprintf(stderr, "\n%s %s:%d: %s\n", marker, file, line, msg); if (severity == GTEST_FATAL) { fflush(NULL); // abort() is not guaranteed to flush open file streams. - abort(); + posix::Abort(); } } @@ -444,6 +446,10 @@ class CapturedStderr { public: // The ctor redirects stderr to a temporary file. CapturedStderr() { +#ifdef _WIN32_WCE + // Not supported on Windows CE. + posix::Abort(); +#else uncaptured_fd_ = dup(kStdErrFileno); #if GTEST_OS_WINDOWS @@ -465,19 +471,24 @@ class CapturedStderr { fflush(NULL); dup2(captured_fd, kStdErrFileno); close(captured_fd); +#endif // _WIN32_WCE } ~CapturedStderr() { +#ifndef _WIN32_WCE remove(filename_.c_str()); +#endif // _WIN32_WCE } // Stops redirecting stderr. void StopCapture() { +#ifndef _WIN32_WCE // Restores the original stream. fflush(NULL); dup2(uncaptured_fd_, kStdErrFileno); close(uncaptured_fd_); uncaptured_fd_ = -1; +#endif // !_WIN32_WCE } // Returns the name of the temporary file holding the stderr output. diff --git a/src/gtest-typed-test.cc b/src/gtest-typed-test.cc index e45e2abb..4a0f657d 100644 --- a/src/gtest-typed-test.cc +++ b/src/gtest-typed-test.cc @@ -86,7 +86,7 @@ const char* TypedTestCasePState::VerifyRegisteredTestNames( fprintf(stderr, "%s %s", FormatFileLocation(file, line).c_str(), errors_str.c_str()); fflush(stderr); - abort(); + posix::Abort(); } return registered_tests; diff --git a/src/gtest.cc b/src/gtest.cc index c093bce9..84784883 100644 --- a/src/gtest.cc +++ b/src/gtest.cc @@ -3364,14 +3364,14 @@ int UnitTest::Run() { SEM_NOGPFAULTERRORBOX | SEM_NOOPENFILEERRORBOX); #endif // _WIN32_WCE -#if defined(_MSC_VER) || defined(__MINGW32__) +#if (defined(_MSC_VER) || defined(__MINGW32__)) && !defined(_WIN32_WCE) // Death test children can be terminated with _abort(). On Windows, // _abort() can show a dialog with a warning message. This forces the // abort message to go to stderr instead. _set_error_mode(_OUT_TO_STDERR); #endif -#if _MSC_VER >= 1400 +#if _MSC_VER >= 1400 && !defined(_WIN32_WCE) // In the debug version, Visual Studio pops up a separate dialog // offering a choice to debug the aborted program. We need to suppress // this dialog or it will pop up for every EXPECT/ASSERT_DEATH statement @@ -3387,7 +3387,7 @@ int UnitTest::Run() { _set_abort_behavior( 0x0, // Clear the following flags: _WRITE_ABORT_MSG | _CALL_REPORTFAULT); // pop-up window, core dump. -#endif // _MSC_VER >= 1400 +#endif } __try { -- cgit v1.2.3 From 3c181b5657a51d73166c1012dad80ed3ee7a30ee Mon Sep 17 00:00:00 2001 From: "zhanyong.wan" Date: Fri, 19 Jun 2009 21:20:40 +0000 Subject: Moves TestResult from gtest-internal-inl.h to gtest.h to prepare for the even listener API work (by Vlad Losev); cleans up the scons script (by Zhanyong Wan). --- src/gtest-internal-inl.h | 96 ------------------------------------------------ src/gtest.cc | 29 +++++++++------ 2 files changed, 18 insertions(+), 107 deletions(-) (limited to 'src') diff --git a/src/gtest-internal-inl.h b/src/gtest-internal-inl.h index f909a0ac..cbe3dbfb 100644 --- a/src/gtest-internal-inl.h +++ b/src/gtest-internal-inl.h @@ -472,102 +472,6 @@ class TestPropertyKeyIs { String key_; }; -// The result of a single Test. This includes a list of -// TestPartResults, a list of TestProperties, a count of how many -// death tests there are in the Test, and how much time it took to run -// the Test. -// -// TestResult is not copyable. -class TestResult { - public: - // Creates an empty TestResult. - TestResult(); - - // D'tor. Do not inherit from TestResult. - ~TestResult(); - - // Gets the list of TestPartResults. - const internal::List & test_part_results() const { - return test_part_results_; - } - - // Gets the list of TestProperties. - const internal::List & test_properties() const { - return test_properties_; - } - - // Gets the number of successful test parts. - int successful_part_count() const; - - // Gets the number of failed test parts. - int failed_part_count() const; - - // Gets the number of all test parts. This is the sum of the number - // of successful test parts and the number of failed test parts. - int total_part_count() const; - - // Returns true iff the test passed (i.e. no test part failed). - bool Passed() const { return !Failed(); } - - // Returns true iff the test failed. - bool Failed() const { return failed_part_count() > 0; } - - // Returns true iff the test fatally failed. - bool HasFatalFailure() const; - - // Returns true iff the test has a non-fatal failure. - bool HasNonfatalFailure() const; - - // Returns the elapsed time, in milliseconds. - TimeInMillis elapsed_time() const { return elapsed_time_; } - - // Sets the elapsed time. - void set_elapsed_time(TimeInMillis elapsed) { elapsed_time_ = elapsed; } - - // Adds a test part result to the list. - void AddTestPartResult(const TestPartResult& test_part_result); - - // Adds a test property to the list. The property is validated and may add - // a non-fatal failure if invalid (e.g., if it conflicts with reserved - // key names). If a property is already recorded for the same key, the - // value will be updated, rather than storing multiple values for the same - // key. - void RecordProperty(const internal::TestProperty& test_property); - - // Adds a failure if the key is a reserved attribute of Google Test - // testcase tags. Returns true if the property is valid. - // TODO(russr): Validate attribute names are legal and human readable. - static bool ValidateTestProperty(const internal::TestProperty& test_property); - - // Returns the death test count. - int death_test_count() const { return death_test_count_; } - - // Increments the death test count, returning the new count. - int increment_death_test_count() { return ++death_test_count_; } - - // Clears the test part results. - void ClearTestPartResults() { test_part_results_.Clear(); } - - // Clears the object. - void Clear(); - private: - // Protects mutable state of the property list and of owned properties, whose - // values may be updated. - internal::Mutex test_properites_mutex_; - - // The list of TestPartResults - internal::List test_part_results_; - // The list of TestProperties - internal::List test_properties_; - // Running count of death tests. - int death_test_count_; - // The elapsed time, in milliseconds. - TimeInMillis elapsed_time_; - - // We disallow copying TestResult. - GTEST_DISALLOW_COPY_AND_ASSIGN_(TestResult); -}; // class TestResult - class TestInfoImpl { public: TestInfoImpl(TestInfo* parent, const char* test_case_name, diff --git a/src/gtest.cc b/src/gtest.cc index 84784883..cec4503e 100644 --- a/src/gtest.cc +++ b/src/gtest.cc @@ -1778,7 +1778,9 @@ String AppendUserMessage(const String& gtest_msg, // Creates an empty TestResult. TestResult::TestResult() - : death_test_count_(0), + : test_part_results_(new List), + test_properties_(new List), + death_test_count_(0), elapsed_time_(0) { } @@ -1786,9 +1788,14 @@ TestResult::TestResult() TestResult::~TestResult() { } +// Clears the test part results. +void TestResult::ClearTestPartResults() { + test_part_results_->Clear(); +} + // Adds a test part result to the list. void TestResult::AddTestPartResult(const TestPartResult& test_part_result) { - test_part_results_.PushBack(test_part_result); + test_part_results_->PushBack(test_part_result); } // Adds a test property to the list. If a property with the same key as the @@ -1800,9 +1807,9 @@ void TestResult::RecordProperty(const TestProperty& test_property) { } MutexLock lock(&test_properites_mutex_); ListNode* const node_with_matching_key = - test_properties_.FindIf(TestPropertyKeyIs(test_property.key())); + test_properties_->FindIf(TestPropertyKeyIs(test_property.key())); if (node_with_matching_key == NULL) { - test_properties_.PushBack(test_property); + test_properties_->PushBack(test_property); return; } TestProperty& property_with_matching_key = node_with_matching_key->element(); @@ -1826,8 +1833,8 @@ bool TestResult::ValidateTestProperty(const TestProperty& test_property) { // Clears the object. void TestResult::Clear() { - test_part_results_.Clear(); - test_properties_.Clear(); + test_part_results_->Clear(); + test_properties_->Clear(); death_test_count_ = 0; elapsed_time_ = 0; } @@ -1839,7 +1846,7 @@ static bool TestPartPassed(const TestPartResult & result) { // Gets the number of successful test parts. int TestResult::successful_part_count() const { - return test_part_results_.CountIf(TestPartPassed); + return test_part_results_->CountIf(TestPartPassed); } // Returns true iff the test part failed. @@ -1849,7 +1856,7 @@ static bool TestPartFailed(const TestPartResult & result) { // Gets the number of failed test parts. int TestResult::failed_part_count() const { - return test_part_results_.CountIf(TestPartFailed); + return test_part_results_->CountIf(TestPartFailed); } // Returns true iff the test part fatally failed. @@ -1859,7 +1866,7 @@ static bool TestPartFatallyFailed(const TestPartResult& result) { // Returns true iff the test fatally failed. bool TestResult::HasFatalFailure() const { - return test_part_results_.CountIf(TestPartFatallyFailed) > 0; + return test_part_results_->CountIf(TestPartFatallyFailed) > 0; } // Returns true iff the test part non-fatally failed. @@ -1869,13 +1876,13 @@ static bool TestPartNonfatallyFailed(const TestPartResult& result) { // Returns true iff the test has a non-fatal failure. bool TestResult::HasNonfatalFailure() const { - return test_part_results_.CountIf(TestPartNonfatallyFailed) > 0; + return test_part_results_->CountIf(TestPartNonfatallyFailed) > 0; } // Gets the number of all test parts. This is the sum of the number // of successful test parts and the number of failed test parts. int TestResult::total_part_count() const { - return test_part_results_.size(); + return test_part_results_->size(); } } // namespace internal -- cgit v1.2.3 From ef29ce3576240e51f289e49b2c4e156b414d6685 Mon Sep 17 00:00:00 2001 From: "zhanyong.wan" Date: Mon, 22 Jun 2009 23:29:24 +0000 Subject: Turns on exceptions when compiling gtest_output_test (by Vlad Losev); moves TestCase to gtest.h to prepare for the event listener API (by Vlad Losev). --- src/gtest-internal-inl.h | 134 ----------------------------------------------- src/gtest.cc | 27 +++++++++- 2 files changed, 25 insertions(+), 136 deletions(-) (limited to 'src') diff --git a/src/gtest-internal-inl.h b/src/gtest-internal-inl.h index cbe3dbfb..589be02e 100644 --- a/src/gtest-internal-inl.h +++ b/src/gtest-internal-inl.h @@ -556,140 +556,6 @@ class TestInfoImpl { GTEST_DISALLOW_COPY_AND_ASSIGN_(TestInfoImpl); }; -} // namespace internal - -// A test case, which consists of a list of TestInfos. -// -// TestCase is not copyable. -class TestCase { - public: - // Creates a TestCase with the given name. - // - // TestCase does NOT have a default constructor. Always use this - // constructor to create a TestCase object. - // - // Arguments: - // - // name: name of the test case - // set_up_tc: pointer to the function that sets up the test case - // tear_down_tc: pointer to the function that tears down the test case - TestCase(const char* name, const char* comment, - Test::SetUpTestCaseFunc set_up_tc, - Test::TearDownTestCaseFunc tear_down_tc); - - // Destructor of TestCase. - virtual ~TestCase(); - - // Gets the name of the TestCase. - const char* name() const { return name_.c_str(); } - - // Returns the test case comment. - const char* comment() const { return comment_.c_str(); } - - // Returns true if any test in this test case should run. - bool should_run() const { return should_run_; } - - // Sets the should_run member. - void set_should_run(bool should) { should_run_ = should; } - - // Gets the (mutable) list of TestInfos in this TestCase. - internal::List& test_info_list() { return *test_info_list_; } - - // Gets the (immutable) list of TestInfos in this TestCase. - const internal::List & test_info_list() const { - return *test_info_list_; - } - - // Gets the number of successful tests in this test case. - int successful_test_count() const; - - // Gets the number of failed tests in this test case. - int failed_test_count() const; - - // Gets the number of disabled tests in this test case. - int disabled_test_count() const; - - // Get the number of tests in this test case that should run. - int test_to_run_count() const; - - // Gets the number of all tests in this test case. - int total_test_count() const; - - // Returns true iff the test case passed. - bool Passed() const { return !Failed(); } - - // Returns true iff the test case failed. - bool Failed() const { return failed_test_count() > 0; } - - // Returns the elapsed time, in milliseconds. - internal::TimeInMillis elapsed_time() const { return elapsed_time_; } - - // Adds a TestInfo to this test case. Will delete the TestInfo upon - // destruction of the TestCase object. - void AddTestInfo(TestInfo * test_info); - - // Finds and returns a TestInfo with the given name. If one doesn't - // exist, returns NULL. - TestInfo* GetTestInfo(const char* test_name); - - // Clears the results of all tests in this test case. - void ClearResult(); - - // Clears the results of all tests in the given test case. - static void ClearTestCaseResult(TestCase* test_case) { - test_case->ClearResult(); - } - - // Runs every test in this TestCase. - void Run(); - - // Runs every test in the given TestCase. - static void RunTestCase(TestCase * test_case) { test_case->Run(); } - - // Returns true iff test passed. - static bool TestPassed(const TestInfo * test_info) { - const internal::TestInfoImpl* const impl = test_info->impl(); - return impl->should_run() && impl->result()->Passed(); - } - - // Returns true iff test failed. - static bool TestFailed(const TestInfo * test_info) { - const internal::TestInfoImpl* const impl = test_info->impl(); - return impl->should_run() && impl->result()->Failed(); - } - - // Returns true iff test is disabled. - static bool TestDisabled(const TestInfo * test_info) { - return test_info->impl()->is_disabled(); - } - - // Returns true if the given test should run. - static bool ShouldRunTest(const TestInfo *test_info) { - return test_info->impl()->should_run(); - } - - private: - // Name of the test case. - internal::String name_; - // Comment on the test case. - internal::String comment_; - // List of TestInfos. - internal::List* test_info_list_; - // Pointer to the function that sets up the test case. - Test::SetUpTestCaseFunc set_up_tc_; - // Pointer to the function that tears down the test case. - Test::TearDownTestCaseFunc tear_down_tc_; - // True iff any test in this test case should run. - bool should_run_; - // Elapsed time, in milliseconds. - internal::TimeInMillis elapsed_time_; - - // We disallow copying TestCases. - GTEST_DISALLOW_COPY_AND_ASSIGN_(TestCase); -}; - -namespace internal { - // Class UnitTestOptions. // // This class contains functions for processing options the user diff --git a/src/gtest.cc b/src/gtest.cc index cec4503e..f5b05b2d 100644 --- a/src/gtest.cc +++ b/src/gtest.cc @@ -129,6 +129,8 @@ namespace testing { +using internal::TestCase; + // Constants. // A test whose test case name or test name matches this filter is @@ -2309,8 +2311,6 @@ void TestInfoImpl::Run() { impl->set_current_test_info(NULL); } -} // namespace internal - // class TestCase // Gets the number of successful tests in this test case. @@ -2401,6 +2401,29 @@ void TestCase::ClearResult() { test_info_list_->ForEach(internal::TestInfoImpl::ClearTestResult); } +// Returns true iff test passed. +bool TestCase::TestPassed(const TestInfo * test_info) { + const internal::TestInfoImpl* const impl = test_info->impl(); + return impl->should_run() && impl->result()->Passed(); +} + +// Returns true iff test failed. +bool TestCase::TestFailed(const TestInfo * test_info) { + const internal::TestInfoImpl* const impl = test_info->impl(); + return impl->should_run() && impl->result()->Failed(); +} + +// Returns true iff test is disabled. +bool TestCase::TestDisabled(const TestInfo * test_info) { + return test_info->impl()->is_disabled(); +} + +// Returns true if the given test should run. +bool TestCase::ShouldRunTest(const TestInfo *test_info) { + return test_info->impl()->should_run(); +} + +} // namespace internal // class UnitTestEventListenerInterface -- cgit v1.2.3 From e6095deec89dcf5237948b3460d84a137622f16c Mon Sep 17 00:00:00 2001 From: "zhanyong.wan" Date: Wed, 24 Jun 2009 23:02:50 +0000 Subject: Makes gtest's tuple implementation work with Symbian 5th edition by bypassing 2 compiler bugs (by Zhanyong Wan); refactors for the event listener API (by Vlad Losev). --- src/gtest-internal-inl.h | 26 +++++ src/gtest.cc | 292 +++++++++++++++++++++++++++++++++-------------- 2 files changed, 230 insertions(+), 88 deletions(-) (limited to 'src') diff --git a/src/gtest-internal-inl.h b/src/gtest-internal-inl.h index 589be02e..3abe9a26 100644 --- a/src/gtest-internal-inl.h +++ b/src/gtest-internal-inl.h @@ -430,6 +430,26 @@ class List { return NULL; } + // Returns a pointer to the i-th element of the list, or NULL if i is not + // in range [0, size()). + const E* GetElement(int i) const { + if (i < 0 || i >= size()) + return NULL; + + const ListNode* node = Head(); + for (int index = 0; index < i && node != NULL; ++index, node = node->next()) + continue; + + return node ? &(node->element()) : NULL; + } + + // Returns the i-th element of the list, or default_value if i is not + // in range [0, size()). + E GetElementOr(int i, E default_value) const { + const E* element = GetElement(i); + return element ? *element : default_value; + } + private: ListNode* head_; // The first node of the list. ListNode* last_; // The last node of the list. @@ -765,6 +785,12 @@ class UnitTestImpl { return failed_test_case_count() > 0 || ad_hoc_test_result()->Failed(); } + // Gets the i-th test case among all the test cases. i can range from 0 to + // total_test_case_count() - 1. If i is not in that range, returns NULL. + const TestCase* GetTestCase(int i) const { + return test_cases_.GetElementOr(i, NULL); + } + // Returns the TestResult for the test that's currently running, or // the TestResult for the ad hoc test if no test is running. internal::TestResult* current_test_result(); diff --git a/src/gtest.cc b/src/gtest.cc index f5b05b2d..ec176918 100644 --- a/src/gtest.cc +++ b/src/gtest.cc @@ -468,40 +468,80 @@ int UnitTestOptions::GTestShouldProcessSEH(DWORD exception_code) { class UnitTestEventListenerInterface { public: // The d'tor is pure virtual as this is an abstract class. - virtual ~UnitTestEventListenerInterface() = 0; + virtual ~UnitTestEventListenerInterface() {} // Called before the unit test starts. - virtual void OnUnitTestStart(const UnitTest*) {} + virtual void OnUnitTestStart(const UnitTest& unit_test) = 0; // Called after the unit test ends. - virtual void OnUnitTestEnd(const UnitTest*) {} + virtual void OnUnitTestEnd(const UnitTest& unit_test) = 0; // Called before the test case starts. - virtual void OnTestCaseStart(const TestCase*) {} + virtual void OnTestCaseStart(const TestCase& test_case) = 0; // Called after the test case ends. - virtual void OnTestCaseEnd(const TestCase*) {} + virtual void OnTestCaseEnd(const TestCase& test_case) = 0; // Called before the global set-up starts. - virtual void OnGlobalSetUpStart(const UnitTest*) {} + virtual void OnGlobalSetUpStart(const UnitTest& unit_test) = 0; // Called after the global set-up ends. - virtual void OnGlobalSetUpEnd(const UnitTest*) {} + virtual void OnGlobalSetUpEnd(const UnitTest& unit_test) = 0; // Called before the global tear-down starts. - virtual void OnGlobalTearDownStart(const UnitTest*) {} + virtual void OnGlobalTearDownStart(const UnitTest& unit_test) = 0; // Called after the global tear-down ends. - virtual void OnGlobalTearDownEnd(const UnitTest*) {} + virtual void OnGlobalTearDownEnd(const UnitTest& unit_test) = 0; // Called before the test starts. - virtual void OnTestStart(const TestInfo*) {} + virtual void OnTestStart(const TestInfo& test_info) = 0; // Called after the test ends. - virtual void OnTestEnd(const TestInfo*) {} + virtual void OnTestEnd(const TestInfo& test_info) = 0; // Called after an assertion. - virtual void OnNewTestPartResult(const TestPartResult*) {} + virtual void OnNewTestPartResult(const TestPartResult& test_part_result) = 0; +}; + +// The convenience class for users who need to override just one or two +// methods and are not concerned that a possible change to a signature of +// the methods they override will not be caught during the build. +class EmptyTestEventListener : public UnitTestEventListenerInterface { + public: + // Called before the unit test starts. + virtual void OnUnitTestStart(const UnitTest& /*unit_test*/) {} + + // Called after the unit test ends. + virtual void OnUnitTestEnd(const UnitTest& /*unit_test*/) {} + + // Called before the test case starts. + virtual void OnTestCaseStart(const TestCase& /*test_case*/) {} + + // Called after the test case ends. + virtual void OnTestCaseEnd(const TestCase& /*test_case&*/) {} + + // Called before the global set-up starts. + virtual void OnGlobalSetUpStart(const UnitTest& /*unit_test*/) {} + + // Called after the global set-up ends. + virtual void OnGlobalSetUpEnd(const UnitTest& /*unit_test*/) {} + + // Called before the global tear-down starts. + virtual void OnGlobalTearDownStart(const UnitTest& /*unit_test*/) {} + + // Called after the global tear-down ends. + virtual void OnGlobalTearDownEnd(const UnitTest& /*unit_test*/) {} + + // Called before the test starts. + virtual void OnTestStart(const TestInfo& /*test_info*/) {} + + // Called after the test ends. + virtual void OnTestEnd(const TestInfo& /*test_info*/) {} + + // Called after an assertion. + virtual void OnNewTestPartResult(const TestPartResult& /*test_part_result*/) { + } }; // The c'tor sets this object as the test part result reporter used by @@ -638,7 +678,7 @@ DefaultGlobalTestPartResultReporter::DefaultGlobalTestPartResultReporter( void DefaultGlobalTestPartResultReporter::ReportTestPartResult( const TestPartResult& result) { unit_test_->current_test_result()->AddTestPartResult(result); - unit_test_->result_printer()->OnNewTestPartResult(&result); + unit_test_->result_printer()->OnNewTestPartResult(result); } DefaultPerThreadTestPartResultReporter::DefaultPerThreadTestPartResultReporter( @@ -1790,6 +1830,19 @@ TestResult::TestResult() TestResult::~TestResult() { } +// Returns the i-th test part result among all the results. i can range +// from 0 to total_part_count() - 1. If i is not in that range, returns +// NULL. +const TestPartResult* TestResult::GetTestPartResult(int i) const { + return test_part_results_->GetElement(i); +} + +// Returns the i-th test property. i can range from 0 to +// test_property_count() - 1. If i is not in that range, returns NULL. +const TestProperty* TestResult::GetTestProperty(int i) const { + return test_properties_->GetElement(i); +} + // Clears the test part results. void TestResult::ClearTestPartResults() { test_part_results_->Clear(); @@ -1887,6 +1940,11 @@ int TestResult::total_part_count() const { return test_part_results_->size(); } +// Returns the number of the test properties. +int TestResult::test_property_count() const { + return test_properties_->size(); +} + } // namespace internal // class Test @@ -2261,7 +2319,7 @@ void TestInfoImpl::Run() { // start. UnitTestEventListenerInterface* const result_printer = impl->result_printer(); - result_printer->OnTestStart(parent_); + result_printer->OnTestStart(*parent_); const TimeInMillis start = GetTimeInMillis(); @@ -2304,7 +2362,7 @@ void TestInfoImpl::Run() { result_.set_elapsed_time(GetTimeInMillis() - start); // Notifies the unit test event listener that a test has just finished. - result_printer->OnTestEnd(parent_); + result_printer->OnTestEnd(*parent_); // Tells UnitTest to stop associating assertion results to this // test. @@ -2366,6 +2424,12 @@ TestCase::~TestCase() { test_info_list_ = NULL; } +// Returns the i-th test among all the tests. i can range from 0 to +// total_test_count() - 1. If i is not in that range, returns NULL. +const TestInfo* TestCase::GetTestInfo(int i) const { + return test_info_list_->GetElementOr(i, NULL); +} + // Adds a test to this test case. Will delete the test upon // destruction of the TestCase object. void TestCase::AddTestInfo(TestInfo * test_info) { @@ -2382,7 +2446,7 @@ void TestCase::Run() { UnitTestEventListenerInterface * const result_printer = impl->result_printer(); - result_printer->OnTestCaseStart(this); + result_printer->OnTestCaseStart(*this); impl->os_stack_trace_getter()->UponLeavingGTest(); set_up_tc_(); @@ -2392,7 +2456,7 @@ void TestCase::Run() { impl->os_stack_trace_getter()->UponLeavingGTest(); tear_down_tc_(); - result_printer->OnTestCaseEnd(this); + result_printer->OnTestCaseEnd(*this); impl->set_current_test_case(NULL); } @@ -2425,15 +2489,9 @@ bool TestCase::ShouldRunTest(const TestInfo *test_info) { } // namespace internal -// class UnitTestEventListenerInterface - -// The virtual d'tor. -UnitTestEventListenerInterface::~UnitTestEventListenerInterface() { -} - // A result printer that never prints anything. Used in the child process // of an exec-style death test to avoid needless output clutter. -class NullUnitTestResultPrinter : public UnitTestEventListenerInterface {}; +class NullUnitTestResultPrinter : public EmptyTestEventListener {}; // Formats a countable noun. Depending on its quantity, either the // singular form or the plural form is used. e.g. @@ -2628,24 +2686,25 @@ class PrettyUnitTestResultPrinter : public UnitTestEventListenerInterface { // The following methods override what's in the // UnitTestEventListenerInterface class. - virtual void OnUnitTestStart(const UnitTest * unit_test); - virtual void OnGlobalSetUpStart(const UnitTest*); - virtual void OnTestCaseStart(const TestCase * test_case); - virtual void OnTestCaseEnd(const TestCase * test_case); - virtual void OnTestStart(const TestInfo * test_info); - virtual void OnNewTestPartResult(const TestPartResult * result); - virtual void OnTestEnd(const TestInfo * test_info); - virtual void OnGlobalTearDownStart(const UnitTest*); - virtual void OnUnitTestEnd(const UnitTest * unit_test); + virtual void OnUnitTestStart(const UnitTest& unit_test); + virtual void OnGlobalSetUpStart(const UnitTest& unit_test); + virtual void OnGlobalSetUpEnd(const UnitTest& /*unit_test*/) {} + virtual void OnTestCaseStart(const TestCase& test_case); + virtual void OnTestCaseEnd(const TestCase& test_case); + virtual void OnTestStart(const TestInfo& test_info); + virtual void OnNewTestPartResult(const TestPartResult& result); + virtual void OnTestEnd(const TestInfo& test_info); + virtual void OnGlobalTearDownStart(const UnitTest& unit_test); + virtual void OnGlobalTearDownEnd(const UnitTest& /*unit_test*/) {} + virtual void OnUnitTestEnd(const UnitTest& unit_test); private: internal::String test_case_name_; }; // Called before the unit test starts. -void PrettyUnitTestResultPrinter::OnUnitTestStart( - const UnitTest * unit_test) { - const char * const filter = GTEST_FLAG(filter).c_str(); +void PrettyUnitTestResultPrinter::OnUnitTestStart(const UnitTest& unit_test) { + const char* const filter = GTEST_FLAG(filter).c_str(); // Prints the filter if it's not *. This reminds the user that some // tests may be skipped. @@ -2661,7 +2720,7 @@ void PrettyUnitTestResultPrinter::OnUnitTestStart( internal::posix::GetEnv(kTestTotalShards)); } - const internal::UnitTestImpl* const impl = unit_test->impl(); + const internal::UnitTestImpl* const impl = unit_test.impl(); ColoredPrintf(COLOR_GREEN, "[==========] "); printf("Running %s from %s.\n", FormatTestCount(impl->test_to_run_count()).c_str(), @@ -2669,62 +2728,61 @@ void PrettyUnitTestResultPrinter::OnUnitTestStart( fflush(stdout); } -void PrettyUnitTestResultPrinter::OnGlobalSetUpStart(const UnitTest*) { +void PrettyUnitTestResultPrinter::OnGlobalSetUpStart( + const UnitTest& /*unit_test*/) { ColoredPrintf(COLOR_GREEN, "[----------] "); printf("Global test environment set-up.\n"); fflush(stdout); } -void PrettyUnitTestResultPrinter::OnTestCaseStart( - const TestCase * test_case) { - test_case_name_ = test_case->name(); +void PrettyUnitTestResultPrinter::OnTestCaseStart(const TestCase& test_case) { + test_case_name_ = test_case.name(); 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, "[----------] "); printf("%s from %s", counts.c_str(), test_case_name_.c_str()); - if (test_case->comment()[0] == '\0') { + if (test_case.comment()[0] == '\0') { printf("\n"); } else { - printf(", where %s\n", test_case->comment()); + printf(", where %s\n", test_case.comment()); } fflush(stdout); } -void PrettyUnitTestResultPrinter::OnTestCaseEnd( - const TestCase * test_case) { +void PrettyUnitTestResultPrinter::OnTestCaseEnd(const TestCase& test_case) { if (!GTEST_FLAG(print_time)) return; - test_case_name_ = test_case->name(); + test_case_name_ = test_case.name(); 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, "[----------] "); printf("%s from %s (%s ms total)\n\n", counts.c_str(), test_case_name_.c_str(), - internal::StreamableToString(test_case->elapsed_time()).c_str()); + internal::StreamableToString(test_case.elapsed_time()).c_str()); fflush(stdout); } -void PrettyUnitTestResultPrinter::OnTestStart(const TestInfo * test_info) { +void PrettyUnitTestResultPrinter::OnTestStart(const TestInfo& test_info) { ColoredPrintf(COLOR_GREEN, "[ RUN ] "); - PrintTestName(test_case_name_.c_str(), test_info->name()); - if (test_info->comment()[0] == '\0') { + PrintTestName(test_case_name_.c_str(), test_info.name()); + if (test_info.comment()[0] == '\0') { printf("\n"); } else { - printf(", where %s\n", test_info->comment()); + printf(", where %s\n", test_info.comment()); } fflush(stdout); } -void PrettyUnitTestResultPrinter::OnTestEnd(const TestInfo * test_info) { - if (test_info->result()->Passed()) { +void PrettyUnitTestResultPrinter::OnTestEnd(const TestInfo& test_info) { + if (test_info.result()->Passed()) { ColoredPrintf(COLOR_GREEN, "[ OK ] "); } else { ColoredPrintf(COLOR_RED, "[ FAILED ] "); } - PrintTestName(test_case_name_.c_str(), test_info->name()); + PrintTestName(test_case_name_.c_str(), test_info.name()); if (GTEST_FLAG(print_time)) { printf(" (%s ms)\n", internal::StreamableToString( - test_info->result()->elapsed_time()).c_str()); + test_info.result()->elapsed_time()).c_str()); } else { printf("\n"); } @@ -2733,17 +2791,18 @@ void PrettyUnitTestResultPrinter::OnTestEnd(const TestInfo * test_info) { // Called after an assertion failure. void PrettyUnitTestResultPrinter::OnNewTestPartResult( - const TestPartResult * result) { + const TestPartResult& result) { // If the test part succeeded, we don't need to do anything. - if (result->type() == TPRT_SUCCESS) + if (result.type() == TPRT_SUCCESS) return; // Print failure message from the assertion (e.g. expected this and got that). - PrintTestPartResult(*result); + PrintTestPartResult(result); fflush(stdout); } -void PrettyUnitTestResultPrinter::OnGlobalTearDownStart(const UnitTest*) { +void PrettyUnitTestResultPrinter::OnGlobalTearDownStart( + const UnitTest& /*unit_test*/) { ColoredPrintf(COLOR_GREEN, "[----------] "); printf("Global test environment tear-down\n"); fflush(stdout); @@ -2788,9 +2847,8 @@ static void PrintFailedTestsPretty(const UnitTestImpl* impl) { } // namespace internal -void PrettyUnitTestResultPrinter::OnUnitTestEnd( - const UnitTest * unit_test) { - const internal::UnitTestImpl* const impl = unit_test->impl(); +void PrettyUnitTestResultPrinter::OnUnitTestEnd(const UnitTest& unit_test) { + const internal::UnitTestImpl* const impl = unit_test.impl(); ColoredPrintf(COLOR_GREEN, "[==========] "); printf("%s from %s ran.", @@ -2841,17 +2899,17 @@ class UnitTestEventsRepeater : public UnitTestEventListenerInterface { virtual ~UnitTestEventsRepeater(); void AddListener(UnitTestEventListenerInterface *listener); - virtual void OnUnitTestStart(const UnitTest* unit_test); - virtual void OnUnitTestEnd(const UnitTest* unit_test); - virtual void OnGlobalSetUpStart(const UnitTest* unit_test); - virtual void OnGlobalSetUpEnd(const UnitTest* unit_test); - virtual void OnGlobalTearDownStart(const UnitTest* unit_test); - virtual void OnGlobalTearDownEnd(const UnitTest* unit_test); - virtual void OnTestCaseStart(const TestCase* test_case); - virtual void OnTestCaseEnd(const TestCase* test_case); - virtual void OnTestStart(const TestInfo* test_info); - virtual void OnTestEnd(const TestInfo* test_info); - virtual void OnNewTestPartResult(const TestPartResult* result); + virtual void OnUnitTestStart(const UnitTest& unit_test); + virtual void OnUnitTestEnd(const UnitTest& unit_test); + virtual void OnGlobalSetUpStart(const UnitTest& unit_test); + virtual void OnGlobalSetUpEnd(const UnitTest& unit_test); + virtual void OnGlobalTearDownStart(const UnitTest& unit_test); + virtual void OnGlobalTearDownEnd(const UnitTest& unit_test); + virtual void OnTestCaseStart(const TestCase& test_case); + virtual void OnTestCaseEnd(const TestCase& test_case); + virtual void OnTestStart(const TestInfo& test_info); + virtual void OnTestEnd(const TestInfo& test_info); + virtual void OnNewTestPartResult(const TestPartResult& result); private: Listeners listeners_; @@ -2875,7 +2933,7 @@ void UnitTestEventsRepeater::AddListener( // Since the methods are identical, use a macro to reduce boilerplate. // This defines a member that repeats the call to all listeners. #define GTEST_REPEATER_METHOD_(Name, Type) \ -void UnitTestEventsRepeater::Name(const Type* parameter) { \ +void UnitTestEventsRepeater::Name(const Type& parameter) { \ for (ListenersNode* listener = listeners_.Head(); \ listener != NULL; \ listener = listener->next()) { \ @@ -2900,11 +2958,11 @@ GTEST_REPEATER_METHOD_(OnNewTestPartResult, TestPartResult) // End PrettyUnitTestResultPrinter // This class generates an XML output file. -class XmlUnitTestResultPrinter : public UnitTestEventListenerInterface { +class XmlUnitTestResultPrinter : public EmptyTestEventListener { public: explicit XmlUnitTestResultPrinter(const char* output_file); - virtual void OnUnitTestEnd(const UnitTest* unit_test); + virtual void OnUnitTestEnd(const UnitTest& unit_test); private: // Is c a whitespace character that is normalized to a space character @@ -2944,7 +3002,7 @@ class XmlUnitTestResultPrinter : public UnitTestEventListenerInterface { static void PrintXmlTestCase(FILE* out, const TestCase* test_case); // Prints an XML summary of unit_test to output stream out. - static void PrintXmlUnitTest(FILE* out, const UnitTest* unit_test); + static void PrintXmlUnitTest(FILE* out, const UnitTest& unit_test); // Produces a string representing the test properties in a result as space // delimited XML attributes based on the property key="value" pairs. @@ -2970,7 +3028,7 @@ XmlUnitTestResultPrinter::XmlUnitTestResultPrinter(const char* output_file) } // Called after the unit test ends. -void XmlUnitTestResultPrinter::OnUnitTestEnd(const UnitTest* unit_test) { +void XmlUnitTestResultPrinter::OnUnitTestEnd(const UnitTest& unit_test) { FILE* xmlout = NULL; internal::FilePath output_file(output_file_); internal::FilePath output_dir(output_file.RemoveFileName()); @@ -3149,8 +3207,8 @@ void XmlUnitTestResultPrinter::PrintXmlTestCase(FILE* out, // Prints an XML summary of unit_test to output stream out. void XmlUnitTestResultPrinter::PrintXmlUnitTest(FILE* out, - const UnitTest* unit_test) { - const internal::UnitTestImpl* const impl = unit_test->impl(); + const UnitTest& unit_test) { + const internal::UnitTestImpl* const impl = unit_test.impl(); fprintf(out, "\n"); fprintf(out, "successful_test_case_count(); +} + +// Gets the number of failed test cases. +int UnitTest::failed_test_case_count() const { + return impl()->failed_test_case_count(); +} + +// Gets the number of all test cases. +int UnitTest::total_test_case_count() const { + return impl()->total_test_case_count(); +} + +// Gets the number of all test cases that contain at least one test +// that should run. +int UnitTest::test_case_to_run_count() const { + return impl()->test_case_to_run_count(); +} + +// Gets the number of successful tests. +int UnitTest::successful_test_count() const { + return impl()->successful_test_count(); +} + +// Gets the number of failed tests. +int UnitTest::failed_test_count() const { return impl()->failed_test_count(); } + +// Gets the number of disabled tests. +int UnitTest::disabled_test_count() const { + return impl()->disabled_test_count(); +} + +// Gets the number of all tests. +int UnitTest::total_test_count() const { return impl()->total_test_count(); } + +// Gets the number of tests that should run. +int UnitTest::test_to_run_count() const { return impl()->test_to_run_count(); } + +// Gets the elapsed time, in milliseconds. +internal::TimeInMillis UnitTest::elapsed_time() const { + return impl()->elapsed_time(); +} + +// Returns true iff the unit test passed (i.e. all test cases passed). +bool UnitTest::Passed() const { return impl()->Passed(); } + +// Returns true iff the unit test failed (i.e. some test case failed +// or something outside of all tests failed). +bool UnitTest::Failed() const { return impl()->Failed(); } + +// Gets the i-th test case among all the test cases. i can range from 0 to +// total_test_case_count() - 1. If i is not in that range, returns NULL. +const TestCase* UnitTest::GetTestCase(int i) const { + return impl()->GetTestCase(i); +} + // Registers and returns a global test environment. When a test // program is run, all global test environments will be set-up in the // order they were registered. After all tests in the program have @@ -3683,16 +3799,16 @@ int UnitTestImpl::RunAllTests() { // Tells the unit test event listener that the tests are about to // start. - printer->OnUnitTestStart(parent_); + printer->OnUnitTestStart(*parent_); const TimeInMillis start = GetTimeInMillis(); // Runs each test case if there is at least one test to run. if (has_tests_to_run) { // Sets up all environments beforehand. - printer->OnGlobalSetUpStart(parent_); + printer->OnGlobalSetUpStart(*parent_); environments_.ForEach(SetUpEnvironment); - printer->OnGlobalSetUpEnd(parent_); + printer->OnGlobalSetUpEnd(*parent_); // Runs the tests only if there was no fatal failure during global // set-up. @@ -3701,16 +3817,16 @@ int UnitTestImpl::RunAllTests() { } // Tears down all environments in reverse order afterwards. - printer->OnGlobalTearDownStart(parent_); + printer->OnGlobalTearDownStart(*parent_); environments_in_reverse_order_.ForEach(TearDownEnvironment); - printer->OnGlobalTearDownEnd(parent_); + printer->OnGlobalTearDownEnd(*parent_); } elapsed_time_ = GetTimeInMillis() - start; // Tells the unit test event listener that the tests have just // finished. - printer->OnUnitTestEnd(parent_); + printer->OnUnitTestEnd(*parent_); // Gets the result and clears it. if (!Passed()) { -- cgit v1.2.3 From aaebfcdc4005afb22b68df61b58edd1ccc002913 Mon Sep 17 00:00:00 2001 From: "zhanyong.wan" Date: Thu, 25 Jun 2009 20:49:23 +0000 Subject: Refactors for the event listener API (by Vlad Losev): hides some methods in UnitTest; implements the result printers using the public API. --- src/gtest-test-part.cc | 9 +-- src/gtest.cc | 167 ++++++++++++++++++++++--------------------------- 2 files changed, 81 insertions(+), 95 deletions(-) (limited to 'src') diff --git a/src/gtest-test-part.cc b/src/gtest-test-part.cc index 9aacd2be..49a6fe5a 100644 --- a/src/gtest-test-part.cc +++ b/src/gtest-test-part.cc @@ -44,6 +44,8 @@ namespace testing { +using internal::GetUnitTestImpl; + // Gets the summary of the failure message by omitting the stack trace // in it. internal::String TestPartResult::ExtractSummary(const char* message) { @@ -101,14 +103,13 @@ namespace internal { HasNewFatalFailureHelper::HasNewFatalFailureHelper() : has_new_fatal_failure_(false), - original_reporter_(UnitTest::GetInstance()->impl()-> + original_reporter_(GetUnitTestImpl()-> GetTestPartResultReporterForCurrentThread()) { - UnitTest::GetInstance()->impl()->SetTestPartResultReporterForCurrentThread( - this); + GetUnitTestImpl()->SetTestPartResultReporterForCurrentThread(this); } HasNewFatalFailureHelper::~HasNewFatalFailureHelper() { - UnitTest::GetInstance()->impl()->SetTestPartResultReporterForCurrentThread( + GetUnitTestImpl()->SetTestPartResultReporterForCurrentThread( original_reporter_); } diff --git a/src/gtest.cc b/src/gtest.cc index ec176918..6e4dbfc7 100644 --- a/src/gtest.cc +++ b/src/gtest.cc @@ -565,7 +565,7 @@ ScopedFakeTestPartResultReporter::ScopedFakeTestPartResultReporter( } void ScopedFakeTestPartResultReporter::Init() { - internal::UnitTestImpl* const impl = UnitTest::GetInstance()->impl(); + internal::UnitTestImpl* const impl = internal::GetUnitTestImpl(); if (intercept_mode_ == INTERCEPT_ALL_THREADS) { old_reporter_ = impl->GetGlobalTestPartResultReporter(); impl->SetGlobalTestPartResultReporter(this); @@ -578,7 +578,7 @@ void ScopedFakeTestPartResultReporter::Init() { // The d'tor restores the test part result reporter used by Google Test // before. ScopedFakeTestPartResultReporter::~ScopedFakeTestPartResultReporter() { - internal::UnitTestImpl* const impl = UnitTest::GetInstance()->impl(); + internal::UnitTestImpl* const impl = internal::GetUnitTestImpl(); if (intercept_mode_ == INTERCEPT_ALL_THREADS) { impl->SetGlobalTestPartResultReporter(old_reporter_); } else { @@ -1985,6 +1985,22 @@ void Test::RecordProperty(const char* key, int value) { RecordProperty(key, value_message.GetString().c_str()); } +namespace internal { + +void ReportFailureInUnknownLocation(TestPartResultType result_type, + const String& message) { + // This function is a friend of UnitTest and as such has access to + // AddTestPartResult. + UnitTest::GetInstance()->AddTestPartResult( + result_type, + NULL, // No info about the source file where the exception occurred. + -1, // We have no info on which line caused the exception. + message, + String()); // No stack trace, either. +} + +} // namespace internal + #if GTEST_OS_WINDOWS // We are on Windows. @@ -1995,15 +2011,8 @@ static void AddExceptionThrownFailure(DWORD exception_code, message << "Exception thrown with code 0x" << std::setbase(16) << exception_code << std::setbase(10) << " in " << location << "."; - UnitTest* const unit_test = UnitTest::GetInstance(); - unit_test->AddTestPartResult( - TPRT_FATAL_FAILURE, - static_cast(NULL), - // We have no info about the source file where the exception - // occurred. - -1, // We have no info on which line caused the exception. - message.GetString(), - internal::String("")); + internal::ReportFailureInUnknownLocation(TPRT_FATAL_FAILURE, + message.GetString()); } #endif // GTEST_OS_WINDOWS @@ -2699,6 +2708,8 @@ class PrettyUnitTestResultPrinter : public UnitTestEventListenerInterface { virtual void OnUnitTestEnd(const UnitTest& unit_test); private: + static void PrintFailedTests(const UnitTest& unit_test); + internal::String test_case_name_; }; @@ -2720,11 +2731,10 @@ void PrettyUnitTestResultPrinter::OnUnitTestStart(const UnitTest& unit_test) { internal::posix::GetEnv(kTestTotalShards)); } - const internal::UnitTestImpl* const impl = unit_test.impl(); ColoredPrintf(COLOR_GREEN, "[==========] "); printf("Running %s from %s.\n", - FormatTestCount(impl->test_to_run_count()).c_str(), - FormatTestCaseCount(impl->test_case_to_run_count()).c_str()); + FormatTestCount(unit_test.test_to_run_count()).c_str(), + FormatTestCaseCount(unit_test.test_case_to_run_count()).c_str()); fflush(stdout); } @@ -2808,71 +2818,62 @@ void PrettyUnitTestResultPrinter::OnGlobalTearDownStart( fflush(stdout); } -namespace internal { - // Internal helper for printing the list of failed tests. -static void PrintFailedTestsPretty(const UnitTestImpl* impl) { - const int failed_test_count = impl->failed_test_count(); +void PrettyUnitTestResultPrinter::PrintFailedTests(const UnitTest& unit_test) { + const int failed_test_count = unit_test.failed_test_count(); if (failed_test_count == 0) { return; } - for (const internal::ListNode* node = impl->test_cases()->Head(); - node != NULL; node = node->next()) { - const TestCase* const tc = node->element(); - if (!tc->should_run() || (tc->failed_test_count() == 0)) { + for (int i = 0; i < unit_test.total_test_case_count(); ++i) { + const TestCase& test_case = *unit_test.GetTestCase(i); + if (!test_case.should_run() || (test_case.failed_test_count() == 0)) { continue; } - for (const internal::ListNode* tinode = - tc->test_info_list().Head(); - tinode != NULL; tinode = tinode->next()) { - const TestInfo* const ti = tinode->element(); - if (!tc->ShouldRunTest(ti) || tc->TestPassed(ti)) { + for (int j = 0; j < test_case.total_test_count(); ++j) { + const TestInfo& test_info = *test_case.GetTestInfo(j); + if (!test_info.should_run() || test_info.result()->Passed()) { continue; } ColoredPrintf(COLOR_RED, "[ FAILED ] "); - printf("%s.%s", ti->test_case_name(), ti->name()); - if (ti->test_case_comment()[0] != '\0' || - ti->comment()[0] != '\0') { - printf(", where %s", ti->test_case_comment()); - if (ti->test_case_comment()[0] != '\0' && - ti->comment()[0] != '\0') { + printf("%s.%s", test_case.name(), test_info.name()); + if (test_case.comment()[0] != '\0' || + test_info.comment()[0] != '\0') { + printf(", where %s", test_case.comment()); + if (test_case.comment()[0] != '\0' && + test_info.comment()[0] != '\0') { printf(" and "); } } - printf("%s\n", ti->comment()); + printf("%s\n", test_info.comment()); } } } -} // namespace internal - void PrettyUnitTestResultPrinter::OnUnitTestEnd(const UnitTest& unit_test) { - const internal::UnitTestImpl* const impl = unit_test.impl(); - ColoredPrintf(COLOR_GREEN, "[==========] "); printf("%s from %s ran.", - FormatTestCount(impl->test_to_run_count()).c_str(), - FormatTestCaseCount(impl->test_case_to_run_count()).c_str()); + FormatTestCount(unit_test.test_to_run_count()).c_str(), + FormatTestCaseCount(unit_test.test_case_to_run_count()).c_str()); if (GTEST_FLAG(print_time)) { printf(" (%s ms total)", - internal::StreamableToString(impl->elapsed_time()).c_str()); + internal::StreamableToString(unit_test.elapsed_time()).c_str()); } printf("\n"); ColoredPrintf(COLOR_GREEN, "[ PASSED ] "); - printf("%s.\n", FormatTestCount(impl->successful_test_count()).c_str()); + printf("%s.\n", FormatTestCount(unit_test.successful_test_count()).c_str()); - int num_failures = impl->failed_test_count(); - if (!impl->Passed()) { - const int failed_test_count = impl->failed_test_count(); + int num_failures = unit_test.failed_test_count(); + if (!unit_test.Passed()) { + const int failed_test_count = unit_test.failed_test_count(); ColoredPrintf(COLOR_RED, "[ FAILED ] "); printf("%s, listed below:\n", FormatTestCount(failed_test_count).c_str()); - internal::PrintFailedTestsPretty(impl); + PrintFailedTests(unit_test); printf("\n%2d FAILED %s\n", num_failures, num_failures == 1 ? "TEST" : "TESTS"); } - int num_disabled = impl->disabled_test_count(); + int num_disabled = unit_test.disabled_test_count(); if (num_disabled && !GTEST_FLAG(also_run_disabled_tests)) { if (!num_failures) { printf("\n"); // Add a spacer if no FAILURE banner is displayed. @@ -2996,10 +2997,10 @@ class XmlUnitTestResultPrinter : public EmptyTestEventListener { // Prints an XML representation of a TestInfo object. static void PrintXmlTestInfo(FILE* out, const char* test_case_name, - const TestInfo* test_info); + const TestInfo& test_info); // Prints an XML representation of a TestCase object - static void PrintXmlTestCase(FILE* out, const TestCase* test_case); + static void PrintXmlTestCase(FILE* out, const TestCase& test_case); // Prints an XML summary of unit_test to output stream out. static void PrintXmlUnitTest(FILE* out, const UnitTest& unit_test); @@ -3009,7 +3010,7 @@ class XmlUnitTestResultPrinter : public EmptyTestEventListener { // When the String is not empty, it includes a space at the beginning, // to delimit this attribute from prior attributes. static internal::String TestPropertiesAsXmlAttributes( - const internal::TestResult* result); + const internal::TestResult& result); // The output file. const internal::String output_file_; @@ -3147,23 +3148,20 @@ const char* FormatTimeInMillisAsSeconds(TimeInMillis ms) { // TODO(wan): There is also value in printing properties with the plain printer. void XmlUnitTestResultPrinter::PrintXmlTestInfo(FILE* out, const char* test_case_name, - const TestInfo* test_info) { - const internal::TestResult * const result = test_info->result(); - const internal::List &results = result->test_part_results(); + const TestInfo& test_info) { + const internal::TestResult& result = *test_info.result(); fprintf(out, " name()).c_str(), - test_info->should_run() ? "run" : "notrun", - internal::FormatTimeInMillisAsSeconds(result->elapsed_time()), + EscapeXmlAttribute(test_info.name()).c_str(), + test_info.should_run() ? "run" : "notrun", + internal::FormatTimeInMillisAsSeconds(result.elapsed_time()), EscapeXmlAttribute(test_case_name).c_str(), TestPropertiesAsXmlAttributes(result).c_str()); int failures = 0; - for (const internal::ListNode* part_node = results.Head(); - part_node != NULL; - part_node = part_node->next()) { - const TestPartResult& part = part_node->element(); + for (int i = 0; i < result.total_part_count(); ++i) { + const TestPartResult& part = *result.GetTestPartResult(i); if (part.failed()) { const internal::String message = internal::String::Format("%s:%d\n%s", part.file_name(), @@ -3185,60 +3183,47 @@ void XmlUnitTestResultPrinter::PrintXmlTestInfo(FILE* out, // Prints an XML representation of a TestCase object void XmlUnitTestResultPrinter::PrintXmlTestCase(FILE* out, - const TestCase* test_case) { + const TestCase& test_case) { fprintf(out, " name()).c_str(), - test_case->total_test_count(), - test_case->failed_test_count(), - test_case->disabled_test_count()); + EscapeXmlAttribute(test_case.name()).c_str(), + test_case.total_test_count(), + test_case.failed_test_count(), + test_case.disabled_test_count()); fprintf(out, "errors=\"0\" time=\"%s\">\n", - internal::FormatTimeInMillisAsSeconds(test_case->elapsed_time())); - for (const internal::ListNode* info_node = - test_case->test_info_list().Head(); - info_node != NULL; - info_node = info_node->next()) { - PrintXmlTestInfo(out, test_case->name(), info_node->element()); - } + internal::FormatTimeInMillisAsSeconds(test_case.elapsed_time())); + for (int i = 0; i < test_case.total_test_count(); ++i) + PrintXmlTestInfo(out, test_case.name(), *test_case.GetTestInfo(i)); fprintf(out, " \n"); } // Prints an XML summary of unit_test to output stream out. void XmlUnitTestResultPrinter::PrintXmlUnitTest(FILE* out, const UnitTest& unit_test) { - const internal::UnitTestImpl* const impl = unit_test.impl(); fprintf(out, "\n"); fprintf(out, "total_test_count(), - impl->failed_test_count(), - impl->disabled_test_count(), - internal::FormatTimeInMillisAsSeconds(impl->elapsed_time())); + unit_test.total_test_count(), + unit_test.failed_test_count(), + unit_test.disabled_test_count(), + internal::FormatTimeInMillisAsSeconds(unit_test.elapsed_time())); fprintf(out, "name=\"AllTests\">\n"); - for (const internal::ListNode* case_node = - impl->test_cases()->Head(); - case_node != NULL; - case_node = case_node->next()) { - PrintXmlTestCase(out, case_node->element()); - } + for (int i = 0; i < unit_test.total_test_case_count(); ++i) + PrintXmlTestCase(out, *unit_test.GetTestCase(i)); fprintf(out, "\n"); } // Produces a string representing the test properties in a result as space // delimited XML attributes based on the property key="value" pairs. internal::String XmlUnitTestResultPrinter::TestPropertiesAsXmlAttributes( - const internal::TestResult* result) { + const internal::TestResult& result) { using internal::TestProperty; Message attributes; - const internal::List& properties = result->test_properties(); - for (const internal::ListNode* property_node = - properties.Head(); - property_node != NULL; - property_node = property_node->next()) { - const TestProperty& property = property_node->element(); + for (int i = 0; i < result.test_property_count(); ++i) { + const TestProperty& property = *result.GetTestProperty(i); attributes << " " << property.key() << "=" << "\"" << EscapeXmlAttribute(property.value()) << "\""; } @@ -4136,7 +4121,7 @@ TestInfoImpl::~TestInfoImpl() { String GetCurrentOsStackTraceExceptTop(UnitTest* unit_test, int skip_count) { // We pass skip_count + 1 to skip this wrapper function in addition // to what the user really wants to skip. - return unit_test->impl()->CurrentOsStackTraceExceptTop(skip_count + 1); + return GetUnitTestImpl()->CurrentOsStackTraceExceptTop(skip_count + 1); } // Returns the number of failed test parts in the given test result object. -- cgit v1.2.3 From 1b61f16aef4ea5bb2a7b28e759996dab10e0ca72 Mon Sep 17 00:00:00 2001 From: "zhanyong.wan" Date: Thu, 25 Jun 2009 22:21:28 +0000 Subject: Makes list traversal O(N) instead of O(N^2) (by Zhanyong Wan). --- src/gtest-internal-inl.h | 63 +++++++++++++++++++++++++++++++++++++++--------- 1 file changed, 51 insertions(+), 12 deletions(-) (limited to 'src') diff --git a/src/gtest-internal-inl.h b/src/gtest-internal-inl.h index 3abe9a26..c68ce5a0 100644 --- a/src/gtest-internal-inl.h +++ b/src/gtest-internal-inl.h @@ -257,7 +257,8 @@ class List { public: // Creates an empty list. - List() : head_(NULL), last_(NULL), size_(0) {} + List() : head_(NULL), last_(NULL), size_(0), + last_read_index_(-1), last_read_(NULL) {} // D'tor. virtual ~List(); @@ -276,8 +277,9 @@ class List { } // 2. Resets the member variables. - head_ = last_ = NULL; + last_read_ = head_ = last_ = NULL; size_ = 0; + last_read_index_ = -1; } } @@ -298,7 +300,8 @@ class List { // Adds an element to the end of the list. A copy of the element is // created using the copy constructor, and then stored in the list. // Changes made to the element in the list doesn't affect the source - // object, and vice versa. + // object, and vice versa. This does not affect the "last read" + // index. void PushBack(const E & element) { ListNode * new_node = new ListNode(element); @@ -312,7 +315,8 @@ class List { } } - // Adds an element to the beginning of this list. + // Adds an element to the beginning of this list. The "last read" + // index is adjusted accordingly. void PushFront(const E& element) { ListNode* const new_node = new ListNode(element); @@ -324,12 +328,18 @@ class List { head_ = new_node; size_++; } + + if (last_read_index_ >= 0) { + // A new element at the head bumps up an existing index by 1. + last_read_index_++; + } } // Removes an element from the beginning of this list. If the // result argument is not NULL, the removed element is stored in the // memory it points to. Otherwise the element is thrown away. - // Returns true iff the list wasn't empty before the operation. + // Returns true iff the list wasn't empty before the operation. The + // "last read" index is adjusted accordingly. bool PopFront(E* result) { if (size_ == 0) return false; @@ -346,13 +356,21 @@ class List { } delete old_head; + if (last_read_index_ > 0) { + last_read_index_--; + } else if (last_read_index_ == 0) { + last_read_index_ = -1; + last_read_ = NULL; + } + return true; } // Inserts an element after a given node in the list. It's the // caller's responsibility to ensure that the given node is in the // list. If the given node is NULL, inserts the element at the - // front of the list. + // front of the list. The "last read" index is adjusted + // accordingly. ListNode* InsertAfter(ListNode* node, const E& element) { if (node == NULL) { PushFront(element); @@ -367,6 +385,11 @@ class List { last_ = new_node; } + // We aren't sure whether this insertion will affect the last read + // index, so we invalidate it to be safe. + last_read_index_ = -1; + last_read_ = NULL; + return new_node; } @@ -431,20 +454,27 @@ class List { } // Returns a pointer to the i-th element of the list, or NULL if i is not - // in range [0, size()). + // in range [0, size()). The "last read" index is adjusted accordingly. const E* GetElement(int i) const { if (i < 0 || i >= size()) return NULL; - const ListNode* node = Head(); - for (int index = 0; index < i && node != NULL; ++index, node = node->next()) - continue; + if (last_read_index_ < 0 || last_read_index_ > i) { + // We have to count from the start. + last_read_index_ = 0; + last_read_ = Head(); + } - return node ? &(node->element()) : NULL; + while (last_read_index_ < i) { + last_read_ = last_read_->next(); + last_read_index_++; + } + + return &(last_read_->element()); } // Returns the i-th element of the list, or default_value if i is not - // in range [0, size()). + // in range [0, size()). The "last read" index is adjusted accordingly. E GetElementOr(int i, E default_value) const { const E* element = GetElement(i); return element ? *element : default_value; @@ -455,6 +485,15 @@ class List { ListNode* last_; // The last node of the list. int size_; // The number of elements in the list. + // These fields point to the last element read via GetElement(i) or + // GetElementOr(i). They are used to speed up list traversal as + // often they allow us to find the wanted element by looking from + // the last visited one instead of the list head. This means a + // sequential traversal of the list can be done in O(N) time instead + // of O(N^2). + mutable int last_read_index_; + mutable const ListNode* last_read_; + // We disallow copying List. GTEST_DISALLOW_COPY_AND_ASSIGN_(List); }; -- cgit v1.2.3 From b2db677c9905a34ca6454aa526f7a0cc5cfaeca1 Mon Sep 17 00:00:00 2001 From: "zhanyong.wan" Date: Wed, 1 Jul 2009 04:58:05 +0000 Subject: Reduces the flakiness of gtest-port_test on Mac; improves the Python tests; hides methods that we don't want to publish; makes win-dbg8 the default scons configuration (all by Vlad Losev). --- src/gtest-internal-inl.h | 5 ----- src/gtest.cc | 11 ----------- 2 files changed, 16 deletions(-) (limited to 'src') diff --git a/src/gtest-internal-inl.h b/src/gtest-internal-inl.h index c68ce5a0..3c9a8d97 100644 --- a/src/gtest-internal-inl.h +++ b/src/gtest-internal-inl.h @@ -1116,11 +1116,6 @@ inline UnitTestImpl* GetUnitTestImpl() { return UnitTest::GetInstance()->impl(); } -// Clears all test part results of the current test. -inline void ClearCurrentTestPartResults() { - GetUnitTestImpl()->current_test_result()->ClearTestPartResults(); -} - // Internal helper functions for implementing the simple regular // expression matcher. bool IsInSet(char ch, const char* str); diff --git a/src/gtest.cc b/src/gtest.cc index 6e4dbfc7..a1d8ac04 100644 --- a/src/gtest.cc +++ b/src/gtest.cc @@ -2290,17 +2290,6 @@ class TestNameIs { } // namespace -// Finds and returns a TestInfo with the given name. If one doesn't -// exist, returns NULL. -TestInfo * TestCase::GetTestInfo(const char* test_name) { - // Can we find a TestInfo with the given name? - internal::ListNode * const node = test_info_list_->FindIf( - TestNameIs(test_name)); - - // Returns the TestInfo found. - return node ? node->element() : NULL; -} - namespace internal { // This method expands all parameterized tests registered with macros TEST_P -- cgit v1.2.3 From 600105ee3ac48a01143486e5536a5b8fff5b5b25 Mon Sep 17 00:00:00 2001 From: "zhanyong.wan" Date: Wed, 1 Jul 2009 22:55:05 +0000 Subject: Makes List a random-access data structure. This simplifies the implementation and makes it easier to implement test shuffling. --- src/gtest-internal-inl.h | 311 +++++++++++++---------------------------------- src/gtest-test-part.cc | 7 +- src/gtest.cc | 118 ++++++++---------- 3 files changed, 134 insertions(+), 302 deletions(-) (limited to 'src') diff --git a/src/gtest-internal-inl.h b/src/gtest-internal-inl.h index 3c9a8d97..b4f6de6c 100644 --- a/src/gtest-internal-inl.h +++ b/src/gtest-internal-inl.h @@ -49,7 +49,8 @@ #include #endif // !_WIN32_WCE #include -#include // For strtoll/_strtoul64. +#include // For strtoll/_strtoul64/malloc/free. +#include // For memmove. #include @@ -198,199 +199,74 @@ Int32 Int32FromEnvOrDie(const char* env_var, Int32 default_val); // method. Assumes that 0 <= shard_index < total_shards. bool ShouldRunTestOnShard(int total_shards, int shard_index, int test_id); -// List is a simple singly-linked list container. +// List is an ordered container that supports random access to the +// elements. // -// We cannot use std::list as Microsoft's implementation of STL has -// problems when exception is disabled. There is a hack to work -// around this, but we've seen cases where the hack fails to work. +// We cannot use std::vector, as Visual C++ 7.1's implementation of +// STL has problems compiling when exceptions are disabled. There is +// a hack to work around the problems, but we've seen cases where the +// hack fails to work. // -// TODO(wan): switch to std::list when we have a reliable fix for the -// STL problem, e.g. when we upgrade to the next version of Visual -// C++, or (more likely) switch to STLport. -// -// The element type must support copy constructor. - -// Forward declare List -template // E is the element type. -class List; - -// ListNode is a node in a singly-linked list. It consists of an -// element and a pointer to the next node. The last node in the list -// has a NULL value for its next pointer. -template // E is the element type. -class ListNode { - friend class List; - - private: - - E element_; - ListNode * next_; - - // The c'tor is private s.t. only in the ListNode class and in its - // friend class List we can create a ListNode object. - // - // Creates a node with a given element value. The next pointer is - // set to NULL. - // - // ListNode does NOT have a default constructor. Always use this - // constructor (with parameter) to create a ListNode object. - explicit ListNode(const E & element) : element_(element), next_(NULL) {} - - // We disallow copying ListNode - GTEST_DISALLOW_COPY_AND_ASSIGN_(ListNode); - - public: - - // Gets the element in this node. - E & element() { return element_; } - const E & element() const { return element_; } - - // Gets the next node in the list. - ListNode * next() { return next_; } - const ListNode * next() const { return next_; } -}; - - -// List is a simple singly-linked list container. +// The element type must support copy constructor and operator=. template // E is the element type. class List { public: - // Creates an empty list. - List() : head_(NULL), last_(NULL), size_(0), - last_read_index_(-1), last_read_(NULL) {} + List() : elements_(NULL), capacity_(0), size_(0) {} // D'tor. - virtual ~List(); + virtual ~List() { Clear(); } // Clears the list. void Clear() { - if ( size_ > 0 ) { - // 1. Deletes every node. - ListNode * node = head_; - ListNode * next = node->next(); - for ( ; ; ) { - delete node; - node = next; - if ( node == NULL ) break; - next = node->next(); + if (elements_ != NULL) { + for (int i = 0; i < size_; i++) { + delete elements_[i]; } - // 2. Resets the member variables. - last_read_ = head_ = last_ = NULL; - size_ = 0; - last_read_index_ = -1; + free(elements_); + elements_ = NULL; + capacity_ = size_ = 0; } } // Gets the number of elements. int size() const { return size_; } - // Returns true if the list is empty. - bool IsEmpty() const { return size() == 0; } - - // Gets the first element of the list, or NULL if the list is empty. - ListNode * Head() { return head_; } - const ListNode * Head() const { return head_; } - - // Gets the last element of the list, or NULL if the list is empty. - ListNode * Last() { return last_; } - const ListNode * Last() const { return last_; } - // Adds an element to the end of the list. A copy of the element is // created using the copy constructor, and then stored in the list. // Changes made to the element in the list doesn't affect the source - // object, and vice versa. This does not affect the "last read" - // index. - void PushBack(const E & element) { - ListNode * new_node = new ListNode(element); - - if ( size_ == 0 ) { - head_ = last_ = new_node; - size_ = 1; - } else { - last_->next_ = new_node; - last_ = new_node; - size_++; - } - } + // object, and vice versa. + void PushBack(const E & element) { Insert(element, size_); } - // Adds an element to the beginning of this list. The "last read" - // index is adjusted accordingly. - void PushFront(const E& element) { - ListNode* const new_node = new ListNode(element); - - if ( size_ == 0 ) { - head_ = last_ = new_node; - size_ = 1; - } else { - new_node->next_ = head_; - head_ = new_node; - size_++; - } - - if (last_read_index_ >= 0) { - // A new element at the head bumps up an existing index by 1. - last_read_index_++; - } - } + // Adds an element to the beginning of this list. + void PushFront(const E& element) { Insert(element, 0); } // Removes an element from the beginning of this list. If the // result argument is not NULL, the removed element is stored in the // memory it points to. Otherwise the element is thrown away. - // Returns true iff the list wasn't empty before the operation. The - // "last read" index is adjusted accordingly. + // Returns true iff the list wasn't empty before the operation. bool PopFront(E* result) { - if (size_ == 0) return false; + if (size_ == 0) + return false; - if (result != NULL) { - *result = head_->element_; - } + if (result != NULL) + *result = *(elements_[0]); - ListNode* const old_head = head_; + delete elements_[0]; size_--; - if (size_ == 0) { - head_ = last_ = NULL; - } else { - head_ = head_->next_; - } - delete old_head; - - if (last_read_index_ > 0) { - last_read_index_--; - } else if (last_read_index_ == 0) { - last_read_index_ = -1; - last_read_ = NULL; - } - + MoveElements(1, size_, 0); return true; } - // Inserts an element after a given node in the list. It's the - // caller's responsibility to ensure that the given node is in the - // list. If the given node is NULL, inserts the element at the - // front of the list. The "last read" index is adjusted - // accordingly. - ListNode* InsertAfter(ListNode* node, const E& element) { - if (node == NULL) { - PushFront(element); - return Head(); - } - - ListNode* const new_node = new ListNode(element); - new_node->next_ = node->next_; - node->next_ = new_node; + // Inserts an element at the given index. It's the caller's + // responsibility to ensure that the given index is in the range [0, + // size()]. + void Insert(const E& element, int index) { + GrowIfNeeded(); + MoveElements(index, size_ - index, index + 1); + elements_[index] = new E(element); size_++; - if (node == last_) { - last_ = new_node; - } - - // We aren't sure whether this insertion will affect the last read - // index, so we invalidate it to be safe. - last_read_index_ = -1; - last_read_ = NULL; - - return new_node; } // Returns the number of elements that satisfy a given predicate. @@ -399,10 +275,8 @@ class List { template // P is the type of the predicate function/functor int CountIf(P predicate) const { int count = 0; - for ( const ListNode * node = Head(); - node != NULL; - node = node->next() ) { - if ( predicate(node->element()) ) { + for (int i = 0; i < size_; i++) { + if (predicate(*(elements_[i]))) { count++; } } @@ -416,10 +290,8 @@ class List { // the elements. template // F is the type of the function/functor void ForEach(F functor) const { - for ( const ListNode * node = Head(); - node != NULL; - node = node->next() ) { - functor(node->element()); + for (int i = 0; i < size_; i++) { + functor(*(elements_[i])); } } @@ -428,81 +300,70 @@ class List { // function/functor that accepts a 'const E &', where E is the // element type. This method does not change the elements. template // P is the type of the predicate function/functor. - const ListNode * FindIf(P predicate) const { - for ( const ListNode * node = Head(); - node != NULL; - node = node->next() ) { - if ( predicate(node->element()) ) { - return node; + const E* FindIf(P predicate) const { + for (int i = 0; i < size_; i++) { + if (predicate(*elements_[i])) { + return elements_[i]; } } - return NULL; } template - ListNode * FindIf(P predicate) { - for ( ListNode * node = Head(); - node != NULL; - node = node->next() ) { - if ( predicate(node->element() ) ) { - return node; + E* FindIf(P predicate) { + for (int i = 0; i < size_; i++) { + if (predicate(*elements_[i])) { + return elements_[i]; } } - return NULL; } - // Returns a pointer to the i-th element of the list, or NULL if i is not - // in range [0, size()). The "last read" index is adjusted accordingly. - const E* GetElement(int i) const { - if (i < 0 || i >= size()) - return NULL; - - if (last_read_index_ < 0 || last_read_index_ > i) { - // We have to count from the start. - last_read_index_ = 0; - last_read_ = Head(); - } + // Returns the i-th element of the list, or aborts the program if i + // is not in range [0, size()). + const E& GetElement(int i) const { + GTEST_CHECK_(0 <= i && i < size_) + << "Invalid list index " << i << ": must be in range [0, " + << (size_ - 1) << "]."; - while (last_read_index_ < i) { - last_read_ = last_read_->next(); - last_read_index_++; - } - - return &(last_read_->element()); + return *(elements_[i]); } // Returns the i-th element of the list, or default_value if i is not - // in range [0, size()). The "last read" index is adjusted accordingly. + // in range [0, size()). E GetElementOr(int i, E default_value) const { - const E* element = GetElement(i); - return element ? *element : default_value; + return (i < 0 || i >= size_) ? default_value : *(elements_[i]); } private: - ListNode* head_; // The first node of the list. - ListNode* last_; // The last node of the list. - int size_; // The number of elements in the list. - - // These fields point to the last element read via GetElement(i) or - // GetElementOr(i). They are used to speed up list traversal as - // often they allow us to find the wanted element by looking from - // the last visited one instead of the list head. This means a - // sequential traversal of the list can be done in O(N) time instead - // of O(N^2). - mutable int last_read_index_; - mutable const ListNode* last_read_; + // Grows the buffer if it is not big enough to hold one more element. + void GrowIfNeeded() { + if (size_ < capacity_) + return; + + // Exponential bump-up is necessary to ensure that inserting N + // elements is O(N) instead of O(N^2). The factor 3/2 means that + // no more than 1/3 of the slots are wasted. + const int new_capacity = 3*(capacity_/2 + 1); + GTEST_CHECK_(new_capacity > capacity_) // Does the new capacity overflow? + << "Cannot grow a list with " << capacity_ << " elements already."; + capacity_ = new_capacity; + elements_ = static_cast( + realloc(elements_, capacity_*sizeof(elements_[0]))); + } + + // Moves the give consecutive elements to a new index in the list. + void MoveElements(int source, int count, int dest) { + memmove(elements_ + dest, elements_ + source, count*sizeof(elements_[0])); + } + + E** elements_; + int capacity_; // The number of elements allocated for elements_. + int size_; // The number of elements; in the range [0, capacity_]. // We disallow copying List. GTEST_DISALLOW_COPY_AND_ASSIGN_(List); -}; - -// The virtual destructor of List. -template -List::~List() { - Clear(); -} +}; // class List // A function for deleting an object. Handy for being used as a // functor. @@ -907,10 +768,8 @@ class UnitTestImpl { // before main() is reached. if (original_working_dir_.IsEmpty()) { original_working_dir_.Set(FilePath::GetCurrentDir()); - if (original_working_dir_.IsEmpty()) { - printf("%s\n", "Failed to get the current working directory."); - posix::Abort(); - } + GTEST_CHECK_(!original_working_dir_.IsEmpty()) + << "Failed to get the current working directory."; } GetTestCase(test_info->test_case_name(), @@ -1057,8 +916,8 @@ class UnitTestImpl { bool parameterized_tests_registered_; #endif // GTEST_HAS_PARAM_TEST - // Points to the last death test case registered. Initially NULL. - internal::ListNode* last_death_test_case_; + // Index of the last death test case registered. Initially -1. + int last_death_test_case_; // This points to the TestCase for the currently running test. It // changes as Google Test goes through one test case after another. diff --git a/src/gtest-test-part.cc b/src/gtest-test-part.cc index 49a6fe5a..472b8c58 100644 --- a/src/gtest-test-part.cc +++ b/src/gtest-test-part.cc @@ -86,12 +86,7 @@ const TestPartResult& TestPartResultArray::GetTestPartResult(int index) const { internal::posix::Abort(); } - const internal::ListNode* p = list_->Head(); - for (int i = 0; i < index; i++) { - p = p->next(); - } - - return p->element(); + return list_->GetElement(index); } // Returns the number of TestPartResult objects in the array. diff --git a/src/gtest.cc b/src/gtest.cc index a1d8ac04..845fb902 100644 --- a/src/gtest.cc +++ b/src/gtest.cc @@ -264,10 +264,8 @@ static bool GTestIsInitialized() { return g_init_gtest_count != 0; } static int SumOverTestCaseList(const internal::List& case_list, int (TestCase::*method)() const) { int sum = 0; - for (const internal::ListNode* node = case_list.Head(); - node != NULL; - node = node->next()) { - sum += (node->element()->*method)(); + for (int i = 0; i < case_list.size(); i++) { + sum += (case_list.GetElement(i)->*method)(); } return sum; } @@ -1830,16 +1828,17 @@ TestResult::TestResult() TestResult::~TestResult() { } -// Returns the i-th test part result among all the results. i can range -// from 0 to total_part_count() - 1. If i is not in that range, returns -// NULL. -const TestPartResult* TestResult::GetTestPartResult(int i) const { +// Returns the i-th test part result among all the results. i can +// range from 0 to total_part_count() - 1. If i is not in that range, +// aborts the program. +const TestPartResult& TestResult::GetTestPartResult(int i) const { return test_part_results_->GetElement(i); } // Returns the i-th test property. i can range from 0 to -// test_property_count() - 1. If i is not in that range, returns NULL. -const TestProperty* TestResult::GetTestProperty(int i) const { +// test_property_count() - 1. If i is not in that range, aborts the +// program. +const TestProperty& TestResult::GetTestProperty(int i) const { return test_properties_->GetElement(i); } @@ -1861,14 +1860,13 @@ void TestResult::RecordProperty(const TestProperty& test_property) { return; } MutexLock lock(&test_properites_mutex_); - ListNode* const node_with_matching_key = + TestProperty* const property_with_matching_key = test_properties_->FindIf(TestPropertyKeyIs(test_property.key())); - if (node_with_matching_key == NULL) { + if (property_with_matching_key == NULL) { test_properties_->PushBack(test_property); return; } - TestProperty& property_with_matching_key = node_with_matching_key->element(); - property_with_matching_key.SetValue(test_property.value()); + property_with_matching_key->SetValue(test_property.value()); } // Adds a failure if the key is a reserved attribute of Google Test @@ -2028,7 +2026,7 @@ bool Test::HasSameFixtureClass() { // Info about the first test in the current test case. const internal::TestInfoImpl* const first_test_info = - test_case->test_info_list().Head()->element()->impl(); + test_case->test_info_list().GetElement(0)->impl(); const internal::TypeId first_fixture_id = first_test_info->fixture_class_id(); const char* const first_test_name = first_test_info->name(); @@ -2884,7 +2882,6 @@ void PrettyUnitTestResultPrinter::OnUnitTestEnd(const UnitTest& unit_test) { class UnitTestEventsRepeater : public UnitTestEventListenerInterface { public: typedef internal::List Listeners; - typedef internal::ListNode ListenersNode; UnitTestEventsRepeater() {} virtual ~UnitTestEventsRepeater(); void AddListener(UnitTestEventListenerInterface *listener); @@ -2908,10 +2905,8 @@ class UnitTestEventsRepeater : public UnitTestEventListenerInterface { }; UnitTestEventsRepeater::~UnitTestEventsRepeater() { - for (ListenersNode* listener = listeners_.Head(); - listener != NULL; - listener = listener->next()) { - delete listener->element(); + for (int i = 0; i < listeners_.size(); i++) { + delete listeners_.GetElement(i); } } @@ -2924,10 +2919,8 @@ void UnitTestEventsRepeater::AddListener( // This defines a member that repeats the call to all listeners. #define GTEST_REPEATER_METHOD_(Name, Type) \ void UnitTestEventsRepeater::Name(const Type& parameter) { \ - for (ListenersNode* listener = listeners_.Head(); \ - listener != NULL; \ - listener = listener->next()) { \ - listener->element()->Name(parameter); \ + for (int i = 0; i < listeners_.size(); i++) { \ + listeners_.GetElement(i)->Name(parameter); \ } \ } @@ -3150,7 +3143,7 @@ void XmlUnitTestResultPrinter::PrintXmlTestInfo(FILE* out, int failures = 0; 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()) { const internal::String message = internal::String::Format("%s:%d\n%s", part.file_name(), @@ -3212,7 +3205,7 @@ internal::String XmlUnitTestResultPrinter::TestPropertiesAsXmlAttributes( using internal::TestProperty; Message attributes; for (int i = 0; i < result.test_property_count(); ++i) { - const TestProperty& property = *result.GetTestProperty(i); + const TestProperty& property = result.GetTestProperty(i); attributes << " " << property.key() << "=" << "\"" << EscapeXmlAttribute(property.value()) << "\""; } @@ -3407,11 +3400,9 @@ void UnitTest::AddTestPartResult(TestPartResultType result_type, if (impl_->gtest_trace_stack()->size() > 0) { msg << "\n" << GTEST_NAME_ << " trace:"; - for (internal::ListNode* node = - impl_->gtest_trace_stack()->Head(); - node != NULL; - node = node->next()) { - const internal::TraceInfo& trace = node->element(); + for (int i = 0; i < impl_->gtest_trace_stack()->size(); i++) { + const internal::TraceInfo& trace = + impl_->gtest_trace_stack()->GetElement(i); msg << "\n" << trace.file << ":" << trace.line << ": " << trace.message; } } @@ -3606,7 +3597,7 @@ UnitTestImpl::UnitTestImpl(UnitTest* parent) parameterized_test_registry_(), parameterized_tests_registered_(false), #endif // GTEST_HAS_PARAM_TEST - last_death_test_case_(NULL), + last_death_test_case_(-1), current_test_case_(NULL), current_test_info_(NULL), ad_hoc_test_result_(), @@ -3670,30 +3661,27 @@ TestCase* UnitTestImpl::GetTestCase(const char* test_case_name, Test::SetUpTestCaseFunc set_up_tc, Test::TearDownTestCaseFunc tear_down_tc) { // Can we find a TestCase with the given name? - internal::ListNode* node = test_cases_.FindIf( - TestCaseNameIs(test_case_name)); + TestCase** test_case = test_cases_.FindIf(TestCaseNameIs(test_case_name)); - if (node == NULL) { - // No. Let's create one. - TestCase* const test_case = + if (test_case != NULL) + return *test_case; + + // No. Let's create one. + TestCase* const new_test_case = new TestCase(test_case_name, comment, set_up_tc, tear_down_tc); - // Is this a death test case? - if (internal::UnitTestOptions::MatchesFilter(String(test_case_name), - kDeathTestCaseFilter)) { - // Yes. Inserts the test case after the last death test case - // defined so far. - node = test_cases_.InsertAfter(last_death_test_case_, test_case); - last_death_test_case_ = node; - } else { - // No. Appends to the end of the list. - test_cases_.PushBack(test_case); - node = test_cases_.Last(); - } + // Is this a death test case? + if (internal::UnitTestOptions::MatchesFilter(String(test_case_name), + kDeathTestCaseFilter)) { + // Yes. Inserts the test case after the last death test case + // defined so far. + test_cases_.Insert(new_test_case, ++last_death_test_case_); + } else { + // No. Appends to the end of the list. + test_cases_.PushBack(new_test_case); } - // Returns the TestCase found. - return node->element(); + return new_test_case; } // Helpers for setting up / tearing down the given environment. They @@ -3925,19 +3913,13 @@ int UnitTestImpl::FilterTests(ReactionToSharding shard_tests) { // this shard. int num_runnable_tests = 0; int num_selected_tests = 0; - for (const internal::ListNode *test_case_node = - test_cases_.Head(); - test_case_node != NULL; - test_case_node = test_case_node->next()) { - TestCase * const test_case = test_case_node->element(); + for (int i = 0; i < test_cases_.size(); i++) { + TestCase* const test_case = test_cases_.GetElement(i); const String &test_case_name = test_case->name(); test_case->set_should_run(false); - for (const internal::ListNode *test_info_node = - test_case->test_info_list().Head(); - test_info_node != NULL; - test_info_node = test_info_node->next()) { - TestInfo * const test_info = test_info_node->element(); + for (int j = 0; j < test_case->test_info_list().size(); j++) { + TestInfo* const test_info = test_case->test_info_list().GetElement(j); const String test_name(test_info->name()); // A test is disabled if test case name or test name matches // kDisableTestFilter. @@ -3974,17 +3956,13 @@ int UnitTestImpl::FilterTests(ReactionToSharding shard_tests) { // Prints the names of the tests matching the user-specified filter flag. void UnitTestImpl::ListTestsMatchingFilter() { - for (const internal::ListNode* test_case_node = test_cases_.Head(); - test_case_node != NULL; - test_case_node = test_case_node->next()) { - const TestCase* const test_case = test_case_node->element(); + for (int i = 0; i < test_cases_.size(); i++) { + const TestCase* const test_case = test_cases_.GetElement(i); bool printed_test_case_name = false; - for (const internal::ListNode* test_info_node = - test_case->test_info_list().Head(); - test_info_node != NULL; - test_info_node = test_info_node->next()) { - const TestInfo* const test_info = test_info_node->element(); + for (int j = 0; j < test_case->test_info_list().size(); j++) { + const TestInfo* const test_info = + test_case->test_info_list().GetElement(j); if (test_info->matches_filter()) { if (!printed_test_case_name) { printed_test_case_name = true; -- cgit v1.2.3 From 89080477aee9bd91536c9fb47bc31c62ea7d75bb Mon Sep 17 00:00:00 2001 From: "zhanyong.wan" Date: Mon, 13 Jul 2009 19:25:02 +0000 Subject: Adds color support for TERM=linux (by Alexander Demin); renames List to Vector (by Zhanyong Wan); implements Vector::Erase (by Vlad Losev). --- src/gtest-internal-inl.h | 82 +++++++++++++++++++++++++++--------------------- src/gtest-test-part.cc | 10 +++--- src/gtest.cc | 19 +++++------ 3 files changed, 61 insertions(+), 50 deletions(-) (limited to 'src') diff --git a/src/gtest-internal-inl.h b/src/gtest-internal-inl.h index b4f6de6c..245dda1c 100644 --- a/src/gtest-internal-inl.h +++ b/src/gtest-internal-inl.h @@ -199,7 +199,7 @@ Int32 Int32FromEnvOrDie(const char* env_var, Int32 default_val); // method. Assumes that 0 <= shard_index < total_shards. bool ShouldRunTestOnShard(int total_shards, int shard_index, int test_id); -// List is an ordered container that supports random access to the +// Vector is an ordered container that supports random access to the // elements. // // We cannot use std::vector, as Visual C++ 7.1's implementation of @@ -209,15 +209,15 @@ bool ShouldRunTestOnShard(int total_shards, int shard_index, int test_id); // // The element type must support copy constructor and operator=. template // E is the element type. -class List { +class Vector { public: - // Creates an empty list. - List() : elements_(NULL), capacity_(0), size_(0) {} + // Creates an empty Vector. + Vector() : elements_(NULL), capacity_(0), size_(0) {} // D'tor. - virtual ~List() { Clear(); } + virtual ~Vector() { Clear(); } - // Clears the list. + // Clears the Vector. void Clear() { if (elements_ != NULL) { for (int i = 0; i < size_; i++) { @@ -233,29 +233,27 @@ class List { // Gets the number of elements. int size() const { return size_; } - // Adds an element to the end of the list. A copy of the element is - // created using the copy constructor, and then stored in the list. - // Changes made to the element in the list doesn't affect the source - // object, and vice versa. + // Adds an element to the end of the Vector. A copy of the element + // is created using the copy constructor, and then stored in the + // Vector. Changes made to the element in the Vector doesn't affect + // the source object, and vice versa. void PushBack(const E & element) { Insert(element, size_); } - // Adds an element to the beginning of this list. + // Adds an element to the beginning of this Vector. void PushFront(const E& element) { Insert(element, 0); } - // Removes an element from the beginning of this list. If the + // Removes an element from the beginning of this Vector. If the // result argument is not NULL, the removed element is stored in the // memory it points to. Otherwise the element is thrown away. - // Returns true iff the list wasn't empty before the operation. + // Returns true iff the vector wasn't empty before the operation. bool PopFront(E* result) { if (size_ == 0) return false; if (result != NULL) - *result = *(elements_[0]); + *result = GetElement(0); - delete elements_[0]; - size_--; - MoveElements(1, size_, 0); + Erase(0); return true; } @@ -269,6 +267,18 @@ class List { size_++; } + // Erases the element at the specified index, or aborts the program if the + // index is not in range [0, size()). + void Erase(int index) { + GTEST_CHECK_(0 <= index && index < size_) + << "Invalid Vector index " << index << ": must be in range [0, " + << (size_ - 1) << "]."; + + delete elements_[index]; + MoveElements(index + 1, size_ - index - 1, index); + size_--; + } + // Returns the number of elements that satisfy a given predicate. // The parameter 'predicate' is a Boolean function or functor that // accepts a 'const E &', where E is the element type. @@ -284,7 +294,7 @@ class List { return count; } - // Applies a function/functor to each element in the list. The + // Applies a function/functor to each element in the Vector. The // parameter 'functor' is a function/functor that accepts a 'const // E &', where E is the element type. This method does not change // the elements. @@ -323,7 +333,7 @@ class List { // is not in range [0, size()). const E& GetElement(int i) const { GTEST_CHECK_(0 <= i && i < size_) - << "Invalid list index " << i << ": must be in range [0, " + << "Invalid Vector index " << i << ": must be in range [0, " << (size_ - 1) << "]."; return *(elements_[i]); @@ -346,13 +356,13 @@ class List { // no more than 1/3 of the slots are wasted. const int new_capacity = 3*(capacity_/2 + 1); GTEST_CHECK_(new_capacity > capacity_) // Does the new capacity overflow? - << "Cannot grow a list with " << capacity_ << " elements already."; + << "Cannot grow a Vector with " << capacity_ << " elements already."; capacity_ = new_capacity; elements_ = static_cast( realloc(elements_, capacity_*sizeof(elements_[0]))); } - // Moves the give consecutive elements to a new index in the list. + // Moves the give consecutive elements to a new index in the Vector. void MoveElements(int source, int count, int dest) { memmove(elements_ + dest, elements_ + source, count*sizeof(elements_[0])); } @@ -361,9 +371,9 @@ class List { int capacity_; // The number of elements allocated for elements_. int size_; // The number of elements; in the range [0, capacity_]. - // We disallow copying List. - GTEST_DISALLOW_COPY_AND_ASSIGN_(List); -}; // class List + // We disallow copying Vector. + GTEST_DISALLOW_COPY_AND_ASSIGN_(Vector); +}; // class Vector // A function for deleting an object. Handy for being used as a // functor. @@ -840,21 +850,21 @@ class UnitTestImpl { TestInfo* current_test_info() { return current_test_info_; } const TestInfo* current_test_info() const { return current_test_info_; } - // Returns the list of environments that need to be set-up/torn-down + // Returns the vector of environments that need to be set-up/torn-down // before/after the tests are run. - internal::List* environments() { return &environments_; } - internal::List* environments_in_reverse_order() { + internal::Vector* environments() { return &environments_; } + internal::Vector* environments_in_reverse_order() { return &environments_in_reverse_order_; } - internal::List* test_cases() { return &test_cases_; } - const internal::List* test_cases() const { return &test_cases_; } + internal::Vector* test_cases() { return &test_cases_; } + const internal::Vector* test_cases() const { return &test_cases_; } // Getters for the per-thread Google Test trace stack. - internal::List* gtest_trace_stack() { + internal::Vector* gtest_trace_stack() { return gtest_trace_stack_.pointer(); } - const internal::List* gtest_trace_stack() const { + const internal::Vector* gtest_trace_stack() const { return gtest_trace_stack_.pointer(); } @@ -899,13 +909,13 @@ class UnitTestImpl { internal::ThreadLocal per_thread_test_part_result_reporter_; - // The list of environments that need to be set-up/torn-down + // The vector of environments that need to be set-up/torn-down // before/after the tests are run. environments_in_reverse_order_ // simply mirrors environments_ in reverse order. - internal::List environments_; - internal::List environments_in_reverse_order_; + internal::Vector environments_; + internal::Vector environments_in_reverse_order_; - internal::List test_cases_; // The list of TestCases. + internal::Vector test_cases_; // The vector of TestCases. #if GTEST_HAS_PARAM_TEST // ParameterizedTestRegistry object used to register value-parameterized @@ -964,7 +974,7 @@ class UnitTestImpl { #endif // GTEST_HAS_DEATH_TEST // A per-thread stack of traces created by the SCOPED_TRACE() macro. - internal::ThreadLocal > gtest_trace_stack_; + internal::ThreadLocal > gtest_trace_stack_; GTEST_DISALLOW_COPY_AND_ASSIGN_(UnitTestImpl); }; // class UnitTestImpl diff --git a/src/gtest-test-part.cc b/src/gtest-test-part.cc index 472b8c58..f053773f 100644 --- a/src/gtest-test-part.cc +++ b/src/gtest-test-part.cc @@ -66,17 +66,17 @@ std::ostream& operator<<(std::ostream& os, const TestPartResult& result) { // Constructs an empty TestPartResultArray. TestPartResultArray::TestPartResultArray() - : list_(new internal::List) { + : array_(new internal::Vector) { } // Destructs a TestPartResultArray. TestPartResultArray::~TestPartResultArray() { - delete list_; + delete array_; } // Appends a TestPartResult to the array. void TestPartResultArray::Append(const TestPartResult& result) { - list_->PushBack(result); + array_->PushBack(result); } // Returns the TestPartResult at the given index (0-based). @@ -86,12 +86,12 @@ const TestPartResult& TestPartResultArray::GetTestPartResult(int index) const { internal::posix::Abort(); } - return list_->GetElement(index); + return array_->GetElement(index); } // Returns the number of TestPartResult objects in the array. int TestPartResultArray::size() const { - return list_->size(); + return array_->size(); } namespace internal { diff --git a/src/gtest.cc b/src/gtest.cc index 845fb902..2861fdb3 100644 --- a/src/gtest.cc +++ b/src/gtest.cc @@ -185,7 +185,7 @@ GTEST_DEFINE_string_( "Whether to use colors in the output. Valid values: yes, no, " "and auto. 'auto' means to use colors if the output is " "being sent to a terminal and the TERM environment variable " - "is set to xterm, xterm-color, xterm-256color or cygwin."); + "is set to xterm, xterm-color, xterm-256color, linux or cygwin."); GTEST_DEFINE_string_( filter, @@ -258,10 +258,10 @@ static bool g_help_flag = false; int g_init_gtest_count = 0; static bool GTestIsInitialized() { return g_init_gtest_count != 0; } -// Iterates over a list of TestCases, keeping a running sum of the +// Iterates over a vector of TestCases, keeping a running sum of the // results of calling a given int-returning method on each. // Returns the sum. -static int SumOverTestCaseList(const internal::List& case_list, +static int SumOverTestCaseList(const internal::Vector& case_list, int (TestCase::*method)() const) { int sum = 0; for (int i = 0; i < case_list.size(); i++) { @@ -1818,8 +1818,8 @@ String AppendUserMessage(const String& gtest_msg, // Creates an empty TestResult. TestResult::TestResult() - : test_part_results_(new List), - test_properties_(new List), + : test_part_results_(new Vector), + test_properties_(new Vector), death_test_count_(0), elapsed_time_(0) { } @@ -2407,7 +2407,7 @@ TestCase::TestCase(const char* name, const char* comment, tear_down_tc_(tear_down_tc), should_run_(false), elapsed_time_(0) { - test_info_list_ = new internal::List; + test_info_list_ = new internal::Vector; } // Destructor of TestCase. @@ -2603,6 +2603,7 @@ bool ShouldUseColor(bool stdout_is_tty) { String::CStringEquals(term, "xterm") || String::CStringEquals(term, "xterm-color") || String::CStringEquals(term, "xterm-256color") || + String::CStringEquals(term, "linux") || String::CStringEquals(term, "cygwin"); return stdout_is_tty && term_supports_color; #endif // GTEST_OS_WINDOWS @@ -2881,7 +2882,7 @@ void PrettyUnitTestResultPrinter::OnUnitTestEnd(const UnitTest& unit_test) { // This class forwards events to other event listeners. class UnitTestEventsRepeater : public UnitTestEventListenerInterface { public: - typedef internal::List Listeners; + typedef internal::Vector Listeners; UnitTestEventsRepeater() {} virtual ~UnitTestEventsRepeater(); void AddListener(UnitTestEventListenerInterface *listener); @@ -3685,7 +3686,7 @@ TestCase* UnitTestImpl::GetTestCase(const char* test_case_name, } // Helpers for setting up / tearing down the given environment. They -// are for use in the List::ForEach() method. +// are for use in the Vector::ForEach() method. static void SetUpEnvironment(Environment* env) { env->SetUp(); } static void TearDownEnvironment(Environment* env) { env->TearDown(); } @@ -3739,7 +3740,7 @@ int UnitTestImpl::RunAllTests() { ? HONOR_SHARDING_PROTOCOL : IGNORE_SHARDING_PROTOCOL) > 0; - // List the tests and exit if the --gtest_list_tests flag was specified. + // Lists the tests and exits if the --gtest_list_tests flag was specified. if (GTEST_FLAG(list_tests)) { // This must be called *after* FilterTests() has been called. ListTestsMatchingFilter(); -- cgit v1.2.3 From 8bdb31e0540c46de485b362178f60e8bb947ff43 Mon Sep 17 00:00:00 2001 From: "zhanyong.wan" Date: Tue, 14 Jul 2009 22:56:46 +0000 Subject: Adds the command line flags needed for test shuffling. Most code by Josh Kelley. --- src/gtest-internal-inl.h | 47 ++++++++++++++++++++++++++++++++++++++- src/gtest.cc | 57 ++++++++++++++++++++++++++++++++++++++++++------ 2 files changed, 96 insertions(+), 8 deletions(-) (limited to 'src') diff --git a/src/gtest-internal-inl.h b/src/gtest-internal-inl.h index 245dda1c..92975dd0 100644 --- a/src/gtest-internal-inl.h +++ b/src/gtest-internal-inl.h @@ -87,9 +87,42 @@ const char kFilterFlag[] = "filter"; const char kListTestsFlag[] = "list_tests"; const char kOutputFlag[] = "output"; const char kPrintTimeFlag[] = "print_time"; +const char kRandomSeedFlag[] = "random_seed"; const char kRepeatFlag[] = "repeat"; +const char kShuffleFlag[] = "shuffle"; const char kThrowOnFailureFlag[] = "throw_on_failure"; +// A valid random seed must be in [1, kMaxRandomSeed]. +const unsigned int kMaxRandomSeed = 99999; + +// Returns the current time in milliseconds. +TimeInMillis GetTimeInMillis(); + +// Returns a random seed in range [1, kMaxRandomSeed] based on the +// given --gtest_random_seed flag value. +inline int GetRandomSeedFromFlag(Int32 random_seed_flag) { + const unsigned int raw_seed = (random_seed_flag == 0) ? + static_cast(GetTimeInMillis()) : + static_cast(random_seed_flag); + + // Normalizes the actual seed to range [1, kMaxRandomSeed] such that + // it's easy to type. + const int normalized_seed = + static_cast((raw_seed - 1U) % kMaxRandomSeed) + 1; + return normalized_seed; +} + +// Returns the first valid random seed after 'seed'. The behavior is +// undefined if 'seed' is invalid. The seed after kMaxRandomSeed is +// considered to be 1. +inline int GetNextRandomSeed(int seed) { + GTEST_CHECK_(1 <= seed && seed <= kMaxRandomSeed) + << "Invalid random seed " << seed << " - must be in [1, " + << kMaxRandomSeed << "]."; + const int next_seed = seed + 1; + return (next_seed > kMaxRandomSeed) ? 1 : next_seed; +} + // This class saves the values of all Google Test flags in its c'tor, and // restores them in its d'tor. class GTestFlagSaver { @@ -107,7 +140,9 @@ class GTestFlagSaver { list_tests_ = GTEST_FLAG(list_tests); output_ = GTEST_FLAG(output); print_time_ = GTEST_FLAG(print_time); + random_seed_ = GTEST_FLAG(random_seed); repeat_ = GTEST_FLAG(repeat); + shuffle_ = GTEST_FLAG(shuffle); throw_on_failure_ = GTEST_FLAG(throw_on_failure); } @@ -124,7 +159,9 @@ class GTestFlagSaver { GTEST_FLAG(list_tests) = list_tests_; GTEST_FLAG(output) = output_; GTEST_FLAG(print_time) = print_time_; + GTEST_FLAG(random_seed) = random_seed_; GTEST_FLAG(repeat) = repeat_; + GTEST_FLAG(shuffle) = shuffle_; GTEST_FLAG(throw_on_failure) = throw_on_failure_; } private: @@ -141,7 +178,9 @@ class GTestFlagSaver { String output_; bool print_time_; bool pretty_; + internal::Int32 random_seed_; internal::Int32 repeat_; + bool shuffle_; bool throw_on_failure_; } GTEST_ATTRIBUTE_UNUSED_; @@ -884,6 +923,9 @@ class UnitTestImpl { friend class ReplaceDeathTestFactory; #endif // GTEST_HAS_DEATH_TEST + // Gets the random seed used at the start of the current test run. + int random_seed() const { return random_seed_; } + private: friend class ::testing::UnitTest; @@ -932,7 +974,7 @@ class UnitTestImpl { // This points to the TestCase for the currently running test. It // changes as Google Test goes through one test case after another. // When no test is running, this is set to NULL and Google Test - // stores assertion results in ad_hoc_test_result_. Initally NULL. + // stores assertion results in ad_hoc_test_result_. Initially NULL. TestCase* current_test_case_; // This points to the TestInfo for the currently running test. It @@ -963,6 +1005,9 @@ class UnitTestImpl { // desired. OsStackTraceGetterInterface* os_stack_trace_getter_; + // The random number seed used at the beginning of the test run. + int random_seed_; + // How long the test took to run, in milliseconds. TimeInMillis elapsed_time_; diff --git a/src/gtest.cc b/src/gtest.cc index 2861fdb3..7bdf18ad 100644 --- a/src/gtest.cc +++ b/src/gtest.cc @@ -217,23 +217,35 @@ GTEST_DEFINE_bool_( "True iff " GTEST_NAME_ " should display elapsed time in text output."); +GTEST_DEFINE_int32_( + random_seed, + internal::Int32FromGTestEnv("random_seed", 0), + "Random number seed to use when shuffling test orders. Must be in range " + "[1, 99999], or 0 to use a seed based on the current time."); + GTEST_DEFINE_int32_( repeat, internal::Int32FromGTestEnv("repeat", 1), "How many times to repeat each test. Specify a negative number " "for repeating forever. Useful for shaking out flaky tests."); +GTEST_DEFINE_bool_( + show_internal_stack_frames, false, + "True iff " GTEST_NAME_ " should include internal stack frames when " + "printing test failure stack traces."); + +GTEST_DEFINE_bool_( + shuffle, + internal::BoolFromGTestEnv("shuffle", false), + "True iff " GTEST_NAME_ + " should randomize tests' order on every run."); + GTEST_DEFINE_int32_( stack_trace_depth, internal::Int32FromGTestEnv("stack_trace_depth", kMaxStackTraceDepth), "The maximum number of stack frames to print when an " "assertion fails. The valid range is 0 through 100, inclusive."); -GTEST_DEFINE_bool_( - show_internal_stack_frames, false, - "True iff " GTEST_NAME_ " should include internal stack frames when " - "printing test failure stack traces."); - GTEST_DEFINE_bool_( throw_on_failure, internal::BoolFromGTestEnv("throw_on_failure", false), @@ -774,9 +786,10 @@ String UnitTestImpl::CurrentOsStackTraceExceptTop(int skip_count) { return String(""); } -static TimeInMillis GetTimeInMillis() { +// Returns the current time in milliseconds. +TimeInMillis GetTimeInMillis() { #if defined(_WIN32_WCE) || defined(__BORLANDC__) - // Difference between 1970-01-01 and 1601-01-01 in miliseconds. + // Difference between 1970-01-01 and 1601-01-01 in milliseconds. // http://analogous.blogspot.com/2005/04/epoch.html const TimeInMillis kJavaEpochToWinFileTimeDelta = static_cast(116444736UL) * 100000UL; @@ -2719,6 +2732,12 @@ void PrettyUnitTestResultPrinter::OnUnitTestStart(const UnitTest& unit_test) { internal::posix::GetEnv(kTestTotalShards)); } + if (GTEST_FLAG(shuffle)) { + ColoredPrintf(COLOR_YELLOW, + "Note: Randomizing tests' orders with a seed of %d .\n", + unit_test.random_seed()); + } + ColoredPrintf(COLOR_GREEN, "[==========] "); printf("Running %s from %s.\n", FormatTestCount(unit_test.test_to_run_count()).c_str(), @@ -3193,6 +3212,9 @@ void XmlUnitTestResultPrinter::PrintXmlUnitTest(FILE* out, unit_test.failed_test_count(), unit_test.disabled_test_count(), internal::FormatTimeInMillisAsSeconds(unit_test.elapsed_time())); + if (GTEST_FLAG(shuffle)) { + fprintf(out, "random_seed=\"%d\" ", unit_test.random_seed()); + } fprintf(out, "name=\"AllTests\">\n"); for (int i = 0; i < unit_test.total_test_case_count(); ++i) PrintXmlTestCase(out, *unit_test.GetTestCase(i)); @@ -3539,6 +3561,9 @@ const TestInfo* UnitTest::current_test_info() const { return impl_->current_test_info(); } +// Returns the random seed used at the start of the current test run. +int UnitTest::random_seed() const { return impl_->random_seed(); } + #if GTEST_HAS_PARAM_TEST // Returns ParameterizedTestCaseRegistry object used to keep track of // value-parameterized tests and instantiate and register them. @@ -3604,6 +3629,7 @@ UnitTestImpl::UnitTestImpl(UnitTest* parent) ad_hoc_test_result_(), result_printer_(NULL), os_stack_trace_getter_(NULL), + random_seed_(0), #if GTEST_HAS_DEATH_TEST elapsed_time_(0), internal_run_death_test_flag_(NULL), @@ -3747,6 +3773,9 @@ int UnitTestImpl::RunAllTests() { return 0; } + random_seed_ = GTEST_FLAG(shuffle) ? + GetRandomSeedFromFlag(GTEST_FLAG(random_seed)) : 0; + // True iff at least one test has failed. bool failed = false; @@ -3796,6 +3825,11 @@ int UnitTestImpl::RunAllTests() { failed = true; } ClearResult(); + + if (GTEST_FLAG(shuffle)) { + // Picks a new random seed for each run. + random_seed_ = GetNextRandomSeed(random_seed_); + } } // Returns 0 if all tests passed, or 1 other wise. @@ -4262,8 +4296,15 @@ static const char kColorEncodedHelpMessage[] = " matches any substring; ':' separates two patterns.\n" " @G--" GTEST_FLAG_PREFIX_ "also_run_disabled_tests@D\n" " Run all disabled tests too.\n" +"\n" +"Test Execution:\n" " @G--" GTEST_FLAG_PREFIX_ "repeat=@Y[COUNT]@D\n" " Run the tests repeatedly; use a negative count to repeat forever.\n" +" @G--" GTEST_FLAG_PREFIX_ "shuffle\n" +" Randomize tests' orders on every run. To be implemented.\n" +" @G--" GTEST_FLAG_PREFIX_ "random_seed=@Y[NUMBER]@D\n" +" Random number seed to use for shuffling test orders (between 1 and\n" +" 99999, or 0 to use a seed based on the current time).\n" "\n" "Test Output:\n" " @G--" GTEST_FLAG_PREFIX_ "color=@Y(@Gyes@Y|@Gno@Y|@Gauto@Y)@D\n" @@ -4332,7 +4373,9 @@ void ParseGoogleTestFlagsOnlyImpl(int* argc, CharType** argv) { ParseBoolFlag(arg, kListTestsFlag, >EST_FLAG(list_tests)) || ParseStringFlag(arg, kOutputFlag, >EST_FLAG(output)) || ParseBoolFlag(arg, kPrintTimeFlag, >EST_FLAG(print_time)) || + ParseInt32Flag(arg, kRandomSeedFlag, >EST_FLAG(random_seed)) || ParseInt32Flag(arg, kRepeatFlag, >EST_FLAG(repeat)) || + ParseBoolFlag(arg, kShuffleFlag, >EST_FLAG(shuffle)) || ParseBoolFlag(arg, kThrowOnFailureFlag, >EST_FLAG(throw_on_failure)) ) { // Yes. Shift the remainder of the argv list left by one. Note -- cgit v1.2.3 From 3a47ddf8ea888b4e5fe06bf79ef03a1456274f00 Mon Sep 17 00:00:00 2001 From: "zhanyong.wan" Date: Wed, 15 Jul 2009 19:01:51 +0000 Subject: Makes gtest report failures to Visual Studio's Output window. Based on code by Alexander Demin. --- src/gtest.cc | 18 ++++++++++++++---- 1 file changed, 14 insertions(+), 4 deletions(-) (limited to 'src') diff --git a/src/gtest.cc b/src/gtest.cc index 7bdf18ad..bc970173 100644 --- a/src/gtest.cc +++ b/src/gtest.cc @@ -2556,10 +2556,19 @@ static internal::String PrintTestPartResultToString( } // Prints a TestPartResult. -static void PrintTestPartResult( - const TestPartResult& test_part_result) { - printf("%s\n", PrintTestPartResultToString(test_part_result).c_str()); +static void PrintTestPartResult(const TestPartResult& test_part_result) { + const internal::String& result = + PrintTestPartResultToString(test_part_result); + printf("%s\n", result.c_str()); fflush(stdout); +#if GTEST_OS_WINDOWS + // If the test program runs in Visual Studio or a debugger, the + // following states add the test part result message to the Output + // window such that the user can double-click on it to jump to the + // corresponding source code location; otherwise they do nothing. + ::OutputDebugStringA(result.c_str()); + ::OutputDebugStringA("\n"); +#endif } // class PrettyUnitTestResultPrinter @@ -3426,7 +3435,8 @@ void UnitTest::AddTestPartResult(TestPartResultType result_type, for (int i = 0; i < impl_->gtest_trace_stack()->size(); i++) { const internal::TraceInfo& trace = impl_->gtest_trace_stack()->GetElement(i); - msg << "\n" << trace.file << ":" << trace.line << ": " << trace.message; + msg << "\n" << internal::FormatFileLocation(trace.file, trace.line) + << " " << trace.message; } } -- cgit v1.2.3 From c214ebc830aa918d54e535c6caa2da6317877e12 Mon Sep 17 00:00:00 2001 From: "zhanyong.wan" Date: Thu, 16 Jul 2009 00:36:55 +0000 Subject: More refactoring for the event listener API, by Vlad Losev. --- src/gtest-internal-inl.h | 38 ++++++++++++++++++++++++-------- src/gtest.cc | 56 ++++++++++++++++++------------------------------ 2 files changed, 50 insertions(+), 44 deletions(-) (limited to 'src') diff --git a/src/gtest-internal-inl.h b/src/gtest-internal-inl.h index 92975dd0..5bb981d2 100644 --- a/src/gtest-internal-inl.h +++ b/src/gtest-internal-inl.h @@ -483,8 +483,8 @@ class TestInfoImpl { TypeId fixture_class_id() const { return fixture_class_id_; } // Returns the test result. - internal::TestResult* result() { return &result_; } - const internal::TestResult* result() const { return &result_; } + TestResult* result() { return &result_; } + const TestResult* result() const { return &result_; } // Creates the test object, runs it, records its result, and then // deletes it. @@ -520,7 +520,7 @@ class TestInfoImpl { // This field is mutable and needs to be reset before running the // test for the second time. - internal::TestResult result_; + TestResult result_; GTEST_DISALLOW_COPY_AND_ASSIGN_(TestInfoImpl); }; @@ -742,19 +742,17 @@ class UnitTestImpl { // Returns the TestResult for the test that's currently running, or // the TestResult for the ad hoc test if no test is running. - internal::TestResult* current_test_result(); + TestResult* current_test_result(); // Returns the TestResult for the ad hoc test. - const internal::TestResult* ad_hoc_test_result() const { - return &ad_hoc_test_result_; - } + const TestResult* ad_hoc_test_result() const { return &ad_hoc_test_result_; } // Sets the unit test result printer. // // Does nothing if the input and the current printer object are the // same; otherwise, deletes the old printer object and makes the // input the current printer. - void set_result_printer(UnitTestEventListenerInterface * result_printer); + void set_result_printer(UnitTestEventListenerInterface* result_printer); // Returns the current unit test result printer if it is not NULL; // otherwise, creates an appropriate result printer, makes it the @@ -991,7 +989,7 @@ class UnitTestImpl { // If an assertion is encountered when no TEST or TEST_F is running, // Google Test attributes the assertion result to an imaginary "ad hoc" // test, and records the result in ad_hoc_test_result_. - internal::TestResult ad_hoc_test_result_; + TestResult ad_hoc_test_result_; // The unit test result printer. Will be deleted when the UnitTest // object is destructed. By default, a plain text printer is used, @@ -1122,6 +1120,28 @@ bool ParseNaturalNumber(const ::std::string& str, Integer* number) { } #endif // GTEST_HAS_DEATH_TEST +// TestResult contains some private methods that should be hidden from +// Google Test user but are required for testing. This class allow our tests +// to access them. +class TestResultAccessor { + public: + static void RecordProperty(TestResult* test_result, + const TestProperty& property) { + test_result->RecordProperty(property); + } + + static bool Passed(const TestResult& result) { return result.Passed(); } + + static void ClearTestPartResults(TestResult* test_result) { + test_result->ClearTestPartResults(); + } + + static const Vector& test_part_results( + const TestResult& test_result) { + return test_result.test_part_results(); + } +}; + } // namespace internal } // namespace testing diff --git a/src/gtest.cc b/src/gtest.cc index bc970173..69d2517f 100644 --- a/src/gtest.cc +++ b/src/gtest.cc @@ -130,6 +130,8 @@ namespace testing { using internal::TestCase; +using internal::TestProperty; +using internal::TestResult; // Constants. @@ -1831,8 +1833,8 @@ String AppendUserMessage(const String& gtest_msg, // Creates an empty TestResult. TestResult::TestResult() - : test_part_results_(new Vector), - test_properties_(new Vector), + : test_part_results_(new internal::Vector), + test_properties_(new internal::Vector), death_test_count_(0), elapsed_time_(0) { } @@ -1872,9 +1874,10 @@ void TestResult::RecordProperty(const TestProperty& test_property) { if (!ValidateTestProperty(test_property)) { return; } - MutexLock lock(&test_properites_mutex_); + internal::MutexLock lock(&test_properites_mutex_); TestProperty* const property_with_matching_key = - test_properties_->FindIf(TestPropertyKeyIs(test_property.key())); + test_properties_->FindIf( + internal::TestPropertyKeyIs(test_property.key())); if (property_with_matching_key == NULL) { test_properties_->PushBack(test_property); return; @@ -1885,7 +1888,7 @@ void TestResult::RecordProperty(const TestProperty& test_property) { // Adds a failure if the key is a reserved attribute of Google Test // testcase tags. Returns true if the property is valid. bool TestResult::ValidateTestProperty(const TestProperty& test_property) { - String key(test_property.key()); + internal::String key(test_property.key()); if (key == "name" || key == "status" || key == "time" || key == "classname") { ADD_FAILURE() << "Reserved key used in RecordProperty(): " @@ -1905,24 +1908,13 @@ void TestResult::Clear() { elapsed_time_ = 0; } -// Returns true iff the test part passed. -static bool TestPartPassed(const TestPartResult & result) { - return result.passed(); -} - -// Gets the number of successful test parts. -int TestResult::successful_part_count() const { - return test_part_results_->CountIf(TestPartPassed); -} - -// Returns true iff the test part failed. -static bool TestPartFailed(const TestPartResult & result) { - return result.failed(); -} - -// Gets the number of failed test parts. -int TestResult::failed_part_count() const { - return test_part_results_->CountIf(TestPartFailed); +// Returns true iff the test failed. +bool TestResult::Failed() const { + for (int i = 0; i < total_part_count(); ++i) { + if (GetTestPartResult(i).failed()) + return true; + } + return false; } // Returns true iff the test part fatally failed. @@ -2264,7 +2256,7 @@ bool TestInfo::should_run() const { return impl_->should_run(); } bool TestInfo::matches_filter() const { return impl_->matches_filter(); } // Returns the result of the test. -const internal::TestResult* TestInfo::result() const { return impl_->result(); } +const TestResult* TestInfo::result() const { return impl_->result(); } // Increments the number of death tests encountered in this test so // far. @@ -3021,7 +3013,7 @@ class XmlUnitTestResultPrinter : public EmptyTestEventListener { // When the String is not empty, it includes a space at the beginning, // to delimit this attribute from prior attributes. static internal::String TestPropertiesAsXmlAttributes( - const internal::TestResult& result); + const TestResult& result); // The output file. const internal::String output_file_; @@ -3160,7 +3152,7 @@ const char* FormatTimeInMillisAsSeconds(TimeInMillis ms) { void XmlUnitTestResultPrinter::PrintXmlTestInfo(FILE* out, const char* test_case_name, const TestInfo& test_info) { - const internal::TestResult& result = *test_info.result(); + const TestResult& result = *test_info.result(); fprintf(out, " current_test_result()->RecordProperty(test_property); } @@ -4089,7 +4080,7 @@ OsStackTraceGetterInterface* UnitTestImpl::os_stack_trace_getter() { // Returns the TestResult for the test that's currently running, or // the TestResult for the ad hoc test if no test is running. -internal::TestResult* UnitTestImpl::current_test_result() { +TestResult* UnitTestImpl::current_test_result() { return current_test_info_ ? current_test_info_->impl()->result() : &ad_hoc_test_result_; } @@ -4136,11 +4127,6 @@ String GetCurrentOsStackTraceExceptTop(UnitTest* unit_test, int skip_count) { return GetUnitTestImpl()->CurrentOsStackTraceExceptTop(skip_count + 1); } -// Returns the number of failed test parts in the given test result object. -int GetFailedPartCount(const TestResult* result) { - return result->failed_part_count(); -} - // Used by the GTEST_HIDE_UNREACHABLE_CODE_ macro to suppress unreachable // code warnings. namespace { -- cgit v1.2.3 From 16b9431ae01d83de80db7ef3e411d9771ee845e4 Mon Sep 17 00:00:00 2001 From: "zhanyong.wan" Date: Wed, 22 Jul 2009 02:16:37 +0000 Subject: Makes gtest compile clean with gcc -Wall -Werror (by Zhanyong Wan); refactors scons script (by Vlad Losev). --- src/gtest-internal-inl.h | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) (limited to 'src') diff --git a/src/gtest-internal-inl.h b/src/gtest-internal-inl.h index 5bb981d2..189852e6 100644 --- a/src/gtest-internal-inl.h +++ b/src/gtest-internal-inl.h @@ -93,7 +93,7 @@ const char kShuffleFlag[] = "shuffle"; const char kThrowOnFailureFlag[] = "throw_on_failure"; // A valid random seed must be in [1, kMaxRandomSeed]. -const unsigned int kMaxRandomSeed = 99999; +const int kMaxRandomSeed = 99999; // Returns the current time in milliseconds. TimeInMillis GetTimeInMillis(); @@ -108,7 +108,8 @@ inline int GetRandomSeedFromFlag(Int32 random_seed_flag) { // Normalizes the actual seed to range [1, kMaxRandomSeed] such that // it's easy to type. const int normalized_seed = - static_cast((raw_seed - 1U) % kMaxRandomSeed) + 1; + static_cast((raw_seed - 1U) % + static_cast(kMaxRandomSeed)) + 1; return normalized_seed; } -- cgit v1.2.3 From 18c31d64e120919e8e04df3035234b9afe8eb6d9 Mon Sep 17 00:00:00 2001 From: "zhanyong.wan" Date: Thu, 23 Jul 2009 06:30:32 +0000 Subject: Makes gtest compilable on Win CE. --- src/gtest.cc | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) (limited to 'src') diff --git a/src/gtest.cc b/src/gtest.cc index 69d2517f..a767d194 100644 --- a/src/gtest.cc +++ b/src/gtest.cc @@ -2553,11 +2553,16 @@ static void PrintTestPartResult(const TestPartResult& test_part_result) { PrintTestPartResultToString(test_part_result); printf("%s\n", result.c_str()); fflush(stdout); -#if GTEST_OS_WINDOWS // If the test program runs in Visual Studio or a debugger, the - // following states add the test part result message to the Output + // following statements add the test part result message to the Output // window such that the user can double-click on it to jump to the // corresponding source code location; otherwise they do nothing. +#ifdef _WIN32_WCE + // Windows Mobile doesn't support the ANSI version of OutputDebugString, + // it works only with UTF16 strings. + ::OutputDebugString(internal::String::AnsiToUtf16(result.c_str())); + ::OutputDebugString(L"\n"); +#elif GTEST_OS_WINDOWS ::OutputDebugStringA(result.c_str()); ::OutputDebugStringA("\n"); #endif -- cgit v1.2.3 From ed8500b341c473ecf46acd13951ae5b4e3acc780 Mon Sep 17 00:00:00 2001 From: "zhanyong.wan" Date: Fri, 7 Aug 2009 06:47:47 +0000 Subject: Implements EXPECT_DEATH_IF_SUPPORTED (by Vlad Losev); Fixes compatibility with Symbian (by Araceli Checa); Removes GetCapturedStderr()'s dependency on std::string (by Vlad Losev). --- src/gtest-death-test.cc | 8 ++------ src/gtest-port.cc | 12 ++++-------- 2 files changed, 6 insertions(+), 14 deletions(-) (limited to 'src') diff --git a/src/gtest-death-test.cc b/src/gtest-death-test.cc index 0d4110bd..02ce48d5 100644 --- a/src/gtest-death-test.cc +++ b/src/gtest-death-test.cc @@ -452,11 +452,7 @@ bool DeathTestImpl::Passed(bool status_ok) { if (!spawned()) return false; -#if GTEST_HAS_GLOBAL_STRING - const ::string error_message = GetCapturedStderr(); -#else - const ::std::string error_message = GetCapturedStderr(); -#endif // GTEST_HAS_GLOBAL_STRING + const String error_message = GetCapturedStderr(); bool success = false; Message buffer; @@ -473,7 +469,7 @@ bool DeathTestImpl::Passed(bool status_ok) { break; case DIED: if (status_ok) { - if (RE::PartialMatch(error_message, *regex())) { + if (RE::PartialMatch(error_message.c_str(), *regex())) { success = true; } else { buffer << " Result: died but not with expected error.\n" diff --git a/src/gtest-port.cc b/src/gtest-port.cc index bc6d8f80..09d1a8e0 100644 --- a/src/gtest-port.cc +++ b/src/gtest-port.cc @@ -431,8 +431,6 @@ void GTestLog(GTestLogSeverity severity, const char* file, } } -#if GTEST_HAS_STD_STRING - // Disable Microsoft deprecation warnings for POSIX functions called from // this class (creat, dup, dup2, and close) #ifdef _MSC_VER @@ -514,7 +512,7 @@ static size_t GetFileSize(FILE * file) { } // Reads the entire content of a file as a string. -static ::std::string ReadEntireFile(FILE * file) { +static String ReadEntireFile(FILE * file) { const size_t file_size = GetFileSize(file); char* const buffer = new char[file_size]; @@ -530,7 +528,7 @@ static ::std::string ReadEntireFile(FILE * file) { bytes_read += bytes_last_read; } while (bytes_last_read > 0 && bytes_read < file_size); - const ::std::string content(buffer, buffer+bytes_read); + const String content(buffer, bytes_read); delete[] buffer; return content; @@ -547,11 +545,11 @@ void CaptureStderr() { // Stops capturing stderr and returns the captured string. // GTEST_HAS_DEATH_TEST implies that we have ::std::string, so we can // use it here. -::std::string GetCapturedStderr() { +String GetCapturedStderr() { g_captured_stderr->StopCapture(); FILE* const file = posix::FOpen(g_captured_stderr->filename().c_str(), "r"); - const ::std::string content = ReadEntireFile(file); + const String content = ReadEntireFile(file); posix::FClose(file); delete g_captured_stderr; @@ -560,8 +558,6 @@ void CaptureStderr() { return content; } -#endif // GTEST_HAS_STD_STRING - #if GTEST_HAS_DEATH_TEST // A copy of all command line arguments. Set by InitGoogleTest(). -- cgit v1.2.3 From 1da9ceefa5994624c9264431e7f65f85d2bd49ec Mon Sep 17 00:00:00 2001 From: "zhanyong.wan" Date: Wed, 26 Aug 2009 17:44:38 +0000 Subject: Fixes an uninitialized field in class OsStackTraceGetter. --- src/gtest-internal-inl.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src') diff --git a/src/gtest-internal-inl.h b/src/gtest-internal-inl.h index 189852e6..84319713 100644 --- a/src/gtest-internal-inl.h +++ b/src/gtest-internal-inl.h @@ -606,7 +606,7 @@ class OsStackTraceGetterInterface { // A working implementation of the OsStackTraceGetterInterface interface. class OsStackTraceGetter : public OsStackTraceGetterInterface { public: - OsStackTraceGetter() {} + OsStackTraceGetter() : caller_frame_(NULL) {} virtual String CurrentStackTrace(int max_depth, int skip_count); virtual void UponLeavingGTest(); -- cgit v1.2.3 From 56a2e686e915d483cb22db091140130b23814127 Mon Sep 17 00:00:00 2001 From: "zhanyong.wan" Date: Tue, 1 Sep 2009 18:53:56 +0000 Subject: Enables String to contain NUL (by Zhanyong Wan); Adds scons scripts (by Vlad Losev). --- src/gtest-filepath.cc | 14 ++++----- src/gtest-port.cc | 2 +- src/gtest.cc | 83 ++++++++++++++++++++------------------------------- 3 files changed, 40 insertions(+), 59 deletions(-) (limited to 'src') diff --git a/src/gtest-filepath.cc b/src/gtest-filepath.cc index f966352b..ef742366 100644 --- a/src/gtest-filepath.cc +++ b/src/gtest-filepath.cc @@ -103,7 +103,7 @@ FilePath FilePath::GetCurrentDir() { FilePath FilePath::RemoveExtension(const char* extension) const { String dot_extension(String::Format(".%s", extension)); if (pathname_.EndsWithCaseInsensitive(dot_extension.c_str())) { - return FilePath(String(pathname_.c_str(), pathname_.GetLength() - 4)); + return FilePath(String(pathname_.c_str(), pathname_.length() - 4)); } return *this; } @@ -217,7 +217,7 @@ bool FilePath::IsRootDirectory() const { // TODO(wan@google.com): on Windows a network share like // \\server\share can be a root directory, although it cannot be the // current directory. Handle this properly. - return pathname_.GetLength() == 3 && IsAbsolutePath(); + return pathname_.length() == 3 && IsAbsolutePath(); #else return pathname_ == kPathSeparatorString; #endif @@ -227,7 +227,7 @@ bool FilePath::IsRootDirectory() const { bool FilePath::IsAbsolutePath() const { const char* const name = pathname_.c_str(); #if GTEST_OS_WINDOWS - return pathname_.GetLength() >= 3 && + return pathname_.length() >= 3 && ((name[0] >= 'a' && name[0] <= 'z') || (name[0] >= 'A' && name[0] <= 'Z')) && name[1] == ':' && @@ -271,7 +271,7 @@ bool FilePath::CreateDirectoriesRecursively() const { return false; } - if (pathname_.GetLength() == 0 || this->DirectoryExists()) { + if (pathname_.length() == 0 || this->DirectoryExists()) { return true; } @@ -307,7 +307,7 @@ bool FilePath::CreateFolder() const { // On Windows platform, uses \ as the separator, other platforms use /. FilePath FilePath::RemoveTrailingPathSeparator() const { return pathname_.EndsWith(kPathSeparatorString) - ? FilePath(String(pathname_.c_str(), pathname_.GetLength() - 1)) + ? FilePath(String(pathname_.c_str(), pathname_.length() - 1)) : *this; } @@ -320,9 +320,9 @@ void FilePath::Normalize() { return; } const char* src = pathname_.c_str(); - char* const dest = new char[pathname_.GetLength() + 1]; + char* const dest = new char[pathname_.length() + 1]; char* dest_ptr = dest; - memset(dest_ptr, 0, pathname_.GetLength() + 1); + memset(dest_ptr, 0, pathname_.length() + 1); while (*src != '\0') { *dest_ptr++ = *src; diff --git a/src/gtest-port.cc b/src/gtest-port.cc index 09d1a8e0..ec107a58 100644 --- a/src/gtest-port.cc +++ b/src/gtest-port.cc @@ -585,7 +585,7 @@ static String FlagToEnvVar(const char* flag) { (Message() << GTEST_FLAG_PREFIX_ << flag).GetString(); Message env_var; - for (int i = 0; i != full_flag.GetLength(); i++) { + for (size_t i = 0; i != full_flag.length(); i++) { env_var << static_cast(toupper(full_flag.c_str()[i])); } diff --git a/src/gtest.cc b/src/gtest.cc index a767d194..5cfabf85 100644 --- a/src/gtest.cc +++ b/src/gtest.cc @@ -445,7 +445,7 @@ bool UnitTestOptions::FilterMatchesTest(const String &test_case_name, positive = GTEST_FLAG(filter).c_str(); // Whole string is a positive filter negative = String(""); } else { - positive.Set(p, dash - p); // Everything up to the dash + positive = String(p, dash - p); // Everything up to the dash negative = String(dash+1); // Everything after the dash if (positive.empty()) { // Treat '-test1' as the same as '*-test1' @@ -926,17 +926,17 @@ bool String::CStringEquals(const char * lhs, const char * rhs) { // Converts an array of wide chars to a narrow string using the UTF-8 // encoding, and streams the result to the given Message object. -static void StreamWideCharsToMessage(const wchar_t* wstr, size_t len, +static void StreamWideCharsToMessage(const wchar_t* wstr, size_t length, Message* msg) { // TODO(wan): consider allowing a testing::String object to // contain '\0'. This will make it behave more like std::string, // and will allow ToUtf8String() to return the correct encoding // for '\0' s.t. we can get rid of the conditional here (and in // several other places). - for (size_t i = 0; i != len; ) { // NOLINT + for (size_t i = 0; i != length; ) { // NOLINT if (wstr[i] != L'\0') { - *msg << WideStringToUtf8(wstr + i, static_cast(len - i)); - while (i != len && wstr[i] != L'\0') + *msg << WideStringToUtf8(wstr + i, static_cast(length - i)); + while (i != length && wstr[i] != L'\0') i++; } else { *msg << '\0'; @@ -1679,24 +1679,30 @@ bool String::CaseInsensitiveWideCStringEquals(const wchar_t* lhs, #endif // OS selector } -// Constructs a String by copying a given number of chars from a -// buffer. E.g. String("hello", 3) will create the string "hel". -String::String(const char * buffer, size_t len) { - char * const temp = new char[ len + 1 ]; - memcpy(temp, buffer, len); - temp[ len ] = '\0'; - c_str_ = temp; -} - // Compares this with another String. // Returns < 0 if this is less than rhs, 0 if this is equal to rhs, or > 0 // if this is greater than rhs. int String::Compare(const String & rhs) const { - if ( c_str_ == NULL ) { - return rhs.c_str_ == NULL ? 0 : -1; // NULL < anything except NULL + const char* const lhs_c_str = c_str(); + const char* const rhs_c_str = rhs.c_str(); + + if (lhs_c_str == NULL) { + return rhs_c_str == NULL ? 0 : -1; // NULL < anything except NULL + } else if (rhs_c_str == NULL) { + return 1; } - return rhs.c_str_ == NULL ? 1 : strcmp(c_str_, rhs.c_str_); + const size_t shorter_str_len = + length() <= rhs.length() ? length() : rhs.length(); + for (size_t i = 0; i != shorter_str_len; i++) { + if (lhs_c_str[i] < rhs_c_str[i]) { + return -1; + } else if (lhs_c_str[i] > rhs_c_str[i]) { + return 1; + } + } + return (length() < rhs.length()) ? -1 : + (length() > rhs.length()) ? 1 : 0; } // Returns true iff this String ends with the given suffix. *Any* @@ -1704,12 +1710,12 @@ int String::Compare(const String & rhs) const { bool String::EndsWith(const char* suffix) const { if (suffix == NULL || CStringEquals(suffix, "")) return true; - if (c_str_ == NULL) return false; + if (c_str() == NULL) return false; - const size_t this_len = strlen(c_str_); + const size_t this_len = strlen(c_str()); const size_t suffix_len = strlen(suffix); return (this_len >= suffix_len) && - CStringEquals(c_str_ + this_len - suffix_len, suffix); + CStringEquals(c_str() + this_len - suffix_len, suffix); } // Returns true iff this String ends with the given suffix, ignoring case. @@ -1717,37 +1723,12 @@ bool String::EndsWith(const char* suffix) const { bool String::EndsWithCaseInsensitive(const char* suffix) const { if (suffix == NULL || CStringEquals(suffix, "")) return true; - if (c_str_ == NULL) return false; + if (c_str() == NULL) return false; - const size_t this_len = strlen(c_str_); + const size_t this_len = strlen(c_str()); const size_t suffix_len = strlen(suffix); return (this_len >= suffix_len) && - CaseInsensitiveCStringEquals(c_str_ + this_len - suffix_len, suffix); -} - -// Sets the 0-terminated C string this String object represents. The -// old string in this object is deleted, and this object will own a -// clone of the input string. This function copies only up to length -// bytes (plus a terminating null byte), or until the first null byte, -// whichever comes first. -// -// This function works even when the c_str parameter has the same -// value as that of the c_str_ field. -void String::Set(const char * c_str, size_t length) { - // Makes sure this works when c_str == c_str_ - const char* const temp = CloneString(c_str, length); - delete[] c_str_; - c_str_ = temp; -} - -// Assigns a C string to this object. Self-assignment works. -const String& String::operator=(const char* c_str) { - // Makes sure this works when c_str == c_str_ - if (c_str != c_str_) { - delete[] c_str_; - c_str_ = CloneCString(c_str); - } - return *this; + CaseInsensitiveCStringEquals(c_str() + this_len - suffix_len, suffix); } // Formats a list of arguments to a String, using the same format @@ -1778,7 +1759,7 @@ String String::Format(const char * format, ...) { #endif // _MSC_VER va_end(args); - return String(size >= 0 ? buffer : ""); + return (size >= 0) ? String(buffer, size) : String(""); } // Converts the buffer in a StrStream to a String, converting NUL @@ -3491,7 +3472,7 @@ int UnitTest::Run() { // Catch SEH-style exceptions. const bool in_death_test_child_process = - internal::GTEST_FLAG(internal_run_death_test).GetLength() > 0; + internal::GTEST_FLAG(internal_run_death_test).length() > 0; // Either the user wants Google Test to catch exceptions thrown by the // tests or this is executing in the context of death test child @@ -4161,7 +4142,7 @@ const char* ParseFlagValue(const char* str, // The flag must start with "--" followed by GTEST_FLAG_PREFIX_. const String flag_str = String::Format("--%s%s", GTEST_FLAG_PREFIX_, flag); - const size_t flag_len = flag_str.GetLength(); + const size_t flag_len = flag_str.length(); if (strncmp(str, flag_str.c_str(), flag_len) != 0) return NULL; // Skips the flag name. -- cgit v1.2.3 From 16e9dd6e28a8a7fb2d611011e7353e042fcb282f Mon Sep 17 00:00:00 2001 From: "zhanyong.wan" Date: Fri, 4 Sep 2009 18:30:25 +0000 Subject: More implementation of the event listener interface (by Vlad Losev); Reduces the stack space usage of assertions by moving AssertHelper's fields to the heap (by Jorg Brown); Makes String faster, smaller, and simpler (by Zhanyong Wan); Fixes a bug in String::Format() (by Chandler); Adds the /MD version of VC projects to the distribution (by Vlad Losev). --- src/gtest-death-test.cc | 6 +- src/gtest-internal-inl.h | 43 +++-- src/gtest.cc | 451 +++++++++++++++++++++++++---------------------- 3 files changed, 270 insertions(+), 230 deletions(-) (limited to 'src') diff --git a/src/gtest-death-test.cc b/src/gtest-death-test.cc index 02ce48d5..d975af77 100644 --- a/src/gtest-death-test.cc +++ b/src/gtest-death-test.cc @@ -469,7 +469,8 @@ bool DeathTestImpl::Passed(bool status_ok) { break; case DIED: if (status_ok) { - if (RE::PartialMatch(error_message.c_str(), *regex())) { + const bool matched = RE::PartialMatch(error_message.c_str(), *regex()); + if (matched) { success = true; } else { buffer << " Result: died but not with expected error.\n" @@ -767,6 +768,9 @@ DeathTest::TestRole NoExecDeathTest::AssumeRole() { // concurrent writes to the log files. We capture stderr in the parent // process and append the child process' output to a log. LogToStderr(); + // Event forwarding to the listeners of event listener API mush be shut + // down in death test subprocesses. + GetUnitTestImpl()->listeners()->SuppressEventForwarding(); return EXECUTE_TEST; } else { GTEST_DEATH_TEST_CHECK_SYSCALL_(close(pipe_fd[1])); diff --git a/src/gtest-internal-inl.h b/src/gtest-internal-inl.h index 84319713..93217f44 100644 --- a/src/gtest-internal-inl.h +++ b/src/gtest-internal-inl.h @@ -741,6 +741,9 @@ class UnitTestImpl { return test_cases_.GetElementOr(i, NULL); } + // Provides access to the event listener list. + EventListeners* listeners() { return &listeners_; } + // Returns the TestResult for the test that's currently running, or // the TestResult for the ad hoc test if no test is running. TestResult* current_test_result(); @@ -748,18 +751,6 @@ class UnitTestImpl { // Returns the TestResult for the ad hoc test. const TestResult* ad_hoc_test_result() const { return &ad_hoc_test_result_; } - // Sets the unit test result printer. - // - // Does nothing if the input and the current printer object are the - // same; otherwise, deletes the old printer object and makes the - // input the current printer. - void set_result_printer(UnitTestEventListenerInterface* result_printer); - - // Returns the current unit test result printer if it is not NULL; - // otherwise, creates an appropriate result printer, makes it the - // current printer, and returns it. - UnitTestEventListenerInterface* result_printer(); - // Sets the OS stack trace getter. // // Does nothing if the input and the current OS stack trace getter @@ -907,9 +898,13 @@ class UnitTestImpl { } #if GTEST_HAS_DEATH_TEST + void InitDeathTestSubprocessControlInfo() { + internal_run_death_test_flag_.reset(ParseInternalRunDeathTestFlag()); + } // Returns a pointer to the parsed --gtest_internal_run_death_test // flag, or NULL if that flag was not specified. // This information is useful only in a death test child process. + // Must not be called before a call to InitGoogleTest. const InternalRunDeathTestFlag* internal_run_death_test_flag() const { return internal_run_death_test_flag_.get(); } @@ -919,9 +914,22 @@ class UnitTestImpl { return death_test_factory_.get(); } + void SuppressTestEventsIfInSubprocess(); + friend class ReplaceDeathTestFactory; #endif // GTEST_HAS_DEATH_TEST + // Initializes the event listener performing XML output as specified by + // UnitTestOptions. Must not be called before InitGoogleTest. + void ConfigureXmlOutput(); + +// Performs initialization dependent upon flag values obtained in +// ParseGoogleTestFlagsOnly. Is called from InitGoogleTest after the call to +// ParseGoogleTestFlagsOnly. In case a user neglects to call InitGoogleTest +// this function is also called from RunAllTests. Since this function can be +// called more than once, it has to be idempotent. + void PostFlagParsingInit(); + // Gets the random seed used at the start of the current test run. int random_seed() const { return random_seed_; } @@ -992,11 +1000,9 @@ class UnitTestImpl { // test, and records the result in ad_hoc_test_result_. TestResult ad_hoc_test_result_; - // The unit test result printer. Will be deleted when the UnitTest - // object is destructed. By default, a plain text printer is used, - // but the user can set this field to use a custom printer if that - // is desired. - UnitTestEventListenerInterface* result_printer_; + // The list of event listeners that can be used to track events inside + // Google Test. + EventListeners listeners_; // The OS stack trace getter. Will be deleted when the UnitTest // object is destructed. By default, an OsStackTraceGetter is used, @@ -1004,6 +1010,9 @@ class UnitTestImpl { // desired. OsStackTraceGetterInterface* os_stack_trace_getter_; + // True iff PostFlagParsingInit() has been called. + bool post_flag_parse_init_performed_; + // The random number seed used at the beginning of the test run. int random_seed_; diff --git a/src/gtest.cc b/src/gtest.cc index 5cfabf85..1b602f54 100644 --- a/src/gtest.cc +++ b/src/gtest.cc @@ -129,9 +129,12 @@ namespace testing { +using internal::EventListeners; +using internal::EmptyTestEventListener; using internal::TestCase; using internal::TestProperty; using internal::TestResult; +using internal::UnitTestEventListenerInterface; // Constants. @@ -303,14 +306,18 @@ static bool ShouldRunTestCase(const TestCase* test_case) { // AssertHelper constructor. AssertHelper::AssertHelper(TestPartResultType type, const char* file, int line, const char* message) - : type_(type), file_(file), line_(line), message_(message) { + : data_(new AssertHelperData(type, file, line, message)) { +} + +AssertHelper::~AssertHelper() { + delete data_; } // Message assignment, for assertion streaming support. void AssertHelper::operator=(const Message& message) const { UnitTest::GetInstance()-> - AddTestPartResult(type_, file_, line_, - AppendUserMessage(message_, message), + AddTestPartResult(data_->type, data_->file, data_->line, + AppendUserMessage(data_->message, message), UnitTest::GetInstance()->impl() ->CurrentOsStackTraceExceptTop(1) // Skips the stack frame for this function itself. @@ -476,86 +483,6 @@ int UnitTestOptions::GTestShouldProcessSEH(DWORD exception_code) { } // namespace internal -// The interface for printing the result of a UnitTest -class UnitTestEventListenerInterface { - public: - // The d'tor is pure virtual as this is an abstract class. - virtual ~UnitTestEventListenerInterface() {} - - // Called before the unit test starts. - virtual void OnUnitTestStart(const UnitTest& unit_test) = 0; - - // Called after the unit test ends. - virtual void OnUnitTestEnd(const UnitTest& unit_test) = 0; - - // Called before the test case starts. - virtual void OnTestCaseStart(const TestCase& test_case) = 0; - - // Called after the test case ends. - virtual void OnTestCaseEnd(const TestCase& test_case) = 0; - - // Called before the global set-up starts. - virtual void OnGlobalSetUpStart(const UnitTest& unit_test) = 0; - - // Called after the global set-up ends. - virtual void OnGlobalSetUpEnd(const UnitTest& unit_test) = 0; - - // Called before the global tear-down starts. - virtual void OnGlobalTearDownStart(const UnitTest& unit_test) = 0; - - // Called after the global tear-down ends. - virtual void OnGlobalTearDownEnd(const UnitTest& unit_test) = 0; - - // Called before the test starts. - virtual void OnTestStart(const TestInfo& test_info) = 0; - - // Called after the test ends. - virtual void OnTestEnd(const TestInfo& test_info) = 0; - - // Called after an assertion. - virtual void OnNewTestPartResult(const TestPartResult& test_part_result) = 0; -}; - -// The convenience class for users who need to override just one or two -// methods and are not concerned that a possible change to a signature of -// the methods they override will not be caught during the build. -class EmptyTestEventListener : public UnitTestEventListenerInterface { - public: - // Called before the unit test starts. - virtual void OnUnitTestStart(const UnitTest& /*unit_test*/) {} - - // Called after the unit test ends. - virtual void OnUnitTestEnd(const UnitTest& /*unit_test*/) {} - - // Called before the test case starts. - virtual void OnTestCaseStart(const TestCase& /*test_case*/) {} - - // Called after the test case ends. - virtual void OnTestCaseEnd(const TestCase& /*test_case&*/) {} - - // Called before the global set-up starts. - virtual void OnGlobalSetUpStart(const UnitTest& /*unit_test*/) {} - - // Called after the global set-up ends. - virtual void OnGlobalSetUpEnd(const UnitTest& /*unit_test*/) {} - - // Called before the global tear-down starts. - virtual void OnGlobalTearDownStart(const UnitTest& /*unit_test*/) {} - - // Called after the global tear-down ends. - virtual void OnGlobalTearDownEnd(const UnitTest& /*unit_test*/) {} - - // Called before the test starts. - virtual void OnTestStart(const TestInfo& /*test_info*/) {} - - // Called after the test ends. - virtual void OnTestEnd(const TestInfo& /*test_info*/) {} - - // Called after an assertion. - virtual void OnNewTestPartResult(const TestPartResult& /*test_part_result*/) { - } -}; - // The c'tor sets this object as the test part result reporter used by // Google Test. The 'result' parameter specifies where to report the // results. Intercepts only failures from the current thread. @@ -690,7 +617,7 @@ DefaultGlobalTestPartResultReporter::DefaultGlobalTestPartResultReporter( void DefaultGlobalTestPartResultReporter::ReportTestPartResult( const TestPartResult& result) { unit_test_->current_test_result()->AddTestPartResult(result); - unit_test_->result_printer()->OnNewTestPartResult(result); + unit_test_->listeners()->repeater()->OnNewTestPartResult(result); } DefaultPerThreadTestPartResultReporter::DefaultPerThreadTestPartResultReporter( @@ -1738,28 +1665,38 @@ bool String::EndsWithCaseInsensitive(const char* suffix) const { // available. // // The result is limited to 4096 characters (including the tailing 0). -// If 4096 characters are not enough to format the input, -// "" is returned. +// If 4096 characters are not enough to format the input, or if +// there's an error, "" is +// returned. String String::Format(const char * format, ...) { va_list args; va_start(args, format); char buffer[4096]; + const int kBufferSize = sizeof(buffer)/sizeof(buffer[0]); + // MSVC 8 deprecates vsnprintf(), so we want to suppress warning // 4996 (deprecated function) there. #ifdef _MSC_VER // We are using MSVC. #pragma warning(push) // Saves the current warning state. #pragma warning(disable:4996) // Temporarily disables warning 4996. - const int size = - vsnprintf(buffer, sizeof(buffer)/sizeof(buffer[0]) - 1, format, args); + const int size = vsnprintf(buffer, kBufferSize, format, args); #pragma warning(pop) // Restores the warning state. #else // We are not using MSVC. - const int size = - vsnprintf(buffer, sizeof(buffer)/sizeof(buffer[0]) - 1, format, args); + const int size = vsnprintf(buffer, kBufferSize, format, args); #endif // _MSC_VER va_end(args); - return (size >= 0) ? String(buffer, size) : String(""); + // vsnprintf()'s behavior is not portable. When the buffer is not + // big enough, it returns a negative value in MSVC, and returns the + // needed buffer size on Linux. When there is an output error, it + // always returns a negative value. For simplicity, we lump the two + // error cases together. + if (size < 0 || size >= kBufferSize) { + return String(""); + } else { + return String(buffer, size); + } } // Converts the buffer in a StrStream to a String, converting NUL @@ -2297,11 +2234,11 @@ void TestInfoImpl::Run() { UnitTestImpl* const impl = internal::GetUnitTestImpl(); impl->set_current_test_info(parent_); - // Notifies the unit test event listener that a test is about to - // start. - UnitTestEventListenerInterface* const result_printer = - impl->result_printer(); - result_printer->OnTestStart(*parent_); + UnitTestEventListenerInterface* repeater = + UnitTest::GetInstance()->listeners().repeater(); + + // Notifies the unit test event listeners that a test is about to start. + repeater->OnTestStart(*parent_); const TimeInMillis start = GetTimeInMillis(); @@ -2344,7 +2281,7 @@ void TestInfoImpl::Run() { result_.set_elapsed_time(GetTimeInMillis() - start); // Notifies the unit test event listener that a test has just finished. - result_printer->OnTestEnd(*parent_); + repeater->OnTestEnd(*parent_); // Tells UnitTest to stop associating assertion results to this // test. @@ -2425,10 +2362,10 @@ void TestCase::Run() { internal::UnitTestImpl* const impl = internal::GetUnitTestImpl(); impl->set_current_test_case(this); - UnitTestEventListenerInterface * const result_printer = - impl->result_printer(); + UnitTestEventListenerInterface* repeater = + UnitTest::GetInstance()->listeners().repeater(); - result_printer->OnTestCaseStart(*this); + repeater->OnTestCaseStart(*this); impl->os_stack_trace_getter()->UponLeavingGTest(); set_up_tc_(); @@ -2438,7 +2375,7 @@ void TestCase::Run() { impl->os_stack_trace_getter()->UponLeavingGTest(); tear_down_tc_(); - result_printer->OnTestCaseEnd(*this); + repeater->OnTestCaseEnd(*this); impl->set_current_test_case(NULL); } @@ -2471,10 +2408,6 @@ bool TestCase::ShouldRunTest(const TestInfo *test_info) { } // namespace internal -// A result printer that never prints anything. Used in the child process -// of an exec-style death test to avoid needless output clutter. -class NullUnitTestResultPrinter : public EmptyTestEventListener {}; - // Formats a countable noun. Depending on its quantity, either the // singular form or the plural form is used. e.g. // @@ -2663,14 +2596,6 @@ void ColoredPrintf(GTestColor color, const char* fmt, ...) { va_end(args); } -} // namespace internal - -using internal::ColoredPrintf; -using internal::COLOR_DEFAULT; -using internal::COLOR_RED; -using internal::COLOR_GREEN; -using internal::COLOR_YELLOW; - // This class implements the UnitTestEventListenerInterface interface. // // Class PrettyUnitTestResultPrinter is copyable. @@ -2888,10 +2813,16 @@ void PrettyUnitTestResultPrinter::OnUnitTestEnd(const UnitTest& unit_test) { // This class forwards events to other event listeners. class UnitTestEventsRepeater : public UnitTestEventListenerInterface { public: - typedef internal::Vector Listeners; - UnitTestEventsRepeater() {} + UnitTestEventsRepeater() : forwarding_enabled_(true) {} virtual ~UnitTestEventsRepeater(); - void AddListener(UnitTestEventListenerInterface *listener); + void Append(UnitTestEventListenerInterface *listener); + UnitTestEventListenerInterface* Release( + UnitTestEventListenerInterface* listener); + + // Controls whether events will be forwarded to listeners_. Set to false + // in death test child processes. + bool forwarding_enabled() const { return forwarding_enabled_; } + void set_forwarding_enabled(bool enable) { forwarding_enabled_ = enable; } virtual void OnUnitTestStart(const UnitTest& unit_test); virtual void OnUnitTestEnd(const UnitTest& unit_test); @@ -2906,7 +2837,11 @@ class UnitTestEventsRepeater : public UnitTestEventListenerInterface { virtual void OnNewTestPartResult(const TestPartResult& result); private: - Listeners listeners_; + // Controls whether events will be forwarded to listeners_. Set to false + // in death test child processes. + bool forwarding_enabled_; + // The list of listeners that receive events. + Vector listeners_; GTEST_DISALLOW_COPY_AND_ASSIGN_(UnitTestEventsRepeater); }; @@ -2917,17 +2852,31 @@ UnitTestEventsRepeater::~UnitTestEventsRepeater() { } } -void UnitTestEventsRepeater::AddListener( - UnitTestEventListenerInterface *listener) { +void UnitTestEventsRepeater::Append(UnitTestEventListenerInterface *listener) { listeners_.PushBack(listener); } +// TODO(vladl@google.com): Factor the search functionality into Vector::Find. +UnitTestEventListenerInterface* UnitTestEventsRepeater::Release( + UnitTestEventListenerInterface *listener) { + for (int i = 0; i < listeners_.size(); ++i) { + if (listeners_.GetElement(i) == listener) { + listeners_.Erase(i); + return listener; + } + } + + return NULL; +} + // Since the methods are identical, use a macro to reduce boilerplate. // This defines a member that repeats the call to all listeners. #define GTEST_REPEATER_METHOD_(Name, Type) \ void UnitTestEventsRepeater::Name(const Type& parameter) { \ - for (int i = 0; i < listeners_.size(); i++) { \ - listeners_.GetElement(i)->Name(parameter); \ + if (forwarding_enabled_) { \ + for (int i = 0; i < listeners_.size(); i++) { \ + listeners_.GetElement(i)->Name(parameter); \ + } \ } \ } @@ -2945,7 +2894,7 @@ GTEST_REPEATER_METHOD_(OnNewTestPartResult, TestPartResult) #undef GTEST_REPEATER_METHOD_ -// End PrettyUnitTestResultPrinter +// End UnitTestEventsRepeater // This class generates an XML output file. class XmlUnitTestResultPrinter : public EmptyTestEventListener { @@ -2970,18 +2919,15 @@ class XmlUnitTestResultPrinter : public EmptyTestEventListener { // is_attribute is true, the text is meant to appear as an attribute // value, and normalizable whitespace is preserved by replacing it // with character references. - static internal::String EscapeXml(const char* str, - bool is_attribute); + static String EscapeXml(const char* str, bool is_attribute); // Convenience wrapper around EscapeXml when str is an attribute value. - static internal::String EscapeXmlAttribute(const char* str) { + static String EscapeXmlAttribute(const char* str) { return EscapeXml(str, true); } // Convenience wrapper around EscapeXml when str is not an attribute value. - static internal::String EscapeXmlText(const char* str) { - return EscapeXml(str, false); - } + static String EscapeXmlText(const char* str) { return EscapeXml(str, false); } // Prints an XML representation of a TestInfo object. static void PrintXmlTestInfo(FILE* out, @@ -2998,11 +2944,10 @@ class XmlUnitTestResultPrinter : public EmptyTestEventListener { // delimited XML attributes based on the property key="value" pairs. // When the String is not empty, it includes a space at the beginning, // to delimit this attribute from prior attributes. - static internal::String TestPropertiesAsXmlAttributes( - const TestResult& result); + static String TestPropertiesAsXmlAttributes(const TestResult& result); // The output file. - const internal::String output_file_; + const String output_file_; GTEST_DISALLOW_COPY_AND_ASSIGN_(XmlUnitTestResultPrinter); }; @@ -3020,11 +2965,11 @@ XmlUnitTestResultPrinter::XmlUnitTestResultPrinter(const char* output_file) // Called after the unit test ends. void XmlUnitTestResultPrinter::OnUnitTestEnd(const UnitTest& unit_test) { FILE* xmlout = NULL; - internal::FilePath output_file(output_file_); - internal::FilePath output_dir(output_file.RemoveFileName()); + FilePath output_file(output_file_); + FilePath output_dir(output_file.RemoveFileName()); if (output_dir.CreateDirectoriesRecursively()) { - xmlout = internal::posix::FOpen(output_file_.c_str(), "w"); + xmlout = posix::FOpen(output_file_.c_str(), "w"); } if (xmlout == NULL) { // TODO(wan): report the reason of the failure. @@ -3059,8 +3004,7 @@ void XmlUnitTestResultPrinter::OnUnitTestEnd(const UnitTest& unit_test) { // most invalid characters can be retained using character references. // TODO(wan): It might be nice to have a minimally invasive, human-readable // escaping scheme for invalid characters, rather than dropping them. -internal::String XmlUnitTestResultPrinter::EscapeXml(const char* str, - bool is_attribute) { +String XmlUnitTestResultPrinter::EscapeXml(const char* str, bool is_attribute) { Message m; if (str != NULL) { @@ -3090,7 +3034,7 @@ internal::String XmlUnitTestResultPrinter::EscapeXml(const char* str, default: if (IsValidXmlCharacter(*src)) { if (is_attribute && IsNormalizableWhitespace(*src)) - m << internal::String::Format("&#x%02X;", unsigned(*src)); + m << String::Format("&#x%02X;", unsigned(*src)); else m << *src; } @@ -3102,7 +3046,6 @@ internal::String XmlUnitTestResultPrinter::EscapeXml(const char* str, return m.GetString(); } - // The following routines generate an XML representation of a UnitTest // object. // @@ -3119,8 +3062,6 @@ internal::String XmlUnitTestResultPrinter::EscapeXml(const char* str, // // -namespace internal { - // Formats the given time in milliseconds as seconds. The returned // C-string is owned by this function and cannot be released by the // caller. Calling the function again invalidates the previous @@ -3131,8 +3072,6 @@ const char* FormatTimeInMillisAsSeconds(TimeInMillis ms) { return str.c_str(); } -} // namespace internal - // Prints an XML representation of a TestInfo object. // TODO(wan): There is also value in printing properties with the plain printer. void XmlUnitTestResultPrinter::PrintXmlTestInfo(FILE* out, @@ -3144,7 +3083,7 @@ void XmlUnitTestResultPrinter::PrintXmlTestInfo(FILE* out, "classname=\"%s\"%s", EscapeXmlAttribute(test_info.name()).c_str(), test_info.should_run() ? "run" : "notrun", - internal::FormatTimeInMillisAsSeconds(result.elapsed_time()), + FormatTimeInMillisAsSeconds(result.elapsed_time()), EscapeXmlAttribute(test_case_name).c_str(), TestPropertiesAsXmlAttributes(result).c_str()); @@ -3152,9 +3091,8 @@ void XmlUnitTestResultPrinter::PrintXmlTestInfo(FILE* out, for (int i = 0; i < result.total_part_count(); ++i) { const TestPartResult& part = result.GetTestPartResult(i); if (part.failed()) { - const internal::String message = - internal::String::Format("%s:%d\n%s", part.file_name(), - part.line_number(), part.message()); + const String message = String::Format("%s:%d\n%s", part.file_name(), + part.line_number(), part.message()); if (++failures == 1) fprintf(out, ">\n"); fprintf(out, @@ -3182,7 +3120,7 @@ void XmlUnitTestResultPrinter::PrintXmlTestCase(FILE* out, test_case.disabled_test_count()); fprintf(out, "errors=\"0\" time=\"%s\">\n", - internal::FormatTimeInMillisAsSeconds(test_case.elapsed_time())); + FormatTimeInMillisAsSeconds(test_case.elapsed_time())); for (int i = 0; i < test_case.total_test_count(); ++i) PrintXmlTestInfo(out, test_case.name(), *test_case.GetTestInfo(i)); fprintf(out, " \n"); @@ -3198,7 +3136,7 @@ void XmlUnitTestResultPrinter::PrintXmlUnitTest(FILE* out, unit_test.total_test_count(), unit_test.failed_test_count(), unit_test.disabled_test_count(), - internal::FormatTimeInMillisAsSeconds(unit_test.elapsed_time())); + FormatTimeInMillisAsSeconds(unit_test.elapsed_time())); if (GTEST_FLAG(shuffle)) { fprintf(out, "random_seed=\"%d\" ", unit_test.random_seed()); } @@ -3210,7 +3148,7 @@ void XmlUnitTestResultPrinter::PrintXmlUnitTest(FILE* out, // Produces a string representing the test properties in a result as space // delimited XML attributes based on the property key="value" pairs. -internal::String XmlUnitTestResultPrinter::TestPropertiesAsXmlAttributes( +String XmlUnitTestResultPrinter::TestPropertiesAsXmlAttributes( const TestResult& result) { Message attributes; for (int i = 0; i < result.test_property_count(); ++i) { @@ -3223,8 +3161,6 @@ internal::String XmlUnitTestResultPrinter::TestPropertiesAsXmlAttributes( // End XmlUnitTestResultPrinter -namespace internal { - // Class ScopedTrace // Pushes the given source file location and message onto a per-thread @@ -3271,6 +3207,84 @@ OsStackTraceGetter::kElidedFramesMarker = } // namespace internal +// class EventListeners + +EventListeners::EventListeners() + : repeater_(new internal::UnitTestEventsRepeater()), + default_result_printer_(NULL), + default_xml_generator_(NULL) { +} + +EventListeners::~EventListeners() { delete repeater_; } + +// Returns the standard listener responsible for the default console +// output. Can be removed from the listeners list to shut down default +// console output. Note that removing this object from the listener list +// with Release transfers its ownership to the user. +void EventListeners::Append(UnitTestEventListenerInterface* listener) { + repeater_->Append(listener); +} + +// Removes the given event listener from the list and returns it. It then +// becomes the caller's responsibility to delete the listener. Returns +// NULL if the listener is not found in the list. +UnitTestEventListenerInterface* EventListeners::Release( + UnitTestEventListenerInterface* listener) { + if (listener == default_result_printer_) + default_result_printer_ = NULL; + else if (listener == default_xml_generator_) + default_xml_generator_ = NULL; + return repeater_->Release(listener); +} + +// Returns repeater that broadcasts the UnitTestEventListenerInterface +// events to all subscribers. +UnitTestEventListenerInterface* EventListeners::repeater() { return repeater_; } + +// Sets the default_result_printer attribute to the provided listener. +// The listener is also added to the listener list and previous +// default_result_printer is removed from it and deleted. The listener can +// also be NULL in which case it will not be added to the list. Does +// nothing if the previous and the current listener objects are the same. +void EventListeners::SetDefaultResultPrinter( + UnitTestEventListenerInterface* listener) { + if (default_result_printer_ != listener) { + // It is an error to pass this method a listener that is already in the + // list. + delete Release(default_result_printer_); + default_result_printer_ = listener; + if (listener != NULL) + Append(listener); + } +} + +// Sets the default_xml_generator attribute to the provided listener. The +// listener is also added to the listener list and previous +// default_xml_generator is removed from it and deleted. The listener can +// also be NULL in which case it will not be added to the list. Does +// nothing if the previous and the current listener objects are the same. +void EventListeners::SetDefaultXmlGenerator( + UnitTestEventListenerInterface* listener) { + if (default_xml_generator_ != listener) { + // It is an error to pass this method a listener that is already in the + // list. + delete Release(default_xml_generator_); + default_xml_generator_ = listener; + if (listener != NULL) + Append(listener); + } +} + +// Controls whether events will be forwarded by the repeater to the +// listeners in the list. +bool EventListeners::EventForwardingEnabled() const { + return repeater_->forwarding_enabled(); +} + +void EventListeners::SuppressEventForwarding() { + repeater_->set_forwarding_enabled(false); +} + // class UnitTest // Gets the singleton UnitTest object. The first time this method is @@ -3359,6 +3373,12 @@ const TestCase* UnitTest::GetTestCase(int i) const { return impl()->GetTestCase(i); } +// Returns the list of event listeners that can be used to track events +// inside Google Test. +EventListeners& UnitTest::listeners() { + return *impl()->listeners(); +} + // Registers and returns a global test environment. When a test // program is run, all global test environments will be set-up in the // order they were registered. After all tests in the program have @@ -3614,8 +3634,8 @@ UnitTestImpl::UnitTestImpl(UnitTest* parent) current_test_case_(NULL), current_test_info_(NULL), ad_hoc_test_result_(), - result_printer_(NULL), os_stack_trace_getter_(NULL), + post_flag_parse_init_performed_(false), random_seed_(0), #if GTEST_HAS_DEATH_TEST elapsed_time_(0), @@ -3624,6 +3644,7 @@ UnitTestImpl::UnitTestImpl(UnitTest* parent) #else elapsed_time_(0) { #endif // GTEST_HAS_DEATH_TEST + listeners()->SetDefaultResultPrinter(new PrettyUnitTestResultPrinter); } UnitTestImpl::~UnitTestImpl() { @@ -3633,12 +3654,58 @@ UnitTestImpl::~UnitTestImpl() { // Deletes every Environment. environments_.ForEach(internal::Delete); - // Deletes the current test result printer. - delete result_printer_; - delete os_stack_trace_getter_; } +#if GTEST_HAS_DEATH_TEST +// Disables event forwarding if the control is currently in a death test +// subprocess. Must not be called before InitGoogleTest. +void UnitTestImpl::SuppressTestEventsIfInSubprocess() { + if (internal_run_death_test_flag_.get() != NULL) + listeners()->SuppressEventForwarding(); +} +#endif // GTEST_HAS_DEATH_TEST + +// Initializes event listeners performing XML output as specified by +// UnitTestOptions. Must not be called before InitGoogleTest. +void UnitTestImpl::ConfigureXmlOutput() { + const String& output_format = UnitTestOptions::GetOutputFormat(); + if (output_format == "xml") { + listeners()->SetDefaultXmlGenerator(new XmlUnitTestResultPrinter( + UnitTestOptions::GetAbsolutePathToOutputFile().c_str())); + } else if (output_format != "") { + printf("WARNING: unrecognized output format \"%s\" ignored.\n", + output_format.c_str()); + fflush(stdout); + } +} + +// Performs initialization dependent upon flag values obtained in +// ParseGoogleTestFlagsOnly. Is called from InitGoogleTest after the call to +// ParseGoogleTestFlagsOnly. In case a user neglects to call InitGoogleTest +// this function is also called from RunAllTests. Since this function can be +// called more than once, it has to be idempotent. +void UnitTestImpl::PostFlagParsingInit() { + // Ensures that this function does not execute more than once. + if (!post_flag_parse_init_performed_) { + post_flag_parse_init_performed_ = true; + +#if GTEST_HAS_DEATH_TEST + InitDeathTestSubprocessControlInfo(); + SuppressTestEventsIfInSubprocess(); +#endif // GTEST_HAS_DEATH_TEST + + // Registers parameterized tests. This makes parameterized tests + // available to the UnitTest reflection API without running + // RUN_ALL_TESTS. + RegisterParameterizedTests(); + + // Configures listeners for XML output. This makes it possible for users + // to shut down the default XML output before invoking RUN_ALL_TESTS. + ConfigureXmlOutput(); + } +} + // A predicate that checks the name of a TestCase against a known // value. // @@ -3726,7 +3793,8 @@ int UnitTestImpl::RunAllTests() { if (g_help_flag) return 0; - RegisterParameterizedTests(); + // TODO(vladl@google.com): Add a call to PostFlagParsingInit() here when + // merging into the main branch. // Even if sharding is not on, test runners may want to use the // GTEST_SHARD_STATUS_FILE to query whether the test supports the sharding @@ -3738,12 +3806,9 @@ int UnitTestImpl::RunAllTests() { bool in_subprocess_for_death_test = false; #if GTEST_HAS_DEATH_TEST - internal_run_death_test_flag_.reset(ParseInternalRunDeathTestFlag()); in_subprocess_for_death_test = (internal_run_death_test_flag_.get() != NULL); #endif // GTEST_HAS_DEATH_TEST - UnitTestEventListenerInterface * const printer = result_printer(); - const bool should_shard = ShouldShard(kTestTotalShards, kTestShardIndex, in_subprocess_for_death_test); @@ -3766,6 +3831,8 @@ int UnitTestImpl::RunAllTests() { // True iff at least one test has failed. bool failed = false; + UnitTestEventListenerInterface* repeater = listeners()->repeater(); + // How many times to repeat the tests? We don't want to repeat them // when we are inside the subprocess of a death test. const int repeat = in_subprocess_for_death_test ? 1 : GTEST_FLAG(repeat); @@ -3773,21 +3840,24 @@ int UnitTestImpl::RunAllTests() { const bool forever = repeat < 0; for (int i = 0; forever || i != repeat; i++) { if (repeat != 1) { + // TODO(vladl@google.com): Move this output to + // PrettyUnitTestResultPrinter. Add the iteration number parameter to + // OnUnitTestStart. printf("\nRepeating all tests (iteration %d) . . .\n\n", i + 1); } - // Tells the unit test event listener that the tests are about to - // start. - printer->OnUnitTestStart(*parent_); + // Tells the unit test event listeners that the tests are about to start. + repeater->OnUnitTestStart(*parent_); + // TODO(vladl@google.com): Move to before the OnUnitTestStart notification? const TimeInMillis start = GetTimeInMillis(); // Runs each test case if there is at least one test to run. if (has_tests_to_run) { // Sets up all environments beforehand. - printer->OnGlobalSetUpStart(*parent_); + repeater->OnGlobalSetUpStart(*parent_); environments_.ForEach(SetUpEnvironment); - printer->OnGlobalSetUpEnd(*parent_); + repeater->OnGlobalSetUpEnd(*parent_); // Runs the tests only if there was no fatal failure during global // set-up. @@ -3796,16 +3866,15 @@ int UnitTestImpl::RunAllTests() { } // Tears down all environments in reverse order afterwards. - printer->OnGlobalTearDownStart(*parent_); + repeater->OnGlobalTearDownStart(*parent_); environments_in_reverse_order_.ForEach(TearDownEnvironment); - printer->OnGlobalTearDownEnd(*parent_); + repeater->OnGlobalTearDownEnd(*parent_); } elapsed_time_ = GetTimeInMillis() - start; - // Tells the unit test event listener that the tests have just - // finished. - printer->OnUnitTestEnd(*parent_); + // Tells the unit test event listener that the tests have just finished. + repeater->OnUnitTestEnd(*parent_); // Gets the result and clears it. if (!Passed()) { @@ -3997,49 +4066,6 @@ void UnitTestImpl::ListTestsMatchingFilter() { fflush(stdout); } -// Sets the unit test result printer. -// -// Does nothing if the input and the current printer object are the -// same; otherwise, deletes the old printer object and makes the -// input the current printer. -void UnitTestImpl::set_result_printer( - UnitTestEventListenerInterface* result_printer) { - if (result_printer_ != result_printer) { - delete result_printer_; - result_printer_ = result_printer; - } -} - -// Returns the current unit test result printer if it is not NULL; -// otherwise, creates an appropriate result printer, makes it the -// current printer, and returns it. -UnitTestEventListenerInterface* UnitTestImpl::result_printer() { - if (result_printer_ != NULL) { - return result_printer_; - } - -#if GTEST_HAS_DEATH_TEST - if (internal_run_death_test_flag_.get() != NULL) { - result_printer_ = new NullUnitTestResultPrinter; - return result_printer_; - } -#endif // GTEST_HAS_DEATH_TEST - - UnitTestEventsRepeater *repeater = new UnitTestEventsRepeater; - const String& output_format = internal::UnitTestOptions::GetOutputFormat(); - if (output_format == "xml") { - repeater->AddListener(new XmlUnitTestResultPrinter( - internal::UnitTestOptions::GetAbsolutePathToOutputFile().c_str())); - } else if (output_format != "") { - printf("WARNING: unrecognized output format \"%s\" ignored.\n", - output_format.c_str()); - fflush(stdout); - } - repeater->AddListener(new PrettyUnitTestResultPrinter); - result_printer_ = repeater; - return result_printer_; -} - // Sets the OS stack trace getter. // // Does nothing if the input and the current OS stack trace getter are @@ -4420,6 +4446,7 @@ void InitGoogleTestImpl(int* argc, CharType** argv) { #endif // GTEST_HAS_DEATH_TEST ParseGoogleTestFlagsOnly(argc, argv); + GetUnitTestImpl()->PostFlagParsingInit(); } } // namespace internal -- cgit v1.2.3 From bcaf6f542fac67549528027c24e530e0e89f700b Mon Sep 17 00:00:00 2001 From: "zhanyong.wan" Date: Fri, 11 Sep 2009 05:41:41 +0000 Subject: Removes deprecated /Wp64 flag from VC projects; also removes unneeded VC projects. --- src/gtest.cc | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) (limited to 'src') diff --git a/src/gtest.cc b/src/gtest.cc index 1b602f54..677396d6 100644 --- a/src/gtest.cc +++ b/src/gtest.cc @@ -3793,8 +3793,9 @@ int UnitTestImpl::RunAllTests() { if (g_help_flag) return 0; - // TODO(vladl@google.com): Add a call to PostFlagParsingInit() here when - // merging into the main branch. + // Repeats the call to the post-flag parsing initialization in case the + // user didn't call InitGoogleTest. + PostFlagParsingInit(); // Even if sharding is not on, test runners may want to use the // GTEST_SHARD_STATUS_FILE to query whether the test supports the sharding -- cgit v1.2.3 From 866f4a94461d765f7f9514b6cb6e82d7b9ea12d2 Mon Sep 17 00:00:00 2001 From: "zhanyong.wan" Date: Wed, 16 Sep 2009 06:59:17 +0000 Subject: Simplifies the implementation of GTEST_LOG_ & GTEST_LOG_; renames GTEST_HIDE_UNREACHABLE_CODE_ to GTEST_SUPPRESS_UNREACHABLE_CODE_WARNING_BELOW_ (by Vlad Losev). --- src/gtest-death-test.cc | 25 +++++++++++-------------- src/gtest-port.cc | 21 +++++++++++++-------- 2 files changed, 24 insertions(+), 22 deletions(-) (limited to 'src') diff --git a/src/gtest-death-test.cc b/src/gtest-death-test.cc index d975af77..91f16de8 100644 --- a/src/gtest-death-test.cc +++ b/src/gtest-death-test.cc @@ -269,13 +269,12 @@ static void FailFromInternalError(int fd) { } while (num_read == -1 && errno == EINTR); if (num_read == 0) { - GTEST_LOG_(FATAL, error); + GTEST_LOG_(FATAL) << error.GetString().c_str(); } else { const int last_error = errno; const String message = GetLastErrnoDescription(); - GTEST_LOG_(FATAL, - Message() << "Error while reading death test internal: " - << message << " [" << last_error << "]"); + GTEST_LOG_(FATAL) << "Error while reading death test internal: " + << message.c_str() << " [" << last_error << "]"; } } @@ -397,15 +396,13 @@ void DeathTestImpl::ReadAndInterpretStatusByte() { FailFromInternalError(read_fd()); // Does not return. break; default: - GTEST_LOG_(FATAL, - Message() << "Death test child process reported " - << "unexpected status byte (" - << static_cast(flag) << ")"); + GTEST_LOG_(FATAL) << "Death test child process reported " + << "unexpected status byte (" + << static_cast(flag) << ")"; } } else { - GTEST_LOG_(FATAL, - Message() << "Read from death test child process failed: " - << GetLastErrnoDescription()); + GTEST_LOG_(FATAL) << "Read from death test child process failed: " + << GetLastErrnoDescription().c_str(); } GTEST_DEATH_TEST_CHECK_SYSCALL_(posix::Close(read_fd())); set_read_fd(-1); @@ -484,8 +481,8 @@ bool DeathTestImpl::Passed(bool status_ok) { break; case IN_PROGRESS: default: - GTEST_LOG_(FATAL, - "DeathTest::Passed somehow called before conclusion of test"); + GTEST_LOG_(FATAL) + << "DeathTest::Passed somehow called before conclusion of test"; } DeathTest::set_last_death_test_message(buffer.GetString()); @@ -741,7 +738,7 @@ class NoExecDeathTest : public ForkingDeathTest { DeathTest::TestRole NoExecDeathTest::AssumeRole() { const size_t thread_count = GetThreadCount(); if (thread_count != 1) { - GTEST_LOG_(WARNING, DeathTestThreadWarning(thread_count)); + GTEST_LOG_(WARNING) << DeathTestThreadWarning(thread_count); } int pipe_fd[2]; diff --git a/src/gtest-port.cc b/src/gtest-port.cc index ec107a58..ba9a9a28 100644 --- a/src/gtest-port.cc +++ b/src/gtest-port.cc @@ -417,20 +417,25 @@ void RE::Init(const char* regex) { #endif // GTEST_USES_POSIX_RE -// Logs a message at the given severity level. -void GTestLog(GTestLogSeverity severity, const char* file, - int line, const char* msg) { + +GTestLog::GTestLog(GTestLogSeverity severity, const char* file, int line) + : severity_(severity) { const char* const marker = severity == GTEST_INFO ? "[ INFO ]" : severity == GTEST_WARNING ? "[WARNING]" : severity == GTEST_ERROR ? "[ ERROR ]" : "[ FATAL ]"; - fprintf(stderr, "\n%s %s:%d: %s\n", marker, file, line, msg); - if (severity == GTEST_FATAL) { - fflush(NULL); // abort() is not guaranteed to flush open file streams. + GetStream() << ::std::endl << marker << " " + << FormatFileLocation(file, line).c_str() << ": "; +} + +// Flushes the buffers and, if severity is GTEST_FATAL, aborts the program. +GTestLog::~GTestLog() { + GetStream() << ::std::endl; + if (severity_ == GTEST_FATAL) { + fflush(stderr); posix::Abort(); } } - // Disable Microsoft deprecation warnings for POSIX functions called from // this class (creat, dup, dup2, and close) #ifdef _MSC_VER @@ -537,7 +542,7 @@ static String ReadEntireFile(FILE * file) { // Starts capturing stderr. void CaptureStderr() { if (g_captured_stderr != NULL) { - GTEST_LOG_(FATAL, "Only one stderr capturer can exist at one time."); + GTEST_LOG_(FATAL) << "Only one stderr capturer can exist at one time."; } g_captured_stderr = new CapturedStderr; } -- cgit v1.2.3 From 302a41c90b1da252028d957fbe2f7bf255b08878 Mon Sep 17 00:00:00 2001 From: "zhanyong.wan" Date: Wed, 16 Sep 2009 17:36:39 +0000 Subject: Small code simplification (by Vlad Losev). --- src/gtest-death-test.cc | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) (limited to 'src') diff --git a/src/gtest-death-test.cc b/src/gtest-death-test.cc index 91f16de8..bf4cbc67 100644 --- a/src/gtest-death-test.cc +++ b/src/gtest-death-test.cc @@ -269,12 +269,11 @@ static void FailFromInternalError(int fd) { } while (num_read == -1 && errno == EINTR); if (num_read == 0) { - GTEST_LOG_(FATAL) << error.GetString().c_str(); + GTEST_LOG_(FATAL) << error.GetString(); } else { const int last_error = errno; - const String message = GetLastErrnoDescription(); GTEST_LOG_(FATAL) << "Error while reading death test internal: " - << message.c_str() << " [" << last_error << "]"; + << GetLastErrnoDescription() << " [" << last_error << "]"; } } @@ -402,7 +401,7 @@ void DeathTestImpl::ReadAndInterpretStatusByte() { } } else { GTEST_LOG_(FATAL) << "Read from death test child process failed: " - << GetLastErrnoDescription().c_str(); + << GetLastErrnoDescription(); } GTEST_DEATH_TEST_CHECK_SYSCALL_(posix::Close(read_fd())); set_read_fd(-1); -- cgit v1.2.3 From 12d740faef11779b27b17c558ca92622bc0d2b54 Mon Sep 17 00:00:00 2001 From: "zhanyong.wan" Date: Thu, 17 Sep 2009 05:04:08 +0000 Subject: Makes gtest compile clean with MSVC's warning 4100 (unused formal parameter) enabled. --- src/gtest.cc | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'src') diff --git a/src/gtest.cc b/src/gtest.cc index 677396d6..5b33d312 100644 --- a/src/gtest.cc +++ b/src/gtest.cc @@ -4134,7 +4134,8 @@ TestInfoImpl::~TestInfoImpl() { // For example, if Foo() calls Bar(), which in turn calls // GetCurrentOsStackTraceExceptTop(..., 1), Foo() will be included in // the trace but Bar() and GetCurrentOsStackTraceExceptTop() won't. -String GetCurrentOsStackTraceExceptTop(UnitTest* unit_test, int skip_count) { +String GetCurrentOsStackTraceExceptTop(UnitTest* /*unit_test*/, + int skip_count) { // We pass skip_count + 1 to skip this wrapper function in addition // to what the user really wants to skip. return GetUnitTestImpl()->CurrentOsStackTraceExceptTop(skip_count + 1); -- cgit v1.2.3 From f43e4ff3ad12ace9d423cc3ce02feadb8f24fe67 Mon Sep 17 00:00:00 2001 From: "zhanyong.wan" Date: Thu, 17 Sep 2009 19:12:30 +0000 Subject: Renames the methods in the event listener API, and changes the order of *End events (by Vlad Losev). --- src/gtest.cc | 168 +++++++++++++++++++++++++++++++++++------------------------ 1 file changed, 101 insertions(+), 67 deletions(-) (limited to 'src') diff --git a/src/gtest.cc b/src/gtest.cc index 5b33d312..04505bdb 100644 --- a/src/gtest.cc +++ b/src/gtest.cc @@ -617,7 +617,7 @@ DefaultGlobalTestPartResultReporter::DefaultGlobalTestPartResultReporter( void DefaultGlobalTestPartResultReporter::ReportTestPartResult( const TestPartResult& result) { unit_test_->current_test_result()->AddTestPartResult(result); - unit_test_->listeners()->repeater()->OnNewTestPartResult(result); + unit_test_->listeners()->repeater()->OnTestPartResult(result); } DefaultPerThreadTestPartResultReporter::DefaultPerThreadTestPartResultReporter( @@ -2471,12 +2471,10 @@ static void PrintTestPartResult(const TestPartResult& test_part_result) { // following statements add the test part result message to the Output // window such that the user can double-click on it to jump to the // corresponding source code location; otherwise they do nothing. -#ifdef _WIN32_WCE - // Windows Mobile doesn't support the ANSI version of OutputDebugString, - // it works only with UTF16 strings. - ::OutputDebugString(internal::String::AnsiToUtf16(result.c_str())); - ::OutputDebugString(L"\n"); -#elif GTEST_OS_WINDOWS +#if GTEST_OS_WINDOWS && !defined(_WIN32_WCE) + // We don't call OutputDebugString*() on Windows Mobile, as printing + // to stdout is done by OutputDebugString() there already - we don't + // want the same message printed twice. ::OutputDebugStringA(result.c_str()); ::OutputDebugStringA("\n"); #endif @@ -2608,17 +2606,19 @@ class PrettyUnitTestResultPrinter : public UnitTestEventListenerInterface { // The following methods override what's in the // UnitTestEventListenerInterface class. - virtual void OnUnitTestStart(const UnitTest& unit_test); - virtual void OnGlobalSetUpStart(const UnitTest& unit_test); - virtual void OnGlobalSetUpEnd(const UnitTest& /*unit_test*/) {} + virtual void OnTestProgramStart(const UnitTest& /*unit_test*/) {} + virtual void OnTestIterationStart(const UnitTest& unit_test, int iteration); + virtual void OnEnvironmentsSetUpStart(const UnitTest& unit_test); + virtual void OnEnvironmentsSetUpEnd(const UnitTest& /*unit_test*/) {} virtual void OnTestCaseStart(const TestCase& test_case); virtual void OnTestCaseEnd(const TestCase& test_case); virtual void OnTestStart(const TestInfo& test_info); - virtual void OnNewTestPartResult(const TestPartResult& result); + virtual void OnTestPartResult(const TestPartResult& result); virtual void OnTestEnd(const TestInfo& test_info); - virtual void OnGlobalTearDownStart(const UnitTest& unit_test); - virtual void OnGlobalTearDownEnd(const UnitTest& /*unit_test*/) {} - virtual void OnUnitTestEnd(const UnitTest& unit_test); + virtual void OnEnvironmentsTearDownStart(const UnitTest& unit_test); + virtual void OnEnvironmentsTearDownEnd(const UnitTest& /*unit_test*/) {} + virtual void OnTestIterationEnd(const UnitTest& unit_test, int iteration); + virtual void OnTestProgramEnd(const UnitTest& /*unit_test*/) {} private: static void PrintFailedTests(const UnitTest& unit_test); @@ -2626,8 +2626,12 @@ class PrettyUnitTestResultPrinter : public UnitTestEventListenerInterface { internal::String test_case_name_; }; -// Called before the unit test starts. -void PrettyUnitTestResultPrinter::OnUnitTestStart(const UnitTest& unit_test) { + // Fired before each iteration of tests starts. +void PrettyUnitTestResultPrinter::OnTestIterationStart( + const UnitTest& unit_test, int iteration) { + if (GTEST_FLAG(repeat) != 1) + printf("\nRepeating all tests (iteration %d) . . .\n\n", iteration + 1); + const char* const filter = GTEST_FLAG(filter).c_str(); // Prints the filter if it's not *. This reminds the user that some @@ -2657,7 +2661,7 @@ void PrettyUnitTestResultPrinter::OnUnitTestStart(const UnitTest& unit_test) { fflush(stdout); } -void PrettyUnitTestResultPrinter::OnGlobalSetUpStart( +void PrettyUnitTestResultPrinter::OnEnvironmentsSetUpStart( const UnitTest& /*unit_test*/) { ColoredPrintf(COLOR_GREEN, "[----------] "); printf("Global test environment set-up.\n"); @@ -2719,7 +2723,7 @@ void PrettyUnitTestResultPrinter::OnTestEnd(const TestInfo& test_info) { } // Called after an assertion failure. -void PrettyUnitTestResultPrinter::OnNewTestPartResult( +void PrettyUnitTestResultPrinter::OnTestPartResult( const TestPartResult& result) { // If the test part succeeded, we don't need to do anything. if (result.type() == TPRT_SUCCESS) @@ -2730,7 +2734,7 @@ void PrettyUnitTestResultPrinter::OnNewTestPartResult( fflush(stdout); } -void PrettyUnitTestResultPrinter::OnGlobalTearDownStart( +void PrettyUnitTestResultPrinter::OnEnvironmentsTearDownStart( const UnitTest& /*unit_test*/) { ColoredPrintf(COLOR_GREEN, "[----------] "); printf("Global test environment tear-down\n"); @@ -2769,7 +2773,8 @@ void PrettyUnitTestResultPrinter::PrintFailedTests(const UnitTest& unit_test) { } } -void PrettyUnitTestResultPrinter::OnUnitTestEnd(const UnitTest& unit_test) { + void PrettyUnitTestResultPrinter::OnTestIterationEnd(const UnitTest& unit_test, + int /*iteration*/) { ColoredPrintf(COLOR_GREEN, "[==========] "); printf("%s from %s ran.", FormatTestCount(unit_test.test_to_run_count()).c_str(), @@ -2808,13 +2813,13 @@ void PrettyUnitTestResultPrinter::OnUnitTestEnd(const UnitTest& unit_test) { // End PrettyUnitTestResultPrinter -// class UnitTestEventsRepeater +// class TestEventRepeater // // This class forwards events to other event listeners. -class UnitTestEventsRepeater : public UnitTestEventListenerInterface { +class TestEventRepeater : public UnitTestEventListenerInterface { public: - UnitTestEventsRepeater() : forwarding_enabled_(true) {} - virtual ~UnitTestEventsRepeater(); + TestEventRepeater() : forwarding_enabled_(true) {} + virtual ~TestEventRepeater(); void Append(UnitTestEventListenerInterface *listener); UnitTestEventListenerInterface* Release( UnitTestEventListenerInterface* listener); @@ -2824,17 +2829,19 @@ class UnitTestEventsRepeater : public UnitTestEventListenerInterface { bool forwarding_enabled() const { return forwarding_enabled_; } void set_forwarding_enabled(bool enable) { forwarding_enabled_ = enable; } - virtual void OnUnitTestStart(const UnitTest& unit_test); - virtual void OnUnitTestEnd(const UnitTest& unit_test); - virtual void OnGlobalSetUpStart(const UnitTest& unit_test); - virtual void OnGlobalSetUpEnd(const UnitTest& unit_test); - virtual void OnGlobalTearDownStart(const UnitTest& unit_test); - virtual void OnGlobalTearDownEnd(const UnitTest& unit_test); + virtual void OnTestProgramStart(const UnitTest& unit_test); + virtual void OnTestProgramEnd(const UnitTest& unit_test); + virtual void OnTestIterationStart(const UnitTest& unit_test, int iteration); + virtual void OnTestIterationEnd(const UnitTest& unit_test, int iteration); + virtual void OnEnvironmentsSetUpStart(const UnitTest& unit_test); + virtual void OnEnvironmentsSetUpEnd(const UnitTest& unit_test); + virtual void OnEnvironmentsTearDownStart(const UnitTest& unit_test); + virtual void OnEnvironmentsTearDownEnd(const UnitTest& unit_test); virtual void OnTestCaseStart(const TestCase& test_case); virtual void OnTestCaseEnd(const TestCase& test_case); virtual void OnTestStart(const TestInfo& test_info); virtual void OnTestEnd(const TestInfo& test_info); - virtual void OnNewTestPartResult(const TestPartResult& result); + virtual void OnTestPartResult(const TestPartResult& result); private: // Controls whether events will be forwarded to listeners_. Set to false @@ -2843,21 +2850,21 @@ class UnitTestEventsRepeater : public UnitTestEventListenerInterface { // The list of listeners that receive events. Vector listeners_; - GTEST_DISALLOW_COPY_AND_ASSIGN_(UnitTestEventsRepeater); + GTEST_DISALLOW_COPY_AND_ASSIGN_(TestEventRepeater); }; -UnitTestEventsRepeater::~UnitTestEventsRepeater() { +TestEventRepeater::~TestEventRepeater() { for (int i = 0; i < listeners_.size(); i++) { delete listeners_.GetElement(i); } } -void UnitTestEventsRepeater::Append(UnitTestEventListenerInterface *listener) { +void TestEventRepeater::Append(UnitTestEventListenerInterface *listener) { listeners_.PushBack(listener); } // TODO(vladl@google.com): Factor the search functionality into Vector::Find. -UnitTestEventListenerInterface* UnitTestEventsRepeater::Release( +UnitTestEventListenerInterface* TestEventRepeater::Release( UnitTestEventListenerInterface *listener) { for (int i = 0; i < listeners_.size(); ++i) { if (listeners_.GetElement(i) == listener) { @@ -2869,39 +2876,68 @@ UnitTestEventListenerInterface* UnitTestEventsRepeater::Release( return NULL; } -// Since the methods are identical, use a macro to reduce boilerplate. -// This defines a member that repeats the call to all listeners. +// Since most methods are very similar, use macros to reduce boilerplate. +// This defines a member that forwards the call to all listeners. #define GTEST_REPEATER_METHOD_(Name, Type) \ -void UnitTestEventsRepeater::Name(const Type& parameter) { \ +void TestEventRepeater::Name(const Type& parameter) { \ if (forwarding_enabled_) { \ for (int i = 0; i < listeners_.size(); i++) { \ listeners_.GetElement(i)->Name(parameter); \ } \ } \ } +// This defines a member that forwards the call to all listeners in reverse +// order. +#define GTEST_REVERSE_REPEATER_METHOD_(Name, Type) \ +void TestEventRepeater::Name(const Type& parameter) { \ + if (forwarding_enabled_) { \ + for (int i = static_cast(listeners_.size()) - 1; i >= 0; i--) { \ + listeners_.GetElement(i)->Name(parameter); \ + } \ + } \ +} -GTEST_REPEATER_METHOD_(OnUnitTestStart, UnitTest) -GTEST_REPEATER_METHOD_(OnUnitTestEnd, UnitTest) -GTEST_REPEATER_METHOD_(OnGlobalSetUpStart, UnitTest) -GTEST_REPEATER_METHOD_(OnGlobalSetUpEnd, UnitTest) -GTEST_REPEATER_METHOD_(OnGlobalTearDownStart, UnitTest) -GTEST_REPEATER_METHOD_(OnGlobalTearDownEnd, UnitTest) +GTEST_REPEATER_METHOD_(OnTestProgramStart, UnitTest) +GTEST_REPEATER_METHOD_(OnEnvironmentsSetUpStart, UnitTest) +GTEST_REPEATER_METHOD_(OnEnvironmentsTearDownStart, UnitTest) GTEST_REPEATER_METHOD_(OnTestCaseStart, TestCase) -GTEST_REPEATER_METHOD_(OnTestCaseEnd, TestCase) GTEST_REPEATER_METHOD_(OnTestStart, TestInfo) -GTEST_REPEATER_METHOD_(OnTestEnd, TestInfo) -GTEST_REPEATER_METHOD_(OnNewTestPartResult, TestPartResult) +GTEST_REPEATER_METHOD_(OnTestPartResult, TestPartResult) +GTEST_REVERSE_REPEATER_METHOD_(OnTestProgramEnd, UnitTest) +GTEST_REVERSE_REPEATER_METHOD_(OnEnvironmentsSetUpEnd, UnitTest) +GTEST_REVERSE_REPEATER_METHOD_(OnEnvironmentsTearDownEnd, UnitTest) +GTEST_REVERSE_REPEATER_METHOD_(OnTestCaseEnd, TestCase) +GTEST_REVERSE_REPEATER_METHOD_(OnTestEnd, TestInfo) #undef GTEST_REPEATER_METHOD_ +#undef GTEST_REVERSE_REPEATER_METHOD_ -// End UnitTestEventsRepeater +void TestEventRepeater::OnTestIterationStart(const UnitTest& unit_test, + int iteration) { + if (forwarding_enabled_) { + for (int i = 0; i < listeners_.size(); i++) { + listeners_.GetElement(i)->OnTestIterationStart(unit_test, iteration); + } + } +} + +void TestEventRepeater::OnTestIterationEnd(const UnitTest& unit_test, + int iteration) { + if (forwarding_enabled_) { + for (int i = static_cast(listeners_.size()) - 1; i >= 0; i--) { + listeners_.GetElement(i)->OnTestIterationEnd(unit_test, iteration); + } + } +} + +// End TestEventRepeater // This class generates an XML output file. class XmlUnitTestResultPrinter : public EmptyTestEventListener { public: explicit XmlUnitTestResultPrinter(const char* output_file); - virtual void OnUnitTestEnd(const UnitTest& unit_test); + virtual void OnTestIterationEnd(const UnitTest& unit_test, int iteration); private: // Is c a whitespace character that is normalized to a space character @@ -2963,7 +2999,8 @@ XmlUnitTestResultPrinter::XmlUnitTestResultPrinter(const char* output_file) } // Called after the unit test ends. -void XmlUnitTestResultPrinter::OnUnitTestEnd(const UnitTest& unit_test) { +void XmlUnitTestResultPrinter::OnTestIterationEnd(const UnitTest& unit_test, + int /*iteration*/) { FILE* xmlout = NULL; FilePath output_file(output_file_); FilePath output_dir(output_file.RemoveFileName()); @@ -3210,7 +3247,7 @@ OsStackTraceGetter::kElidedFramesMarker = // class EventListeners EventListeners::EventListeners() - : repeater_(new internal::UnitTestEventsRepeater()), + : repeater_(new internal::TestEventRepeater()), default_result_printer_(NULL), default_xml_generator_(NULL) { } @@ -3834,31 +3871,27 @@ int UnitTestImpl::RunAllTests() { UnitTestEventListenerInterface* repeater = listeners()->repeater(); + repeater->OnTestProgramStart(*parent_); + // How many times to repeat the tests? We don't want to repeat them // when we are inside the subprocess of a death test. const int repeat = in_subprocess_for_death_test ? 1 : GTEST_FLAG(repeat); // Repeats forever if the repeat count is negative. const bool forever = repeat < 0; for (int i = 0; forever || i != repeat; i++) { - if (repeat != 1) { - // TODO(vladl@google.com): Move this output to - // PrettyUnitTestResultPrinter. Add the iteration number parameter to - // OnUnitTestStart. - printf("\nRepeating all tests (iteration %d) . . .\n\n", i + 1); - } - - // Tells the unit test event listeners that the tests are about to start. - repeater->OnUnitTestStart(*parent_); + ClearResult(); - // TODO(vladl@google.com): Move to before the OnUnitTestStart notification? const TimeInMillis start = GetTimeInMillis(); + // Tells the unit test event listeners that the tests are about to start. + repeater->OnTestIterationStart(*parent_, i); + // Runs each test case if there is at least one test to run. if (has_tests_to_run) { // Sets up all environments beforehand. - repeater->OnGlobalSetUpStart(*parent_); + repeater->OnEnvironmentsSetUpStart(*parent_); environments_.ForEach(SetUpEnvironment); - repeater->OnGlobalSetUpEnd(*parent_); + repeater->OnEnvironmentsSetUpEnd(*parent_); // Runs the tests only if there was no fatal failure during global // set-up. @@ -3867,21 +3900,20 @@ int UnitTestImpl::RunAllTests() { } // Tears down all environments in reverse order afterwards. - repeater->OnGlobalTearDownStart(*parent_); + repeater->OnEnvironmentsTearDownStart(*parent_); environments_in_reverse_order_.ForEach(TearDownEnvironment); - repeater->OnGlobalTearDownEnd(*parent_); + repeater->OnEnvironmentsTearDownEnd(*parent_); } elapsed_time_ = GetTimeInMillis() - start; // Tells the unit test event listener that the tests have just finished. - repeater->OnUnitTestEnd(*parent_); + repeater->OnTestIterationEnd(*parent_, i); // Gets the result and clears it. if (!Passed()) { failed = true; } - ClearResult(); if (GTEST_FLAG(shuffle)) { // Picks a new random seed for each run. @@ -3889,6 +3921,8 @@ int UnitTestImpl::RunAllTests() { } } + repeater->OnTestProgramEnd(*parent_); + // Returns 0 if all tests passed, or 1 other wise. return failed ? 1 : 0; } -- cgit v1.2.3 From e5373af0cb9cae249e7bc618cae3483397332895 Mon Sep 17 00:00:00 2001 From: "zhanyong.wan" Date: Fri, 18 Sep 2009 18:16:20 +0000 Subject: Renames the TestPartResult type enums and adjusts the order of methods in the event listener interface (by Vlad Losev). --- src/gtest-test-part.cc | 12 +++--- src/gtest.cc | 102 +++++++++++++++++++++++++------------------------ 2 files changed, 58 insertions(+), 56 deletions(-) (limited to 'src') diff --git a/src/gtest-test-part.cc b/src/gtest-test-part.cc index f053773f..4f36df66 100644 --- a/src/gtest-test-part.cc +++ b/src/gtest-test-part.cc @@ -56,12 +56,12 @@ internal::String TestPartResult::ExtractSummary(const char* message) { // Prints a TestPartResult object. std::ostream& operator<<(std::ostream& os, const TestPartResult& result) { - return os << result.file_name() << ":" - << result.line_number() << ": " - << (result.type() == TPRT_SUCCESS ? "Success" : - result.type() == TPRT_FATAL_FAILURE ? "Fatal failure" : - "Non-fatal failure") << ":\n" - << result.message() << std::endl; + return os + << result.file_name() << ":" << result.line_number() << ": " + << (result.type() == TestPartResult::kSuccess ? "Success" : + result.type() == TestPartResult::kFatalFailure ? "Fatal failure" : + "Non-fatal failure") << ":\n" + << result.message() << std::endl; } // Constructs an empty TestPartResultArray. diff --git a/src/gtest.cc b/src/gtest.cc index 04505bdb..bb5ffacc 100644 --- a/src/gtest.cc +++ b/src/gtest.cc @@ -304,8 +304,10 @@ static bool ShouldRunTestCase(const TestCase* test_case) { } // AssertHelper constructor. -AssertHelper::AssertHelper(TestPartResultType type, const char* file, - int line, const char* message) +AssertHelper::AssertHelper(TestPartResult::Type type, + const char* file, + int line, + const char* message) : data_(new AssertHelperData(type, file, line, message)) { } @@ -558,11 +560,11 @@ AssertionResult HasOneFailure(const char* /* results_expr */, const char* /* type_expr */, const char* /* substr_expr */, const TestPartResultArray& results, - TestPartResultType type, + TestPartResult::Type type, const char* substr) { - const String expected( - type == TPRT_FATAL_FAILURE ? "1 fatal failure" : - "1 non-fatal failure"); + const String expected(type == TestPartResult::kFatalFailure ? + "1 fatal failure" : + "1 non-fatal failure"); Message msg; if (results.size() != 1) { msg << "Expected: " << expected << "\n" @@ -597,7 +599,7 @@ AssertionResult HasOneFailure(const char* /* results_expr */, // substring the failure message should contain. SingleFailureChecker:: SingleFailureChecker( const TestPartResultArray* results, - TestPartResultType type, + TestPartResult::Type type, const char* substr) : results_(results), type_(type), @@ -1908,7 +1910,7 @@ void Test::RecordProperty(const char* key, int value) { namespace internal { -void ReportFailureInUnknownLocation(TestPartResultType result_type, +void ReportFailureInUnknownLocation(TestPartResult::Type result_type, const String& message) { // This function is a friend of UnitTest and as such has access to // AddTestPartResult. @@ -1932,7 +1934,7 @@ static void AddExceptionThrownFailure(DWORD exception_code, message << "Exception thrown with code 0x" << std::setbase(16) << exception_code << std::setbase(10) << " in " << location << "."; - internal::ReportFailureInUnknownLocation(TPRT_FATAL_FAILURE, + internal::ReportFailureInUnknownLocation(TestPartResult::kFatalFailure, message.GetString()); } @@ -2430,17 +2432,17 @@ static internal::String FormatTestCaseCount(int test_case_count) { return FormatCountableNoun(test_case_count, "test case", "test cases"); } -// Converts a TestPartResultType enum to human-friendly string -// representation. Both TPRT_NONFATAL_FAILURE and TPRT_FATAL_FAILURE -// are translated to "Failure", as the user usually doesn't care about -// the difference between the two when viewing the test result. -static const char * TestPartResultTypeToString(TestPartResultType type) { +// Converts a TestPartResult::Type enum to human-friendly string +// representation. Both kNonFatalFailure and kFatalFailure are translated +// to "Failure", as the user usually doesn't care about the difference +// between the two when viewing the test result. +static const char * TestPartResultTypeToString(TestPartResult::Type type) { switch (type) { - case TPRT_SUCCESS: + case TestPartResult::kSuccess: return "Success"; - case TPRT_NONFATAL_FAILURE: - case TPRT_FATAL_FAILURE: + case TestPartResult::kNonFatalFailure: + case TestPartResult::kFatalFailure: #ifdef _MSC_VER return "error: "; #else @@ -2611,10 +2613,10 @@ class PrettyUnitTestResultPrinter : public UnitTestEventListenerInterface { virtual void OnEnvironmentsSetUpStart(const UnitTest& unit_test); virtual void OnEnvironmentsSetUpEnd(const UnitTest& /*unit_test*/) {} virtual void OnTestCaseStart(const TestCase& test_case); - virtual void OnTestCaseEnd(const TestCase& test_case); virtual void OnTestStart(const TestInfo& test_info); virtual void OnTestPartResult(const TestPartResult& result); virtual void OnTestEnd(const TestInfo& test_info); + virtual void OnTestCaseEnd(const TestCase& test_case); virtual void OnEnvironmentsTearDownStart(const UnitTest& unit_test); virtual void OnEnvironmentsTearDownEnd(const UnitTest& /*unit_test*/) {} virtual void OnTestIterationEnd(const UnitTest& unit_test, int iteration); @@ -2682,19 +2684,6 @@ void PrettyUnitTestResultPrinter::OnTestCaseStart(const TestCase& test_case) { fflush(stdout); } -void PrettyUnitTestResultPrinter::OnTestCaseEnd(const TestCase& test_case) { - if (!GTEST_FLAG(print_time)) return; - - test_case_name_ = test_case.name(); - const internal::String counts = - FormatCountableNoun(test_case.test_to_run_count(), "test", "tests"); - ColoredPrintf(COLOR_GREEN, "[----------] "); - printf("%s from %s (%s ms total)\n\n", - counts.c_str(), test_case_name_.c_str(), - internal::StreamableToString(test_case.elapsed_time()).c_str()); - fflush(stdout); -} - void PrettyUnitTestResultPrinter::OnTestStart(const TestInfo& test_info) { ColoredPrintf(COLOR_GREEN, "[ RUN ] "); PrintTestName(test_case_name_.c_str(), test_info.name()); @@ -2706,6 +2695,18 @@ void PrettyUnitTestResultPrinter::OnTestStart(const TestInfo& test_info) { fflush(stdout); } +// Called after an assertion failure. +void PrettyUnitTestResultPrinter::OnTestPartResult( + const TestPartResult& result) { + // If the test part succeeded, we don't need to do anything. + if (result.type() == TestPartResult::kSuccess) + return; + + // Print failure message from the assertion (e.g. expected this and got that). + PrintTestPartResult(result); + fflush(stdout); +} + void PrettyUnitTestResultPrinter::OnTestEnd(const TestInfo& test_info) { if (test_info.result()->Passed()) { ColoredPrintf(COLOR_GREEN, "[ OK ] "); @@ -2722,15 +2723,16 @@ void PrettyUnitTestResultPrinter::OnTestEnd(const TestInfo& test_info) { fflush(stdout); } -// Called after an assertion failure. -void PrettyUnitTestResultPrinter::OnTestPartResult( - const TestPartResult& result) { - // If the test part succeeded, we don't need to do anything. - if (result.type() == TPRT_SUCCESS) - return; +void PrettyUnitTestResultPrinter::OnTestCaseEnd(const TestCase& test_case) { + if (!GTEST_FLAG(print_time)) return; - // Print failure message from the assertion (e.g. expected this and got that). - PrintTestPartResult(result); + test_case_name_ = test_case.name(); + const internal::String counts = + FormatCountableNoun(test_case.test_to_run_count(), "test", "tests"); + ColoredPrintf(COLOR_GREEN, "[----------] "); + printf("%s from %s (%s ms total)\n\n", + counts.c_str(), test_case_name_.c_str(), + internal::StreamableToString(test_case.elapsed_time()).c_str()); fflush(stdout); } @@ -2830,18 +2832,18 @@ class TestEventRepeater : public UnitTestEventListenerInterface { void set_forwarding_enabled(bool enable) { forwarding_enabled_ = enable; } virtual void OnTestProgramStart(const UnitTest& unit_test); - virtual void OnTestProgramEnd(const UnitTest& unit_test); virtual void OnTestIterationStart(const UnitTest& unit_test, int iteration); - virtual void OnTestIterationEnd(const UnitTest& unit_test, int iteration); virtual void OnEnvironmentsSetUpStart(const UnitTest& unit_test); virtual void OnEnvironmentsSetUpEnd(const UnitTest& unit_test); - virtual void OnEnvironmentsTearDownStart(const UnitTest& unit_test); - virtual void OnEnvironmentsTearDownEnd(const UnitTest& unit_test); virtual void OnTestCaseStart(const TestCase& test_case); - virtual void OnTestCaseEnd(const TestCase& test_case); virtual void OnTestStart(const TestInfo& test_info); - virtual void OnTestEnd(const TestInfo& test_info); virtual void OnTestPartResult(const TestPartResult& result); + virtual void OnTestEnd(const TestInfo& test_info); + virtual void OnTestCaseEnd(const TestCase& test_case); + virtual void OnEnvironmentsTearDownStart(const UnitTest& unit_test); + virtual void OnEnvironmentsTearDownEnd(const UnitTest& unit_test); + virtual void OnTestIterationEnd(const UnitTest& unit_test, int iteration); + virtual void OnTestProgramEnd(const UnitTest& unit_test); private: // Controls whether events will be forwarded to listeners_. Set to false @@ -2899,15 +2901,15 @@ void TestEventRepeater::Name(const Type& parameter) { \ GTEST_REPEATER_METHOD_(OnTestProgramStart, UnitTest) GTEST_REPEATER_METHOD_(OnEnvironmentsSetUpStart, UnitTest) -GTEST_REPEATER_METHOD_(OnEnvironmentsTearDownStart, UnitTest) GTEST_REPEATER_METHOD_(OnTestCaseStart, TestCase) GTEST_REPEATER_METHOD_(OnTestStart, TestInfo) GTEST_REPEATER_METHOD_(OnTestPartResult, TestPartResult) -GTEST_REVERSE_REPEATER_METHOD_(OnTestProgramEnd, UnitTest) +GTEST_REPEATER_METHOD_(OnEnvironmentsTearDownStart, UnitTest) GTEST_REVERSE_REPEATER_METHOD_(OnEnvironmentsSetUpEnd, UnitTest) GTEST_REVERSE_REPEATER_METHOD_(OnEnvironmentsTearDownEnd, UnitTest) -GTEST_REVERSE_REPEATER_METHOD_(OnTestCaseEnd, TestCase) GTEST_REVERSE_REPEATER_METHOD_(OnTestEnd, TestInfo) +GTEST_REVERSE_REPEATER_METHOD_(OnTestCaseEnd, TestCase) +GTEST_REVERSE_REPEATER_METHOD_(OnTestProgramEnd, UnitTest) #undef GTEST_REPEATER_METHOD_ #undef GTEST_REVERSE_REPEATER_METHOD_ @@ -3454,7 +3456,7 @@ class GoogleTestFailureException : public ::std::runtime_error { // this to report their results. The user code should use the // assertion macros instead of calling this directly. // L < mutex_ -void UnitTest::AddTestPartResult(TestPartResultType result_type, +void UnitTest::AddTestPartResult(TestPartResult::Type result_type, const char* file_name, int line_number, const internal::String& message, @@ -3484,7 +3486,7 @@ void UnitTest::AddTestPartResult(TestPartResultType result_type, impl_->GetTestPartResultReporterForCurrentThread()-> ReportTestPartResult(result); - if (result_type != TPRT_SUCCESS) { + if (result_type != TestPartResult::kSuccess) { // gtest_break_on_failure takes precedence over // gtest_throw_on_failure. This allows a user to set the latter // in the code (perhaps in order to use Google Test assertions -- cgit v1.2.3 From 2534ae201e47986d36d5fab0e523a7f046b8ec1e Mon Sep 17 00:00:00 2001 From: "zhanyong.wan" Date: Mon, 21 Sep 2009 19:42:03 +0000 Subject: Adds a Random class to support --gtest_shuffle (by Josh Kelley); Makes the scons script build in a deterministic order (by Zhanyong Wan). --- src/gtest.cc | 21 ++++++++++++++++++++- 1 file changed, 20 insertions(+), 1 deletion(-) (limited to 'src') diff --git a/src/gtest.cc b/src/gtest.cc index bb5ffacc..30652fe1 100644 --- a/src/gtest.cc +++ b/src/gtest.cc @@ -260,6 +260,25 @@ GTEST_DEFINE_bool_( namespace internal { +// Generates a random number from [0, range), using a Linear +// Congruential Generator (LCG). Crashes if 'range' is 0 or greater +// than kMaxRange. +UInt32 Random::Generate(UInt32 range) { + // These constants are the same as are used in glibc's rand(3). + state_ = (1103515245U*state_ + 12345U) % kMaxRange; + + GTEST_CHECK_(range > 0) + << "Cannot generate a number in the range [0, 0)."; + GTEST_CHECK_(range <= kMaxRange) + << "Generation of a number in [0, " << range << ") was requested, " + << "but this can only generate numbers in [0, " << kMaxRange << ")."; + + // Converting via modulus introduces a bit of downward bias, but + // it's simple, and a linear congruential generator isn't too good + // to begin with. + return state_ % range; +} + // g_help_flag is true iff the --help flag or an equivalent form is // specified on the command line. static bool g_help_flag = false; @@ -3815,7 +3834,7 @@ static void TearDownEnvironment(Environment* env) { env->TearDown(); } // considered to be failed, but the rest of the tests will still be // run. (We disable exceptions on Linux and Mac OS X, so the issue // doesn't apply there.) -// When parameterized tests are enabled, it explands and registers +// When parameterized tests are enabled, it expands and registers // parameterized tests first in RegisterParameterizedTests(). // All other functions called from RunAllTests() may safely assume that // parameterized tests are ready to be counted and run. -- cgit v1.2.3 From b50ef44a3527d958270ff1f08cb99e3ac633bd17 Mon Sep 17 00:00:00 2001 From: "zhanyong.wan" Date: Thu, 24 Sep 2009 21:15:59 +0000 Subject: Publishes the even listener API (by Vlad Losev); adds OS-indicating macros to simplify gtest code (by Zhanyong Wan). --- src/gtest-filepath.cc | 33 ++++++++------- src/gtest-internal-inl.h | 2 - src/gtest-port.cc | 28 ++++++------- src/gtest.cc | 103 ++++++++++++++++++++--------------------------- 4 files changed, 72 insertions(+), 94 deletions(-) (limited to 'src') diff --git a/src/gtest-filepath.cc b/src/gtest-filepath.cc index ef742366..515d61c7 100644 --- a/src/gtest-filepath.cc +++ b/src/gtest-filepath.cc @@ -34,7 +34,7 @@ #include -#ifdef _WIN32_WCE +#if GTEST_OS_WINDOWS_MOBILE #include #elif GTEST_OS_WINDOWS #include @@ -45,7 +45,7 @@ #else #include #include // Some Linux distributions define PATH_MAX here. -#endif // _WIN32_WCE or _WIN32 +#endif // GTEST_OS_WINDOWS_MOBILE #if GTEST_OS_WINDOWS #define GTEST_PATH_MAX_ _MAX_PATH @@ -65,7 +65,7 @@ namespace internal { #if GTEST_OS_WINDOWS const char kPathSeparator = '\\'; const char kPathSeparatorString[] = "\\"; -#ifdef _WIN32_WCE +#if GTEST_OS_WINDOWS_MOBILE // Windows CE doesn't have a current directory. You should not use // the current directory in tests on Windows CE, but this at least // provides a reasonable fallback. @@ -74,7 +74,7 @@ const char kCurrentDirectoryString[] = "\\"; const DWORD kInvalidFileAttributes = 0xffffffff; #else const char kCurrentDirectoryString[] = ".\\"; -#endif // _WIN32_WCE +#endif // GTEST_OS_WINDOWS_MOBILE #else const char kPathSeparator = '/'; const char kPathSeparatorString[] = "/"; @@ -83,9 +83,9 @@ const char kCurrentDirectoryString[] = "./"; // Returns the current working directory, or "" if unsuccessful. FilePath FilePath::GetCurrentDir() { -#ifdef _WIN32_WCE -// Windows CE doesn't have a current directory, so we just return -// something reasonable. +#if GTEST_OS_WINDOWS_MOBILE + // Windows CE doesn't have a current directory, so we just return + // something reasonable. return FilePath(kCurrentDirectoryString); #elif GTEST_OS_WINDOWS char cwd[GTEST_PATH_MAX_ + 1] = { '\0' }; @@ -93,7 +93,7 @@ FilePath FilePath::GetCurrentDir() { #else char cwd[GTEST_PATH_MAX_ + 1] = { '\0' }; return FilePath(getcwd(cwd, sizeof(cwd)) == NULL ? "" : cwd); -#endif +#endif // GTEST_OS_WINDOWS_MOBILE } // Returns a copy of the FilePath with the case-insensitive extension removed. @@ -169,7 +169,7 @@ FilePath FilePath::ConcatPaths(const FilePath& directory, // Returns true if pathname describes something findable in the file-system, // either a file, directory, or whatever. bool FilePath::FileOrDirectoryExists() const { -#ifdef _WIN32_WCE +#if GTEST_OS_WINDOWS_MOBILE LPCWSTR unicode = String::AnsiToUtf16(pathname_.c_str()); const DWORD attributes = GetFileAttributes(unicode); delete [] unicode; @@ -177,7 +177,7 @@ bool FilePath::FileOrDirectoryExists() const { #else posix::StatStruct file_stat; return posix::Stat(pathname_.c_str(), &file_stat) == 0; -#endif // _WIN32_WCE +#endif // GTEST_OS_WINDOWS_MOBILE } // Returns true if pathname describes a directory in the file-system @@ -193,7 +193,7 @@ bool FilePath::DirectoryExists() const { const FilePath& path(*this); #endif -#ifdef _WIN32_WCE +#if GTEST_OS_WINDOWS_MOBILE LPCWSTR unicode = String::AnsiToUtf16(path.c_str()); const DWORD attributes = GetFileAttributes(unicode); delete [] unicode; @@ -205,7 +205,7 @@ bool FilePath::DirectoryExists() const { posix::StatStruct file_stat; result = posix::Stat(path.c_str(), &file_stat) == 0 && posix::IsDir(file_stat); -#endif // _WIN32_WCE +#endif // GTEST_OS_WINDOWS_MOBILE return result; } @@ -284,18 +284,17 @@ bool FilePath::CreateDirectoriesRecursively() const { // directory for any reason, including if the parent directory does not // exist. Not named "CreateDirectory" because that's a macro on Windows. bool FilePath::CreateFolder() const { -#if GTEST_OS_WINDOWS -#ifdef _WIN32_WCE +#if GTEST_OS_WINDOWS_MOBILE FilePath removed_sep(this->RemoveTrailingPathSeparator()); LPCWSTR unicode = String::AnsiToUtf16(removed_sep.c_str()); int result = CreateDirectory(unicode, NULL) ? 0 : -1; delete [] unicode; -#else +#elif GTEST_OS_WINDOWS int result = _mkdir(pathname_.c_str()); -#endif // !WIN32_WCE #else int result = mkdir(pathname_.c_str(), 0777); -#endif // _WIN32 +#endif // GTEST_OS_WINDOWS_MOBILE + if (result == -1) { return this->DirectoryExists(); // An error is OK if the directory exists. } diff --git a/src/gtest-internal-inl.h b/src/gtest-internal-inl.h index 93217f44..9826bdd3 100644 --- a/src/gtest-internal-inl.h +++ b/src/gtest-internal-inl.h @@ -1140,8 +1140,6 @@ class TestResultAccessor { test_result->RecordProperty(property); } - static bool Passed(const TestResult& result) { return result.Passed(); } - static void ClearTestPartResults(TestResult* test_result) { test_result->ClearTestPartResults(); } diff --git a/src/gtest-port.cc b/src/gtest-port.cc index ba9a9a28..de169e2a 100644 --- a/src/gtest-port.cc +++ b/src/gtest-port.cc @@ -35,14 +35,14 @@ #include #include -#if GTEST_OS_WINDOWS -#ifndef _WIN32_WCE +#if GTEST_OS_WINDOWS_MOBILE +#include // For TerminateProcess() +#elif GTEST_OS_WINDOWS #include #include -#endif // _WIN32_WCE #else #include -#endif // GTEST_OS_WINDOWS +#endif // GTEST_OS_WINDOWS_MOBILE #if GTEST_OS_MAC #include @@ -50,10 +50,6 @@ #include #endif // GTEST_OS_MAC -#ifdef _WIN32_WCE -#include // For TerminateProcess() -#endif // _WIN32_WCE - #include #include #include @@ -449,7 +445,7 @@ class CapturedStderr { public: // The ctor redirects stderr to a temporary file. CapturedStderr() { -#ifdef _WIN32_WCE +#if GTEST_OS_WINDOWS_MOBILE // Not supported on Windows CE. posix::Abort(); #else @@ -474,24 +470,24 @@ class CapturedStderr { fflush(NULL); dup2(captured_fd, kStdErrFileno); close(captured_fd); -#endif // _WIN32_WCE +#endif // GTEST_OS_WINDOWS_MOBILE } ~CapturedStderr() { -#ifndef _WIN32_WCE +#if !GTEST_OS_WINDOWS_MOBILE remove(filename_.c_str()); -#endif // _WIN32_WCE +#endif // !GTEST_OS_WINDOWS_MOBILE } // Stops redirecting stderr. void StopCapture() { -#ifndef _WIN32_WCE +#if !GTEST_OS_WINDOWS_MOBILE // Restores the original stream. fflush(NULL); dup2(uncaptured_fd_, kStdErrFileno); close(uncaptured_fd_); uncaptured_fd_ = -1; -#endif // !_WIN32_WCE +#endif // !GTEST_OS_WINDOWS_MOBILE } // Returns the name of the temporary file holding the stderr output. @@ -573,14 +569,14 @@ const ::std::vector& GetArgvs() { return g_argvs; } #endif // GTEST_HAS_DEATH_TEST -#ifdef _WIN32_WCE +#if GTEST_OS_WINDOWS_MOBILE namespace posix { void Abort() { DebugBreak(); TerminateProcess(GetCurrentProcess(), 1); } } // namespace posix -#endif // _WIN32_WCE +#endif // GTEST_OS_WINDOWS_MOBILE // Returns the name of the environment variable corresponding to the // given flag. For example, FlagToEnvVar("foo") will return diff --git a/src/gtest.cc b/src/gtest.cc index 30652fe1..44ec9496 100644 --- a/src/gtest.cc +++ b/src/gtest.cc @@ -70,7 +70,7 @@ // On z/OS we additionally need strings.h for strcasecmp. #include // NOLINT -#elif defined(_WIN32_WCE) // We are on Windows CE. +#elif GTEST_OS_WINDOWS_MOBILE // We are on Windows CE. #include // NOLINT @@ -81,7 +81,7 @@ #include // NOLINT #include // NOLINT -#if defined(__MINGW__) || defined(__MINGW32__) +#if GTEST_OS_WINDOWS_MINGW // MinGW has gettimeofday() but not _ftime64(). // TODO(kenton@google.com): Use autoconf to detect availability of // gettimeofday(). @@ -90,7 +90,7 @@ // supports these. consider using them instead. #define GTEST_HAS_GETTIMEOFDAY_ 1 #include // NOLINT -#endif // defined(__MINGW__) || defined(__MINGW32__) +#endif // GTEST_OS_WINDOWS_MINGW // cpplint thinks that the header is already included, so we want to // silence it. @@ -129,13 +129,6 @@ namespace testing { -using internal::EventListeners; -using internal::EmptyTestEventListener; -using internal::TestCase; -using internal::TestProperty; -using internal::TestResult; -using internal::UnitTestEventListenerInterface; - // Constants. // A test whose test case name or test name matches this filter is @@ -356,11 +349,11 @@ String g_executable_path; FilePath GetCurrentExecutableName() { FilePath result; -#if defined(_WIN32_WCE) || GTEST_OS_WINDOWS +#if GTEST_OS_WINDOWS result.Set(FilePath(g_executable_path).RemoveExtension("exe")); #else result.Set(FilePath(g_executable_path)); -#endif // _WIN32_WCE || GTEST_OS_WINDOWS +#endif // GTEST_OS_WINDOWS return result.RemoveDirectoryName(); } @@ -738,7 +731,7 @@ String UnitTestImpl::CurrentOsStackTraceExceptTop(int skip_count) { // Returns the current time in milliseconds. TimeInMillis GetTimeInMillis() { -#if defined(_WIN32_WCE) || defined(__BORLANDC__) +#if GTEST_OS_WINDOWS_MOBILE || defined(__BORLANDC__) // Difference between 1970-01-01 and 1601-01-01 in milliseconds. // http://analogous.blogspot.com/2005/04/epoch.html const TimeInMillis kJavaEpochToWinFileTimeDelta = @@ -821,7 +814,7 @@ const char * String::CloneCString(const char* c_str) { NULL : CloneString(c_str, strlen(c_str)); } -#ifdef _WIN32_WCE +#if GTEST_OS_WINDOWS_MOBILE // Creates a UTF-16 wide string from the given ANSI string, allocating // memory using new. The caller is responsible for deleting the return // value using delete[]. Returns the wide string, or NULL if the @@ -855,7 +848,7 @@ const char* String::Utf16ToAnsi(LPCWSTR utf16_str) { return ansi; } -#endif // _WIN32_WCE +#endif // GTEST_OS_WINDOWS_MOBILE // Compares two C strings. Returns true iff they have the same content. // @@ -1329,7 +1322,7 @@ namespace { AssertionResult HRESULTFailureHelper(const char* expr, const char* expected, long hr) { // NOLINT -#ifdef _WIN32_WCE +#if GTEST_OS_WINDOWS_MOBILE // Windows CE doesn't support FormatMessage. const char error_text[] = ""; #else @@ -1353,7 +1346,7 @@ AssertionResult HRESULTFailureHelper(const char* expr, --message_length) { error_text[message_length - 1] = '\0'; } -#endif // _WIN32_WCE +#endif // GTEST_OS_WINDOWS_MOBILE const String error_hex(String::Format("0x%08X ", hr)); Message msg; @@ -1768,6 +1761,8 @@ String AppendUserMessage(const String& gtest_msg, return msg.GetString(); } +} // namespace internal + // class TestResult // Creates an empty TestResult. @@ -1887,8 +1882,6 @@ int TestResult::test_property_count() const { return test_properties_->size(); } -} // namespace internal - // class Test // Creates a Test object. @@ -2255,8 +2248,7 @@ void TestInfoImpl::Run() { UnitTestImpl* const impl = internal::GetUnitTestImpl(); impl->set_current_test_info(parent_); - UnitTestEventListenerInterface* repeater = - UnitTest::GetInstance()->listeners().repeater(); + TestEventListener* repeater = UnitTest::GetInstance()->listeners().repeater(); // Notifies the unit test event listeners that a test is about to start. repeater->OnTestStart(*parent_); @@ -2309,6 +2301,8 @@ void TestInfoImpl::Run() { impl->set_current_test_info(NULL); } +} // namespace internal + // class TestCase // Gets the number of successful tests in this test case. @@ -2383,8 +2377,7 @@ void TestCase::Run() { internal::UnitTestImpl* const impl = internal::GetUnitTestImpl(); impl->set_current_test_case(this); - UnitTestEventListenerInterface* repeater = - UnitTest::GetInstance()->listeners().repeater(); + TestEventListener* repeater = UnitTest::GetInstance()->listeners().repeater(); repeater->OnTestCaseStart(*this); impl->os_stack_trace_getter()->UponLeavingGTest(); @@ -2427,8 +2420,6 @@ bool TestCase::ShouldRunTest(const TestInfo *test_info) { return test_info->impl()->should_run(); } -} // namespace internal - // Formats a countable noun. Depending on its quantity, either the // singular form or the plural form is used. e.g. // @@ -2492,7 +2483,7 @@ static void PrintTestPartResult(const TestPartResult& test_part_result) { // following statements add the test part result message to the Output // window such that the user can double-click on it to jump to the // corresponding source code location; otherwise they do nothing. -#if GTEST_OS_WINDOWS && !defined(_WIN32_WCE) +#if GTEST_OS_WINDOWS && !GTEST_OS_WINDOWS_MOBILE // We don't call OutputDebugString*() on Windows Mobile, as printing // to stdout is done by OutputDebugString() there already - we don't // want the same message printed twice. @@ -2512,7 +2503,7 @@ enum GTestColor { COLOR_YELLOW }; -#if GTEST_OS_WINDOWS && !defined(_WIN32_WCE) +#if GTEST_OS_WINDOWS && !GTEST_OS_WINDOWS_MOBILE // Returns the character attribute for the given color. WORD GetColorAttribute(GTestColor color) { @@ -2537,7 +2528,7 @@ const char* GetAnsiColorCode(GTestColor color) { }; } -#endif // GTEST_OS_WINDOWS && !_WIN32_WCE +#endif // GTEST_OS_WINDOWS && !GTEST_OS_WINDOWS_MOBILE // Returns true iff Google Test should use colors in the output. bool ShouldUseColor(bool stdout_is_tty) { @@ -2578,13 +2569,13 @@ void ColoredPrintf(GTestColor color, const char* fmt, ...) { va_list args; va_start(args, fmt); -#if defined(_WIN32_WCE) || GTEST_OS_SYMBIAN || GTEST_OS_ZOS +#if GTEST_OS_WINDOWS_MOBILE || GTEST_OS_SYMBIAN || GTEST_OS_ZOS const bool use_color = false; #else static const bool in_color_mode = ShouldUseColor(posix::IsATTY(posix::FileNo(stdout)) != 0); const bool use_color = in_color_mode && (color != COLOR_DEFAULT); -#endif // defined(_WIN32_WCE) || GTEST_OS_SYMBIAN || GTEST_OS_ZOS +#endif // GTEST_OS_WINDOWS_MOBILE || GTEST_OS_SYMBIAN || GTEST_OS_ZOS // The '!= 0' comparison is necessary to satisfy MSVC 7.1. if (!use_color) { @@ -2593,7 +2584,7 @@ void ColoredPrintf(GTestColor color, const char* fmt, ...) { return; } -#if GTEST_OS_WINDOWS && !defined(_WIN32_WCE) +#if GTEST_OS_WINDOWS && !GTEST_OS_WINDOWS_MOBILE const HANDLE stdout_handle = GetStdHandle(STD_OUTPUT_HANDLE); // Gets the current text color. @@ -2611,22 +2602,21 @@ void ColoredPrintf(GTestColor color, const char* fmt, ...) { printf("\033[0;3%sm", GetAnsiColorCode(color)); vprintf(fmt, args); printf("\033[m"); // Resets the terminal to default. -#endif // GTEST_OS_WINDOWS && !defined(_WIN32_WCE) +#endif // GTEST_OS_WINDOWS && !GTEST_OS_WINDOWS_MOBILE va_end(args); } -// This class implements the UnitTestEventListenerInterface interface. +// This class implements the TestEventListener interface. // // Class PrettyUnitTestResultPrinter is copyable. -class PrettyUnitTestResultPrinter : public UnitTestEventListenerInterface { +class PrettyUnitTestResultPrinter : public TestEventListener { public: PrettyUnitTestResultPrinter() {} static void PrintTestName(const char * test_case, const char * test) { printf("%s.%s", test_case, test); } - // The following methods override what's in the - // UnitTestEventListenerInterface class. + // The following methods override what's in the TestEventListener class. virtual void OnTestProgramStart(const UnitTest& /*unit_test*/) {} virtual void OnTestIterationStart(const UnitTest& unit_test, int iteration); virtual void OnEnvironmentsSetUpStart(const UnitTest& unit_test); @@ -2837,13 +2827,12 @@ void PrettyUnitTestResultPrinter::PrintFailedTests(const UnitTest& unit_test) { // class TestEventRepeater // // This class forwards events to other event listeners. -class TestEventRepeater : public UnitTestEventListenerInterface { +class TestEventRepeater : public TestEventListener { public: TestEventRepeater() : forwarding_enabled_(true) {} virtual ~TestEventRepeater(); - void Append(UnitTestEventListenerInterface *listener); - UnitTestEventListenerInterface* Release( - UnitTestEventListenerInterface* listener); + void Append(TestEventListener *listener); + TestEventListener* Release(TestEventListener* listener); // Controls whether events will be forwarded to listeners_. Set to false // in death test child processes. @@ -2869,7 +2858,7 @@ class TestEventRepeater : public UnitTestEventListenerInterface { // in death test child processes. bool forwarding_enabled_; // The list of listeners that receive events. - Vector listeners_; + Vector listeners_; GTEST_DISALLOW_COPY_AND_ASSIGN_(TestEventRepeater); }; @@ -2880,13 +2869,12 @@ TestEventRepeater::~TestEventRepeater() { } } -void TestEventRepeater::Append(UnitTestEventListenerInterface *listener) { +void TestEventRepeater::Append(TestEventListener *listener) { listeners_.PushBack(listener); } // TODO(vladl@google.com): Factor the search functionality into Vector::Find. -UnitTestEventListenerInterface* TestEventRepeater::Release( - UnitTestEventListenerInterface *listener) { +TestEventListener* TestEventRepeater::Release(TestEventListener *listener) { for (int i = 0; i < listeners_.size(); ++i) { if (listeners_.GetElement(i) == listener) { listeners_.Erase(i); @@ -3279,15 +3267,14 @@ EventListeners::~EventListeners() { delete repeater_; } // output. Can be removed from the listeners list to shut down default // console output. Note that removing this object from the listener list // with Release transfers its ownership to the user. -void EventListeners::Append(UnitTestEventListenerInterface* listener) { +void EventListeners::Append(TestEventListener* listener) { repeater_->Append(listener); } // Removes the given event listener from the list and returns it. It then // becomes the caller's responsibility to delete the listener. Returns // NULL if the listener is not found in the list. -UnitTestEventListenerInterface* EventListeners::Release( - UnitTestEventListenerInterface* listener) { +TestEventListener* EventListeners::Release(TestEventListener* listener) { if (listener == default_result_printer_) default_result_printer_ = NULL; else if (listener == default_xml_generator_) @@ -3295,17 +3282,16 @@ UnitTestEventListenerInterface* EventListeners::Release( return repeater_->Release(listener); } -// Returns repeater that broadcasts the UnitTestEventListenerInterface -// events to all subscribers. -UnitTestEventListenerInterface* EventListeners::repeater() { return repeater_; } +// Returns repeater that broadcasts the TestEventListener events to all +// subscribers. +TestEventListener* EventListeners::repeater() { return repeater_; } // Sets the default_result_printer attribute to the provided listener. // The listener is also added to the listener list and previous // default_result_printer is removed from it and deleted. The listener can // also be NULL in which case it will not be added to the list. Does // nothing if the previous and the current listener objects are the same. -void EventListeners::SetDefaultResultPrinter( - UnitTestEventListenerInterface* listener) { +void EventListeners::SetDefaultResultPrinter(TestEventListener* listener) { if (default_result_printer_ != listener) { // It is an error to pass this method a listener that is already in the // list. @@ -3321,8 +3307,7 @@ void EventListeners::SetDefaultResultPrinter( // default_xml_generator is removed from it and deleted. The listener can // also be NULL in which case it will not be added to the list. Does // nothing if the previous and the current listener objects are the same. -void EventListeners::SetDefaultXmlGenerator( - UnitTestEventListenerInterface* listener) { +void EventListeners::SetDefaultXmlGenerator(TestEventListener* listener) { if (default_xml_generator_ != listener) { // It is an error to pass this method a listener that is already in the // list. @@ -3557,20 +3542,20 @@ int UnitTest::Run() { // process. In either case the user does not want to see pop-up dialogs // about crashes - they are expected.. if (GTEST_FLAG(catch_exceptions) || in_death_test_child_process) { -#if !defined(_WIN32_WCE) +#if !GTEST_OS_WINDOWS_MOBILE // SetErrorMode doesn't exist on CE. SetErrorMode(SEM_FAILCRITICALERRORS | SEM_NOALIGNMENTFAULTEXCEPT | SEM_NOGPFAULTERRORBOX | SEM_NOOPENFILEERRORBOX); -#endif // _WIN32_WCE +#endif // !GTEST_OS_WINDOWS_MOBILE -#if (defined(_MSC_VER) || defined(__MINGW32__)) && !defined(_WIN32_WCE) +#if (defined(_MSC_VER) || GTEST_OS_WINDOWS_MINGW) && !GTEST_OS_WINDOWS_MOBILE // Death test children can be terminated with _abort(). On Windows, // _abort() can show a dialog with a warning message. This forces the // abort message to go to stderr instead. _set_error_mode(_OUT_TO_STDERR); #endif -#if _MSC_VER >= 1400 && !defined(_WIN32_WCE) +#if _MSC_VER >= 1400 && !GTEST_OS_WINDOWS_MOBILE // In the debug version, Visual Studio pops up a separate dialog // offering a choice to debug the aborted program. We need to suppress // this dialog or it will pop up for every EXPECT/ASSERT_DEATH statement @@ -3890,7 +3875,7 @@ int UnitTestImpl::RunAllTests() { // True iff at least one test has failed. bool failed = false; - UnitTestEventListenerInterface* repeater = listeners()->repeater(); + TestEventListener* repeater = listeners()->repeater(); repeater->OnTestProgramStart(*parent_); -- cgit v1.2.3 From f8b268ee86ca74bba3276352f1e7de53d1336c3e Mon Sep 17 00:00:00 2001 From: "zhanyong.wan" Date: Wed, 30 Sep 2009 20:23:50 +0000 Subject: Makes gtest compile cleanly with MSVC's /W4 (by Zhanyong Wan). Renames EventListenrs to TestEventListeners (by Zhanyong Wan). Fixes invalid characters in XML report (by Vlad Losev). Refacotrs SConscript (by Vlad Losev). --- src/gtest-death-test.cc | 25 +++++----- src/gtest-internal-inl.h | 4 +- src/gtest.cc | 127 +++++++++++++++++++++++++++++++++-------------- 3 files changed, 104 insertions(+), 52 deletions(-) (limited to 'src') diff --git a/src/gtest-death-test.cc b/src/gtest-death-test.cc index bf4cbc67..106b01c7 100644 --- a/src/gtest-death-test.cc +++ b/src/gtest-death-test.cc @@ -220,12 +220,12 @@ void DeathTestAbort(const String& message) { // fails. #define GTEST_DEATH_TEST_CHECK_(expression) \ do { \ - if (!(expression)) { \ - DeathTestAbort(::testing::internal::String::Format(\ + if (!::testing::internal::IsTrue(expression)) { \ + DeathTestAbort(::testing::internal::String::Format( \ "CHECK failed: File %s, line %d: %s", \ __FILE__, __LINE__, #expression)); \ } \ - } while (0) + } while (::testing::internal::AlwaysFalse()) // This macro is similar to GTEST_DEATH_TEST_CHECK_, but it is meant for // evaluating any system call that fulfills two conditions: it must return @@ -241,11 +241,11 @@ void DeathTestAbort(const String& message) { gtest_retval = (expression); \ } while (gtest_retval == -1 && errno == EINTR); \ if (gtest_retval == -1) { \ - DeathTestAbort(::testing::internal::String::Format(\ + DeathTestAbort(::testing::internal::String::Format( \ "CHECK failed: File %s, line %d: %s != -1", \ __FILE__, __LINE__, #expression)); \ } \ - } while (0) + } while (::testing::internal::AlwaysFalse()) // Returns the message describing the last system error in errno. String GetLastErrnoDescription() { @@ -581,8 +581,8 @@ int WindowsDeathTest::Wait() { WAIT_OBJECT_0 == ::WaitForSingleObject(child_handle_.Get(), INFINITE)); DWORD status; - GTEST_DEATH_TEST_CHECK_(::GetExitCodeProcess(child_handle_.Get(), - &status)); + GTEST_DEATH_TEST_CHECK_(::GetExitCodeProcess(child_handle_.Get(), &status) + != FALSE); child_handle_.Reset(); set_status(static_cast(status)); return this->status(); @@ -612,9 +612,10 @@ DeathTest::TestRole WindowsDeathTest::AssumeRole() { SECURITY_ATTRIBUTES handles_are_inheritable = { sizeof(SECURITY_ATTRIBUTES), NULL, TRUE }; HANDLE read_handle, write_handle; - GTEST_DEATH_TEST_CHECK_(::CreatePipe(&read_handle, &write_handle, - &handles_are_inheritable, - 0)); // Default buffer size. + GTEST_DEATH_TEST_CHECK_( + ::CreatePipe(&read_handle, &write_handle, &handles_are_inheritable, + 0) // Default buffer size. + != FALSE); set_read_fd(::_open_osfhandle(reinterpret_cast(read_handle), O_RDONLY)); write_handle_.Reset(write_handle); @@ -677,7 +678,7 @@ DeathTest::TestRole WindowsDeathTest::AssumeRole() { NULL, // Inherit the parent's environment. UnitTest::GetInstance()->original_working_dir(), &startup_info, - &process_info)); + &process_info) != FALSE); child_handle_.Reset(process_info.hProcess); ::CloseHandle(process_info.hThread); set_spawned(true); @@ -1042,7 +1043,7 @@ static void SplitString(const ::std::string& str, char delimiter, ::std::vector< ::std::string>* dest) { ::std::vector< ::std::string> parsed; ::std::string::size_type pos = 0; - while (true) { + while (::testing::internal::AlwaysTrue()) { const ::std::string::size_type colon = str.find(delimiter, pos); if (colon == ::std::string::npos) { parsed.push_back(str.substr(pos)); diff --git a/src/gtest-internal-inl.h b/src/gtest-internal-inl.h index 9826bdd3..d593e82c 100644 --- a/src/gtest-internal-inl.h +++ b/src/gtest-internal-inl.h @@ -742,7 +742,7 @@ class UnitTestImpl { } // Provides access to the event listener list. - EventListeners* listeners() { return &listeners_; } + TestEventListeners* listeners() { return &listeners_; } // Returns the TestResult for the test that's currently running, or // the TestResult for the ad hoc test if no test is running. @@ -1002,7 +1002,7 @@ class UnitTestImpl { // The list of event listeners that can be used to track events inside // Google Test. - EventListeners listeners_; + TestEventListeners listeners_; // The OS stack trace getter. Will be deleted when the UnitTest // object is destructed. By default, an OsStackTraceGetter is used, diff --git a/src/gtest.cc b/src/gtest.cc index 44ec9496..f0d8c38c 100644 --- a/src/gtest.cc +++ b/src/gtest.cc @@ -42,6 +42,8 @@ #include #include +#include + #if GTEST_OS_LINUX // TODO(kenton@google.com): Use autoconf to detect availability of @@ -2966,6 +2968,9 @@ class XmlUnitTestResultPrinter : public EmptyTestEventListener { // with character references. static String EscapeXml(const char* str, bool is_attribute); + // Returns the given string with all characters invalid in XML removed. + static String RemoveInvalidXmlCharacters(const char* str); + // Convenience wrapper around EscapeXml when str is an attribute value. static String EscapeXmlAttribute(const char* str) { return EscapeXml(str, true); @@ -2974,10 +2979,13 @@ class XmlUnitTestResultPrinter : public EmptyTestEventListener { // Convenience wrapper around EscapeXml when str is not an attribute value. static String EscapeXmlText(const char* str) { return EscapeXml(str, false); } - // Prints an XML representation of a TestInfo object. - static void PrintXmlTestInfo(FILE* out, - const char* test_case_name, - const TestInfo& test_info); + // Streams an XML CDATA section, escaping invalid CDATA sequences as needed. + static void OutputXmlCDataSection(::std::ostream* stream, const char* data); + + // Streams an XML representation of a TestInfo object. + static void OutputXmlTestInfo(::std::ostream* stream, + const char* test_case_name, + const TestInfo& test_info); // Prints an XML representation of a TestCase object static void PrintXmlTestCase(FILE* out, const TestCase& test_case); @@ -3092,6 +3100,22 @@ String XmlUnitTestResultPrinter::EscapeXml(const char* str, bool is_attribute) { return m.GetString(); } +// Returns the given string with all characters invalid in XML removed. +// Currently invalid characters are dropped from the string. An +// alternative is to replace them with certain characters such as . or ?. +String XmlUnitTestResultPrinter::RemoveInvalidXmlCharacters(const char* str) { + char* const output = new char[strlen(str) + 1]; + char* appender = output; + for (char ch = *str; ch != '\0'; ch = *++str) + if (IsValidXmlCharacter(ch)) + *appender++ = ch; + *appender = '\0'; + + String ret_value(output); + delete[] output; + return ret_value; +} + // The following routines generate an XML representation of a UnitTest // object. // @@ -3118,40 +3142,62 @@ const char* FormatTimeInMillisAsSeconds(TimeInMillis ms) { return str.c_str(); } +// Streams an XML CDATA section, escaping invalid CDATA sequences as needed. +void XmlUnitTestResultPrinter::OutputXmlCDataSection(::std::ostream* stream, + const char* data) { + const char* segment = data; + *stream << ""); + if (next_segment != NULL) { + stream->write(segment, next_segment - segment); + *stream << "]]>]]>"); + } else { + *stream << segment; + break; + } + } + *stream << "]]>"; +} + // Prints an XML representation of a TestInfo object. // TODO(wan): There is also value in printing properties with the plain printer. -void XmlUnitTestResultPrinter::PrintXmlTestInfo(FILE* out, - const char* test_case_name, - const TestInfo& test_info) { +void XmlUnitTestResultPrinter::OutputXmlTestInfo(::std::ostream* stream, + const char* test_case_name, + const TestInfo& test_info) { const TestResult& result = *test_info.result(); - fprintf(out, - " \n"); - fprintf(out, - " " - "\n", - EscapeXmlAttribute(part.summary()).c_str(), message.c_str()); + *stream << ">\n"; + *stream << " "; + const String message = RemoveInvalidXmlCharacters(String::Format( + "%s:%d\n%s", + part.file_name(), part.line_number(), + part.message()).c_str()); + OutputXmlCDataSection(stream, message.c_str()); + *stream << "\n"; } } if (failures == 0) - fprintf(out, " />\n"); + *stream << " />\n"; else - fprintf(out, " \n"); + *stream << " \n"; } // Prints an XML representation of a TestCase object @@ -3167,8 +3213,11 @@ void XmlUnitTestResultPrinter::PrintXmlTestCase(FILE* out, fprintf(out, "errors=\"0\" time=\"%s\">\n", FormatTimeInMillisAsSeconds(test_case.elapsed_time())); - for (int i = 0; i < test_case.total_test_count(); ++i) - PrintXmlTestInfo(out, test_case.name(), *test_case.GetTestInfo(i)); + for (int i = 0; i < test_case.total_test_count(); ++i) { + StrStream stream; + OutputXmlTestInfo(&stream, test_case.name(), *test_case.GetTestInfo(i)); + fprintf(out, "%s", StrStreamToString(&stream).c_str()); + } fprintf(out, " \n"); } @@ -3253,28 +3302,28 @@ OsStackTraceGetter::kElidedFramesMarker = } // namespace internal -// class EventListeners +// class TestEventListeners -EventListeners::EventListeners() +TestEventListeners::TestEventListeners() : repeater_(new internal::TestEventRepeater()), default_result_printer_(NULL), default_xml_generator_(NULL) { } -EventListeners::~EventListeners() { delete repeater_; } +TestEventListeners::~TestEventListeners() { delete repeater_; } // Returns the standard listener responsible for the default console // output. Can be removed from the listeners list to shut down default // console output. Note that removing this object from the listener list // with Release transfers its ownership to the user. -void EventListeners::Append(TestEventListener* listener) { +void TestEventListeners::Append(TestEventListener* listener) { repeater_->Append(listener); } // Removes the given event listener from the list and returns it. It then // becomes the caller's responsibility to delete the listener. Returns // NULL if the listener is not found in the list. -TestEventListener* EventListeners::Release(TestEventListener* listener) { +TestEventListener* TestEventListeners::Release(TestEventListener* listener) { if (listener == default_result_printer_) default_result_printer_ = NULL; else if (listener == default_xml_generator_) @@ -3284,14 +3333,14 @@ TestEventListener* EventListeners::Release(TestEventListener* listener) { // Returns repeater that broadcasts the TestEventListener events to all // subscribers. -TestEventListener* EventListeners::repeater() { return repeater_; } +TestEventListener* TestEventListeners::repeater() { return repeater_; } // Sets the default_result_printer attribute to the provided listener. // The listener is also added to the listener list and previous // default_result_printer is removed from it and deleted. The listener can // also be NULL in which case it will not be added to the list. Does // nothing if the previous and the current listener objects are the same. -void EventListeners::SetDefaultResultPrinter(TestEventListener* listener) { +void TestEventListeners::SetDefaultResultPrinter(TestEventListener* listener) { if (default_result_printer_ != listener) { // It is an error to pass this method a listener that is already in the // list. @@ -3307,7 +3356,7 @@ void EventListeners::SetDefaultResultPrinter(TestEventListener* listener) { // default_xml_generator is removed from it and deleted. The listener can // also be NULL in which case it will not be added to the list. Does // nothing if the previous and the current listener objects are the same. -void EventListeners::SetDefaultXmlGenerator(TestEventListener* listener) { +void TestEventListeners::SetDefaultXmlGenerator(TestEventListener* listener) { if (default_xml_generator_ != listener) { // It is an error to pass this method a listener that is already in the // list. @@ -3320,11 +3369,11 @@ void EventListeners::SetDefaultXmlGenerator(TestEventListener* listener) { // Controls whether events will be forwarded by the repeater to the // listeners in the list. -bool EventListeners::EventForwardingEnabled() const { +bool TestEventListeners::EventForwardingEnabled() const { return repeater_->forwarding_enabled(); } -void EventListeners::SuppressEventForwarding() { +void TestEventListeners::SuppressEventForwarding() { repeater_->set_forwarding_enabled(false); } @@ -3418,7 +3467,7 @@ const TestCase* UnitTest::GetTestCase(int i) const { // Returns the list of event listeners that can be used to track events // inside Google Test. -EventListeners& UnitTest::listeners() { +TestEventListeners& UnitTest::listeners() { return *impl()->listeners(); } @@ -4187,11 +4236,13 @@ namespace { class ClassUniqueToAlwaysTrue {}; } +bool IsTrue(bool condition) { return condition; } + bool AlwaysTrue() { #if GTEST_HAS_EXCEPTIONS // This condition is always false so AlwaysTrue() never actually throws, // but it makes the compiler think that it may throw. - if (atoi("42") == 36) // NOLINT + if (IsTrue(false)) throw ClassUniqueToAlwaysTrue(); #endif // GTEST_HAS_EXCEPTIONS return true; -- cgit v1.2.3 From bd851333e89517762c91a3fef67cf25a6f1bd37a Mon Sep 17 00:00:00 2001 From: "zhanyong.wan" Date: Wed, 30 Sep 2009 23:46:28 +0000 Subject: Implements test shuffling (by Zhanyong Wan, based on Josh Kelley's original patch). Enables death tests on minGW (by Vlad Losev). --- src/gtest-internal-inl.h | 139 +++++++++++++++++++++++++++++++++++++++-------- src/gtest.cc | 106 +++++++++++++++++++++++++++++++----- 2 files changed, 206 insertions(+), 39 deletions(-) (limited to 'src') diff --git a/src/gtest-internal-inl.h b/src/gtest-internal-inl.h index d593e82c..9a366fe5 100644 --- a/src/gtest-internal-inl.h +++ b/src/gtest-internal-inl.h @@ -277,7 +277,7 @@ class Vector { // is created using the copy constructor, and then stored in the // Vector. Changes made to the element in the Vector doesn't affect // the source object, and vice versa. - void PushBack(const E & element) { Insert(element, size_); } + void PushBack(const E& element) { Insert(element, size_); } // Adds an element to the beginning of this Vector. void PushFront(const E& element) { Insert(element, 0); } @@ -369,7 +369,7 @@ class Vector { return NULL; } - // Returns the i-th element of the list, or aborts the program if i + // Returns the i-th element of the Vector, or aborts the program if i // is not in range [0, size()). const E& GetElement(int i) const { GTEST_CHECK_(0 <= i && i < size_) @@ -379,13 +379,84 @@ class Vector { return *(elements_[i]); } - // Returns the i-th element of the list, or default_value if i is not + // Returns a mutable reference to the i-th element of the Vector, or + // aborts the program if i is not in range [0, size()). + E& GetMutableElement(int i) { + GTEST_CHECK_(0 <= i && i < size_) + << "Invalid Vector index " << i << ": must be in range [0, " + << (size_ - 1) << "]."; + + return *(elements_[i]); + } + + // Returns the i-th element of the Vector, or default_value if i is not // in range [0, size()). E GetElementOr(int i, E default_value) const { return (i < 0 || i >= size_) ? default_value : *(elements_[i]); } + // Swaps the i-th and j-th elements of the Vector. Crashes if i or + // j is invalid. + void Swap(int i, int j) { + GTEST_CHECK_(0 <= i && i < size_) + << "Invalid first swap element " << i << ": must be in range [0, " + << (size_ - 1) << "]."; + GTEST_CHECK_(0 <= j && j < size_) + << "Invalid second swap element " << j << ": must be in range [0, " + << (size_ - 1) << "]."; + + E* const temp = elements_[i]; + elements_[i] = elements_[j]; + elements_[j] = temp; + } + + // Performs an in-place shuffle of a range of this Vector's nodes. + // 'begin' and 'end' are element indices as an STL-style range; + // i.e. [begin, end) are shuffled, where 'end' == size() means to + // shuffle to the end of the Vector. + void ShuffleRange(internal::Random* random, int begin, int end) { + GTEST_CHECK_(0 <= begin && begin <= size_) + << "Invalid shuffle range start " << begin << ": must be in range [0, " + << size_ << "]."; + GTEST_CHECK_(begin <= end && end <= size_) + << "Invalid shuffle range finish " << end << ": must be in range [" + << begin << ", " << size_ << "]."; + + // Fisher-Yates shuffle, from + // http://en.wikipedia.org/wiki/Fisher-Yates_shuffle + for (int range_width = end - begin; range_width >= 2; range_width--) { + const int last_in_range = begin + range_width - 1; + const int selected = begin + random->Generate(range_width); + Swap(selected, last_in_range); + } + } + + // Performs an in-place shuffle of this Vector's nodes. + void Shuffle(internal::Random* random) { + ShuffleRange(random, 0, size()); + } + + // Returns a copy of this Vector. + Vector* Clone() const { + Vector* const clone = new Vector; + clone->Reserve(size_); + for (int i = 0; i < size_; i++) { + clone->PushBack(GetElement(i)); + } + return clone; + } + private: + // Makes sure this Vector's capacity is at least the given value. + void Reserve(int new_capacity) { + if (new_capacity <= capacity_) + return; + + capacity_ = new_capacity; + elements_ = static_cast( + realloc(elements_, capacity_*sizeof(elements_[0]))); + } + // Grows the buffer if it is not big enough to hold one more element. void GrowIfNeeded() { if (size_ < capacity_) @@ -397,9 +468,7 @@ class Vector { const int new_capacity = 3*(capacity_/2 + 1); GTEST_CHECK_(new_capacity > capacity_) // Does the new capacity overflow? << "Cannot grow a Vector with " << capacity_ << " elements already."; - capacity_ = new_capacity; - elements_ = static_cast( - realloc(elements_, capacity_*sizeof(elements_[0]))); + Reserve(new_capacity); } // Moves the give consecutive elements to a new index in the Vector. @@ -491,11 +560,6 @@ class TestInfoImpl { // deletes it. void Run(); - // Calls the given TestInfo object's Run() method. - static void RunTest(TestInfo * test_info) { - test_info->impl()->Run(); - } - // Clears the test result. void ClearResult() { result_.Clear(); } @@ -738,7 +802,15 @@ class UnitTestImpl { // Gets the i-th test case among all the test cases. i can range from 0 to // total_test_case_count() - 1. If i is not in that range, returns NULL. const TestCase* GetTestCase(int i) const { - return test_cases_.GetElementOr(i, NULL); + const int index = test_case_indices_.GetElementOr(i, -1); + return index < 0 ? NULL : test_cases_.GetElement(i); + } + + // Gets the i-th test case among all the test cases. i can range from 0 to + // total_test_case_count() - 1. If i is not in that range, returns NULL. + TestCase* GetMutableTestCase(int i) { + const int index = test_case_indices_.GetElementOr(i, -1); + return index < 0 ? NULL : test_cases_.GetElement(index); } // Provides access to the event listener list. @@ -886,9 +958,6 @@ class UnitTestImpl { return &environments_in_reverse_order_; } - internal::Vector* test_cases() { return &test_cases_; } - const internal::Vector* test_cases() const { return &test_cases_; } - // Getters for the per-thread Google Test trace stack. internal::Vector* gtest_trace_stack() { return gtest_trace_stack_.pointer(); @@ -923,16 +992,26 @@ class UnitTestImpl { // UnitTestOptions. Must not be called before InitGoogleTest. void ConfigureXmlOutput(); -// Performs initialization dependent upon flag values obtained in -// ParseGoogleTestFlagsOnly. Is called from InitGoogleTest after the call to -// ParseGoogleTestFlagsOnly. In case a user neglects to call InitGoogleTest -// this function is also called from RunAllTests. Since this function can be -// called more than once, it has to be idempotent. + // Performs initialization dependent upon flag values obtained in + // ParseGoogleTestFlagsOnly. Is called from InitGoogleTest after the call to + // ParseGoogleTestFlagsOnly. In case a user neglects to call InitGoogleTest + // this function is also called from RunAllTests. Since this function can be + // called more than once, it has to be idempotent. void PostFlagParsingInit(); - // Gets the random seed used at the start of the current test run. + // Gets the random seed used at the start of the current test iteration. int random_seed() const { return random_seed_; } + // Gets the random number generator. + internal::Random* random() { return &random_; } + + // Shuffles all test cases, and the tests within each test case, + // making sure that death tests are still run first. + void ShuffleTests(); + + // Restores the test cases and tests to their order before the first shuffle. + void UnshuffleTests(); + private: friend class ::testing::UnitTest; @@ -964,7 +1043,15 @@ class UnitTestImpl { internal::Vector environments_; internal::Vector environments_in_reverse_order_; - internal::Vector test_cases_; // The vector of TestCases. + // The vector of TestCases in their original order. It owns the + // elements in the vector. + internal::Vector test_cases_; + + // Provides a level of indirection for the test case list to allow + // easy shuffling and restoring the test case order. The i-th + // element of this vector is the index of the i-th test case in the + // shuffled order. + internal::Vector test_case_indices_; #if GTEST_HAS_PARAM_TEST // ParameterizedTestRegistry object used to register value-parameterized @@ -1016,6 +1103,9 @@ class UnitTestImpl { // The random number seed used at the beginning of the test run. int random_seed_; + // Our random number generator. + internal::Random random_; + // How long the test took to run, in milliseconds. TimeInMillis elapsed_time_; @@ -1108,13 +1198,14 @@ bool ParseNaturalNumber(const ::std::string& str, Integer* number) { char* end; // BiggestConvertible is the largest integer type that system-provided // string-to-number conversion routines can return. -#if GTEST_OS_WINDOWS +#if GTEST_OS_WINDOWS && !defined(__GNU_C__) + // MSVC and C++ Builder define __int64 instead of the standard long long. typedef unsigned __int64 BiggestConvertible; const BiggestConvertible parsed = _strtoui64(str.c_str(), &end, 10); #else typedef unsigned long long BiggestConvertible; // NOLINT const BiggestConvertible parsed = strtoull(str.c_str(), &end, 10); -#endif // GTEST_OS_WINDOWS +#endif // GTEST_OS_WINDOWS && !defined(__GNU_C__) const bool parse_success = *end == '\0' && errno == 0; // TODO(vladl@google.com): Convert this to compile time assertion when it is diff --git a/src/gtest.cc b/src/gtest.cc index f0d8c38c..93407245 100644 --- a/src/gtest.cc +++ b/src/gtest.cc @@ -2343,33 +2343,39 @@ TestCase::TestCase(const char* name, const char* comment, Test::TearDownTestCaseFunc tear_down_tc) : name_(name), comment_(comment), + test_info_list_(new internal::Vector), + test_indices_(new internal::Vector), set_up_tc_(set_up_tc), tear_down_tc_(tear_down_tc), should_run_(false), elapsed_time_(0) { - test_info_list_ = new internal::Vector; } // Destructor of TestCase. TestCase::~TestCase() { // Deletes every Test in the collection. test_info_list_->ForEach(internal::Delete); - - // Then deletes the Test collection. - delete test_info_list_; - test_info_list_ = NULL; } // Returns the i-th test among all the tests. i can range from 0 to // total_test_count() - 1. If i is not in that range, returns NULL. const TestInfo* TestCase::GetTestInfo(int i) const { - return test_info_list_->GetElementOr(i, NULL); + const int index = test_indices_->GetElementOr(i, -1); + return index < 0 ? NULL : test_info_list_->GetElement(index); +} + +// Returns the i-th test among all the tests. i can range from 0 to +// total_test_count() - 1. If i is not in that range, returns NULL. +TestInfo* TestCase::GetMutableTestInfo(int i) { + const int index = test_indices_->GetElementOr(i, -1); + return index < 0 ? NULL : test_info_list_->GetElement(index); } // Adds a test to this test case. Will delete the test upon // destruction of the TestCase object. void TestCase::AddTestInfo(TestInfo * test_info) { test_info_list_->PushBack(test_info); + test_indices_->PushBack(test_indices_->size()); } // Runs every test in this TestCase. @@ -2386,7 +2392,9 @@ void TestCase::Run() { set_up_tc_(); const internal::TimeInMillis start = internal::GetTimeInMillis(); - test_info_list_->ForEach(internal::TestInfoImpl::RunTest); + for (int i = 0; i < total_test_count(); i++) { + GetMutableTestInfo(i)->impl()->Run(); + } elapsed_time_ = internal::GetTimeInMillis() - start; impl->os_stack_trace_getter()->UponLeavingGTest(); @@ -2422,6 +2430,18 @@ bool TestCase::ShouldRunTest(const TestInfo *test_info) { return test_info->impl()->should_run(); } +// Shuffles the tests in this test case. +void TestCase::ShuffleTests(internal::Random* random) { + test_indices_->Shuffle(random); +} + +// Restores the test order to before the first shuffle. +void TestCase::UnshuffleTests() { + for (int i = 0; i < test_indices_->size(); i++) { + test_indices_->GetMutableElement(i) = i; + } +} + // Formats a countable noun. Depending on its quantity, either the // singular form or the plural form is used. e.g. // @@ -3465,6 +3485,12 @@ const TestCase* UnitTest::GetTestCase(int i) const { return impl()->GetTestCase(i); } +// Gets the i-th test case among all the test cases. i can range from 0 to +// total_test_case_count() - 1. If i is not in that range, returns NULL. +TestCase* UnitTest::GetMutableTestCase(int i) { + return impl()->GetMutableTestCase(i); +} + // Returns the list of event listeners that can be used to track events // inside Google Test. TestEventListeners& UnitTest::listeners() { @@ -3717,7 +3743,6 @@ UnitTestImpl::UnitTestImpl(UnitTest* parent) &default_global_test_part_result_reporter_), per_thread_test_part_result_reporter_( &default_per_thread_test_part_result_reporter_), - test_cases_(), #if GTEST_HAS_PARAM_TEST parameterized_test_registry_(), parameterized_tests_registered_(false), @@ -3728,7 +3753,8 @@ UnitTestImpl::UnitTestImpl(UnitTest* parent) ad_hoc_test_result_(), os_stack_trace_getter_(NULL), post_flag_parse_init_performed_(false), - random_seed_(0), + random_seed_(0), // Will be overridden by the flag before first use. + random_(0), // Will be reseeded before first use. #if GTEST_HAS_DEATH_TEST elapsed_time_(0), internal_run_death_test_flag_(NULL), @@ -3822,7 +3848,9 @@ class TestCaseNameIs { }; // 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. It's the CALLER'S +// RESPONSIBILITY to ensure that this function is only called WHEN THE +// TESTS ARE NOT SHUFFLED. // // Arguments: // @@ -3847,13 +3875,16 @@ TestCase* UnitTestImpl::GetTestCase(const char* test_case_name, if (internal::UnitTestOptions::MatchesFilter(String(test_case_name), kDeathTestCaseFilter)) { // Yes. Inserts the test case after the last death test case - // defined so far. + // defined so far. This only works when the test cases haven't + // been shuffled. Otherwise we may end up running a death test + // after a non-death test. test_cases_.Insert(new_test_case, ++last_death_test_case_); } else { // No. Appends to the end of the list. test_cases_.PushBack(new_test_case); } + test_case_indices_.PushBack(test_case_indices_.size()); return new_test_case; } @@ -3938,6 +3969,15 @@ int UnitTestImpl::RunAllTests() { const TimeInMillis start = GetTimeInMillis(); + // Shuffles test cases and tests if requested. + if (has_tests_to_run && GTEST_FLAG(shuffle)) { + random()->Reseed(random_seed_); + // This should be done before calling OnTestIterationStart(), + // such that a test event listener can see the actual test order + // in the event. + ShuffleTests(); + } + // Tells the unit test event listeners that the tests are about to start. repeater->OnTestIterationStart(*parent_, i); @@ -3951,7 +3991,9 @@ int UnitTestImpl::RunAllTests() { // Runs the tests only if there was no fatal failure during global // set-up. if (!Test::HasFatalFailure()) { - test_cases_.ForEach(TestCase::RunTestCase); + for (int i = 0; i < total_test_case_count(); i++) { + GetMutableTestCase(i)->Run(); + } } // Tears down all environments in reverse order afterwards. @@ -3970,8 +4012,16 @@ int UnitTestImpl::RunAllTests() { failed = true; } + // Restores the original test order after the iteration. This + // allows the user to quickly repro a failure that happens in the + // N-th iteration without repeating the first (N - 1) iterations. + // This is not enclosed in "if (GTEST_FLAG(shuffle)) { ... }", in + // case the user somehow changes the value of the flag somewhere + // (it's always safe to unshuffle the tests). + UnshuffleTests(); + if (GTEST_FLAG(shuffle)) { - // Picks a new random seed for each run. + // Picks a new random seed for each iteration. random_seed_ = GetNextRandomSeed(random_seed_); } } @@ -4187,6 +4237,32 @@ TestResult* UnitTestImpl::current_test_result() { current_test_info_->impl()->result() : &ad_hoc_test_result_; } +// Shuffles all test cases, and the tests within each test case, +// making sure that death tests are still run first. +void UnitTestImpl::ShuffleTests() { + // Shuffles the death test cases. + test_case_indices_.ShuffleRange(random(), 0, last_death_test_case_ + 1); + + // Shuffles the non-death test cases. + test_case_indices_.ShuffleRange(random(), last_death_test_case_ + 1, + test_cases_.size()); + + // Shuffles the tests inside each test case. + for (int i = 0; i < test_cases_.size(); i++) { + test_cases_.GetElement(i)->ShuffleTests(random()); + } +} + +// Restores the test cases and tests to their order before the first shuffle. +void UnitTestImpl::UnshuffleTests() { + for (int i = 0; i < test_cases_.size(); i++) { + // Unshuffles the tests in each test case. + test_cases_.GetElement(i)->UnshuffleTests(); + // Resets the index of each test case. + test_case_indices_.GetMutableElement(i) = i; + } +} + // TestInfoImpl constructor. The new instance assumes ownership of the test // factory object. TestInfoImpl::TestInfoImpl(TestInfo* parent, @@ -4401,8 +4477,8 @@ static const char kColorEncodedHelpMessage[] = "Test Execution:\n" " @G--" GTEST_FLAG_PREFIX_ "repeat=@Y[COUNT]@D\n" " Run the tests repeatedly; use a negative count to repeat forever.\n" -" @G--" GTEST_FLAG_PREFIX_ "shuffle\n" -" Randomize tests' orders on every run. To be implemented.\n" +" @G--" GTEST_FLAG_PREFIX_ "shuffle@D\n" +" Randomize tests' orders on every iteration.\n" " @G--" GTEST_FLAG_PREFIX_ "random_seed=@Y[NUMBER]@D\n" " Random number seed to use for shuffling test orders (between 1 and\n" " 99999, or 0 to use a seed based on the current time).\n" -- cgit v1.2.3 From 95279071b17f9f147c8f627b51984a55c1338e78 Mon Sep 17 00:00:00 2001 From: "zhanyong.wan" Date: Wed, 30 Sep 2009 23:55:07 +0000 Subject: Refactors the scons script (by Vlad Losev). Fixes a typo in __GNUC__ (by Zhanyong Wan). --- src/gtest-internal-inl.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'src') diff --git a/src/gtest-internal-inl.h b/src/gtest-internal-inl.h index 9a366fe5..47aec22d 100644 --- a/src/gtest-internal-inl.h +++ b/src/gtest-internal-inl.h @@ -1198,14 +1198,14 @@ bool ParseNaturalNumber(const ::std::string& str, Integer* number) { char* end; // BiggestConvertible is the largest integer type that system-provided // string-to-number conversion routines can return. -#if GTEST_OS_WINDOWS && !defined(__GNU_C__) +#if GTEST_OS_WINDOWS && !defined(__GNUC__) // MSVC and C++ Builder define __int64 instead of the standard long long. typedef unsigned __int64 BiggestConvertible; const BiggestConvertible parsed = _strtoui64(str.c_str(), &end, 10); #else typedef unsigned long long BiggestConvertible; // NOLINT const BiggestConvertible parsed = strtoull(str.c_str(), &end, 10); -#endif // GTEST_OS_WINDOWS && !defined(__GNU_C__) +#endif // GTEST_OS_WINDOWS && !defined(__GNUC__) const bool parse_success = *end == '\0' && errno == 0; // TODO(vladl@google.com): Convert this to compile time assertion when it is -- cgit v1.2.3 From 060804deb8c05b5ea5735b875eaea2c7493e2262 Mon Sep 17 00:00:00 2001 From: vladlosev Date: Wed, 14 Oct 2009 22:33:03 +0000 Subject: Fixes: Scons build file broken when used in another SConstruct; warning in VC 8.0 when compiled with /Wp64 --- src/gtest.cc | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'src') diff --git a/src/gtest.cc b/src/gtest.cc index 93407245..55f03ce9 100644 --- a/src/gtest.cc +++ b/src/gtest.cc @@ -3170,7 +3170,8 @@ void XmlUnitTestResultPrinter::OutputXmlCDataSection(::std::ostream* stream, for (;;) { const char* const next_segment = strstr(segment, "]]>"); if (next_segment != NULL) { - stream->write(segment, next_segment - segment); + stream->write( + segment, static_cast(next_segment - segment)); *stream << "]]>]]>"); } else { -- cgit v1.2.3 From bad778caa39a88b7c11b159e20730aeec4fd711e Mon Sep 17 00:00:00 2001 From: vladlosev Date: Tue, 20 Oct 2009 21:03:10 +0000 Subject: Implements support for AssertionResult in Boolean assertions such as EXPECT_TRUE; Fixes Google Tests's tuple implementation to default-initialize its fields in the default constructor (by Zhanyong Wan); Populates gtest_stress_test.cc with actual tests. --- src/gtest.cc | 40 +++++++++++++++++++++++++++++++++++----- 1 file changed, 35 insertions(+), 5 deletions(-) (limited to 'src') diff --git a/src/gtest.cc b/src/gtest.cc index 55f03ce9..5efb5baa 100644 --- a/src/gtest.cc +++ b/src/gtest.cc @@ -952,21 +952,37 @@ String FormatForFailureMessage(wchar_t wchar) { } // namespace internal -// AssertionResult constructor. -AssertionResult::AssertionResult(const internal::String& failure_message) - : failure_message_(failure_message) { +// AssertionResult constructors. +// Used in EXPECT_TRUE/FALSE(assertion_result). +AssertionResult::AssertionResult(const AssertionResult& other) + : success_(other.success_), + message_(other.message_.get() != NULL ? + new internal::String(*other.message_) : + static_cast(NULL)) { } +// Returns the assertion's negation. Used with EXPECT/ASSERT_FALSE. +AssertionResult AssertionResult::operator!() const { + AssertionResult negation(!success_); + if (message_.get() != NULL) + negation << *message_; + return negation; +} // Makes a successful assertion result. AssertionResult AssertionSuccess() { - return AssertionResult(); + return AssertionResult(true); } +// Makes a failed assertion result. +AssertionResult AssertionFailure() { + return AssertionResult(false); +} // Makes a failed assertion result with the given failure message. +// Deprecated; use AssertionFailure() << message. AssertionResult AssertionFailure(const Message& message) { - return AssertionResult(message.GetString()); + return AssertionFailure() << message; } namespace internal { @@ -1008,6 +1024,20 @@ AssertionResult EqFailure(const char* expected_expression, return AssertionFailure(msg); } +// Constructs a failure message for Boolean assertions such as EXPECT_TRUE. +String GetBoolAssertionFailureMessage(const AssertionResult& assertion_result, + const char* expression_text, + const char* actual_predicate_value, + const char* expected_predicate_value) { + const char* actual_message = assertion_result.message(); + Message msg; + msg << "Value of: " << expression_text + << "\n Actual: " << actual_predicate_value; + if (actual_message[0] != '\0') + msg << " (" << actual_message << ")"; + msg << "\nExpected: " << expected_predicate_value; + return msg.GetString(); +} // Helper function for implementing ASSERT_NEAR. AssertionResult DoubleNearPredFormat(const char* expr1, -- cgit v1.2.3 From 6bfc4b2bd378940fa006bd32b9667ad4137d8f15 Mon Sep 17 00:00:00 2001 From: vladlosev Date: Thu, 22 Oct 2009 01:22:29 +0000 Subject: Prints help when encountering unrecognized Google Test flags. --- src/gtest.cc | 32 +++++++++++++++++++++++++++++++- 1 file changed, 31 insertions(+), 1 deletion(-) (limited to 'src') diff --git a/src/gtest.cc b/src/gtest.cc index 5efb5baa..ca27b313 100644 --- a/src/gtest.cc +++ b/src/gtest.cc @@ -4444,6 +4444,33 @@ bool ParseStringFlag(const char* str, const char* flag, String* value) { return true; } +// Determines whether a string pointed by *str has the prefix parameter as +// its prefix and advances it to point past the prefix if it does. +bool SkipPrefix(const char* prefix, const char** str) { + const int prefix_len = strlen(prefix); + + if (strncmp(*str, prefix, prefix_len) != 0) + return false; + + *str += prefix_len; + return true; +} + +// Determines whether a string has a prefix that Google Test uses for its +// flags, i.e., starts with GTEST_FLAG_PREFIX_ or GTEST_FLAG_PREFIX_DASH_. +// If Google Test detects that a command line flag has its prefix but is not +// recognized, it will print its help message. Flags starting with +// GTEST_INTERNAL_PREFIX_ followed by "internal_" are considered Google Test +// internal flags and do not trigger the help message. +bool HasGoogleTestFlagPrefix(const char* str) { + return (SkipPrefix("--", &str) || + SkipPrefix("-", &str) || + SkipPrefix("/", &str)) && + !SkipPrefix(GTEST_FLAG_PREFIX_ "internal_", &str) && + (SkipPrefix(GTEST_FLAG_PREFIX_, &str) || + SkipPrefix(GTEST_FLAG_PREFIX_DASH_, &str)); +} + // Prints a string containing code-encoded text. The following escape // sequences can be used in the string to control the text color: // @@ -4601,7 +4628,10 @@ void ParseGoogleTestFlagsOnlyImpl(int* argc, CharType** argv) { // an element. i--; } else if (arg_string == "--help" || arg_string == "-h" || - arg_string == "-?" || arg_string == "/?") { + arg_string == "-?" || arg_string == "/?" || + HasGoogleTestFlagPrefix(arg)) { + // Both help flag and unrecognized Google Test flags (excluding + // internal ones) trigger help display. g_help_flag = true; } } -- cgit v1.2.3 From edba5d808c10731938a23a53daf182a297124607 Mon Sep 17 00:00:00 2001 From: vladlosev Date: Fri, 23 Oct 2009 00:49:33 +0000 Subject: Fixes linker error when used with gMock on Windows --- src/gtest.cc | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'src') diff --git a/src/gtest.cc b/src/gtest.cc index ca27b313..f269b2ab 100644 --- a/src/gtest.cc +++ b/src/gtest.cc @@ -4446,8 +4446,8 @@ bool ParseStringFlag(const char* str, const char* flag, String* value) { // Determines whether a string pointed by *str has the prefix parameter as // its prefix and advances it to point past the prefix if it does. -bool SkipPrefix(const char* prefix, const char** str) { - const int prefix_len = strlen(prefix); +static bool SkipPrefix(const char* prefix, const char** str) { + const size_t prefix_len = strlen(prefix); if (strncmp(*str, prefix, prefix_len) != 0) return false; @@ -4462,7 +4462,7 @@ bool SkipPrefix(const char* prefix, const char** str) { // recognized, it will print its help message. Flags starting with // GTEST_INTERNAL_PREFIX_ followed by "internal_" are considered Google Test // internal flags and do not trigger the help message. -bool HasGoogleTestFlagPrefix(const char* str) { +static bool HasGoogleTestFlagPrefix(const char* str) { return (SkipPrefix("--", &str) || SkipPrefix("-", &str) || SkipPrefix("/", &str)) && -- cgit v1.2.3 From 7e13e0f5dd2f9458e0a613e0a91c894eb80126fc Mon Sep 17 00:00:00 2001 From: "zhanyong.wan" Date: Tue, 10 Nov 2009 19:17:35 +0000 Subject: Fixes the code to work with fuse_gtest.py. --- src/gtest-all.cc | 6 ++++++ 1 file changed, 6 insertions(+) (limited to 'src') diff --git a/src/gtest-all.cc b/src/gtest-all.cc index a67ea0fa..fe34765f 100644 --- a/src/gtest-all.cc +++ b/src/gtest-all.cc @@ -33,6 +33,12 @@ // // Sometimes it's desirable to build Google Test by compiling a single file. // This file serves this purpose. + +// This line ensures that gtest.h can be compiled on its own, even +// when it's fused. +#include + +// The following lines pull in the real gtest *.cc files. #include "src/gtest.cc" #include "src/gtest-death-test.cc" #include "src/gtest-filepath.cc" -- cgit v1.2.3 From bf26ca01f23e432f8b2355fd700707ba217a7605 Mon Sep 17 00:00:00 2001 From: vladlosev Date: Tue, 17 Nov 2009 22:43:15 +0000 Subject: Prevents Google Test from printing help message upon seeing the --gtest_stack_trace_depth flag. This was breaking gmock_output_test. --- src/gtest-internal-inl.h | 4 ++++ src/gtest.cc | 12 +++++++----- 2 files changed, 11 insertions(+), 5 deletions(-) (limited to 'src') diff --git a/src/gtest-internal-inl.h b/src/gtest-internal-inl.h index 47aec22d..45a4c105 100644 --- a/src/gtest-internal-inl.h +++ b/src/gtest-internal-inl.h @@ -90,6 +90,7 @@ const char kPrintTimeFlag[] = "print_time"; const char kRandomSeedFlag[] = "random_seed"; const char kRepeatFlag[] = "repeat"; const char kShuffleFlag[] = "shuffle"; +const char kStackTraceDepthFlag[] = "stack_trace_depth"; const char kThrowOnFailureFlag[] = "throw_on_failure"; // A valid random seed must be in [1, kMaxRandomSeed]. @@ -144,6 +145,7 @@ class GTestFlagSaver { random_seed_ = GTEST_FLAG(random_seed); repeat_ = GTEST_FLAG(repeat); shuffle_ = GTEST_FLAG(shuffle); + stack_trace_depth_ = GTEST_FLAG(stack_trace_depth); throw_on_failure_ = GTEST_FLAG(throw_on_failure); } @@ -163,6 +165,7 @@ class GTestFlagSaver { GTEST_FLAG(random_seed) = random_seed_; GTEST_FLAG(repeat) = repeat_; GTEST_FLAG(shuffle) = shuffle_; + GTEST_FLAG(stack_trace_depth) = stack_trace_depth_; GTEST_FLAG(throw_on_failure) = throw_on_failure_; } private: @@ -182,6 +185,7 @@ class GTestFlagSaver { internal::Int32 random_seed_; internal::Int32 repeat_; bool shuffle_; + internal::Int32 stack_trace_depth_; bool throw_on_failure_; } GTEST_ATTRIBUTE_UNUSED_; diff --git a/src/gtest.cc b/src/gtest.cc index f269b2ab..55861544 100644 --- a/src/gtest.cc +++ b/src/gtest.cc @@ -161,6 +161,10 @@ namespace internal { // stack trace. const char kStackTraceMarker[] = "\nStack trace:\n"; +// g_help_flag is true iff the --help flag or an equivalent form is +// specified on the command line. +bool g_help_flag = false; + } // namespace internal GTEST_DEFINE_bool_( @@ -242,7 +246,7 @@ GTEST_DEFINE_bool_( GTEST_DEFINE_int32_( stack_trace_depth, - internal::Int32FromGTestEnv("stack_trace_depth", kMaxStackTraceDepth), + internal::Int32FromGTestEnv("stack_trace_depth", kMaxStackTraceDepth), "The maximum number of stack frames to print when an " "assertion fails. The valid range is 0 through 100, inclusive."); @@ -274,10 +278,6 @@ UInt32 Random::Generate(UInt32 range) { return state_ % range; } -// g_help_flag is true iff the --help flag or an equivalent form is -// specified on the command line. -static bool g_help_flag = false; - // GTestIsInitialized() returns true iff the user has initialized // Google Test. Useful for catching the user mistake of not initializing // Google Test before calling RUN_ALL_TESTS(). @@ -4611,6 +4611,8 @@ void ParseGoogleTestFlagsOnlyImpl(int* argc, CharType** argv) { ParseInt32Flag(arg, kRandomSeedFlag, >EST_FLAG(random_seed)) || ParseInt32Flag(arg, kRepeatFlag, >EST_FLAG(repeat)) || ParseBoolFlag(arg, kShuffleFlag, >EST_FLAG(shuffle)) || + ParseInt32Flag(arg, kStackTraceDepthFlag, + >EST_FLAG(stack_trace_depth)) || ParseBoolFlag(arg, kThrowOnFailureFlag, >EST_FLAG(throw_on_failure)) ) { // Yes. Shift the remainder of the argv list left by one. Note -- cgit v1.2.3 From 891b3716c4b6e4bd7fdbd642ecaab37776eb5935 Mon Sep 17 00:00:00 2001 From: "zhanyong.wan" Date: Tue, 1 Dec 2009 19:39:52 +0000 Subject: Exposes SkipPrefix s.t. it can be used by gmock (by Vlad Losev). --- src/gtest.cc | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) (limited to 'src') diff --git a/src/gtest.cc b/src/gtest.cc index 55861544..aa50b25b 100644 --- a/src/gtest.cc +++ b/src/gtest.cc @@ -4355,6 +4355,18 @@ bool AlwaysTrue() { return true; } +// If *pstr starts with the given prefix, modifies *pstr to be right +// past the prefix and returns true; otherwise leaves *pstr unchanged +// and returns false. None of pstr, *pstr, and prefix can be NULL. +bool SkipPrefix(const char* prefix, const char** pstr) { + const size_t prefix_len = strlen(prefix); + if (strncmp(*pstr, prefix, prefix_len) == 0) { + *pstr += prefix_len; + return true; + } + return false; +} + // Parses a string as a command line flag. The string should have // the format "--flag=value". When def_optional is true, the "=value" // part can be omitted. @@ -4444,18 +4456,6 @@ bool ParseStringFlag(const char* str, const char* flag, String* value) { return true; } -// Determines whether a string pointed by *str has the prefix parameter as -// its prefix and advances it to point past the prefix if it does. -static bool SkipPrefix(const char* prefix, const char** str) { - const size_t prefix_len = strlen(prefix); - - if (strncmp(*str, prefix, prefix_len) != 0) - return false; - - *str += prefix_len; - return true; -} - // Determines whether a string has a prefix that Google Test uses for its // flags, i.e., starts with GTEST_FLAG_PREFIX_ or GTEST_FLAG_PREFIX_DASH_. // If Google Test detects that a command line flag has its prefix but is not -- cgit v1.2.3 From d56773b492b7b675d5c547baab815289a7815bdd Mon Sep 17 00:00:00 2001 From: "zhanyong.wan" Date: Wed, 16 Dec 2009 19:54:05 +0000 Subject: Turns on -Wshadow (by Preston Jackson). --- src/gtest-death-test.cc | 32 ++++++++++++++++---------------- src/gtest-internal-inl.h | 8 ++++---- src/gtest.cc | 43 ++++++++++++++++++++++--------------------- 3 files changed, 42 insertions(+), 41 deletions(-) (limited to 'src') diff --git a/src/gtest-death-test.cc b/src/gtest-death-test.cc index 106b01c7..5f2fbbcf 100644 --- a/src/gtest-death-test.cc +++ b/src/gtest-death-test.cc @@ -308,9 +308,9 @@ String DeathTest::last_death_test_message_; // Provides cross platform implementation for some death functionality. class DeathTestImpl : public DeathTest { protected: - DeathTestImpl(const char* statement, const RE* regex) - : statement_(statement), - regex_(regex), + DeathTestImpl(const char* a_statement, const RE* a_regex) + : statement_(a_statement), + regex_(a_regex), spawned_(false), status_(-1), outcome_(IN_PROGRESS), @@ -326,11 +326,11 @@ class DeathTestImpl : public DeathTest { const char* statement() const { return statement_; } const RE* regex() const { return regex_; } bool spawned() const { return spawned_; } - void set_spawned(bool spawned) { spawned_ = spawned; } + void set_spawned(bool is_spawned) { spawned_ = is_spawned; } int status() const { return status_; } - void set_status(int status) { status_ = status; } + void set_status(int a_status) { status_ = a_status; } DeathTestOutcome outcome() const { return outcome_; } - void set_outcome(DeathTestOutcome outcome) { outcome_ = outcome; } + void set_outcome(DeathTestOutcome an_outcome) { outcome_ = an_outcome; } int read_fd() const { return read_fd_; } void set_read_fd(int fd) { read_fd_ = fd; } int write_fd() const { return write_fd_; } @@ -705,8 +705,8 @@ class ForkingDeathTest : public DeathTestImpl { }; // Constructs a ForkingDeathTest. -ForkingDeathTest::ForkingDeathTest(const char* statement, const RE* regex) - : DeathTestImpl(statement, regex), +ForkingDeathTest::ForkingDeathTest(const char* a_statement, const RE* a_regex) + : DeathTestImpl(a_statement, a_regex), child_pid_(-1) {} // Waits for the child in a death test to exit, returning its exit @@ -718,18 +718,18 @@ int ForkingDeathTest::Wait() { ReadAndInterpretStatusByte(); - int status; - GTEST_DEATH_TEST_CHECK_SYSCALL_(waitpid(child_pid_, &status, 0)); - set_status(status); - return status; + int status_value; + GTEST_DEATH_TEST_CHECK_SYSCALL_(waitpid(child_pid_, &status_value, 0)); + set_status(status_value); + return status_value; } // A concrete death test class that forks, then immediately runs the test // in the child process. class NoExecDeathTest : public ForkingDeathTest { public: - NoExecDeathTest(const char* statement, const RE* regex) : - ForkingDeathTest(statement, regex) { } + NoExecDeathTest(const char* a_statement, const RE* a_regex) : + ForkingDeathTest(a_statement, a_regex) { } virtual TestRole AssumeRole(); }; @@ -782,9 +782,9 @@ DeathTest::TestRole NoExecDeathTest::AssumeRole() { // only this specific death test to be run. class ExecDeathTest : public ForkingDeathTest { public: - ExecDeathTest(const char* statement, const RE* regex, + ExecDeathTest(const char* a_statement, const RE* a_regex, const char* file, int line) : - ForkingDeathTest(statement, regex), file_(file), line_(line) { } + ForkingDeathTest(a_statement, a_regex), file_(file), line_(line) { } virtual TestRole AssumeRole(); private: // The name of the file in which the death test is located. diff --git a/src/gtest-internal-inl.h b/src/gtest-internal-inl.h index 45a4c105..596dc553 100644 --- a/src/gtest-internal-inl.h +++ b/src/gtest-internal-inl.h @@ -902,15 +902,15 @@ class UnitTestImpl { #endif // GTEST_HAS_PARAM_TEST // Sets the TestCase object for the test that's currently running. - void set_current_test_case(TestCase* current_test_case) { - current_test_case_ = current_test_case; + void set_current_test_case(TestCase* a_current_test_case) { + current_test_case_ = a_current_test_case; } // Sets the TestInfo object for the test that's currently running. If // current_test_info is NULL, the assertion results will be stored in // ad_hoc_test_result_. - void set_current_test_info(TestInfo* current_test_info) { - current_test_info_ = current_test_info; + void set_current_test_info(TestInfo* a_current_test_info) { + current_test_info_ = a_current_test_info; } // Registers all parameterized tests defined using TEST_P and diff --git a/src/gtest.cc b/src/gtest.cc index aa50b25b..bd16bc6e 100644 --- a/src/gtest.cc +++ b/src/gtest.cc @@ -2123,14 +2123,14 @@ bool Test::HasNonfatalFailure() { // Constructs a TestInfo object. It assumes ownership of the test factory // object via impl_. -TestInfo::TestInfo(const char* test_case_name, - const char* name, - const char* test_case_comment, - const char* comment, +TestInfo::TestInfo(const char* a_test_case_name, + const char* a_name, + const char* a_test_case_comment, + const char* a_comment, internal::TypeId fixture_class_id, internal::TestFactoryBase* factory) { - impl_ = new internal::TestInfoImpl(this, test_case_name, name, - test_case_comment, comment, + impl_ = new internal::TestInfoImpl(this, a_test_case_name, a_name, + a_test_case_comment, a_comment, fixture_class_id, factory); } @@ -2368,11 +2368,11 @@ int TestCase::total_test_count() const { // name: name of the test case // set_up_tc: pointer to the function that sets up the test case // tear_down_tc: pointer to the function that tears down the test case -TestCase::TestCase(const char* name, const char* comment, +TestCase::TestCase(const char* a_name, const char* a_comment, Test::SetUpTestCaseFunc set_up_tc, Test::TearDownTestCaseFunc tear_down_tc) - : name_(name), - comment_(comment), + : name_(a_name), + comment_(a_comment), test_info_list_(new internal::Vector), test_indices_(new internal::Vector), set_up_tc_(set_up_tc), @@ -4022,8 +4022,9 @@ int UnitTestImpl::RunAllTests() { // Runs the tests only if there was no fatal failure during global // set-up. if (!Test::HasFatalFailure()) { - for (int i = 0; i < total_test_case_count(); i++) { - GetMutableTestCase(i)->Run(); + for (int test_index = 0; test_index < total_test_case_count(); + test_index++) { + GetMutableTestCase(test_index)->Run(); } } @@ -4297,18 +4298,18 @@ void UnitTestImpl::UnshuffleTests() { // TestInfoImpl constructor. The new instance assumes ownership of the test // factory object. TestInfoImpl::TestInfoImpl(TestInfo* parent, - const char* test_case_name, - const char* name, - const char* test_case_comment, - const char* comment, - TypeId fixture_class_id, + const char* a_test_case_name, + const char* a_name, + const char* a_test_case_comment, + const char* a_comment, + TypeId a_fixture_class_id, internal::TestFactoryBase* factory) : parent_(parent), - test_case_name_(String(test_case_name)), - name_(String(name)), - test_case_comment_(String(test_case_comment)), - comment_(String(comment)), - fixture_class_id_(fixture_class_id), + test_case_name_(String(a_test_case_name)), + name_(String(a_name)), + test_case_comment_(String(a_test_case_comment)), + comment_(String(a_comment)), + fixture_class_id_(a_fixture_class_id), should_run_(false), is_disabled_(false), matches_filter_(false), -- cgit v1.2.3 From 88e97c822c988eaa9f8bcbaa1ea5d702ffd7d384 Mon Sep 17 00:00:00 2001 From: "zhanyong.wan" Date: Wed, 16 Dec 2009 23:34:59 +0000 Subject: Removes uses of GTEST_HAS_STD_STRING. --- src/gtest.cc | 14 -------------- 1 file changed, 14 deletions(-) (limited to 'src') diff --git a/src/gtest.cc b/src/gtest.cc index bd16bc6e..c6d6c09e 100644 --- a/src/gtest.cc +++ b/src/gtest.cc @@ -1316,7 +1316,6 @@ AssertionResult IsNotSubstring( return IsSubstringImpl(false, needle_expr, haystack_expr, needle, haystack); } -#if GTEST_HAS_STD_STRING AssertionResult IsSubstring( const char* needle_expr, const char* haystack_expr, const ::std::string& needle, const ::std::string& haystack) { @@ -1328,7 +1327,6 @@ AssertionResult IsNotSubstring( const ::std::string& needle, const ::std::string& haystack) { return IsSubstringImpl(false, needle_expr, haystack_expr, needle, haystack); } -#endif // GTEST_HAS_STD_STRING #if GTEST_HAS_STD_WSTRING AssertionResult IsSubstring( @@ -1748,14 +1746,9 @@ String String::Format(const char * format, ...) { // Converts the buffer in a StrStream to a String, converting NUL // bytes to "\\0" along the way. String StrStreamToString(StrStream* ss) { -#if GTEST_HAS_STD_STRING const ::std::string& str = ss->str(); const char* const start = str.c_str(); const char* const end = start + str.length(); -#else - const char* const start = ss->str(); - const char* const end = start + ss->pcount(); -#endif // GTEST_HAS_STD_STRING // We need to use a helper StrStream to do this transformation // because String doesn't support push_back(). @@ -1768,14 +1761,7 @@ String StrStreamToString(StrStream* ss) { } } -#if GTEST_HAS_STD_STRING return String(helper.str().c_str()); -#else - const String str(helper.str(), helper.pcount()); - helper.freeze(false); - ss->freeze(false); - return str; -#endif // GTEST_HAS_STD_STRING } // Appends the user-supplied message to the Google-Test-generated message. -- cgit v1.2.3 From a3dd9d97c57eb1be851a27ffcd6edaed69ee816e Mon Sep 17 00:00:00 2001 From: "zhanyong.wan" Date: Fri, 18 Dec 2009 05:23:04 +0000 Subject: Supports building gtest as a DLL (by Vlad Losev). --- src/gtest.def | 123 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 123 insertions(+) create mode 100644 src/gtest.def (limited to 'src') diff --git a/src/gtest.def b/src/gtest.def new file mode 100644 index 00000000..a5583dfd --- /dev/null +++ b/src/gtest.def @@ -0,0 +1,123 @@ +; This file is auto-generated. DO NOT EDIT DIRECTLY. +; For more information, see scripts/generate_gtest_def.py. + +LIBRARY + +EXPORTS + ??0AssertHelper@internal@testing@@QAE@W4Type@TestPartResult@2@PBDH1@Z + ??0AssertionResult@testing@@QAE@ABV01@@Z + ??0ExitedWithCode@testing@@QAE@H@Z + ??0GTestLog@internal@testing@@QAE@W4GTestLogSeverity@12@PBDH@Z + ??0HasNewFatalFailureHelper@internal@testing@@QAE@XZ + ??0ScopedFakeTestPartResultReporter@testing@@QAE@W4InterceptMode@01@PAVTestPartResultArray@1@@Z + ??0ScopedTrace@internal@testing@@QAE@PBDHABVMessage@2@@Z + ??0SingleFailureChecker@internal@testing@@QAE@PBVTestPartResultArray@2@W4Type@TestPartResult@2@PBD@Z + ??0Test@testing@@IAE@XZ + ??0TestPartResultArray@testing@@QAE@XZ + ??1AssertHelper@internal@testing@@QAE@XZ + ??1GTestLog@internal@testing@@QAE@XZ + ??1HasNewFatalFailureHelper@internal@testing@@UAE@XZ + ??1RE@internal@testing@@QAE@XZ + ??1ScopedFakeTestPartResultReporter@testing@@UAE@XZ + ??1ScopedTrace@internal@testing@@QAE@XZ + ??1SingleFailureChecker@internal@testing@@QAE@XZ + ??1Test@testing@@UAE@XZ + ??1TestPartResultArray@testing@@QAE@XZ + ??4AssertHelper@internal@testing@@QBEXABVMessage@2@@Z + ??6Message@testing@@QAEAAV01@ABV?$basic_string@_WU?$char_traits@_W@std@@V?$allocator@_W@2@@std@@@Z + ??7AssertionResult@testing@@QBE?AV01@XZ + ??RExitedWithCode@testing@@QBE_NH@Z + ?AddEnvironment@UnitTest@testing@@AAEPAVEnvironment@2@PAV32@@Z + ?AlwaysTrue@internal@testing@@YA_NXZ + ?Append@TestEventListeners@testing@@QAEXPAVTestEventListener@2@@Z + ?AssertionFailure@testing@@YA?AVAssertionResult@1@ABVMessage@1@@Z + ?AssertionFailure@testing@@YA?AVAssertionResult@1@XZ + ?AssertionSuccess@testing@@YA?AVAssertionResult@1@XZ + ?CmpHelperSTRCASEEQ@internal@testing@@YA?AVAssertionResult@2@PBD000@Z + ?CmpHelperSTRCASENE@internal@testing@@YA?AVAssertionResult@2@PBD000@Z + ?CmpHelperSTREQ@internal@testing@@YA?AVAssertionResult@2@PBD000@Z + ?CmpHelperSTREQ@internal@testing@@YA?AVAssertionResult@2@PBD0PB_W1@Z + ?CmpHelperSTRNE@internal@testing@@YA?AVAssertionResult@2@PBD000@Z + ?CmpHelperSTRNE@internal@testing@@YA?AVAssertionResult@2@PBD0PB_W1@Z + ?Compare@String@internal@testing@@QBEHABV123@@Z + ?Create@DeathTest@internal@testing@@SA_NPBDPBVRE@23@0HPAPAV123@@Z + ?DoubleLE@testing@@YA?AVAssertionResult@1@PBD0NN@Z + ?DoubleNearPredFormat@internal@testing@@YA?AVAssertionResult@2@PBD00NNN@Z + ?EqFailure@internal@testing@@YA?AVAssertionResult@2@PBD0ABVString@12@1_N@Z + ?ExitedUnsuccessfully@internal@testing@@YA_NH@Z + ?FLAGS_gtest_also_run_disabled_tests@testing@@3_NA + ?FLAGS_gtest_break_on_failure@testing@@3_NA + ?FLAGS_gtest_catch_exceptions@testing@@3_NA + ?FLAGS_gtest_color@testing@@3VString@internal@1@A + ?FLAGS_gtest_filter@testing@@3VString@internal@1@A + ?FLAGS_gtest_output@testing@@3VString@internal@1@A + ?FLAGS_gtest_print_time@testing@@3_NA + ?FLAGS_gtest_random_seed@testing@@3HA + ?FLAGS_gtest_repeat@testing@@3HA + ?FLAGS_gtest_shuffle@testing@@3_NA + ?FLAGS_gtest_stack_trace_depth@testing@@3HA + ?FLAGS_gtest_throw_on_failure@testing@@3_NA + ?Failed@TestResult@testing@@QBE_NXZ + ?Failed@UnitTest@testing@@QBE_NXZ + ?FloatLE@testing@@YA?AVAssertionResult@1@PBD0MM@Z + ?Format@String@internal@testing@@SA?AV123@PBDZZ + ?FormatForFailureMessage@internal@testing@@YA?AVString@12@D@Z + ?GetBoolAssertionFailureMessage@internal@testing@@YA?AVString@12@ABVAssertionResult@2@PBD11@Z + ?GetInstance@UnitTest@testing@@SAPAV12@XZ + ?GetTestCase@UnitTest@testing@@QBEPBVTestCase@2@H@Z + ?GetTestInfo@TestCase@testing@@QBEPBVTestInfo@2@H@Z + ?GetTestPartResult@TestResult@testing@@QBEABVTestPartResult@2@H@Z + ?GetTestProperty@TestResult@testing@@QBEABVTestProperty@2@H@Z + ?GetTestTypeId@internal@testing@@YAPBXXZ + ?HasFatalFailure@Test@testing@@SA_NXZ + ?HasFatalFailure@TestResult@testing@@QBE_NXZ + ?HasNonfatalFailure@Test@testing@@SA_NXZ + ?HasNonfatalFailure@TestResult@testing@@QBE_NXZ + ?Init@RE@internal@testing@@AAEXPBD@Z + ?InitGoogleTest@testing@@YAXPAHPAPAD@Z + ?IsHRESULTFailure@internal@testing@@YA?AVAssertionResult@2@PBDJ@Z + ?IsHRESULTSuccess@internal@testing@@YA?AVAssertionResult@2@PBDJ@Z + ?IsTrue@internal@testing@@YA_N_N@Z + ?LastMessage@DeathTest@internal@testing@@SAPBDXZ + ?MakeAndRegisterTestInfo@internal@testing@@YAPAVTestInfo@2@PBD000PBXP6AXXZ2PAVTestFactoryBase@12@@Z + ?Passed@UnitTest@testing@@QBE_NXZ + ?RecordProperty@Test@testing@@SAXPBD0@Z + ?Release@TestEventListeners@testing@@QAEPAVTestEventListener@2@PAV32@@Z + ?ReportInvalidTestCaseType@internal@testing@@YAXPBD0H@Z + ?Run@UnitTest@testing@@QAEHXZ + ?SetUp@Test@testing@@MAEXXZ + ?ShowCStringQuoted@String@internal@testing@@SA?AV123@PBD@Z + ?ShowWideCStringQuoted@String@internal@testing@@SA?AV123@PB_W@Z + ?StrStreamToString@internal@testing@@YA?AVString@12@PAV?$basic_stringstream@DU?$char_traits@D@std@@V?$allocator@D@2@@std@@@Z + ?TearDown@Test@testing@@MAEXXZ + ?VerifyRegisteredTestNames@TypedTestCasePState@internal@testing@@QAEPBDPBDH0@Z + ?comment@TestInfo@testing@@QBEPBDXZ + ?current_test_case@UnitTest@testing@@QBEPBVTestCase@2@XZ + ?current_test_info@UnitTest@testing@@QBEPBVTestInfo@2@XZ + ?disabled_test_count@TestCase@testing@@QBEHXZ + ?disabled_test_count@UnitTest@testing@@QBEHXZ + ?elapsed_time@UnitTest@testing@@QBE_JXZ + ?failed_test_case_count@UnitTest@testing@@QBEHXZ + ?failed_test_count@TestCase@testing@@QBEHXZ + ?failed_test_count@UnitTest@testing@@QBEHXZ + ?g_linked_ptr_mutex@internal@testing@@3VMutex@12@A + ?listeners@UnitTest@testing@@QAEAAVTestEventListeners@2@XZ + ?name@TestInfo@testing@@QBEPBDXZ + ?original_working_dir@UnitTest@testing@@QBEPBDXZ + ?parameterized_test_registry@UnitTest@testing@@QAEAAVParameterizedTestCaseRegistry@internal@2@XZ + ?random_seed@UnitTest@testing@@QBEHXZ + ?result@TestInfo@testing@@QBEPBVTestResult@2@XZ + ?should_run@TestInfo@testing@@QBE_NXZ + ?successful_test_case_count@UnitTest@testing@@QBEHXZ + ?successful_test_count@TestCase@testing@@QBEHXZ + ?successful_test_count@UnitTest@testing@@QBEHXZ + ?test_case_comment@TestInfo@testing@@QBEPBDXZ + ?test_case_name@TestInfo@testing@@QBEPBDXZ + ?test_case_to_run_count@UnitTest@testing@@QBEHXZ + ?test_property_count@TestResult@testing@@QBEHXZ + ?test_to_run_count@TestCase@testing@@QBEHXZ + ?test_to_run_count@UnitTest@testing@@QBEHXZ + ?total_part_count@TestResult@testing@@QBEHXZ + ?total_test_case_count@UnitTest@testing@@QBEHXZ + ?total_test_count@TestCase@testing@@QBEHXZ + ?total_test_count@UnitTest@testing@@QBEHXZ -- cgit v1.2.3 From 940ce8a21024d9eb4221e5a9375615dbca926061 Mon Sep 17 00:00:00 2001 From: "zhanyong.wan" Date: Fri, 18 Dec 2009 16:48:20 +0000 Subject: Moves gtest.def from src/ to msvc/. --- src/gtest.def | 123 ---------------------------------------------------------- 1 file changed, 123 deletions(-) delete mode 100644 src/gtest.def (limited to 'src') diff --git a/src/gtest.def b/src/gtest.def deleted file mode 100644 index a5583dfd..00000000 --- a/src/gtest.def +++ /dev/null @@ -1,123 +0,0 @@ -; This file is auto-generated. DO NOT EDIT DIRECTLY. -; For more information, see scripts/generate_gtest_def.py. - -LIBRARY - -EXPORTS - ??0AssertHelper@internal@testing@@QAE@W4Type@TestPartResult@2@PBDH1@Z - ??0AssertionResult@testing@@QAE@ABV01@@Z - ??0ExitedWithCode@testing@@QAE@H@Z - ??0GTestLog@internal@testing@@QAE@W4GTestLogSeverity@12@PBDH@Z - ??0HasNewFatalFailureHelper@internal@testing@@QAE@XZ - ??0ScopedFakeTestPartResultReporter@testing@@QAE@W4InterceptMode@01@PAVTestPartResultArray@1@@Z - ??0ScopedTrace@internal@testing@@QAE@PBDHABVMessage@2@@Z - ??0SingleFailureChecker@internal@testing@@QAE@PBVTestPartResultArray@2@W4Type@TestPartResult@2@PBD@Z - ??0Test@testing@@IAE@XZ - ??0TestPartResultArray@testing@@QAE@XZ - ??1AssertHelper@internal@testing@@QAE@XZ - ??1GTestLog@internal@testing@@QAE@XZ - ??1HasNewFatalFailureHelper@internal@testing@@UAE@XZ - ??1RE@internal@testing@@QAE@XZ - ??1ScopedFakeTestPartResultReporter@testing@@UAE@XZ - ??1ScopedTrace@internal@testing@@QAE@XZ - ??1SingleFailureChecker@internal@testing@@QAE@XZ - ??1Test@testing@@UAE@XZ - ??1TestPartResultArray@testing@@QAE@XZ - ??4AssertHelper@internal@testing@@QBEXABVMessage@2@@Z - ??6Message@testing@@QAEAAV01@ABV?$basic_string@_WU?$char_traits@_W@std@@V?$allocator@_W@2@@std@@@Z - ??7AssertionResult@testing@@QBE?AV01@XZ - ??RExitedWithCode@testing@@QBE_NH@Z - ?AddEnvironment@UnitTest@testing@@AAEPAVEnvironment@2@PAV32@@Z - ?AlwaysTrue@internal@testing@@YA_NXZ - ?Append@TestEventListeners@testing@@QAEXPAVTestEventListener@2@@Z - ?AssertionFailure@testing@@YA?AVAssertionResult@1@ABVMessage@1@@Z - ?AssertionFailure@testing@@YA?AVAssertionResult@1@XZ - ?AssertionSuccess@testing@@YA?AVAssertionResult@1@XZ - ?CmpHelperSTRCASEEQ@internal@testing@@YA?AVAssertionResult@2@PBD000@Z - ?CmpHelperSTRCASENE@internal@testing@@YA?AVAssertionResult@2@PBD000@Z - ?CmpHelperSTREQ@internal@testing@@YA?AVAssertionResult@2@PBD000@Z - ?CmpHelperSTREQ@internal@testing@@YA?AVAssertionResult@2@PBD0PB_W1@Z - ?CmpHelperSTRNE@internal@testing@@YA?AVAssertionResult@2@PBD000@Z - ?CmpHelperSTRNE@internal@testing@@YA?AVAssertionResult@2@PBD0PB_W1@Z - ?Compare@String@internal@testing@@QBEHABV123@@Z - ?Create@DeathTest@internal@testing@@SA_NPBDPBVRE@23@0HPAPAV123@@Z - ?DoubleLE@testing@@YA?AVAssertionResult@1@PBD0NN@Z - ?DoubleNearPredFormat@internal@testing@@YA?AVAssertionResult@2@PBD00NNN@Z - ?EqFailure@internal@testing@@YA?AVAssertionResult@2@PBD0ABVString@12@1_N@Z - ?ExitedUnsuccessfully@internal@testing@@YA_NH@Z - ?FLAGS_gtest_also_run_disabled_tests@testing@@3_NA - ?FLAGS_gtest_break_on_failure@testing@@3_NA - ?FLAGS_gtest_catch_exceptions@testing@@3_NA - ?FLAGS_gtest_color@testing@@3VString@internal@1@A - ?FLAGS_gtest_filter@testing@@3VString@internal@1@A - ?FLAGS_gtest_output@testing@@3VString@internal@1@A - ?FLAGS_gtest_print_time@testing@@3_NA - ?FLAGS_gtest_random_seed@testing@@3HA - ?FLAGS_gtest_repeat@testing@@3HA - ?FLAGS_gtest_shuffle@testing@@3_NA - ?FLAGS_gtest_stack_trace_depth@testing@@3HA - ?FLAGS_gtest_throw_on_failure@testing@@3_NA - ?Failed@TestResult@testing@@QBE_NXZ - ?Failed@UnitTest@testing@@QBE_NXZ - ?FloatLE@testing@@YA?AVAssertionResult@1@PBD0MM@Z - ?Format@String@internal@testing@@SA?AV123@PBDZZ - ?FormatForFailureMessage@internal@testing@@YA?AVString@12@D@Z - ?GetBoolAssertionFailureMessage@internal@testing@@YA?AVString@12@ABVAssertionResult@2@PBD11@Z - ?GetInstance@UnitTest@testing@@SAPAV12@XZ - ?GetTestCase@UnitTest@testing@@QBEPBVTestCase@2@H@Z - ?GetTestInfo@TestCase@testing@@QBEPBVTestInfo@2@H@Z - ?GetTestPartResult@TestResult@testing@@QBEABVTestPartResult@2@H@Z - ?GetTestProperty@TestResult@testing@@QBEABVTestProperty@2@H@Z - ?GetTestTypeId@internal@testing@@YAPBXXZ - ?HasFatalFailure@Test@testing@@SA_NXZ - ?HasFatalFailure@TestResult@testing@@QBE_NXZ - ?HasNonfatalFailure@Test@testing@@SA_NXZ - ?HasNonfatalFailure@TestResult@testing@@QBE_NXZ - ?Init@RE@internal@testing@@AAEXPBD@Z - ?InitGoogleTest@testing@@YAXPAHPAPAD@Z - ?IsHRESULTFailure@internal@testing@@YA?AVAssertionResult@2@PBDJ@Z - ?IsHRESULTSuccess@internal@testing@@YA?AVAssertionResult@2@PBDJ@Z - ?IsTrue@internal@testing@@YA_N_N@Z - ?LastMessage@DeathTest@internal@testing@@SAPBDXZ - ?MakeAndRegisterTestInfo@internal@testing@@YAPAVTestInfo@2@PBD000PBXP6AXXZ2PAVTestFactoryBase@12@@Z - ?Passed@UnitTest@testing@@QBE_NXZ - ?RecordProperty@Test@testing@@SAXPBD0@Z - ?Release@TestEventListeners@testing@@QAEPAVTestEventListener@2@PAV32@@Z - ?ReportInvalidTestCaseType@internal@testing@@YAXPBD0H@Z - ?Run@UnitTest@testing@@QAEHXZ - ?SetUp@Test@testing@@MAEXXZ - ?ShowCStringQuoted@String@internal@testing@@SA?AV123@PBD@Z - ?ShowWideCStringQuoted@String@internal@testing@@SA?AV123@PB_W@Z - ?StrStreamToString@internal@testing@@YA?AVString@12@PAV?$basic_stringstream@DU?$char_traits@D@std@@V?$allocator@D@2@@std@@@Z - ?TearDown@Test@testing@@MAEXXZ - ?VerifyRegisteredTestNames@TypedTestCasePState@internal@testing@@QAEPBDPBDH0@Z - ?comment@TestInfo@testing@@QBEPBDXZ - ?current_test_case@UnitTest@testing@@QBEPBVTestCase@2@XZ - ?current_test_info@UnitTest@testing@@QBEPBVTestInfo@2@XZ - ?disabled_test_count@TestCase@testing@@QBEHXZ - ?disabled_test_count@UnitTest@testing@@QBEHXZ - ?elapsed_time@UnitTest@testing@@QBE_JXZ - ?failed_test_case_count@UnitTest@testing@@QBEHXZ - ?failed_test_count@TestCase@testing@@QBEHXZ - ?failed_test_count@UnitTest@testing@@QBEHXZ - ?g_linked_ptr_mutex@internal@testing@@3VMutex@12@A - ?listeners@UnitTest@testing@@QAEAAVTestEventListeners@2@XZ - ?name@TestInfo@testing@@QBEPBDXZ - ?original_working_dir@UnitTest@testing@@QBEPBDXZ - ?parameterized_test_registry@UnitTest@testing@@QAEAAVParameterizedTestCaseRegistry@internal@2@XZ - ?random_seed@UnitTest@testing@@QBEHXZ - ?result@TestInfo@testing@@QBEPBVTestResult@2@XZ - ?should_run@TestInfo@testing@@QBE_NXZ - ?successful_test_case_count@UnitTest@testing@@QBEHXZ - ?successful_test_count@TestCase@testing@@QBEHXZ - ?successful_test_count@UnitTest@testing@@QBEHXZ - ?test_case_comment@TestInfo@testing@@QBEPBDXZ - ?test_case_name@TestInfo@testing@@QBEPBDXZ - ?test_case_to_run_count@UnitTest@testing@@QBEHXZ - ?test_property_count@TestResult@testing@@QBEHXZ - ?test_to_run_count@TestCase@testing@@QBEHXZ - ?test_to_run_count@UnitTest@testing@@QBEHXZ - ?total_part_count@TestResult@testing@@QBEHXZ - ?total_test_case_count@UnitTest@testing@@QBEHXZ - ?total_test_count@TestCase@testing@@QBEHXZ - ?total_test_count@UnitTest@testing@@QBEHXZ -- cgit v1.2.3 From e92ccedad996eeb4f0d9244a1acd8882b5f54fd0 Mon Sep 17 00:00:00 2001 From: "zhanyong.wan" Date: Fri, 8 Jan 2010 00:23:45 +0000 Subject: Changes Message() to print double with enough precision by default. --- src/gtest.cc | 18 ++++++++---------- 1 file changed, 8 insertions(+), 10 deletions(-) (limited to 'src') diff --git a/src/gtest.cc b/src/gtest.cc index c6d6c09e..11ce571b 100644 --- a/src/gtest.cc +++ b/src/gtest.cc @@ -43,6 +43,7 @@ #include #include +#include #if GTEST_OS_LINUX @@ -3168,14 +3169,11 @@ String XmlUnitTestResultPrinter::RemoveInvalidXmlCharacters(const char* str) { // // -// Formats the given time in milliseconds as seconds. The returned -// C-string is owned by this function and cannot be released by the -// caller. Calling the function again invalidates the previous -// result. -const char* FormatTimeInMillisAsSeconds(TimeInMillis ms) { - static String str; - str = (Message() << (ms/1000.0)).GetString(); - return str.c_str(); +// Formats the given time in milliseconds as seconds. +std::string FormatTimeInMillisAsSeconds(TimeInMillis ms) { + ::std::stringstream ss; + ss << ms/1000.0; + return ss.str(); } // Streams an XML CDATA section, escaping invalid CDATA sequences as needed. @@ -3249,7 +3247,7 @@ void XmlUnitTestResultPrinter::PrintXmlTestCase(FILE* out, test_case.disabled_test_count()); fprintf(out, "errors=\"0\" time=\"%s\">\n", - FormatTimeInMillisAsSeconds(test_case.elapsed_time())); + FormatTimeInMillisAsSeconds(test_case.elapsed_time()).c_str()); for (int i = 0; i < test_case.total_test_count(); ++i) { StrStream stream; OutputXmlTestInfo(&stream, test_case.name(), *test_case.GetTestInfo(i)); @@ -3268,7 +3266,7 @@ void XmlUnitTestResultPrinter::PrintXmlUnitTest(FILE* out, unit_test.total_test_count(), unit_test.failed_test_count(), unit_test.disabled_test_count(), - FormatTimeInMillisAsSeconds(unit_test.elapsed_time())); + FormatTimeInMillisAsSeconds(unit_test.elapsed_time()).c_str()); if (GTEST_FLAG(shuffle)) { fprintf(out, "random_seed=\"%d\" ", unit_test.random_seed()); } -- cgit v1.2.3 From fd6f2a8a4b3fe8beb31f26b774b460727c410b66 Mon Sep 17 00:00:00 2001 From: "zhanyong.wan" Date: Wed, 27 Jan 2010 22:27:30 +0000 Subject: Implements stdout capturing (by Vlad Losev); fixes compiler error on NVCC (by Zhanyong Wan). --- src/gtest-port.cc | 126 +++++++++++++++++++++++++++++++----------------------- src/gtest.cc | 3 ++ 2 files changed, 75 insertions(+), 54 deletions(-) (limited to 'src') diff --git a/src/gtest-port.cc b/src/gtest-port.cc index de169e2a..1890a802 100644 --- a/src/gtest-port.cc +++ b/src/gtest-port.cc @@ -68,8 +68,10 @@ namespace internal { #if defined(_MSC_VER) || defined(__BORLANDC__) // MSVC and C++Builder do not provide a definition of STDERR_FILENO. +const int kStdOutFileno = 1; const int kStdErrFileno = 2; #else +const int kStdOutFileno = STDOUT_FILENO; const int kStdErrFileno = STDERR_FILENO; #endif // _MSC_VER @@ -439,18 +441,14 @@ GTestLog::~GTestLog() { #pragma warning(disable: 4996) #endif // _MSC_VER -// Defines the stderr capturer. +// Stream capturing is not supported on Windows Mobile. +#if !GTEST_OS_WINDOWS_MOBILE -class CapturedStderr { +// Object that captures an output stream (stdout/stderr). +class CapturedStream { public: - // The ctor redirects stderr to a temporary file. - CapturedStderr() { -#if GTEST_OS_WINDOWS_MOBILE - // Not supported on Windows CE. - posix::Abort(); -#else - uncaptured_fd_ = dup(kStdErrFileno); - + // The ctor redirects the stream to a temporary file. + CapturedStream(int fd) : fd_(fd), uncaptured_fd_(dup(fd)) { #if GTEST_OS_WINDOWS char temp_dir_path[MAX_PATH + 1] = { '\0' }; // NOLINT char temp_file_path[MAX_PATH + 1] = { '\0' }; // NOLINT @@ -463,57 +461,57 @@ class CapturedStderr { // There's no guarantee that a test has write access to the // current directory, so we create the temporary file in the /tmp // directory instead. - char name_template[] = "/tmp/captured_stderr.XXXXXX"; + char name_template[] = "/tmp/captured_stream.XXXXXX"; const int captured_fd = mkstemp(name_template); filename_ = name_template; #endif // GTEST_OS_WINDOWS fflush(NULL); - dup2(captured_fd, kStdErrFileno); + dup2(captured_fd, fd_); close(captured_fd); -#endif // GTEST_OS_WINDOWS_MOBILE } - ~CapturedStderr() { -#if !GTEST_OS_WINDOWS_MOBILE + ~CapturedStream() { remove(filename_.c_str()); -#endif // !GTEST_OS_WINDOWS_MOBILE } - // Stops redirecting stderr. - void StopCapture() { -#if !GTEST_OS_WINDOWS_MOBILE - // Restores the original stream. - fflush(NULL); - dup2(uncaptured_fd_, kStdErrFileno); - close(uncaptured_fd_); - uncaptured_fd_ = -1; -#endif // !GTEST_OS_WINDOWS_MOBILE - } + String GetCapturedString() { + if (uncaptured_fd_ != -1) { + // Restores the original stream. + fflush(NULL); + dup2(uncaptured_fd_, fd_); + close(uncaptured_fd_); + uncaptured_fd_ = -1; + } - // Returns the name of the temporary file holding the stderr output. - // GTEST_HAS_DEATH_TEST implies that we have ::std::string, so we - // can use it here. - ::std::string filename() const { return filename_; } + FILE* const file = posix::FOpen(filename_.c_str(), "r"); + const String content = ReadEntireFile(file); + posix::FClose(file); + return content; + } private: + // Reads the entire content of a file as a String. + static String ReadEntireFile(FILE* file); + + // Returns the size (in bytes) of a file. + static size_t GetFileSize(FILE* file); + + const int fd_; // A stream to capture. int uncaptured_fd_; + // Name of the temporary file holding the stderr output. ::std::string filename_; -}; - -#ifdef _MSC_VER -#pragma warning(pop) -#endif // _MSC_VER -static CapturedStderr* g_captured_stderr = NULL; + GTEST_DISALLOW_COPY_AND_ASSIGN_(CapturedStream); +}; // Returns the size (in bytes) of a file. -static size_t GetFileSize(FILE * file) { +size_t CapturedStream::GetFileSize(FILE* file) { fseek(file, 0, SEEK_END); return static_cast(ftell(file)); } // Reads the entire content of a file as a string. -static String ReadEntireFile(FILE * file) { +String CapturedStream::ReadEntireFile(FILE* file) { const size_t file_size = GetFileSize(file); char* const buffer = new char[file_size]; @@ -535,30 +533,50 @@ static String ReadEntireFile(FILE * file) { return content; } -// Starts capturing stderr. -void CaptureStderr() { - if (g_captured_stderr != NULL) { - GTEST_LOG_(FATAL) << "Only one stderr capturer can exist at one time."; +#ifdef _MSC_VER +#pragma warning(pop) +#endif // _MSC_VER + +static CapturedStream* g_captured_stderr = NULL; +static CapturedStream* g_captured_stdout = NULL; + +// Starts capturing an output stream (stdout/stderr). +void CaptureStream(int fd, const char* stream_name, CapturedStream** stream) { + if (*stream != NULL) { + GTEST_LOG_(FATAL) << "Only one " << stream_name + << " capturer can exist at a time."; } - g_captured_stderr = new CapturedStderr; + *stream = new CapturedStream(fd); } -// Stops capturing stderr and returns the captured string. -// GTEST_HAS_DEATH_TEST implies that we have ::std::string, so we can -// use it here. -String GetCapturedStderr() { - g_captured_stderr->StopCapture(); +// Stops capturing the output stream and returns the captured string. +String GetCapturedStream(CapturedStream** captured_stream) { + const String content = (*captured_stream)->GetCapturedString(); - FILE* const file = posix::FOpen(g_captured_stderr->filename().c_str(), "r"); - const String content = ReadEntireFile(file); - posix::FClose(file); - - delete g_captured_stderr; - g_captured_stderr = NULL; + delete *captured_stream; + *captured_stream = NULL; return content; } +// Starts capturing stdout. +void CaptureStdout() { + CaptureStream(kStdOutFileno, "stdout", &g_captured_stdout); +} + +// Starts capturing stderr. +void CaptureStderr() { + CaptureStream(kStdErrFileno, "stderr", &g_captured_stderr); +} + +// Stops capturing stdout and returns the captured string. +String GetCapturedStdout() { return GetCapturedStream(&g_captured_stdout); } + +// Stops capturing stderr and returns the captured string. +String GetCapturedStderr() { return GetCapturedStream(&g_captured_stderr); } + +#endif // !GTEST_OS_WINDOWS_MOBILE + #if GTEST_HAS_DEATH_TEST // A copy of all command line arguments. Set by InitGoogleTest(). diff --git a/src/gtest.cc b/src/gtest.cc index 11ce571b..f5de645b 100644 --- a/src/gtest.cc +++ b/src/gtest.cc @@ -2634,6 +2634,9 @@ void ColoredPrintf(GTestColor color, const char* fmt, ...) { SetConsoleTextAttribute(stdout_handle, GetColorAttribute(color) | FOREGROUND_INTENSITY); vprintf(fmt, args); + // Unless we flush stream buffers now the next SetConsoleTextAttribute + // call can reset the color before the output reaches the console. + fflush(stdout); // Restores the text color. SetConsoleTextAttribute(stdout_handle, old_color_attrs); -- cgit v1.2.3 From 81e1cc73c83265e54b2ec7edc17e77f4d1b89e86 Mon Sep 17 00:00:00 2001 From: "zhanyong.wan" Date: Thu, 28 Jan 2010 21:50:29 +0000 Subject: Introduces macro GTEST_HAS_STREAM_REDIRECTION_ (by Vlad Losev); fixes unsynchronized color text output on Windows (by Vlad Losev); fixes the cmake script to work with MSVC 10 (by Manuel Klimek). --- src/gtest-port.cc | 5 ++--- src/gtest.cc | 8 +++++--- 2 files changed, 7 insertions(+), 6 deletions(-) (limited to 'src') diff --git a/src/gtest-port.cc b/src/gtest-port.cc index 1890a802..957595ad 100644 --- a/src/gtest-port.cc +++ b/src/gtest-port.cc @@ -441,8 +441,7 @@ GTestLog::~GTestLog() { #pragma warning(disable: 4996) #endif // _MSC_VER -// Stream capturing is not supported on Windows Mobile. -#if !GTEST_OS_WINDOWS_MOBILE +#if GTEST_HAS_STREAM_REDIRECTION_ // Object that captures an output stream (stdout/stderr). class CapturedStream { @@ -575,7 +574,7 @@ String GetCapturedStdout() { return GetCapturedStream(&g_captured_stdout); } // Stops capturing stderr and returns the captured string. String GetCapturedStderr() { return GetCapturedStream(&g_captured_stderr); } -#endif // !GTEST_OS_WINDOWS_MOBILE +#endif // GTEST_HAS_STREAM_REDIRECTION_ #if GTEST_HAS_DEATH_TEST diff --git a/src/gtest.cc b/src/gtest.cc index f5de645b..fb5bae94 100644 --- a/src/gtest.cc +++ b/src/gtest.cc @@ -2631,13 +2631,15 @@ void ColoredPrintf(GTestColor color, const char* fmt, ...) { GetConsoleScreenBufferInfo(stdout_handle, &buffer_info); const WORD old_color_attrs = buffer_info.wAttributes; + // We need to flush the stream buffers into the console before each + // SetConsoleTextAttribute call lest it affect the text that is already + // printed but has not yet reached the console. + fflush(stdout); SetConsoleTextAttribute(stdout_handle, GetColorAttribute(color) | FOREGROUND_INTENSITY); vprintf(fmt, args); - // Unless we flush stream buffers now the next SetConsoleTextAttribute - // call can reset the color before the output reaches the console. - fflush(stdout); + fflush(stdout); // Restores the text color. SetConsoleTextAttribute(stdout_handle, old_color_attrs); #else -- cgit v1.2.3 From 8d373310561a8d68d2a22ca7c6613deff5fa6e05 Mon Sep 17 00:00:00 2001 From: "zhanyong.wan" Date: Tue, 2 Feb 2010 22:33:34 +0000 Subject: Adds support for alternate path separator on Windows, and make all tests pass with CMake and VC++ 9 (by Manuel Klimek). --- src/gtest-filepath.cc | 61 +++++++++++++++++++++++++++++++++++++++++---------- 1 file changed, 50 insertions(+), 11 deletions(-) (limited to 'src') diff --git a/src/gtest-filepath.cc b/src/gtest-filepath.cc index 515d61c7..27a33424 100644 --- a/src/gtest-filepath.cc +++ b/src/gtest-filepath.cc @@ -63,8 +63,14 @@ namespace testing { namespace internal { #if GTEST_OS_WINDOWS +// On Windows, '\\' is the standard path separator, but many tools and the +// Windows API also accept '/' as an alternate path separator. Unless otherwise +// noted, a file path can contain either kind of path separators, or a mixture +// of them. const char kPathSeparator = '\\'; +const char kAlternatePathSeparator = '/'; const char kPathSeparatorString[] = "\\"; +const char kAlternatePathSeparatorString[] = "/"; #if GTEST_OS_WINDOWS_MOBILE // Windows CE doesn't have a current directory. You should not use // the current directory in tests on Windows CE, but this at least @@ -81,6 +87,15 @@ const char kPathSeparatorString[] = "/"; const char kCurrentDirectoryString[] = "./"; #endif // GTEST_OS_WINDOWS +// Returns whether the given character is a valid path separator. +static bool IsPathSeparator(char c) { +#if GTEST_HAS_ALT_PATH_SEP_ + return (c == kPathSeparator) || (c == kAlternatePathSeparator); +#else + return c == kPathSeparator; +#endif +} + // Returns the current working directory, or "" if unsuccessful. FilePath FilePath::GetCurrentDir() { #if GTEST_OS_WINDOWS_MOBILE @@ -108,6 +123,22 @@ FilePath FilePath::RemoveExtension(const char* extension) const { return *this; } +// Returns a pointer to the last occurence of a valid path separator in +// the FilePath. On Windows, for example, both '/' and '\' are valid path +// separators. Returns NULL if no path separator was found. +const char* FilePath::FindLastPathSeparator() const { + const char* const last_sep = strrchr(c_str(), kPathSeparator); +#if GTEST_HAS_ALT_PATH_SEP_ + const char* const last_alt_sep = strrchr(c_str(), kAlternatePathSeparator); + // Comparing two pointers of which only one is NULL is undefined. + if (last_alt_sep != NULL && + (last_sep == NULL || last_alt_sep > last_sep)) { + return last_alt_sep; + } +#endif + return last_sep; +} + // Returns a copy of the FilePath with the directory part removed. // Example: FilePath("path/to/file").RemoveDirectoryName() returns // FilePath("file"). If there is no directory part ("just_a_file"), it returns @@ -115,7 +146,7 @@ FilePath FilePath::RemoveExtension(const char* extension) const { // returns an empty FilePath (""). // On Windows platform, '\' is the path separator, otherwise it is '/'. FilePath FilePath::RemoveDirectoryName() const { - const char* const last_sep = strrchr(c_str(), kPathSeparator); + const char* const last_sep = FindLastPathSeparator(); return last_sep ? FilePath(String(last_sep + 1)) : *this; } @@ -126,7 +157,7 @@ FilePath FilePath::RemoveDirectoryName() const { // not have a file, like "just/a/dir/", it returns the FilePath unmodified. // On Windows platform, '\' is the path separator, otherwise it is '/'. FilePath FilePath::RemoveFileName() const { - const char* const last_sep = strrchr(c_str(), kPathSeparator); + const char* const last_sep = FindLastPathSeparator(); String dir; if (last_sep) { dir = String(c_str(), last_sep + 1 - c_str()); @@ -219,7 +250,7 @@ bool FilePath::IsRootDirectory() const { // current directory. Handle this properly. return pathname_.length() == 3 && IsAbsolutePath(); #else - return pathname_ == kPathSeparatorString; + return pathname_.length() == 1 && IsPathSeparator(pathname_.c_str()[0]); #endif } @@ -231,9 +262,9 @@ bool FilePath::IsAbsolutePath() const { ((name[0] >= 'a' && name[0] <= 'z') || (name[0] >= 'A' && name[0] <= 'Z')) && name[1] == ':' && - name[2] == kPathSeparator; + IsPathSeparator(name[2]); #else - return name[0] == kPathSeparator; + return IsPathSeparator(name[0]); #endif } @@ -260,7 +291,8 @@ FilePath FilePath::GenerateUniqueFileName(const FilePath& directory, // it is intended to represent a directory. Returns false otherwise. // This does NOT check that a directory (or file) actually exists. bool FilePath::IsDirectory() const { - return pathname_.EndsWith(kPathSeparatorString); + return !pathname_.empty() && + IsPathSeparator(pathname_.c_str()[pathname_.length() - 1]); } // Create directories so that path exists. Returns true if successful or if @@ -305,7 +337,7 @@ bool FilePath::CreateFolder() const { // name, otherwise return the name string unmodified. // On Windows platform, uses \ as the separator, other platforms use /. FilePath FilePath::RemoveTrailingPathSeparator() const { - return pathname_.EndsWith(kPathSeparatorString) + return IsDirectory() ? FilePath(String(pathname_.c_str(), pathname_.length() - 1)) : *this; } @@ -324,12 +356,19 @@ void FilePath::Normalize() { memset(dest_ptr, 0, pathname_.length() + 1); while (*src != '\0') { - *dest_ptr++ = *src; - if (*src != kPathSeparator) + *dest_ptr = *src; + if (!IsPathSeparator(*src)) { src++; - else - while (*src == kPathSeparator) + } else { +#if GTEST_HAS_ALT_PATH_SEP_ + if (*dest_ptr == kAlternatePathSeparator) { + *dest_ptr = kPathSeparator; + } +#endif + while (IsPathSeparator(*src)) src++; + } + dest_ptr++; } *dest_ptr = '\0'; pathname_ = dest; -- cgit v1.2.3 From cfcbc298cd91806e0e3417e03fce42bc4f1fa150 Mon Sep 17 00:00:00 2001 From: vladlosev Date: Wed, 3 Feb 2010 02:27:02 +0000 Subject: Adds Solaris support (by Hady Zalek) --- src/gtest-filepath.cc | 3 ++- src/gtest-port.cc | 17 ++++++++++++----- src/gtest-typed-test.cc | 12 ++++++++++++ 3 files changed, 26 insertions(+), 6 deletions(-) (limited to 'src') diff --git a/src/gtest-filepath.cc b/src/gtest-filepath.cc index 27a33424..c1ef9188 100644 --- a/src/gtest-filepath.cc +++ b/src/gtest-filepath.cc @@ -342,9 +342,10 @@ FilePath FilePath::RemoveTrailingPathSeparator() const { : *this; } -// Normalize removes any redundant separators that might be in the pathname. +// Removes any redundant separators that might be in the pathname. // For example, "bar///foo" becomes "bar/foo". Does not eliminate other // redundancies that might be in a pathname involving "." or "..". +// TODO(wan@google.com): handle Windows network shares (e.g. \\server\share). void FilePath::Normalize() { if (pathname_.c_str() == NULL) { pathname_ = ""; diff --git a/src/gtest-port.cc b/src/gtest-port.cc index 957595ad..7d89e26d 100644 --- a/src/gtest-port.cc +++ b/src/gtest-port.cc @@ -111,8 +111,14 @@ size_t GetThreadCount() { // Implements RE. Currently only needed for death tests. RE::~RE() { - regfree(&partial_regex_); - regfree(&full_regex_); + if (is_valid_) { + // regfree'ing an invalid regex might crash because the content + // of the regex is undefined. Since the regex's are essentially + // the same, one cannot be valid (or invalid) without the other + // being so too. + regfree(&partial_regex_); + regfree(&full_regex_); + } free(const_cast(pattern_)); } @@ -152,9 +158,10 @@ void RE::Init(const char* regex) { // Some implementation of POSIX regex (e.g. on at least some // versions of Cygwin) doesn't accept the empty string as a valid // regex. We change it to an equivalent form "()" to be safe. - const char* const partial_regex = (*regex == '\0') ? "()" : regex; - is_valid_ = (regcomp(&partial_regex_, partial_regex, REG_EXTENDED) == 0) - && is_valid_; + if (is_valid_) { + const char* const partial_regex = (*regex == '\0') ? "()" : regex; + is_valid_ = regcomp(&partial_regex_, partial_regex, REG_EXTENDED) == 0; + } EXPECT_TRUE(is_valid_) << "Regular expression \"" << regex << "\" is not a valid POSIX Extended regular expression."; diff --git a/src/gtest-typed-test.cc b/src/gtest-typed-test.cc index 4a0f657d..3cc4b5de 100644 --- a/src/gtest-typed-test.cc +++ b/src/gtest-typed-test.cc @@ -37,6 +37,14 @@ namespace internal { #if GTEST_HAS_TYPED_TEST_P +// Skips to the first non-space char in str. Returns an empty string if str +// contains only whitespace characters. +static const char* SkipSpaces(const char* str) { + while (isspace(*str)) + str++; + return str; +} + // Verifies that registered_tests match the test names in // defined_test_names_; returns registered_tests if successful, or // aborts the program otherwise. @@ -45,6 +53,10 @@ const char* TypedTestCasePState::VerifyRegisteredTestNames( typedef ::std::set::const_iterator DefinedTestIter; registered_ = true; + // Skip initial whitespace in registered_tests since some + // preprocessors prefix stringizied literals with whitespace. + registered_tests = SkipSpaces(registered_tests); + Message errors; ::std::set tests; for (const char* names = registered_tests; names != NULL; -- cgit v1.2.3 From 9d965bbeefdd8e309e23145b1b475a0961e108a7 Mon Sep 17 00:00:00 2001 From: vladlosev Date: Thu, 11 Feb 2010 06:37:32 +0000 Subject: Adds Solaris support to test scripts. --- src/gtest-port.cc | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) (limited to 'src') diff --git a/src/gtest-port.cc b/src/gtest-port.cc index 7d89e26d..b9504f56 100644 --- a/src/gtest-port.cc +++ b/src/gtest-port.cc @@ -460,8 +460,15 @@ class CapturedStream { char temp_file_path[MAX_PATH + 1] = { '\0' }; // NOLINT ::GetTempPathA(sizeof(temp_dir_path), temp_dir_path); - ::GetTempFileNameA(temp_dir_path, "gtest_redir", 0, temp_file_path); + const UINT success = ::GetTempFileNameA(temp_dir_path, + "gtest_redir", + 0, // Generate unique file name. + temp_file_path); + GTEST_CHECK_(success != 0) + << "Unable to create a temporary file in " << temp_dir_path; const int captured_fd = creat(temp_file_path, _S_IREAD | _S_IWRITE); + GTEST_CHECK_(captured_fd != -1) << "Unable to open temporary file " + << temp_file_path; filename_ = temp_file_path; #else // There's no guarantee that a test has write access to the -- cgit v1.2.3 From 3bef459eac9aa84c579f34249aebc9ff56832054 Mon Sep 17 00:00:00 2001 From: "zhanyong.wan" Date: Wed, 24 Feb 2010 17:19:25 +0000 Subject: Adds threading support (by Miklos Fazekas, Vlad Losev, and Chandler Carruth); adds wide InitGoogleTest to gtest.def (by Vlad Losev); updates the version number (by Zhanyong Wan); updates the release notes for 1.5.0 (by Vlad Losev); removes scons scripts from the distribution (by Zhanyong Wan); adds the cmake build script to the distribution (by Zhanyong Wan); adds fused source files to the distribution (by Vlad Losev and Chandler Carruth). --- src/gtest-internal-inl.h | 5 ++- src/gtest-port.cc | 88 ++++++++++++++++++++++++++++++++++++++++++++++++ src/gtest.cc | 2 +- 3 files changed, 93 insertions(+), 2 deletions(-) (limited to 'src') diff --git a/src/gtest-internal-inl.h b/src/gtest-internal-inl.h index 596dc553..4142e7a7 100644 --- a/src/gtest-internal-inl.h +++ b/src/gtest-internal-inl.h @@ -60,7 +60,7 @@ #include // For DWORD. #endif // GTEST_OS_WINDOWS -#include +#include // NOLINT #include namespace testing { @@ -1228,6 +1228,9 @@ bool ParseNaturalNumber(const ::std::string& str, Integer* number) { // TestResult contains some private methods that should be hidden from // Google Test user but are required for testing. This class allow our tests // to access them. +// +// This class is supplied only for the purpose of testing Google Test's own +// constructs. Do not use it in user tests, either directly or indirectly. class TestResultAccessor { public: static void RecordProperty(TestResult* test_result, diff --git a/src/gtest-port.cc b/src/gtest-port.cc index b9504f56..5994fd54 100644 --- a/src/gtest-port.cc +++ b/src/gtest-port.cc @@ -75,6 +75,94 @@ const int kStdOutFileno = STDOUT_FILENO; const int kStdErrFileno = STDERR_FILENO; #endif // _MSC_VER +#if GTEST_HAS_PTHREAD + +// ThreadStartSemaphore allows the controller thread to pause execution of +// newly created test threads until signalled. Instances of this class must +// be created and destroyed in the controller thread. +ThreadStartSemaphore::ThreadStartSemaphore() : signalled_(false) { + int err = pthread_mutex_init(&mutex_, NULL); + GTEST_CHECK_(err == 0) << "pthread_mutex_init failed with error " << err; + err = pthread_cond_init(&cond_, NULL); + GTEST_CHECK_(err == 0) << "pthread_cond_init failed with error " << err; + pthread_mutex_lock(&mutex_); +} + +ThreadStartSemaphore::~ThreadStartSemaphore() { + // Every ThreadStartSemaphore object must be signalled. It locks + // internal mutex upon creation and Signal unlocks it. + GTEST_CHECK_(signalled_); + + int err = pthread_mutex_destroy(&mutex_); + GTEST_CHECK_(err == 0) + << "pthread_mutex_destroy failed with error " << err; + err = pthread_cond_destroy(&cond_); + GTEST_CHECK_(err == 0) + << "pthread_cond_destroy failed with error " << err; +} + +// Signals to all test threads to start. Must be called from the +// controlling thread. +void ThreadStartSemaphore::Signal() { + signalled_ = true; + int err = pthread_cond_signal(&cond_); + GTEST_CHECK_(err == 0) + << "pthread_cond_signal failed with error " << err; + err = pthread_mutex_unlock(&mutex_); + GTEST_CHECK_(err == 0) + << "pthread_mutex_unlock failed with error " << err; +} + +// Blocks until the controlling thread signals. Should be called from a +// test thread. +void ThreadStartSemaphore::Wait() { + int err = pthread_mutex_lock(&mutex_); + GTEST_CHECK_(err == 0) << "pthread_mutex_lock failed with error " << err; + + while (!signalled_) { + err = pthread_cond_wait(&cond_, &mutex_); + GTEST_CHECK_(err == 0) + << "pthread_cond_wait failed with error " << err; + } + err = pthread_mutex_unlock(&mutex_); + GTEST_CHECK_(err == 0) + << "pthread_mutex_unlock failed with error " << err; +} + +void MutexBase::Lock() { + const int err = pthread_mutex_lock(&mutex_); + GTEST_CHECK_(err == 0) << "pthread_mutex_lock failed with error " << err; + owner_ = pthread_self(); +} + +void MutexBase::Unlock() { + // We don't protect writing to owner_ here, as it's the caller's + // responsibility to ensure that the current thread holds the mutex when + // this is called. + owner_ = 0; + const int err = pthread_mutex_unlock(&mutex_); + GTEST_CHECK_(err == 0) << "pthread_mutex_unlock failed with error " << err; +} + +// Does nothing if the current thread holds the mutex. Otherwise, crashes +// with high probability. +void MutexBase::AssertHeld() const { + GTEST_CHECK_(owner_ == pthread_self()) + << "Current thread is not holding mutex." << this; +} + +Mutex::Mutex() { + owner_ = 0; + const int err = pthread_mutex_init(&mutex_, NULL); + GTEST_CHECK_(err == 0) << "pthread_mutex_init failed with error " << err; +} + +Mutex::~Mutex() { + const int err = pthread_mutex_destroy(&mutex_); + GTEST_CHECK_(err == 0) << "pthread_mutex_destroy failed with error " << err; +} +#endif // GTEST_HAS_PTHREAD + #if GTEST_OS_MAC // Returns the number of threads running in the process, or 0 to indicate that diff --git a/src/gtest.cc b/src/gtest.cc index fb5bae94..3306f3fa 100644 --- a/src/gtest.cc +++ b/src/gtest.cc @@ -342,7 +342,7 @@ void AssertHelper::operator=(const Message& message) const { } // Mutex for linked pointers. -Mutex g_linked_ptr_mutex(Mutex::NO_CONSTRUCTOR_NEEDED_FOR_STATIC_MUTEX); +GTEST_DEFINE_STATIC_MUTEX_(g_linked_ptr_mutex); // Application pathname gotten in InitGoogleTest. String g_executable_path; -- cgit v1.2.3 From 0d27868d0faef474594682f25336229daa89d6d7 Mon Sep 17 00:00:00 2001 From: "zhanyong.wan" Date: Thu, 25 Feb 2010 01:09:07 +0000 Subject: Simplifies the implementation by using std::vector instead of Vector. --- src/gtest-internal-inl.h | 324 ++++++++++------------------------------------- src/gtest-test-part.cc | 16 +-- src/gtest.cc | 186 ++++++++++++++------------- 3 files changed, 162 insertions(+), 364 deletions(-) (limited to 'src') diff --git a/src/gtest-internal-inl.h b/src/gtest-internal-inl.h index 4142e7a7..d14fb6a9 100644 --- a/src/gtest-internal-inl.h +++ b/src/gtest-internal-inl.h @@ -52,7 +52,9 @@ #include // For strtoll/_strtoul64/malloc/free. #include // For memmove. +#include #include +#include #include @@ -243,255 +245,62 @@ Int32 Int32FromEnvOrDie(const char* env_var, Int32 default_val); // method. Assumes that 0 <= shard_index < total_shards. bool ShouldRunTestOnShard(int total_shards, int shard_index, int test_id); -// Vector is an ordered container that supports random access to the -// elements. -// -// We cannot use std::vector, as Visual C++ 7.1's implementation of -// STL has problems compiling when exceptions are disabled. There is -// a hack to work around the problems, but we've seen cases where the -// hack fails to work. -// -// The element type must support copy constructor and operator=. -template // E is the element type. -class Vector { - public: - // Creates an empty Vector. - Vector() : elements_(NULL), capacity_(0), size_(0) {} - - // D'tor. - virtual ~Vector() { Clear(); } - - // Clears the Vector. - void Clear() { - if (elements_ != NULL) { - for (int i = 0; i < size_; i++) { - delete elements_[i]; - } - - free(elements_); - elements_ = NULL; - capacity_ = size_ = 0; - } - } - - // Gets the number of elements. - int size() const { return size_; } - - // Adds an element to the end of the Vector. A copy of the element - // is created using the copy constructor, and then stored in the - // Vector. Changes made to the element in the Vector doesn't affect - // the source object, and vice versa. - void PushBack(const E& element) { Insert(element, size_); } - - // Adds an element to the beginning of this Vector. - void PushFront(const E& element) { Insert(element, 0); } - - // Removes an element from the beginning of this Vector. If the - // result argument is not NULL, the removed element is stored in the - // memory it points to. Otherwise the element is thrown away. - // Returns true iff the vector wasn't empty before the operation. - bool PopFront(E* result) { - if (size_ == 0) - return false; - - if (result != NULL) - *result = GetElement(0); - - Erase(0); - return true; - } - - // Inserts an element at the given index. It's the caller's - // responsibility to ensure that the given index is in the range [0, - // size()]. - void Insert(const E& element, int index) { - GrowIfNeeded(); - MoveElements(index, size_ - index, index + 1); - elements_[index] = new E(element); - size_++; - } +// STL container utilities. - // Erases the element at the specified index, or aborts the program if the - // index is not in range [0, size()). - void Erase(int index) { - GTEST_CHECK_(0 <= index && index < size_) - << "Invalid Vector index " << index << ": must be in range [0, " - << (size_ - 1) << "]."; - - delete elements_[index]; - MoveElements(index + 1, size_ - index - 1, index); - size_--; - } - - // Returns the number of elements that satisfy a given predicate. - // The parameter 'predicate' is a Boolean function or functor that - // accepts a 'const E &', where E is the element type. - template // P is the type of the predicate function/functor - int CountIf(P predicate) const { - int count = 0; - for (int i = 0; i < size_; i++) { - if (predicate(*(elements_[i]))) { - count++; - } - } - - return count; - } - - // Applies a function/functor to each element in the Vector. The - // parameter 'functor' is a function/functor that accepts a 'const - // E &', where E is the element type. This method does not change - // the elements. - template // F is the type of the function/functor - void ForEach(F functor) const { - for (int i = 0; i < size_; i++) { - functor(*(elements_[i])); - } - } - - // Returns the first node whose element satisfies a given predicate, - // or NULL if none is found. The parameter 'predicate' is a - // function/functor that accepts a 'const E &', where E is the - // element type. This method does not change the elements. - template // P is the type of the predicate function/functor. - const E* FindIf(P predicate) const { - for (int i = 0; i < size_; i++) { - if (predicate(*elements_[i])) { - return elements_[i]; - } - } - return NULL; - } - - template - E* FindIf(P predicate) { - for (int i = 0; i < size_; i++) { - if (predicate(*elements_[i])) { - return elements_[i]; - } - } - return NULL; - } - - // Returns the i-th element of the Vector, or aborts the program if i - // is not in range [0, size()). - const E& GetElement(int i) const { - GTEST_CHECK_(0 <= i && i < size_) - << "Invalid Vector index " << i << ": must be in range [0, " - << (size_ - 1) << "]."; - - return *(elements_[i]); - } - - // Returns a mutable reference to the i-th element of the Vector, or - // aborts the program if i is not in range [0, size()). - E& GetMutableElement(int i) { - GTEST_CHECK_(0 <= i && i < size_) - << "Invalid Vector index " << i << ": must be in range [0, " - << (size_ - 1) << "]."; - - return *(elements_[i]); - } - - // Returns the i-th element of the Vector, or default_value if i is not - // in range [0, size()). - E GetElementOr(int i, E default_value) const { - return (i < 0 || i >= size_) ? default_value : *(elements_[i]); - } - - // Swaps the i-th and j-th elements of the Vector. Crashes if i or - // j is invalid. - void Swap(int i, int j) { - GTEST_CHECK_(0 <= i && i < size_) - << "Invalid first swap element " << i << ": must be in range [0, " - << (size_ - 1) << "]."; - GTEST_CHECK_(0 <= j && j < size_) - << "Invalid second swap element " << j << ": must be in range [0, " - << (size_ - 1) << "]."; - - E* const temp = elements_[i]; - elements_[i] = elements_[j]; - elements_[j] = temp; - } - - // Performs an in-place shuffle of a range of this Vector's nodes. - // 'begin' and 'end' are element indices as an STL-style range; - // i.e. [begin, end) are shuffled, where 'end' == size() means to - // shuffle to the end of the Vector. - void ShuffleRange(internal::Random* random, int begin, int end) { - GTEST_CHECK_(0 <= begin && begin <= size_) - << "Invalid shuffle range start " << begin << ": must be in range [0, " - << size_ << "]."; - GTEST_CHECK_(begin <= end && end <= size_) - << "Invalid shuffle range finish " << end << ": must be in range [" - << begin << ", " << size_ << "]."; - - // Fisher-Yates shuffle, from - // http://en.wikipedia.org/wiki/Fisher-Yates_shuffle - for (int range_width = end - begin; range_width >= 2; range_width--) { - const int last_in_range = begin + range_width - 1; - const int selected = begin + random->Generate(range_width); - Swap(selected, last_in_range); - } - } - - // Performs an in-place shuffle of this Vector's nodes. - void Shuffle(internal::Random* random) { - ShuffleRange(random, 0, size()); - } - - // Returns a copy of this Vector. - Vector* Clone() const { - Vector* const clone = new Vector; - clone->Reserve(size_); - for (int i = 0; i < size_; i++) { - clone->PushBack(GetElement(i)); - } - return clone; - } +// Returns the number of elements in the given container that satisfy +// the given predicate. +template +inline int CountIf(const Container& c, Predicate predicate) { + return std::count_if(c.begin(), c.end(), predicate); +} - private: - // Makes sure this Vector's capacity is at least the given value. - void Reserve(int new_capacity) { - if (new_capacity <= capacity_) - return; - - capacity_ = new_capacity; - elements_ = static_cast( - realloc(elements_, capacity_*sizeof(elements_[0]))); - } +// Applies a function/functor to each element in the container. +template +void ForEach(const Container& c, Functor functor) { + std::for_each(c.begin(), c.end(), functor); +} - // Grows the buffer if it is not big enough to hold one more element. - void GrowIfNeeded() { - if (size_ < capacity_) - return; - - // Exponential bump-up is necessary to ensure that inserting N - // elements is O(N) instead of O(N^2). The factor 3/2 means that - // no more than 1/3 of the slots are wasted. - const int new_capacity = 3*(capacity_/2 + 1); - GTEST_CHECK_(new_capacity > capacity_) // Does the new capacity overflow? - << "Cannot grow a Vector with " << capacity_ << " elements already."; - Reserve(new_capacity); - } +// Returns the i-th element of the vector, or default_value if i is not +// in range [0, v.size()). +template +inline E GetElementOr(const std::vector& v, int i, E default_value) { + return (i < 0 || i >= static_cast(v.size())) ? default_value : v[i]; +} - // Moves the give consecutive elements to a new index in the Vector. - void MoveElements(int source, int count, int dest) { - memmove(elements_ + dest, elements_ + source, count*sizeof(elements_[0])); +// Performs an in-place shuffle of a range of the vector's elements. +// 'begin' and 'end' are element indices as an STL-style range; +// i.e. [begin, end) are shuffled, where 'end' == size() means to +// shuffle to the end of the vector. +template +void ShuffleRange(internal::Random* random, int begin, int end, + std::vector* v) { + const int size = static_cast(v->size()); + GTEST_CHECK_(0 <= begin && begin <= size) + << "Invalid shuffle range start " << begin << ": must be in range [0, " + << size << "]."; + GTEST_CHECK_(begin <= end && end <= size) + << "Invalid shuffle range finish " << end << ": must be in range [" + << begin << ", " << size << "]."; + + // Fisher-Yates shuffle, from + // http://en.wikipedia.org/wiki/Fisher-Yates_shuffle + for (int range_width = end - begin; range_width >= 2; range_width--) { + const int last_in_range = begin + range_width - 1; + const int selected = begin + random->Generate(range_width); + std::swap((*v)[selected], (*v)[last_in_range]); } +} - E** elements_; - int capacity_; // The number of elements allocated for elements_. - int size_; // The number of elements; in the range [0, capacity_]. - - // We disallow copying Vector. - GTEST_DISALLOW_COPY_AND_ASSIGN_(Vector); -}; // class Vector +// Performs an in-place shuffle of the vector's elements. +template +inline void Shuffle(internal::Random* random, std::vector* v) { + ShuffleRange(random, 0, v->size(), v); +} // A function for deleting an object. Handy for being used as a // functor. template -static void Delete(T * x) { +static void Delete(T* x) { delete x; } @@ -806,15 +615,15 @@ class UnitTestImpl { // Gets the i-th test case among all the test cases. i can range from 0 to // total_test_case_count() - 1. If i is not in that range, returns NULL. const TestCase* GetTestCase(int i) const { - const int index = test_case_indices_.GetElementOr(i, -1); - return index < 0 ? NULL : test_cases_.GetElement(i); + const int index = GetElementOr(test_case_indices_, i, -1); + return index < 0 ? NULL : test_cases_[i]; } // Gets the i-th test case among all the test cases. i can range from 0 to // total_test_case_count() - 1. If i is not in that range, returns NULL. TestCase* GetMutableTestCase(int i) { - const int index = test_case_indices_.GetElementOr(i, -1); - return index < 0 ? NULL : test_cases_.GetElement(index); + const int index = GetElementOr(test_case_indices_, i, -1); + return index < 0 ? NULL : test_cases_[index]; } // Provides access to the event listener list. @@ -931,7 +740,7 @@ class UnitTestImpl { // Clears the results of all tests, including the ad hoc test. void ClearResult() { - test_cases_.ForEach(TestCase::ClearTestCaseResult); + ForEach(test_cases_, TestCase::ClearTestCaseResult); ad_hoc_test_result_.Clear(); } @@ -957,17 +766,14 @@ class UnitTestImpl { // Returns the vector of environments that need to be set-up/torn-down // before/after the tests are run. - internal::Vector* environments() { return &environments_; } - internal::Vector* environments_in_reverse_order() { - return &environments_in_reverse_order_; - } + std::vector& environments() { return environments_; } // Getters for the per-thread Google Test trace stack. - internal::Vector* gtest_trace_stack() { - return gtest_trace_stack_.pointer(); + std::vector& gtest_trace_stack() { + return *(gtest_trace_stack_.pointer()); } - const internal::Vector* gtest_trace_stack() const { - return gtest_trace_stack_.pointer(); + const std::vector& gtest_trace_stack() const { + return gtest_trace_stack_.get(); } #if GTEST_HAS_DEATH_TEST @@ -1042,20 +848,18 @@ class UnitTestImpl { per_thread_test_part_result_reporter_; // The vector of environments that need to be set-up/torn-down - // before/after the tests are run. environments_in_reverse_order_ - // simply mirrors environments_ in reverse order. - internal::Vector environments_; - internal::Vector environments_in_reverse_order_; + // before/after the tests are run. + std::vector environments_; // The vector of TestCases in their original order. It owns the // elements in the vector. - internal::Vector test_cases_; + std::vector test_cases_; // Provides a level of indirection for the test case list to allow // easy shuffling and restoring the test case order. The i-th // element of this vector is the index of the i-th test case in the // shuffled order. - internal::Vector test_case_indices_; + std::vector test_case_indices_; #if GTEST_HAS_PARAM_TEST // ParameterizedTestRegistry object used to register value-parameterized @@ -1121,7 +925,7 @@ class UnitTestImpl { #endif // GTEST_HAS_DEATH_TEST // A per-thread stack of traces created by the SCOPED_TRACE() macro. - internal::ThreadLocal > gtest_trace_stack_; + internal::ThreadLocal > gtest_trace_stack_; GTEST_DISALLOW_COPY_AND_ASSIGN_(UnitTestImpl); }; // class UnitTestImpl @@ -1242,7 +1046,7 @@ class TestResultAccessor { test_result->ClearTestPartResults(); } - static const Vector& test_part_results( + static const std::vector& test_part_results( const TestResult& test_result) { return test_result.test_part_results(); } diff --git a/src/gtest-test-part.cc b/src/gtest-test-part.cc index 4f36df66..7d9adef7 100644 --- a/src/gtest-test-part.cc +++ b/src/gtest-test-part.cc @@ -64,19 +64,9 @@ std::ostream& operator<<(std::ostream& os, const TestPartResult& result) { << result.message() << std::endl; } -// Constructs an empty TestPartResultArray. -TestPartResultArray::TestPartResultArray() - : array_(new internal::Vector) { -} - -// Destructs a TestPartResultArray. -TestPartResultArray::~TestPartResultArray() { - delete array_; -} - // Appends a TestPartResult to the array. void TestPartResultArray::Append(const TestPartResult& result) { - array_->PushBack(result); + array_.push_back(result); } // Returns the TestPartResult at the given index (0-based). @@ -86,12 +76,12 @@ const TestPartResult& TestPartResultArray::GetTestPartResult(int index) const { internal::posix::Abort(); } - return array_->GetElement(index); + return array_[index]; } // Returns the number of TestPartResult objects in the array. int TestPartResultArray::size() const { - return array_->size(); + return array_.size(); } namespace internal { diff --git a/src/gtest.cc b/src/gtest.cc index 3306f3fa..2a49012e 100644 --- a/src/gtest.cc +++ b/src/gtest.cc @@ -42,8 +42,10 @@ #include #include +#include #include #include +#include #if GTEST_OS_LINUX @@ -132,6 +134,11 @@ namespace testing { +using internal::CountIf; +using internal::ForEach; +using internal::GetElementOr; +using internal::Shuffle; + // Constants. // A test whose test case name or test name matches this filter is @@ -293,11 +300,11 @@ static bool GTestIsInitialized() { return g_init_gtest_count != 0; } // Iterates over a vector of TestCases, keeping a running sum of the // results of calling a given int-returning method on each. // Returns the sum. -static int SumOverTestCaseList(const internal::Vector& case_list, +static int SumOverTestCaseList(const std::vector& case_list, int (TestCase::*method)() const) { int sum = 0; - for (int i = 0; i < case_list.size(); i++) { - sum += (case_list.GetElement(i)->*method)(); + for (size_t i = 0; i < case_list.size(); i++) { + sum += (case_list[i]->*method)(); } return sum; } @@ -673,12 +680,12 @@ void UnitTestImpl::SetTestPartResultReporterForCurrentThread( // Gets the number of successful test cases. int UnitTestImpl::successful_test_case_count() const { - return test_cases_.CountIf(TestCasePassed); + return CountIf(test_cases_, TestCasePassed); } // Gets the number of failed test cases. int UnitTestImpl::failed_test_case_count() const { - return test_cases_.CountIf(TestCaseFailed); + return CountIf(test_cases_, TestCaseFailed); } // Gets the number of all test cases. @@ -689,7 +696,7 @@ int UnitTestImpl::total_test_case_count() const { // Gets the number of all test cases that contain at least one test // that should run. int UnitTestImpl::test_case_to_run_count() const { - return test_cases_.CountIf(ShouldRunTestCase); + return CountIf(test_cases_, ShouldRunTestCase); } // Gets the number of successful tests. @@ -1786,9 +1793,7 @@ String AppendUserMessage(const String& gtest_msg, // Creates an empty TestResult. TestResult::TestResult() - : test_part_results_(new internal::Vector), - test_properties_(new internal::Vector), - death_test_count_(0), + : death_test_count_(0), elapsed_time_(0) { } @@ -1800,24 +1805,24 @@ TestResult::~TestResult() { // range from 0 to total_part_count() - 1. If i is not in that range, // aborts the program. const TestPartResult& TestResult::GetTestPartResult(int i) const { - return test_part_results_->GetElement(i); + return test_part_results_.at(i); } // Returns the i-th test property. i can range from 0 to // test_property_count() - 1. If i is not in that range, aborts the // program. const TestProperty& TestResult::GetTestProperty(int i) const { - return test_properties_->GetElement(i); + return test_properties_.at(i); } // Clears the test part results. void TestResult::ClearTestPartResults() { - test_part_results_->Clear(); + test_part_results_.clear(); } // Adds a test part result to the list. void TestResult::AddTestPartResult(const TestPartResult& test_part_result) { - test_part_results_->PushBack(test_part_result); + test_part_results_.push_back(test_part_result); } // Adds a test property to the list. If a property with the same key as the @@ -1828,11 +1833,11 @@ void TestResult::RecordProperty(const TestProperty& test_property) { return; } internal::MutexLock lock(&test_properites_mutex_); - TestProperty* const property_with_matching_key = - test_properties_->FindIf( - internal::TestPropertyKeyIs(test_property.key())); - if (property_with_matching_key == NULL) { - test_properties_->PushBack(test_property); + const std::vector::iterator property_with_matching_key = + std::find_if(test_properties_.begin(), test_properties_.end(), + internal::TestPropertyKeyIs(test_property.key())); + if (property_with_matching_key == test_properties_.end()) { + test_properties_.push_back(test_property); return; } property_with_matching_key->SetValue(test_property.value()); @@ -1855,8 +1860,8 @@ bool TestResult::ValidateTestProperty(const TestProperty& test_property) { // Clears the object. void TestResult::Clear() { - test_part_results_->Clear(); - test_properties_->Clear(); + test_part_results_.clear(); + test_properties_.clear(); death_test_count_ = 0; elapsed_time_ = 0; } @@ -1877,7 +1882,7 @@ static bool TestPartFatallyFailed(const TestPartResult& result) { // Returns true iff the test fatally failed. bool TestResult::HasFatalFailure() const { - return test_part_results_->CountIf(TestPartFatallyFailed) > 0; + return CountIf(test_part_results_, TestPartFatallyFailed) > 0; } // Returns true iff the test part non-fatally failed. @@ -1887,18 +1892,18 @@ static bool TestPartNonfatallyFailed(const TestPartResult& result) { // Returns true iff the test has a non-fatal failure. bool TestResult::HasNonfatalFailure() const { - return test_part_results_->CountIf(TestPartNonfatallyFailed) > 0; + return CountIf(test_part_results_, TestPartNonfatallyFailed) > 0; } // Gets the number of all test parts. This is the sum of the number // of successful test parts and the number of failed test parts. int TestResult::total_part_count() const { - return test_part_results_->size(); + return test_part_results_.size(); } // Returns the number of the test properties. int TestResult::test_property_count() const { - return test_properties_->size(); + return test_properties_.size(); } // class Test @@ -1982,7 +1987,7 @@ bool Test::HasSameFixtureClass() { // Info about the first test in the current test case. const internal::TestInfoImpl* const first_test_info = - test_case->test_info_list().GetElement(0)->impl(); + test_case->test_info_list()[0]->impl(); const internal::TypeId first_fixture_id = first_test_info->fixture_class_id(); const char* const first_test_name = first_test_info->name(); @@ -2326,26 +2331,26 @@ void TestInfoImpl::Run() { // Gets the number of successful tests in this test case. int TestCase::successful_test_count() const { - return test_info_list_->CountIf(TestPassed); + return CountIf(test_info_list_, TestPassed); } // Gets the number of failed tests in this test case. int TestCase::failed_test_count() const { - return test_info_list_->CountIf(TestFailed); + return CountIf(test_info_list_, TestFailed); } int TestCase::disabled_test_count() const { - return test_info_list_->CountIf(TestDisabled); + return CountIf(test_info_list_, TestDisabled); } // Get the number of tests in this test case that should run. int TestCase::test_to_run_count() const { - return test_info_list_->CountIf(ShouldRunTest); + return CountIf(test_info_list_, ShouldRunTest); } // Gets the number of all tests. int TestCase::total_test_count() const { - return test_info_list_->size(); + return test_info_list_.size(); } // Creates a TestCase with the given name. @@ -2360,8 +2365,6 @@ TestCase::TestCase(const char* a_name, const char* a_comment, Test::TearDownTestCaseFunc tear_down_tc) : name_(a_name), comment_(a_comment), - test_info_list_(new internal::Vector), - test_indices_(new internal::Vector), set_up_tc_(set_up_tc), tear_down_tc_(tear_down_tc), should_run_(false), @@ -2371,28 +2374,28 @@ TestCase::TestCase(const char* a_name, const char* a_comment, // Destructor of TestCase. TestCase::~TestCase() { // Deletes every Test in the collection. - test_info_list_->ForEach(internal::Delete); + ForEach(test_info_list_, internal::Delete); } // Returns the i-th test among all the tests. i can range from 0 to // total_test_count() - 1. If i is not in that range, returns NULL. const TestInfo* TestCase::GetTestInfo(int i) const { - const int index = test_indices_->GetElementOr(i, -1); - return index < 0 ? NULL : test_info_list_->GetElement(index); + const int index = GetElementOr(test_indices_, i, -1); + return index < 0 ? NULL : test_info_list_[index]; } // Returns the i-th test among all the tests. i can range from 0 to // total_test_count() - 1. If i is not in that range, returns NULL. TestInfo* TestCase::GetMutableTestInfo(int i) { - const int index = test_indices_->GetElementOr(i, -1); - return index < 0 ? NULL : test_info_list_->GetElement(index); + const int index = GetElementOr(test_indices_, i, -1); + return index < 0 ? NULL : test_info_list_[index]; } // Adds a test to this test case. Will delete the test upon // destruction of the TestCase object. void TestCase::AddTestInfo(TestInfo * test_info) { - test_info_list_->PushBack(test_info); - test_indices_->PushBack(test_indices_->size()); + test_info_list_.push_back(test_info); + test_indices_.push_back(test_indices_.size()); } // Runs every test in this TestCase. @@ -2422,7 +2425,7 @@ void TestCase::Run() { // Clears the results of all tests in this test case. void TestCase::ClearResult() { - test_info_list_->ForEach(internal::TestInfoImpl::ClearTestResult); + ForEach(test_info_list_, internal::TestInfoImpl::ClearTestResult); } // Returns true iff test passed. @@ -2449,13 +2452,13 @@ bool TestCase::ShouldRunTest(const TestInfo *test_info) { // Shuffles the tests in this test case. void TestCase::ShuffleTests(internal::Random* random) { - test_indices_->Shuffle(random); + Shuffle(random, &test_indices_); } // Restores the test order to before the first shuffle. void TestCase::UnshuffleTests() { - for (int i = 0; i < test_indices_->size(); i++) { - test_indices_->GetMutableElement(i) = i; + for (size_t i = 0; i < test_indices_.size(); i++) { + test_indices_[i] = i; } } @@ -2902,26 +2905,24 @@ class TestEventRepeater : public TestEventListener { // in death test child processes. bool forwarding_enabled_; // The list of listeners that receive events. - Vector listeners_; + std::vector listeners_; GTEST_DISALLOW_COPY_AND_ASSIGN_(TestEventRepeater); }; TestEventRepeater::~TestEventRepeater() { - for (int i = 0; i < listeners_.size(); i++) { - delete listeners_.GetElement(i); - } + ForEach(listeners_, Delete); } void TestEventRepeater::Append(TestEventListener *listener) { - listeners_.PushBack(listener); + listeners_.push_back(listener); } // TODO(vladl@google.com): Factor the search functionality into Vector::Find. TestEventListener* TestEventRepeater::Release(TestEventListener *listener) { - for (int i = 0; i < listeners_.size(); ++i) { - if (listeners_.GetElement(i) == listener) { - listeners_.Erase(i); + for (size_t i = 0; i < listeners_.size(); ++i) { + if (listeners_[i] == listener) { + listeners_.erase(listeners_.begin() + i); return listener; } } @@ -2934,8 +2935,8 @@ TestEventListener* TestEventRepeater::Release(TestEventListener *listener) { #define GTEST_REPEATER_METHOD_(Name, Type) \ void TestEventRepeater::Name(const Type& parameter) { \ if (forwarding_enabled_) { \ - for (int i = 0; i < listeners_.size(); i++) { \ - listeners_.GetElement(i)->Name(parameter); \ + for (size_t i = 0; i < listeners_.size(); i++) { \ + listeners_[i]->Name(parameter); \ } \ } \ } @@ -2945,7 +2946,7 @@ void TestEventRepeater::Name(const Type& parameter) { \ void TestEventRepeater::Name(const Type& parameter) { \ if (forwarding_enabled_) { \ for (int i = static_cast(listeners_.size()) - 1; i >= 0; i--) { \ - listeners_.GetElement(i)->Name(parameter); \ + listeners_[i]->Name(parameter); \ } \ } \ } @@ -2968,8 +2969,8 @@ GTEST_REVERSE_REPEATER_METHOD_(OnTestProgramEnd, UnitTest) void TestEventRepeater::OnTestIterationStart(const UnitTest& unit_test, int iteration) { if (forwarding_enabled_) { - for (int i = 0; i < listeners_.size(); i++) { - listeners_.GetElement(i)->OnTestIterationStart(unit_test, iteration); + for (size_t i = 0; i < listeners_.size(); i++) { + listeners_[i]->OnTestIterationStart(unit_test, iteration); } } } @@ -2978,7 +2979,7 @@ void TestEventRepeater::OnTestIterationEnd(const UnitTest& unit_test, int iteration) { if (forwarding_enabled_) { for (int i = static_cast(listeners_.size()) - 1; i >= 0; i--) { - listeners_.GetElement(i)->OnTestIterationEnd(unit_test, iteration); + listeners_[i]->OnTestIterationEnd(unit_test, iteration); } } } @@ -3532,8 +3533,7 @@ Environment* UnitTest::AddEnvironment(Environment* env) { return NULL; } - impl_->environments()->PushBack(env); - impl_->environments_in_reverse_order()->PushFront(env); + impl_->environments().push_back(env); return env; } @@ -3564,12 +3564,11 @@ void UnitTest::AddTestPartResult(TestPartResult::Type result_type, msg << message; internal::MutexLock lock(&mutex_); - if (impl_->gtest_trace_stack()->size() > 0) { + if (impl_->gtest_trace_stack().size() > 0) { msg << "\n" << GTEST_NAME_ << " trace:"; - for (int i = 0; i < impl_->gtest_trace_stack()->size(); i++) { - const internal::TraceInfo& trace = - impl_->gtest_trace_stack()->GetElement(i); + for (int i = impl_->gtest_trace_stack().size(); i > 0; --i) { + const internal::TraceInfo& trace = impl_->gtest_trace_stack()[i - 1]; msg << "\n" << internal::FormatFileLocation(trace.file, trace.line) << " " << trace.message; } @@ -3734,14 +3733,14 @@ UnitTest::~UnitTest() { // L < mutex_ void UnitTest::PushGTestTrace(const internal::TraceInfo& trace) { internal::MutexLock lock(&mutex_); - impl_->gtest_trace_stack()->PushFront(trace); + impl_->gtest_trace_stack().push_back(trace); } // Pops a trace from the per-thread Google Test trace stack. // L < mutex_ void UnitTest::PopGTestTrace() { internal::MutexLock lock(&mutex_); - impl_->gtest_trace_stack()->PopFront(NULL); + impl_->gtest_trace_stack().pop_back(); } namespace internal { @@ -3787,10 +3786,10 @@ UnitTestImpl::UnitTestImpl(UnitTest* parent) UnitTestImpl::~UnitTestImpl() { // Deletes every TestCase. - test_cases_.ForEach(internal::Delete); + ForEach(test_cases_, internal::Delete); // Deletes every Environment. - environments_.ForEach(internal::Delete); + ForEach(environments_, internal::Delete); delete os_stack_trace_getter_; } @@ -3882,9 +3881,11 @@ TestCase* UnitTestImpl::GetTestCase(const char* test_case_name, Test::SetUpTestCaseFunc set_up_tc, Test::TearDownTestCaseFunc tear_down_tc) { // Can we find a TestCase with the given name? - TestCase** test_case = test_cases_.FindIf(TestCaseNameIs(test_case_name)); + const std::vector::const_iterator test_case = + std::find_if(test_cases_.begin(), test_cases_.end(), + TestCaseNameIs(test_case_name)); - if (test_case != NULL) + if (test_case != test_cases_.end()) return *test_case; // No. Let's create one. @@ -3898,18 +3899,20 @@ TestCase* UnitTestImpl::GetTestCase(const char* test_case_name, // defined so far. This only works when the test cases haven't // been shuffled. Otherwise we may end up running a death test // after a non-death test. - test_cases_.Insert(new_test_case, ++last_death_test_case_); + ++last_death_test_case_; + test_cases_.insert(test_cases_.begin() + last_death_test_case_, + new_test_case); } else { // No. Appends to the end of the list. - test_cases_.PushBack(new_test_case); + test_cases_.push_back(new_test_case); } - test_case_indices_.PushBack(test_case_indices_.size()); + test_case_indices_.push_back(test_case_indices_.size()); return new_test_case; } // Helpers for setting up / tearing down the given environment. They -// are for use in the Vector::ForEach() method. +// are for use in the ForEach() function. static void SetUpEnvironment(Environment* env) { env->SetUp(); } static void TearDownEnvironment(Environment* env) { env->TearDown(); } @@ -4005,7 +4008,7 @@ int UnitTestImpl::RunAllTests() { if (has_tests_to_run) { // Sets up all environments beforehand. repeater->OnEnvironmentsSetUpStart(*parent_); - environments_.ForEach(SetUpEnvironment); + ForEach(environments_, SetUpEnvironment); repeater->OnEnvironmentsSetUpEnd(*parent_); // Runs the tests only if there was no fatal failure during global @@ -4019,7 +4022,8 @@ int UnitTestImpl::RunAllTests() { // Tears down all environments in reverse order afterwards. repeater->OnEnvironmentsTearDownStart(*parent_); - environments_in_reverse_order_.ForEach(TearDownEnvironment); + std::for_each(environments_.rbegin(), environments_.rend(), + TearDownEnvironment); repeater->OnEnvironmentsTearDownEnd(*parent_); } @@ -4165,13 +4169,13 @@ int UnitTestImpl::FilterTests(ReactionToSharding shard_tests) { // this shard. int num_runnable_tests = 0; int num_selected_tests = 0; - for (int i = 0; i < test_cases_.size(); i++) { - TestCase* const test_case = test_cases_.GetElement(i); + for (size_t i = 0; i < test_cases_.size(); i++) { + TestCase* const test_case = test_cases_[i]; const String &test_case_name = test_case->name(); test_case->set_should_run(false); - for (int j = 0; j < test_case->test_info_list().size(); j++) { - TestInfo* const test_info = test_case->test_info_list().GetElement(j); + for (size_t j = 0; j < test_case->test_info_list().size(); j++) { + TestInfo* const test_info = test_case->test_info_list()[j]; const String test_name(test_info->name()); // A test is disabled if test case name or test name matches // kDisableTestFilter. @@ -4208,13 +4212,13 @@ int UnitTestImpl::FilterTests(ReactionToSharding shard_tests) { // Prints the names of the tests matching the user-specified filter flag. void UnitTestImpl::ListTestsMatchingFilter() { - for (int i = 0; i < test_cases_.size(); i++) { - const TestCase* const test_case = test_cases_.GetElement(i); + for (size_t i = 0; i < test_cases_.size(); i++) { + const TestCase* const test_case = test_cases_[i]; bool printed_test_case_name = false; - for (int j = 0; j < test_case->test_info_list().size(); j++) { + for (size_t j = 0; j < test_case->test_info_list().size(); j++) { const TestInfo* const test_info = - test_case->test_info_list().GetElement(j); + test_case->test_info_list()[j]; if (test_info->matches_filter()) { if (!printed_test_case_name) { printed_test_case_name = true; @@ -4262,25 +4266,25 @@ TestResult* UnitTestImpl::current_test_result() { // making sure that death tests are still run first. void UnitTestImpl::ShuffleTests() { // Shuffles the death test cases. - test_case_indices_.ShuffleRange(random(), 0, last_death_test_case_ + 1); + ShuffleRange(random(), 0, last_death_test_case_ + 1, &test_case_indices_); // Shuffles the non-death test cases. - test_case_indices_.ShuffleRange(random(), last_death_test_case_ + 1, - test_cases_.size()); + ShuffleRange(random(), last_death_test_case_ + 1, + test_cases_.size(), &test_case_indices_); // Shuffles the tests inside each test case. - for (int i = 0; i < test_cases_.size(); i++) { - test_cases_.GetElement(i)->ShuffleTests(random()); + for (size_t i = 0; i < test_cases_.size(); i++) { + test_cases_[i]->ShuffleTests(random()); } } // Restores the test cases and tests to their order before the first shuffle. void UnitTestImpl::UnshuffleTests() { - for (int i = 0; i < test_cases_.size(); i++) { + for (size_t i = 0; i < test_cases_.size(); i++) { // Unshuffles the tests in each test case. - test_cases_.GetElement(i)->UnshuffleTests(); + test_cases_[i]->UnshuffleTests(); // Resets the index of each test case. - test_case_indices_.GetMutableElement(i) = i; + test_case_indices_[i] = i; } } -- cgit v1.2.3 From 4879aac74991ad4552c5ed2ec178af511f3feb5e Mon Sep 17 00:00:00 2001 From: "zhanyong.wan" Date: Thu, 25 Feb 2010 21:40:08 +0000 Subject: Simplifies the threading implementation and improves some comments. --- src/gtest-port.cc | 66 ++++++++----------------------------------------------- 1 file changed, 9 insertions(+), 57 deletions(-) (limited to 'src') diff --git a/src/gtest-port.cc b/src/gtest-port.cc index 5994fd54..1c4c1bdc 100644 --- a/src/gtest-port.cc +++ b/src/gtest-port.cc @@ -81,10 +81,8 @@ const int kStdErrFileno = STDERR_FILENO; // newly created test threads until signalled. Instances of this class must // be created and destroyed in the controller thread. ThreadStartSemaphore::ThreadStartSemaphore() : signalled_(false) { - int err = pthread_mutex_init(&mutex_, NULL); - GTEST_CHECK_(err == 0) << "pthread_mutex_init failed with error " << err; - err = pthread_cond_init(&cond_, NULL); - GTEST_CHECK_(err == 0) << "pthread_cond_init failed with error " << err; + GTEST_CHECK_POSIX_SUCCESS_(pthread_mutex_init(&mutex_, NULL)); + GTEST_CHECK_POSIX_SUCCESS_(pthread_cond_init(&cond_, NULL)); pthread_mutex_lock(&mutex_); } @@ -92,75 +90,29 @@ ThreadStartSemaphore::~ThreadStartSemaphore() { // Every ThreadStartSemaphore object must be signalled. It locks // internal mutex upon creation and Signal unlocks it. GTEST_CHECK_(signalled_); - - int err = pthread_mutex_destroy(&mutex_); - GTEST_CHECK_(err == 0) - << "pthread_mutex_destroy failed with error " << err; - err = pthread_cond_destroy(&cond_); - GTEST_CHECK_(err == 0) - << "pthread_cond_destroy failed with error " << err; + GTEST_CHECK_POSIX_SUCCESS_(pthread_mutex_destroy(&mutex_)); + GTEST_CHECK_POSIX_SUCCESS_(pthread_cond_destroy(&cond_)); } // Signals to all test threads to start. Must be called from the // controlling thread. void ThreadStartSemaphore::Signal() { signalled_ = true; - int err = pthread_cond_signal(&cond_); - GTEST_CHECK_(err == 0) - << "pthread_cond_signal failed with error " << err; - err = pthread_mutex_unlock(&mutex_); - GTEST_CHECK_(err == 0) - << "pthread_mutex_unlock failed with error " << err; + GTEST_CHECK_POSIX_SUCCESS_(pthread_cond_signal(&cond_)); + GTEST_CHECK_POSIX_SUCCESS_(pthread_mutex_unlock(&mutex_)); } // Blocks until the controlling thread signals. Should be called from a // test thread. void ThreadStartSemaphore::Wait() { - int err = pthread_mutex_lock(&mutex_); - GTEST_CHECK_(err == 0) << "pthread_mutex_lock failed with error " << err; + GTEST_CHECK_POSIX_SUCCESS_(pthread_mutex_lock(&mutex_)); while (!signalled_) { - err = pthread_cond_wait(&cond_, &mutex_); - GTEST_CHECK_(err == 0) - << "pthread_cond_wait failed with error " << err; + GTEST_CHECK_POSIX_SUCCESS_(pthread_cond_wait(&cond_, &mutex_)); } - err = pthread_mutex_unlock(&mutex_); - GTEST_CHECK_(err == 0) - << "pthread_mutex_unlock failed with error " << err; -} - -void MutexBase::Lock() { - const int err = pthread_mutex_lock(&mutex_); - GTEST_CHECK_(err == 0) << "pthread_mutex_lock failed with error " << err; - owner_ = pthread_self(); -} - -void MutexBase::Unlock() { - // We don't protect writing to owner_ here, as it's the caller's - // responsibility to ensure that the current thread holds the mutex when - // this is called. - owner_ = 0; - const int err = pthread_mutex_unlock(&mutex_); - GTEST_CHECK_(err == 0) << "pthread_mutex_unlock failed with error " << err; + GTEST_CHECK_POSIX_SUCCESS_(pthread_mutex_unlock(&mutex_)); } -// Does nothing if the current thread holds the mutex. Otherwise, crashes -// with high probability. -void MutexBase::AssertHeld() const { - GTEST_CHECK_(owner_ == pthread_self()) - << "Current thread is not holding mutex." << this; -} - -Mutex::Mutex() { - owner_ = 0; - const int err = pthread_mutex_init(&mutex_, NULL); - GTEST_CHECK_(err == 0) << "pthread_mutex_init failed with error " << err; -} - -Mutex::~Mutex() { - const int err = pthread_mutex_destroy(&mutex_); - GTEST_CHECK_(err == 0) << "pthread_mutex_destroy failed with error " << err; -} #endif // GTEST_HAS_PTHREAD #if GTEST_OS_MAC -- cgit v1.2.3 From 6baed3c1173c19f5d43af75798d3685853fbe8bd Mon Sep 17 00:00:00 2001 From: "zhanyong.wan" Date: Thu, 25 Feb 2010 22:15:27 +0000 Subject: Fixes MSVC warnings in 64-bit mode. --- src/gtest-internal-inl.h | 4 ++-- src/gtest-test-part.cc | 2 +- src/gtest.cc | 21 +++++++++++---------- 3 files changed, 14 insertions(+), 13 deletions(-) (limited to 'src') diff --git a/src/gtest-internal-inl.h b/src/gtest-internal-inl.h index d14fb6a9..269798a8 100644 --- a/src/gtest-internal-inl.h +++ b/src/gtest-internal-inl.h @@ -251,7 +251,7 @@ bool ShouldRunTestOnShard(int total_shards, int shard_index, int test_id); // the given predicate. template inline int CountIf(const Container& c, Predicate predicate) { - return std::count_if(c.begin(), c.end(), predicate); + return static_cast(std::count_if(c.begin(), c.end(), predicate)); } // Applies a function/functor to each element in the container. @@ -294,7 +294,7 @@ void ShuffleRange(internal::Random* random, int begin, int end, // Performs an in-place shuffle of the vector's elements. template inline void Shuffle(internal::Random* random, std::vector* v) { - ShuffleRange(random, 0, v->size(), v); + ShuffleRange(random, 0, static_cast(v->size()), v); } // A function for deleting an object. Handy for being used as a diff --git a/src/gtest-test-part.cc b/src/gtest-test-part.cc index 7d9adef7..5d183a44 100644 --- a/src/gtest-test-part.cc +++ b/src/gtest-test-part.cc @@ -81,7 +81,7 @@ const TestPartResult& TestPartResultArray::GetTestPartResult(int index) const { // Returns the number of TestPartResult objects in the array. int TestPartResultArray::size() const { - return array_.size(); + return static_cast(array_.size()); } namespace internal { diff --git a/src/gtest.cc b/src/gtest.cc index 2a49012e..987e6904 100644 --- a/src/gtest.cc +++ b/src/gtest.cc @@ -690,7 +690,7 @@ int UnitTestImpl::failed_test_case_count() const { // Gets the number of all test cases. int UnitTestImpl::total_test_case_count() const { - return test_cases_.size(); + return static_cast(test_cases_.size()); } // Gets the number of all test cases that contain at least one test @@ -1898,12 +1898,12 @@ bool TestResult::HasNonfatalFailure() const { // Gets the number of all test parts. This is the sum of the number // of successful test parts and the number of failed test parts. int TestResult::total_part_count() const { - return test_part_results_.size(); + return static_cast(test_part_results_.size()); } // Returns the number of the test properties. int TestResult::test_property_count() const { - return test_properties_.size(); + return static_cast(test_properties_.size()); } // class Test @@ -2350,7 +2350,7 @@ int TestCase::test_to_run_count() const { // Gets the number of all tests. int TestCase::total_test_count() const { - return test_info_list_.size(); + return static_cast(test_info_list_.size()); } // Creates a TestCase with the given name. @@ -2395,7 +2395,7 @@ TestInfo* TestCase::GetMutableTestInfo(int i) { // destruction of the TestCase object. void TestCase::AddTestInfo(TestInfo * test_info) { test_info_list_.push_back(test_info); - test_indices_.push_back(test_indices_.size()); + test_indices_.push_back(static_cast(test_indices_.size())); } // Runs every test in this TestCase. @@ -2458,7 +2458,7 @@ void TestCase::ShuffleTests(internal::Random* random) { // Restores the test order to before the first shuffle. void TestCase::UnshuffleTests() { for (size_t i = 0; i < test_indices_.size(); i++) { - test_indices_[i] = i; + test_indices_[i] = static_cast(i); } } @@ -3567,7 +3567,8 @@ void UnitTest::AddTestPartResult(TestPartResult::Type result_type, if (impl_->gtest_trace_stack().size() > 0) { msg << "\n" << GTEST_NAME_ << " trace:"; - for (int i = impl_->gtest_trace_stack().size(); i > 0; --i) { + for (int i = static_cast(impl_->gtest_trace_stack().size()); + i > 0; --i) { const internal::TraceInfo& trace = impl_->gtest_trace_stack()[i - 1]; msg << "\n" << internal::FormatFileLocation(trace.file, trace.line) << " " << trace.message; @@ -3907,7 +3908,7 @@ TestCase* UnitTestImpl::GetTestCase(const char* test_case_name, test_cases_.push_back(new_test_case); } - test_case_indices_.push_back(test_case_indices_.size()); + test_case_indices_.push_back(static_cast(test_case_indices_.size())); return new_test_case; } @@ -4270,7 +4271,7 @@ void UnitTestImpl::ShuffleTests() { // Shuffles the non-death test cases. ShuffleRange(random(), last_death_test_case_ + 1, - test_cases_.size(), &test_case_indices_); + static_cast(test_cases_.size()), &test_case_indices_); // Shuffles the tests inside each test case. for (size_t i = 0; i < test_cases_.size(); i++) { @@ -4284,7 +4285,7 @@ void UnitTestImpl::UnshuffleTests() { // Unshuffles the tests in each test case. test_cases_[i]->UnshuffleTests(); // Resets the index of each test case. - test_case_indices_[i] = i; + test_case_indices_[i] = static_cast(i); } } -- cgit v1.2.3 From c85a77a6ab0ef05c4a9a8554bf8c5e1c8687cc75 Mon Sep 17 00:00:00 2001 From: "zhanyong.wan" Date: Fri, 26 Feb 2010 05:42:53 +0000 Subject: Simplifies ThreadStartSemaphore's implementation. --- src/gtest-port.cc | 40 ---------------------------------------- 1 file changed, 40 deletions(-) (limited to 'src') diff --git a/src/gtest-port.cc b/src/gtest-port.cc index 1c4c1bdc..b9504f56 100644 --- a/src/gtest-port.cc +++ b/src/gtest-port.cc @@ -75,46 +75,6 @@ const int kStdOutFileno = STDOUT_FILENO; const int kStdErrFileno = STDERR_FILENO; #endif // _MSC_VER -#if GTEST_HAS_PTHREAD - -// ThreadStartSemaphore allows the controller thread to pause execution of -// newly created test threads until signalled. Instances of this class must -// be created and destroyed in the controller thread. -ThreadStartSemaphore::ThreadStartSemaphore() : signalled_(false) { - GTEST_CHECK_POSIX_SUCCESS_(pthread_mutex_init(&mutex_, NULL)); - GTEST_CHECK_POSIX_SUCCESS_(pthread_cond_init(&cond_, NULL)); - pthread_mutex_lock(&mutex_); -} - -ThreadStartSemaphore::~ThreadStartSemaphore() { - // Every ThreadStartSemaphore object must be signalled. It locks - // internal mutex upon creation and Signal unlocks it. - GTEST_CHECK_(signalled_); - GTEST_CHECK_POSIX_SUCCESS_(pthread_mutex_destroy(&mutex_)); - GTEST_CHECK_POSIX_SUCCESS_(pthread_cond_destroy(&cond_)); -} - -// Signals to all test threads to start. Must be called from the -// controlling thread. -void ThreadStartSemaphore::Signal() { - signalled_ = true; - GTEST_CHECK_POSIX_SUCCESS_(pthread_cond_signal(&cond_)); - GTEST_CHECK_POSIX_SUCCESS_(pthread_mutex_unlock(&mutex_)); -} - -// Blocks until the controlling thread signals. Should be called from a -// test thread. -void ThreadStartSemaphore::Wait() { - GTEST_CHECK_POSIX_SUCCESS_(pthread_mutex_lock(&mutex_)); - - while (!signalled_) { - GTEST_CHECK_POSIX_SUCCESS_(pthread_cond_wait(&cond_, &mutex_)); - } - GTEST_CHECK_POSIX_SUCCESS_(pthread_mutex_unlock(&mutex_)); -} - -#endif // GTEST_HAS_PTHREAD - #if GTEST_OS_MAC // Returns the number of threads running in the process, or 0 to indicate that -- cgit v1.2.3 From 12a92c26fc0e0de81f687dbe739a6aa24f37f9dd Mon Sep 17 00:00:00 2001 From: "zhanyong.wan" Date: Thu, 4 Mar 2010 22:15:53 +0000 Subject: Renames ThreadStartSempahore to Notificaton (by Vlad Losev); adds threading tests for SCOPED_TRACE() (by Vlad Losev); replaces native pthread calls with gtest's threading constructs (by Vlad Losev); fixes flakiness in CountedDestructor (by Vlad Losev); minor MSVC 7.1 clean-up (by Zhanyong Wan). --- src/gtest-death-test.cc | 2 -- 1 file changed, 2 deletions(-) (limited to 'src') diff --git a/src/gtest-death-test.cc b/src/gtest-death-test.cc index 5f2fbbcf..3b73b01d 100644 --- a/src/gtest-death-test.cc +++ b/src/gtest-death-test.cc @@ -1037,8 +1037,6 @@ bool DefaultDeathTestFactory::Create(const char* statement, const RE* regex, // Splits a given string on a given delimiter, populating a given // vector with the fields. GTEST_HAS_DEATH_TEST implies that we have // ::std::string, so we can use it here. -// TODO(vladl@google.com): Get rid of std::vector to be able to build on -// Visual C++ 7.1 with exceptions disabled. static void SplitString(const ::std::string& str, char delimiter, ::std::vector< ::std::string>* dest) { ::std::vector< ::std::string> parsed; -- cgit v1.2.3 From 83589cca345d2f03d93b0555437aa480e0ed6699 Mon Sep 17 00:00:00 2001 From: "zhanyong.wan" Date: Fri, 5 Mar 2010 21:21:06 +0000 Subject: Supports building gtest as a DLL (by Vlad Losev). --- src/gtest_main.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src') diff --git a/src/gtest_main.cc b/src/gtest_main.cc index d20c02fd..6d4d22d2 100644 --- a/src/gtest_main.cc +++ b/src/gtest_main.cc @@ -31,7 +31,7 @@ #include -int main(int argc, char **argv) { +GTEST_API_ int main(int argc, char **argv) { std::cout << "Running main() from gtest_main.cc\n"; testing::InitGoogleTest(&argc, argv); -- cgit v1.2.3 From 9f0824b0a61b50fd40e47da2387cd9b3f872ce47 Mon Sep 17 00:00:00 2001 From: "zhanyong.wan" Date: Mon, 22 Mar 2010 21:23:51 +0000 Subject: Adds missing gtest DLL exports. --- src/gtest-internal-inl.h | 72 +++++++++++++++++++++++++++++------------------- src/gtest_main.cc | 2 +- 2 files changed, 45 insertions(+), 29 deletions(-) (limited to 'src') diff --git a/src/gtest-internal-inl.h b/src/gtest-internal-inl.h index 269798a8..855b2155 100644 --- a/src/gtest-internal-inl.h +++ b/src/gtest-internal-inl.h @@ -78,7 +78,7 @@ namespace internal { // The value of GetTestTypeId() as seen from within the Google Test // library. This is solely for testing GetTestTypeId(). -extern const TypeId kTestTypeIdInGoogleTest; +GTEST_API_ extern const TypeId kTestTypeIdInGoogleTest; // Names of the flags (needed for parsing Google Test flags). const char kAlsoRunDisabledTestsFlag[] = "also_run_disabled_tests"; @@ -98,8 +98,25 @@ const char kThrowOnFailureFlag[] = "throw_on_failure"; // A valid random seed must be in [1, kMaxRandomSeed]. const int kMaxRandomSeed = 99999; +// g_help_flag is true iff the --help flag or an equivalent form is +// specified on the command line. +GTEST_API_ extern bool g_help_flag; + // Returns the current time in milliseconds. -TimeInMillis GetTimeInMillis(); +GTEST_API_ TimeInMillis GetTimeInMillis(); + +// Returns true iff Google Test should use colors in the output. +GTEST_API_ bool ShouldUseColor(bool stdout_is_tty); + +// Formats the given time in milliseconds as seconds. +GTEST_API_ std::string FormatTimeInMillisAsSeconds(TimeInMillis ms); + +// 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 +// true. On failure, returns false without changing *value. +GTEST_API_ bool ParseInt32Flag( + const char* str, const char* flag, Int32* value); // Returns a random seed in range [1, kMaxRandomSeed] based on the // given --gtest_random_seed flag value. @@ -199,7 +216,7 @@ class GTestFlagSaver { // If the code_point is not a valid Unicode code point // (i.e. outside of Unicode range U+0 to U+10FFFF) it will be output // as '(Invalid Unicode 0xXXXXXXXX)'. -char* CodePointToUtf8(UInt32 code_point, char* str); +GTEST_API_ char* CodePointToUtf8(UInt32 code_point, char* str); // Converts a wide string to a narrow string in UTF-8 encoding. // The wide string is assumed to have the following encoding: @@ -214,10 +231,7 @@ char* CodePointToUtf8(UInt32 code_point, char* str); // as '(Invalid Unicode 0xXXXXXXXX)'. If the string is in UTF16 encoding // and contains invalid UTF-16 surrogate pairs, values in those pairs // will be encoded as individual Unicode characters from Basic Normal Plane. -String WideStringToUtf8(const wchar_t* str, int num_chars); - -// Returns the number of active threads, or 0 when there is an error. -size_t GetThreadCount(); +GTEST_API_ String WideStringToUtf8(const wchar_t* str, int num_chars); // Reads the GTEST_SHARD_STATUS_FILE environment variable, and creates the file // if the variable is present. If a file already exists at this location, this @@ -231,19 +245,21 @@ void WriteToShardStatusFileIfNeeded(); // an error and exits. If in_subprocess_for_death_test, sharding is // disabled because it must only be applied to the original test // process. Otherwise, we could filter out death tests we intended to execute. -bool ShouldShard(const char* total_shards_str, const char* shard_index_str, - bool in_subprocess_for_death_test); +GTEST_API_ bool ShouldShard(const char* total_shards_str, + const char* shard_index_str, + bool in_subprocess_for_death_test); // Parses the environment variable var as an Int32. If it is unset, // returns default_val. If it is not an Int32, prints an error and // and aborts. -Int32 Int32FromEnvOrDie(const char* env_var, Int32 default_val); +GTEST_API_ Int32 Int32FromEnvOrDie(const char* env_var, Int32 default_val); // Given the total number of shards, the shard index, and the test id, // returns true iff the test should be run on this shard. The test id is // some arbitrary but unique non-negative integer assigned to each test // method. Assumes that 0 <= shard_index < total_shards. -bool ShouldRunTestOnShard(int total_shards, int shard_index, int test_id); +GTEST_API_ bool ShouldRunTestOnShard( + int total_shards, int shard_index, int test_id); // STL container utilities. @@ -413,7 +429,7 @@ class TestInfoImpl { // test filter using either GTEST_FILTER or --gtest_filter. If both // the variable and the flag are present, the latter overrides the // former. -class UnitTestOptions { +class GTEST_API_ UnitTestOptions { public: // Functions for processing the gtest_output flag. @@ -455,7 +471,7 @@ class UnitTestOptions { // Returns the current application's name, removing directory path if that // is present. Used by UnitTestOptions::GetOutputFile. -FilePath GetCurrentExecutableName(); +GTEST_API_ FilePath GetCurrentExecutableName(); // The role interface for getting the OS stack trace as a string. class OsStackTraceGetterInterface { @@ -546,7 +562,7 @@ class DefaultPerThreadTestPartResultReporter // the methods under a mutex, as this class is not accessible by a // user and the UnitTest class that delegates work to this class does // proper locking. -class UnitTestImpl { +class GTEST_API_ UnitTestImpl { public: explicit UnitTestImpl(UnitTest* parent); virtual ~UnitTestImpl(); @@ -938,24 +954,24 @@ inline UnitTestImpl* GetUnitTestImpl() { // Internal helper functions for implementing the simple regular // expression matcher. -bool IsInSet(char ch, const char* str); -bool IsDigit(char ch); -bool IsPunct(char ch); -bool IsRepeat(char ch); -bool IsWhiteSpace(char ch); -bool IsWordChar(char ch); -bool IsValidEscape(char ch); -bool AtomMatchesChar(bool escaped, char pattern, char ch); -bool ValidateRegex(const char* regex); -bool MatchRegexAtHead(const char* regex, const char* str); -bool MatchRepetitionAndRegexAtHead( +GTEST_API_ bool IsInSet(char ch, const char* str); +GTEST_API_ bool IsDigit(char ch); +GTEST_API_ bool IsPunct(char ch); +GTEST_API_ bool IsRepeat(char ch); +GTEST_API_ bool IsWhiteSpace(char ch); +GTEST_API_ bool IsWordChar(char ch); +GTEST_API_ bool IsValidEscape(char ch); +GTEST_API_ bool AtomMatchesChar(bool escaped, char pattern, char ch); +GTEST_API_ bool ValidateRegex(const char* regex); +GTEST_API_ bool MatchRegexAtHead(const char* regex, const char* str); +GTEST_API_ bool MatchRepetitionAndRegexAtHead( bool escaped, char ch, char repeat, const char* regex, const char* str); -bool MatchRegexAnywhere(const char* regex, const char* str); +GTEST_API_ bool MatchRegexAnywhere(const char* regex, const char* str); // Parses the command line for Google Test flags, without initializing // other parts of Google Test. -void ParseGoogleTestFlagsOnly(int* argc, char** argv); -void ParseGoogleTestFlagsOnly(int* argc, wchar_t** argv); +GTEST_API_ void ParseGoogleTestFlagsOnly(int* argc, char** argv); +GTEST_API_ void ParseGoogleTestFlagsOnly(int* argc, wchar_t** argv); #if GTEST_HAS_DEATH_TEST diff --git a/src/gtest_main.cc b/src/gtest_main.cc index 6d4d22d2..d20c02fd 100644 --- a/src/gtest_main.cc +++ b/src/gtest_main.cc @@ -31,7 +31,7 @@ #include -GTEST_API_ int main(int argc, char **argv) { +int main(int argc, char **argv) { std::cout << "Running main() from gtest_main.cc\n"; testing::InitGoogleTest(&argc, argv); -- cgit v1.2.3 From 17e4860871d225bce440a3ca9ef1bdaceaed60d8 Mon Sep 17 00:00:00 2001 From: "zhanyong.wan" Date: Tue, 23 Mar 2010 19:53:07 +0000 Subject: Enables death tests on AIX, by Hady Zalek. --- src/gtest.cc | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'src') diff --git a/src/gtest.cc b/src/gtest.cc index 987e6904..342d4582 100644 --- a/src/gtest.cc +++ b/src/gtest.cc @@ -1805,6 +1805,8 @@ TestResult::~TestResult() { // range from 0 to total_part_count() - 1. If i is not in that range, // aborts the program. const TestPartResult& TestResult::GetTestPartResult(int i) const { + if (i < 0 || i >= total_part_count()) + internal::posix::Abort(); return test_part_results_.at(i); } @@ -1812,6 +1814,8 @@ const TestPartResult& TestResult::GetTestPartResult(int i) const { // test_property_count() - 1. If i is not in that range, aborts the // program. const TestProperty& TestResult::GetTestProperty(int i) const { + if (i < 0 || i >= test_property_count()) + internal::posix::Abort(); return test_properties_.at(i); } -- cgit v1.2.3 From e05489605fc58736f837563db1fc33f9131ee810 Mon Sep 17 00:00:00 2001 From: vladlosev Date: Thu, 22 Apr 2010 11:44:59 +0000 Subject: Implements color output in GNU Screen sessions (issue 277). --- src/gtest.cc | 1 + 1 file changed, 1 insertion(+) (limited to 'src') diff --git a/src/gtest.cc b/src/gtest.cc index 342d4582..302c3276 100644 --- a/src/gtest.cc +++ b/src/gtest.cc @@ -2592,6 +2592,7 @@ bool ShouldUseColor(bool stdout_is_tty) { String::CStringEquals(term, "xterm") || String::CStringEquals(term, "xterm-color") || String::CStringEquals(term, "xterm-256color") || + String::CStringEquals(term, "screen") || String::CStringEquals(term, "linux") || String::CStringEquals(term, "cygwin"); return stdout_is_tty && term_supports_color; -- cgit v1.2.3 From c476707e82f8db4974912594fbf419326973cb2a Mon Sep 17 00:00:00 2001 From: vladlosev Date: Wed, 5 May 2010 13:09:35 +0000 Subject: Improves support for building Google Test as Windows DLL. --- src/gtest-death-test.cc | 9 ++++++++- src/gtest-internal-inl.h | 2 +- src/gtest_main.cc | 2 +- 3 files changed, 10 insertions(+), 3 deletions(-) (limited to 'src') diff --git a/src/gtest-death-test.cc b/src/gtest-death-test.cc index 3b73b01d..66bf1898 100644 --- a/src/gtest-death-test.cc +++ b/src/gtest-death-test.cc @@ -418,7 +418,14 @@ void DeathTestImpl::Abort(AbortReason reason) { const char status_ch = reason == TEST_DID_NOT_DIE ? kDeathTestLived : kDeathTestReturned; GTEST_DEATH_TEST_CHECK_SYSCALL_(posix::Write(write_fd(), &status_ch, 1)); - GTEST_DEATH_TEST_CHECK_SYSCALL_(posix::Close(write_fd())); + // We are leaking the descriptor here because on some platforms (i.e., + // when built as Windows DLL), destructors of global objects will still + // run after calling _exit(). On such systems, write_fd_ will be + // indirectly closed from the destructor of UnitTestImpl, causing double + // close if it is also closed here. On debug configurations, double close + // may assert. As there are no in-process buffers to flush here, we are + // relying on the OS to close the descriptor after the process terminates + // when the destructors are not run. _exit(1); // Exits w/o any normal exit hooks (we were supposed to crash) } diff --git a/src/gtest-internal-inl.h b/src/gtest-internal-inl.h index 855b2155..a3cda754 100644 --- a/src/gtest-internal-inl.h +++ b/src/gtest-internal-inl.h @@ -977,7 +977,7 @@ GTEST_API_ void ParseGoogleTestFlagsOnly(int* argc, wchar_t** argv); // Returns the message describing the last system error, regardless of the // platform. -String GetLastErrnoDescription(); +GTEST_API_ String GetLastErrnoDescription(); #if GTEST_OS_WINDOWS // Provides leak-safe Windows kernel handle ownership. diff --git a/src/gtest_main.cc b/src/gtest_main.cc index d20c02fd..6d4d22d2 100644 --- a/src/gtest_main.cc +++ b/src/gtest_main.cc @@ -31,7 +31,7 @@ #include -int main(int argc, char **argv) { +GTEST_API_ int main(int argc, char **argv) { std::cout << "Running main() from gtest_main.cc\n"; testing::InitGoogleTest(&argc, argv); -- cgit v1.2.3 From 2ccea88c99d1ae23383d1b8eb3680a4a4d2edd66 Mon Sep 17 00:00:00 2001 From: "zhanyong.wan" Date: Mon, 10 May 2010 17:11:58 +0000 Subject: Moves the universal printer from gmock to gtest and refactors the cmake script for reusing in gmock (by Vlad Losev). --- src/gtest-all.cc | 1 + src/gtest-printers.cc | 318 ++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 319 insertions(+) create mode 100644 src/gtest-printers.cc (limited to 'src') diff --git a/src/gtest-all.cc b/src/gtest-all.cc index fe34765f..f3e22dd7 100644 --- a/src/gtest-all.cc +++ b/src/gtest-all.cc @@ -43,5 +43,6 @@ #include "src/gtest-death-test.cc" #include "src/gtest-filepath.cc" #include "src/gtest-port.cc" +#include "src/gtest-printers.cc" #include "src/gtest-test-part.cc" #include "src/gtest-typed-test.cc" diff --git a/src/gtest-printers.cc b/src/gtest-printers.cc new file mode 100644 index 00000000..611180e7 --- /dev/null +++ b/src/gtest-printers.cc @@ -0,0 +1,318 @@ +// Copyright 2007, 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. +// +// Author: wan@google.com (Zhanyong Wan) + +// Google Test - The Google C++ Testing Framework +// +// This file implements a universal value printer that can print a +// value of any type T: +// +// void ::testing::internal::UniversalPrinter::Print(value, ostream_ptr); +// +// It uses the << operator when possible, and prints the bytes in the +// object otherwise. A user can override its behavior for a class +// type Foo by defining either operator<<(::std::ostream&, const Foo&) +// or void PrintTo(const Foo&, ::std::ostream*) in the namespace that +// defines Foo. + +#include +#include +#include +#include // NOLINT +#include +#include + +namespace testing { + +namespace { + +using ::std::ostream; + +#if GTEST_OS_WINDOWS_MOBILE // Windows CE does not define _snprintf_s. +#define snprintf _snprintf +#elif _MSC_VER >= 1400 // VC 8.0 and later deprecate snprintf and _snprintf. +#define snprintf _snprintf_s +#elif _MSC_VER +#define snprintf _snprintf +#endif // GTEST_OS_WINDOWS_MOBILE + +// Prints a segment of bytes in the given object. +void PrintByteSegmentInObjectTo(const unsigned char* obj_bytes, size_t start, + size_t count, ostream* os) { + char text[5] = ""; + for (size_t i = 0; i != count; i++) { + const size_t j = start + i; + if (i != 0) { + // Organizes the bytes into groups of 2 for easy parsing by + // human. + if ((j % 2) == 0) { + *os << " "; + } + } + snprintf(text, sizeof(text), "%02X", obj_bytes[j]); + *os << text; + } +} + +// Prints the bytes in the given value to the given ostream. +void PrintBytesInObjectToImpl(const unsigned char* obj_bytes, size_t count, + ostream* os) { + // Tells the user how big the object is. + *os << count << "-byte object <"; + + const size_t kThreshold = 132; + const size_t kChunkSize = 64; + // If the object size is bigger than kThreshold, we'll have to omit + // some details by printing only the first and the last kChunkSize + // bytes. + // TODO(wan): let the user control the threshold using a flag. + if (count < kThreshold) { + PrintByteSegmentInObjectTo(obj_bytes, 0, count, os); + } else { + PrintByteSegmentInObjectTo(obj_bytes, 0, kChunkSize, os); + *os << " ... "; + // Rounds up to 2-byte boundary. + const size_t resume_pos = (count - kChunkSize + 1)/2*2; + PrintByteSegmentInObjectTo(obj_bytes, resume_pos, count - resume_pos, os); + } + *os << ">"; +} + +} // namespace + +namespace internal2 { + +// Delegates to PrintBytesInObjectToImpl() to print the bytes in the +// given object. The delegation simplifies the implementation, which +// uses the << operator and thus is easier done outside of the +// ::testing::internal namespace, which contains a << operator that +// sometimes conflicts with the one in STL. +void PrintBytesInObjectTo(const unsigned char* obj_bytes, size_t count, + ostream* os) { + PrintBytesInObjectToImpl(obj_bytes, count, os); +} + +} // namespace internal2 + +namespace internal { + +// Prints a wide char as a char literal without the quotes, escaping it +// when necessary. +static void PrintAsWideCharLiteralTo(wchar_t c, ostream* os) { + switch (c) { + case L'\0': + *os << "\\0"; + break; + case L'\'': + *os << "\\'"; + break; + case L'\?': + *os << "\\?"; + break; + case L'\\': + *os << "\\\\"; + break; + case L'\a': + *os << "\\a"; + break; + case L'\b': + *os << "\\b"; + break; + case L'\f': + *os << "\\f"; + break; + case L'\n': + *os << "\\n"; + break; + case L'\r': + *os << "\\r"; + break; + case L'\t': + *os << "\\t"; + break; + case L'\v': + *os << "\\v"; + break; + default: + // Checks whether c is printable or not. Printable characters are in + // the range [0x20,0x7E]. + // We test the value of c directly instead of calling isprint(), as + // isprint() is buggy on Windows mobile. + if (0x20 <= c && c <= 0x7E) { + *os << static_cast(c); + } else { + // Buffer size enough for the maximum number of digits and \0. + char text[2 * sizeof(unsigned long) + 1] = ""; + snprintf(text, sizeof(text), "%lX", static_cast(c)); + *os << "\\x" << text; + } + } +} + +// Prints a char as if it's part of a string literal, escaping it when +// necessary. +static void PrintAsWideStringLiteralTo(wchar_t c, ostream* os) { + switch (c) { + case L'\'': + *os << "'"; + break; + case L'"': + *os << "\\\""; + break; + default: + PrintAsWideCharLiteralTo(c, os); + } +} + +// Prints a char as a char literal without the quotes, escaping it +// when necessary. +static void PrintAsCharLiteralTo(char c, ostream* os) { + PrintAsWideCharLiteralTo(static_cast(c), os); +} + +// Prints a char as if it's part of a string literal, escaping it when +// necessary. +static void PrintAsStringLiteralTo(char c, ostream* os) { + PrintAsWideStringLiteralTo(static_cast(c), os); +} + +// Prints a char and its code. The '\0' char is printed as "'\\0'", +// other unprintable characters are also properly escaped using the +// standard C++ escape sequence. +void PrintCharTo(char c, int char_code, ostream* os) { + *os << "'"; + PrintAsCharLiteralTo(c, os); + *os << "'"; + if (c != '\0') + *os << " (" << char_code << ")"; +} + +// Prints a wchar_t as a symbol if it is printable or as its internal +// code otherwise and also as its decimal code (except for L'\0'). +// The L'\0' char is printed as "L'\\0'". The decimal code is printed +// as signed integer when wchar_t is implemented by the compiler +// as a signed type and is printed as an unsigned integer when wchar_t +// is implemented as an unsigned type. +void PrintTo(wchar_t wc, ostream* os) { + *os << "L'"; + PrintAsWideCharLiteralTo(wc, os); + *os << "'"; + if (wc != L'\0') { + // Type Int64 is used because it provides more storage than wchar_t thus + // when the compiler converts signed or unsigned implementation of wchar_t + // to Int64 it fills higher bits with either zeros or the sign bit + // passing it to operator <<() as either signed or unsigned integer. + *os << " (" << static_cast(wc) << ")"; + } +} + +// Prints the given array of characters to the ostream. +// The array starts at *begin, the length is len, it may include '\0' characters +// and may not be null-terminated. +static void PrintCharsAsStringTo(const char* begin, size_t len, ostream* os) { + *os << "\""; + for (size_t index = 0; index < len; ++index) { + PrintAsStringLiteralTo(begin[index], os); + } + *os << "\""; +} + +// Prints a (const) char array of 'len' elements, starting at address 'begin'. +void UniversalPrintArray(const char* begin, size_t len, ostream* os) { + PrintCharsAsStringTo(begin, len, os); +} + +// Prints the given array of wide characters to the ostream. +// The array starts at *begin, the length is len, it may include L'\0' +// characters and may not be null-terminated. +static void PrintWideCharsAsStringTo(const wchar_t* begin, size_t len, + ostream* os) { + *os << "L\""; + for (size_t index = 0; index < len; ++index) { + PrintAsWideStringLiteralTo(begin[index], os); + } + *os << "\""; +} + +// Prints the given C string to the ostream. +void PrintTo(const char* s, ostream* os) { + if (s == NULL) { + *os << "NULL"; + } else { + *os << implicit_cast(s) << " pointing to "; + PrintCharsAsStringTo(s, strlen(s), os); + } +} + +// MSVC compiler can be configured to define whar_t as a typedef +// of unsigned short. Defining an overload for const wchar_t* in that case +// would cause pointers to unsigned shorts be printed as wide strings, +// possibly accessing more memory than intended and causing invalid +// memory accesses. MSVC defines _NATIVE_WCHAR_T_DEFINED symbol when +// wchar_t is implemented as a native type. +#if !defined(_MSC_VER) || defined(_NATIVE_WCHAR_T_DEFINED) +// Prints the given wide C string to the ostream. +void PrintTo(const wchar_t* s, ostream* os) { + if (s == NULL) { + *os << "NULL"; + } else { + *os << implicit_cast(s) << " pointing to "; + PrintWideCharsAsStringTo(s, wcslen(s), os); + } +} +#endif // wchar_t is native + +// Prints a ::string object. +#if GTEST_HAS_GLOBAL_STRING +void PrintStringTo(const ::string& s, ostream* os) { + PrintCharsAsStringTo(s.data(), s.size(), os); +} +#endif // GTEST_HAS_GLOBAL_STRING + +void PrintStringTo(const ::std::string& s, ostream* os) { + PrintCharsAsStringTo(s.data(), s.size(), os); +} + +// Prints a ::wstring object. +#if GTEST_HAS_GLOBAL_WSTRING +void PrintWideStringTo(const ::wstring& s, ostream* os) { + PrintWideCharsAsStringTo(s.data(), s.size(), os); +} +#endif // GTEST_HAS_GLOBAL_WSTRING + +#if GTEST_HAS_STD_WSTRING +void PrintWideStringTo(const ::std::wstring& s, ostream* os) { + PrintWideCharsAsStringTo(s.data(), s.size(), os); +} +#endif // GTEST_HAS_STD_WSTRING + +} // namespace internal + +} // namespace testing -- cgit v1.2.3 From 65f2fd5920ad2b761e48d070b32540af1a09c531 Mon Sep 17 00:00:00 2001 From: vladlosev Date: Mon, 17 May 2010 16:35:55 +0000 Subject: Fixes a typo in comments. --- src/gtest-internal-inl.h | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) (limited to 'src') diff --git a/src/gtest-internal-inl.h b/src/gtest-internal-inl.h index a3cda754..9e63aed7 100644 --- a/src/gtest-internal-inl.h +++ b/src/gtest-internal-inl.h @@ -739,11 +739,11 @@ class GTEST_API_ UnitTestImpl { } // Registers all parameterized tests defined using TEST_P and - // INSTANTIATE_TEST_P, creating regular tests for each test/parameter - // combination. This method can be called more then once; it has - // guards protecting from registering the tests more then once. - // If value-parameterized tests are disabled, RegisterParameterizedTests - // is present but does nothing. + // INSTANTIATE_TEST_CASE_P, creating regular tests for each test/parameter + // combination. This method can be called more then once; it has guards + // protecting from registering the tests more then once. If + // value-parameterized tests are disabled, RegisterParameterizedTests is + // present but does nothing. void RegisterParameterizedTests(); // Runs all tests in this UnitTest object, prints the result, and -- cgit v1.2.3 From 1097b54dcf1cd393e64ec0adf54301a575bbbc1c Mon Sep 17 00:00:00 2001 From: vladlosev Date: Tue, 18 May 2010 21:13:48 +0000 Subject: Implements printing parameters of failed parameterized tests (issue 71). --- src/gtest.cc | 33 +++++++++++++++++++-------------- 1 file changed, 19 insertions(+), 14 deletions(-) (limited to 'src') diff --git a/src/gtest.cc b/src/gtest.cc index 302c3276..e136a18b 100644 --- a/src/gtest.cc +++ b/src/gtest.cc @@ -2658,6 +2658,19 @@ void ColoredPrintf(GTestColor color, const char* fmt, ...) { va_end(args); } +void PrintFullTestCommentIfPresent(const TestInfo& test_info) { + const char* const comment = test_info.comment(); + const char* const test_case_comment = test_info.test_case_comment(); + + if (test_case_comment[0] != '\0' || comment[0] != '\0') { + printf(", where %s", test_case_comment); + if (test_case_comment[0] != '\0' && comment[0] != '\0') { + printf(" and "); + } + printf("%s", comment); + } +} + // This class implements the TestEventListener interface. // // Class PrettyUnitTestResultPrinter is copyable. @@ -2748,11 +2761,7 @@ void PrettyUnitTestResultPrinter::OnTestCaseStart(const TestCase& test_case) { void PrettyUnitTestResultPrinter::OnTestStart(const TestInfo& test_info) { ColoredPrintf(COLOR_GREEN, "[ RUN ] "); PrintTestName(test_case_name_.c_str(), test_info.name()); - if (test_info.comment()[0] == '\0') { - printf("\n"); - } else { - printf(", where %s\n", test_info.comment()); - } + printf("\n"); fflush(stdout); } @@ -2775,6 +2784,9 @@ void PrettyUnitTestResultPrinter::OnTestEnd(const TestInfo& test_info) { ColoredPrintf(COLOR_RED, "[ FAILED ] "); } PrintTestName(test_case_name_.c_str(), test_info.name()); + if (test_info.result()->Failed()) + PrintFullTestCommentIfPresent(test_info); + if (GTEST_FLAG(print_time)) { printf(" (%s ms)\n", internal::StreamableToString( test_info.result()->elapsed_time()).c_str()); @@ -2823,15 +2835,8 @@ void PrettyUnitTestResultPrinter::PrintFailedTests(const UnitTest& unit_test) { } ColoredPrintf(COLOR_RED, "[ FAILED ] "); printf("%s.%s", test_case.name(), test_info.name()); - if (test_case.comment()[0] != '\0' || - test_info.comment()[0] != '\0') { - printf(", where %s", test_case.comment()); - if (test_case.comment()[0] != '\0' && - test_info.comment()[0] != '\0') { - printf(" and "); - } - } - printf("%s\n", test_info.comment()); + PrintFullTestCommentIfPresent(test_info); + printf("\n"); } } } -- cgit v1.2.3 From 682c89f7557eb53c7359b6cbf3670c05165f2419 Mon Sep 17 00:00:00 2001 From: "zhanyong.wan" Date: Wed, 16 Jun 2010 22:47:13 +0000 Subject: Makes gtest report failures in ad hoc test assertions executed before RUN_ALL_TESTS(). --- src/gtest-internal-inl.h | 8 ++++++-- src/gtest.cc | 4 +++- 2 files changed, 9 insertions(+), 3 deletions(-) (limited to 'src') diff --git a/src/gtest-internal-inl.h b/src/gtest-internal-inl.h index 9e63aed7..c5608c99 100644 --- a/src/gtest-internal-inl.h +++ b/src/gtest-internal-inl.h @@ -754,9 +754,13 @@ class GTEST_API_ UnitTestImpl { // doesn't apply there.) int RunAllTests(); - // Clears the results of all tests, including the ad hoc test. - void ClearResult() { + // Clears the results of all tests, except the ad hoc tests. + void ClearNonAdHocTestResult() { ForEach(test_cases_, TestCase::ClearTestCaseResult); + } + + // Clears the results of ad-hoc test assertions. + void ClearAdHocTestResult() { ad_hoc_test_result_.Clear(); } diff --git a/src/gtest.cc b/src/gtest.cc index e136a18b..cb2c34c7 100644 --- a/src/gtest.cc +++ b/src/gtest.cc @@ -3999,7 +3999,9 @@ int UnitTestImpl::RunAllTests() { // Repeats forever if the repeat count is negative. const bool forever = repeat < 0; for (int i = 0; forever || i != repeat; i++) { - ClearResult(); + // We want to preserve failures generated by ad-hoc test + // assertions executed before RUN_ALL_TESTS(). + ClearNonAdHocTestResult(); const TimeInMillis start = GetTimeInMillis(); -- cgit v1.2.3 From 5e4214cee4f74d25f1d89dc1c95dc247ed20b6c8 Mon Sep 17 00:00:00 2001 From: "zhanyong.wan" Date: Thu, 8 Jul 2010 21:44:59 +0000 Subject: Makes gtest_break_on_failure_unittest work on minGW (by vladl); improves the NULL-dereferencing hack to work with LLVM (by chandlerc). --- src/gtest.cc | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) (limited to 'src') diff --git a/src/gtest.cc b/src/gtest.cc index cb2c34c7..9855f53d 100644 --- a/src/gtest.cc +++ b/src/gtest.cc @@ -3608,7 +3608,11 @@ void UnitTest::AddTestPartResult(TestPartResult::Type result_type, // the --gtest_catch_exceptions flags are specified. DebugBreak(); #else - *static_cast(NULL) = 1; + // Dereference NULL through a volatile pointer to prevent the compiler + // from removing. We use this rather than abort() or __builtin_trap() for + // portability: Symbian doesn't implement abort() well, and some debuggers + // don't correctly trap abort(). + *static_cast(NULL) = 1; #endif // GTEST_OS_WINDOWS } else if (GTEST_FLAG(throw_on_failure)) { #if GTEST_HAS_EXCEPTIONS -- cgit v1.2.3 From 447ed6474deca82844b211e57503579ab1c560f0 Mon Sep 17 00:00:00 2001 From: vladlosev Date: Wed, 14 Jul 2010 22:36:31 +0000 Subject: Fixes warnings when built by GCC with -Wswitch-default. Original patch by Zhixu Liu (zhixu.liu@gmail.com). --- src/gtest.cc | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'src') diff --git a/src/gtest.cc b/src/gtest.cc index 9855f53d..a64327b9 100644 --- a/src/gtest.cc +++ b/src/gtest.cc @@ -2504,9 +2504,9 @@ static const char * TestPartResultTypeToString(TestPartResult::Type type) { #else return "Failure\n"; #endif + default: + return "Unknown result type"; } - - return "Unknown result type"; } // Prints a TestPartResult to a String. -- cgit v1.2.3 From e2a7f03b80fc0e9e6a6f36acb43776509486a6d4 Mon Sep 17 00:00:00 2001 From: "zhanyong.wan" Date: Wed, 21 Jul 2010 22:15:17 +0000 Subject: Allows EXPECT_EQ to accept arguments that don't have operator << (by Zhanyong Wan). Allows a user to customize how the universal printer prints a pointer of a specific type by overloading << (by Zhanyong Wan). Works around a bug in Cymbian's C++ compiler (by Vlad Losev). --- src/gtest-printers.cc | 114 ++++++++++++++++++++++++++++++-------------------- src/gtest.cc | 42 ------------------- 2 files changed, 69 insertions(+), 87 deletions(-) (limited to 'src') diff --git a/src/gtest-printers.cc b/src/gtest-printers.cc index 611180e7..1d97b534 100644 --- a/src/gtest-printers.cc +++ b/src/gtest-printers.cc @@ -123,10 +123,31 @@ void PrintBytesInObjectTo(const unsigned char* obj_bytes, size_t count, namespace internal { -// Prints a wide char as a char literal without the quotes, escaping it -// when necessary. -static void PrintAsWideCharLiteralTo(wchar_t c, ostream* os) { - switch (c) { +// Depending on the value of a char (or wchar_t), we print it in one +// of three formats: +// - as is if it's a printable ASCII (e.g. 'a', '2', ' '), +// - as a hexidecimal escape sequence (e.g. '\x7F'), or +// - as a special escape sequence (e.g. '\r', '\n'). +enum CharFormat { + kAsIs, + kHexEscape, + kSpecialEscape +}; + +// Returns true if c is a printable ASCII character. We test the +// value of c directly instead of calling isprint(), which is buggy on +// Windows Mobile. +static inline bool IsPrintableAscii(wchar_t c) { + return 0x20 <= c && c <= 0x7E; +} + +// Prints a wide or narrow char c as a character literal without the +// quotes, escaping it when necessary; returns how c was formatted. +// The template argument UnsignedChar is the unsigned version of Char, +// which is the type of c. +template +static CharFormat PrintAsCharLiteralTo(Char c, ostream* os) { + switch (static_cast(c)) { case L'\0': *os << "\\0"; break; @@ -161,19 +182,15 @@ static void PrintAsWideCharLiteralTo(wchar_t c, ostream* os) { *os << "\\v"; break; default: - // Checks whether c is printable or not. Printable characters are in - // the range [0x20,0x7E]. - // We test the value of c directly instead of calling isprint(), as - // isprint() is buggy on Windows mobile. - if (0x20 <= c && c <= 0x7E) { + if (IsPrintableAscii(c)) { *os << static_cast(c); + return kAsIs; } else { - // Buffer size enough for the maximum number of digits and \0. - char text[2 * sizeof(unsigned long) + 1] = ""; - snprintf(text, sizeof(text), "%lX", static_cast(c)); - *os << "\\x" << text; + *os << String::Format("\\x%X", static_cast(c)); + return kHexEscape; } } + return kSpecialEscape; } // Prints a char as if it's part of a string literal, escaping it when @@ -187,50 +204,57 @@ static void PrintAsWideStringLiteralTo(wchar_t c, ostream* os) { *os << "\\\""; break; default: - PrintAsWideCharLiteralTo(c, os); + PrintAsCharLiteralTo(c, os); } } -// Prints a char as a char literal without the quotes, escaping it -// when necessary. -static void PrintAsCharLiteralTo(char c, ostream* os) { - PrintAsWideCharLiteralTo(static_cast(c), os); -} - // Prints a char as if it's part of a string literal, escaping it when // necessary. -static void PrintAsStringLiteralTo(char c, ostream* os) { +static void PrintAsNarrowStringLiteralTo(char c, ostream* os) { PrintAsWideStringLiteralTo(static_cast(c), os); } -// Prints a char and its code. The '\0' char is printed as "'\\0'", -// other unprintable characters are also properly escaped using the -// standard C++ escape sequence. -void PrintCharTo(char c, int char_code, ostream* os) { +// Prints a wide or narrow character c and its code. '\0' is printed +// as "'\\0'", other unprintable characters are also properly escaped +// using the standard C++ escape sequence. The template argument +// UnsignedChar is the unsigned version of Char, which is the type of c. +template +void PrintCharAndCodeTo(Char c, ostream* os) { + // First, print c as a literal in the most readable form we can find. + *os << ((sizeof(c) > 1) ? "L'" : "'"); + const CharFormat format = PrintAsCharLiteralTo(c, os); *os << "'"; - PrintAsCharLiteralTo(c, os); - *os << "'"; - if (c != '\0') - *os << " (" << char_code << ")"; + + // To aid user debugging, we also print c's code in decimal, unless + // it's 0 (in which case c was printed as '\\0', making the code + // obvious). + if (c == 0) + return; + *os << " (" << String::Format("%d", c).c_str(); + + // For more convenience, we print c's code again in hexidecimal, + // unless c was already printed in the form '\x##' or the code is in + // [1, 9]. + if (format == kHexEscape || (1 <= c && c <= 9)) { + // Do nothing. + } else { + *os << String::Format(", 0x%X", + static_cast(c)).c_str(); + } + *os << ")"; +} + +void PrintTo(unsigned char c, ::std::ostream* os) { + PrintCharAndCodeTo(c, os); +} +void PrintTo(signed char c, ::std::ostream* os) { + PrintCharAndCodeTo(c, os); } // Prints a wchar_t as a symbol if it is printable or as its internal -// code otherwise and also as its decimal code (except for L'\0'). -// The L'\0' char is printed as "L'\\0'". The decimal code is printed -// as signed integer when wchar_t is implemented by the compiler -// as a signed type and is printed as an unsigned integer when wchar_t -// is implemented as an unsigned type. +// code otherwise and also as its code. L'\0' is printed as "L'\\0'". void PrintTo(wchar_t wc, ostream* os) { - *os << "L'"; - PrintAsWideCharLiteralTo(wc, os); - *os << "'"; - if (wc != L'\0') { - // Type Int64 is used because it provides more storage than wchar_t thus - // when the compiler converts signed or unsigned implementation of wchar_t - // to Int64 it fills higher bits with either zeros or the sign bit - // passing it to operator <<() as either signed or unsigned integer. - *os << " (" << static_cast(wc) << ")"; - } + PrintCharAndCodeTo(wc, os); } // Prints the given array of characters to the ostream. @@ -239,7 +263,7 @@ void PrintTo(wchar_t wc, ostream* os) { static void PrintCharsAsStringTo(const char* begin, size_t len, ostream* os) { *os << "\""; for (size_t index = 0; index < len; ++index) { - PrintAsStringLiteralTo(begin[index], os); + PrintAsNarrowStringLiteralTo(begin[index], os); } *os << "\""; } diff --git a/src/gtest.cc b/src/gtest.cc index a64327b9..03799a2b 100644 --- a/src/gtest.cc +++ b/src/gtest.cc @@ -918,48 +918,6 @@ Message& Message::operator <<(const ::wstring& wstr) { } #endif // GTEST_HAS_GLOBAL_WSTRING -namespace internal { - -// Formats a value to be used in a failure message. - -// For a char value, we print it as a C++ char literal and as an -// unsigned integer (both in decimal and in hexadecimal). -String FormatForFailureMessage(char ch) { - const unsigned int ch_as_uint = ch; - // A String object cannot contain '\0', so we print "\\0" when ch is - // '\0'. - return String::Format("'%s' (%u, 0x%X)", - ch ? String::Format("%c", ch).c_str() : "\\0", - ch_as_uint, ch_as_uint); -} - -// For a wchar_t value, we print it as a C++ wchar_t literal and as an -// unsigned integer (both in decimal and in hexidecimal). -String FormatForFailureMessage(wchar_t wchar) { - // The C++ standard doesn't specify the exact size of the wchar_t - // type. It just says that it shall have the same size as another - // integral type, called its underlying type. - // - // Therefore, in order to print a wchar_t value in the numeric form, - // we first convert it to the largest integral type (UInt64) and - // then print the converted value. - // - // We use streaming to print the value as "%llu" doesn't work - // correctly with MSVC 7.1. - const UInt64 wchar_as_uint64 = wchar; - Message msg; - // A String object cannot contain '\0', so we print "\\0" when wchar is - // L'\0'. - char buffer[32]; // CodePointToUtf8 requires a buffer that big. - msg << "L'" - << (wchar ? CodePointToUtf8(static_cast(wchar), buffer) : "\\0") - << "' (" << wchar_as_uint64 << ", 0x" << ::std::setbase(16) - << wchar_as_uint64 << ")"; - return msg.GetString(); -} - -} // namespace internal - // AssertionResult constructors. // Used in EXPECT_TRUE/FALSE(assertion_result). AssertionResult::AssertionResult(const AssertionResult& other) -- cgit v1.2.3 From e96d247b20116646f343b6e2ec37af154f655977 Mon Sep 17 00:00:00 2001 From: vladlosev Date: Thu, 22 Jul 2010 21:07:19 +0000 Subject: Allows Google Test to build on OSes other then a pre-determined set and implements GTEST_HAS_POSIX_REGEX condition for compatibility with them. --- src/gtest-port.cc | 1 + 1 file changed, 1 insertion(+) (limited to 'src') diff --git a/src/gtest-port.cc b/src/gtest-port.cc index b9504f56..5eec8fa7 100644 --- a/src/gtest-port.cc +++ b/src/gtest-port.cc @@ -34,6 +34,7 @@ #include #include #include +#include #if GTEST_OS_WINDOWS_MOBILE #include // For TerminateProcess() -- cgit v1.2.3 From 5c4b472bbf8c81fc3d52fc69a92f174821a96280 Mon Sep 17 00:00:00 2001 From: "zhanyong.wan" Date: Mon, 9 Aug 2010 18:19:15 +0000 Subject: Makes gtest print enums as integers instead of hex dumps (by Zhanyong Wan); improves the hex dump format (by Zhanyong Wan); gets rid of class TestInfoImpl (by Zhanyong Wan); adds exception handling (by Vlad Losev). --- src/gtest-internal-inl.h | 89 +--------- src/gtest-printers.cc | 7 +- src/gtest.cc | 426 +++++++++++++++++++++-------------------------- 3 files changed, 197 insertions(+), 325 deletions(-) (limited to 'src') diff --git a/src/gtest-internal-inl.h b/src/gtest-internal-inl.h index c5608c99..d1e0b59a 100644 --- a/src/gtest-internal-inl.h +++ b/src/gtest-internal-inl.h @@ -340,85 +340,6 @@ class TestPropertyKeyIs { String key_; }; -class TestInfoImpl { - public: - TestInfoImpl(TestInfo* parent, const char* test_case_name, - const char* name, const char* test_case_comment, - const char* comment, TypeId fixture_class_id, - internal::TestFactoryBase* factory); - ~TestInfoImpl(); - - // Returns true if this test should run. - bool should_run() const { return should_run_; } - - // Sets the should_run member. - void set_should_run(bool should) { should_run_ = should; } - - // Returns true if this test is disabled. Disabled tests are not run. - bool is_disabled() const { return is_disabled_; } - - // Sets the is_disabled member. - void set_is_disabled(bool is) { is_disabled_ = is; } - - // Returns true if this test matches the filter specified by the user. - bool matches_filter() const { return matches_filter_; } - - // Sets the matches_filter member. - void set_matches_filter(bool matches) { matches_filter_ = matches; } - - // Returns the test case name. - const char* test_case_name() const { return test_case_name_.c_str(); } - - // Returns the test name. - const char* name() const { return name_.c_str(); } - - // Returns the test case comment. - const char* test_case_comment() const { return test_case_comment_.c_str(); } - - // Returns the test comment. - const char* comment() const { return comment_.c_str(); } - - // Returns the ID of the test fixture class. - TypeId fixture_class_id() const { return fixture_class_id_; } - - // Returns the test result. - TestResult* result() { return &result_; } - const TestResult* result() const { return &result_; } - - // Creates the test object, runs it, records its result, and then - // deletes it. - void Run(); - - // Clears the test result. - void ClearResult() { result_.Clear(); } - - // Clears the test result in the given TestInfo object. - static void ClearTestResult(TestInfo * test_info) { - test_info->impl()->ClearResult(); - } - - private: - // These fields are immutable properties of the test. - TestInfo* const parent_; // The owner of this object - const String test_case_name_; // Test case name - const String name_; // Test name - const String test_case_comment_; // Test case comment - const String comment_; // Test comment - const TypeId fixture_class_id_; // ID of the test fixture class - bool should_run_; // True iff this test should run - bool is_disabled_; // True iff this test is disabled - bool matches_filter_; // True if this test matches the - // user-specified filter. - internal::TestFactoryBase* const factory_; // The factory that creates - // the test object - - // This field is mutable and needs to be reset before running the - // test for the second time. - TestResult result_; - - GTEST_DISALLOW_COPY_AND_ASSIGN_(TestInfoImpl); -}; - // Class UnitTestOptions. // // This class contains functions for processing options the user @@ -747,12 +668,10 @@ class GTEST_API_ UnitTestImpl { void RegisterParameterizedTests(); // Runs all tests in this UnitTest object, prints the result, and - // returns 0 if all tests are successful, or 1 otherwise. If any - // exception is thrown during a test on Windows, this test is - // considered to be failed, but the rest of the tests will still be - // run. (We disable exceptions on Linux and Mac OS X, so the issue - // doesn't apply there.) - int RunAllTests(); + // returns true if all tests are successful. If any exception is + // thrown during a test, this test is considered to be failed, but + // the rest of the tests will still be run. + bool RunAllTests(); // Clears the results of all tests, except the ad hoc tests. void ClearNonAdHocTestResult() { diff --git a/src/gtest-printers.cc b/src/gtest-printers.cc index 1d97b534..07a0d857 100644 --- a/src/gtest-printers.cc +++ b/src/gtest-printers.cc @@ -72,9 +72,10 @@ void PrintByteSegmentInObjectTo(const unsigned char* obj_bytes, size_t start, if (i != 0) { // Organizes the bytes into groups of 2 for easy parsing by // human. - if ((j % 2) == 0) { - *os << " "; - } + if ((j % 2) == 0) + *os << ' '; + else + *os << '-'; } snprintf(text, sizeof(text), "%02X", obj_bytes[j]); *os << text; diff --git a/src/gtest.cc b/src/gtest.cc index 03799a2b..f3768e34 100644 --- a/src/gtest.cc +++ b/src/gtest.cc @@ -495,13 +495,26 @@ bool UnitTestOptions::FilterMatchesTest(const String &test_case_name, // given SEH exception, or EXCEPTION_CONTINUE_SEARCH otherwise. // This function is useful as an __except condition. int UnitTestOptions::GTestShouldProcessSEH(DWORD exception_code) { - // Google Test should handle an exception if: + // Google Test should handle a SEH exception if: // 1. the user wants it to, AND - // 2. this is not a breakpoint exception. - return (GTEST_FLAG(catch_exceptions) && - exception_code != EXCEPTION_BREAKPOINT) ? - EXCEPTION_EXECUTE_HANDLER : - EXCEPTION_CONTINUE_SEARCH; + // 2. this is not a breakpoint exception, AND + // 3. this is not a C++ exception (VC++ implements them via SEH, + // apparently). + // + // SEH exception code for C++ exceptions. + // (see http://support.microsoft.com/kb/185294 for more information). + const DWORD kCxxExceptionCode = 0xe06d7363; + + bool should_handle = true; + + if (!GTEST_FLAG(catch_exceptions)) + should_handle = false; + else if (exception_code == EXCEPTION_BREAKPOINT) + should_handle = false; + else if (exception_code == kCxxExceptionCode) + should_handle = false; + + return should_handle ? EXCEPTION_EXECUTE_HANDLER : EXCEPTION_CONTINUE_SEARCH; } #endif // GTEST_OS_WINDOWS @@ -1922,22 +1935,6 @@ void ReportFailureInUnknownLocation(TestPartResult::Type result_type, } // namespace internal -#if GTEST_OS_WINDOWS -// We are on Windows. - -// Adds an "exception thrown" fatal failure to the current test. -static void AddExceptionThrownFailure(DWORD exception_code, - const char* location) { - Message message; - message << "Exception thrown with code 0x" << std::setbase(16) << - exception_code << std::setbase(10) << " in " << location << "."; - - internal::ReportFailureInUnknownLocation(TestPartResult::kFatalFailure, - message.GetString()); -} - -#endif // GTEST_OS_WINDOWS - // Google Test requires all tests in the same test case to use the same test // fixture class. This function checks if the current test has the // same fixture class as the first test in the current test case. If @@ -1948,15 +1945,13 @@ bool Test::HasSameFixtureClass() { const TestCase* const test_case = impl->current_test_case(); // Info about the first test in the current test case. - const internal::TestInfoImpl* const first_test_info = - test_case->test_info_list()[0]->impl(); - const internal::TypeId first_fixture_id = first_test_info->fixture_class_id(); + const TestInfo* const first_test_info = test_case->test_info_list()[0]; + const internal::TypeId first_fixture_id = first_test_info->fixture_class_id_; const char* const first_test_name = first_test_info->name(); // Info about the current test. - const internal::TestInfoImpl* const this_test_info = - impl->current_test_info()->impl(); - const internal::TypeId this_fixture_id = this_test_info->fixture_class_id(); + const TestInfo* const this_test_info = impl->current_test_info(); + const internal::TypeId this_fixture_id = this_test_info->fixture_class_id_; const char* const this_test_name = this_test_info->name(); if (this_fixture_id != first_fixture_id) { @@ -2006,62 +2001,134 @@ bool Test::HasSameFixtureClass() { return true; } -// Runs the test and updates the test result. -void Test::Run() { - if (!HasSameFixtureClass()) return; +#if GTEST_HAS_SEH - internal::UnitTestImpl* const impl = internal::GetUnitTestImpl(); +// Adds an "exception thrown" fatal failure to the current test. This +// function returns its result via an output parameter pointer because VC++ +// prohibits creation of objects with destructors on stack in functions +// using __try (see error C2712). +static internal::String* FormatSehExceptionMessage(DWORD exception_code, + const char* location) { + Message message; + message << "SEH exception with code 0x" << std::setbase(16) << + exception_code << std::setbase(10) << " thrown in " << location << "."; + + return new internal::String(message.GetString()); +} + +#endif // GTEST_HAS_SEH + +#if GTEST_HAS_EXCEPTIONS + +// Adds an "exception thrown" fatal failure to the current test. +static internal::String FormatCxxExceptionMessage(const char* description, + const char* location) { + Message message; + if (description != NULL) { + message << "C++ exception with description \"" << description << "\""; + } else { + message << "Unknown C++ exception"; + } + message << " thrown in " << location << "."; + + return message.GetString(); +} + +static internal::String PrintTestPartResultToString( + const TestPartResult& test_part_result); + +// A failed Google Test assertion will throw an exception of this type when +// GTEST_FLAG(throw_on_failure) is true (if exceptions are enabled). We +// derive it from std::runtime_error, which is for errors presumably +// detectable only at run time. Since std::runtime_error inherits from +// std::exception, many testing frameworks know how to extract and print the +// message inside it. +class GoogleTestFailureException : public ::std::runtime_error { + public: + explicit GoogleTestFailureException(const TestPartResult& failure) + : ::std::runtime_error(PrintTestPartResultToString(failure).c_str()) {} +}; +#endif // GTEST_HAS_EXCEPTIONS + +// Runs the given method and handles SEH exceptions it throws, when +// SEH is supported; returns the 0-value for type Result in case of an +// SEH exception. (Microsoft compilers cannot handle SEH and C++ +// exceptions in the same function. Therefore, we provide a separate +// wrapper function for handling SEH exceptions.) +template +static Result HandleSehExceptionsInMethodIfSupported( + T* object, Result (T::*method)(), const char* location) { #if GTEST_HAS_SEH - // Catch SEH-style exceptions. - impl->os_stack_trace_getter()->UponLeavingGTest(); __try { - SetUp(); - } __except(internal::UnitTestOptions::GTestShouldProcessSEH( + return (object->*method)(); + } __except (internal::UnitTestOptions::GTestShouldProcessSEH( // NOLINT GetExceptionCode())) { - AddExceptionThrownFailure(GetExceptionCode(), "SetUp()"); + // We create the exception message on the heap because VC++ prohibits + // creation of objects with destructors on stack in functions using __try + // (see error C2712). + internal::String* exception_message = FormatSehExceptionMessage( + GetExceptionCode(), location); + internal::ReportFailureInUnknownLocation(TestPartResult::kFatalFailure, + *exception_message); + delete exception_message; + return static_cast(0); } +#else + (void)location; + return (object->*method)(); +#endif // GTEST_HAS_SEH +} - // We will run the test only if SetUp() had no fatal failure. - if (!HasFatalFailure()) { - impl->os_stack_trace_getter()->UponLeavingGTest(); - __try { - TestBody(); - } __except(internal::UnitTestOptions::GTestShouldProcessSEH( - GetExceptionCode())) { - AddExceptionThrownFailure(GetExceptionCode(), "the test body"); - } +// Runs the given method and catches and reports C++ and/or SEH-style +// exceptions, if they are supported; returns the 0-value for type +// Result in case of an SEH exception. +template +static Result HandleExceptionsInMethodIfSupported( + T* object, Result (T::*method)(), const char* location) { +#if GTEST_HAS_EXCEPTIONS + try { + return HandleSehExceptionsInMethodIfSupported(object, method, location); + } catch (const GoogleTestFailureException&) { // NOLINT + // This exception doesn't originate in code under test. It makes no + // sense to report it as a test failure. + throw; + } catch (const std::exception& e) { // NOLINT + internal::ReportFailureInUnknownLocation( + TestPartResult::kFatalFailure, + FormatCxxExceptionMessage(e.what(), location)); + } catch (...) { // NOLINT + internal::ReportFailureInUnknownLocation( + TestPartResult::kFatalFailure, + FormatCxxExceptionMessage(NULL, location)); } + return static_cast(0); +#else + return HandleSehExceptionsInMethodIfSupported(object, method, location); +#endif // GTEST_HAS_EXCEPTIONS +} - // However, we want to clean up as much as possible. Hence we will - // always call TearDown(), even if SetUp() or the test body has - // failed. - impl->os_stack_trace_getter()->UponLeavingGTest(); - __try { - TearDown(); - } __except(internal::UnitTestOptions::GTestShouldProcessSEH( - GetExceptionCode())) { - AddExceptionThrownFailure(GetExceptionCode(), "TearDown()"); - } +// Runs the test and updates the test result. +void Test::Run() { + if (!HasSameFixtureClass()) return; -#else // We are on a compiler or platform that doesn't support SEH. + internal::UnitTestImpl* const impl = internal::GetUnitTestImpl(); impl->os_stack_trace_getter()->UponLeavingGTest(); - SetUp(); - + HandleExceptionsInMethodIfSupported(this, &Test::SetUp, "SetUp()"); // We will run the test only if SetUp() was successful. if (!HasFatalFailure()) { impl->os_stack_trace_getter()->UponLeavingGTest(); - TestBody(); + HandleExceptionsInMethodIfSupported( + this, &Test::TestBody, "the test body"); } // However, we want to clean up as much as possible. Hence we will // always call TearDown(), even if SetUp() or the test body has // failed. impl->os_stack_trace_getter()->UponLeavingGTest(); - TearDown(); -#endif // GTEST_HAS_SEH + HandleExceptionsInMethodIfSupported( + this, &Test::TearDown, "TearDown()"); } - // Returns true iff the current test has a fatal failure. bool Test::HasFatalFailure() { return internal::GetUnitTestImpl()->current_test_result()->HasFatalFailure(); @@ -2076,22 +2143,26 @@ bool Test::HasNonfatalFailure() { // class TestInfo // Constructs a TestInfo object. It assumes ownership of the test factory -// object via impl_. +// object. TestInfo::TestInfo(const char* a_test_case_name, const char* a_name, const char* a_test_case_comment, const char* a_comment, internal::TypeId fixture_class_id, - internal::TestFactoryBase* factory) { - impl_ = new internal::TestInfoImpl(this, a_test_case_name, a_name, - a_test_case_comment, a_comment, - fixture_class_id, factory); -} + internal::TestFactoryBase* factory) + : test_case_name_(a_test_case_name), + name_(a_name), + test_case_comment_(a_test_case_comment), + comment_(a_comment), + fixture_class_id_(fixture_class_id), + should_run_(false), + is_disabled_(false), + matches_filter_(false), + factory_(factory), + result_() {} // Destructs a TestInfo object. -TestInfo::~TestInfo() { - delete impl_; -} +TestInfo::~TestInfo() { delete factory_; } namespace internal { @@ -2147,41 +2218,6 @@ void ReportInvalidTestCaseType(const char* test_case_name, } // namespace internal -// Returns the test case name. -const char* TestInfo::test_case_name() const { - return impl_->test_case_name(); -} - -// Returns the test name. -const char* TestInfo::name() const { - return impl_->name(); -} - -// Returns the test case comment. -const char* TestInfo::test_case_comment() const { - return impl_->test_case_comment(); -} - -// Returns the test comment. -const char* TestInfo::comment() const { - return impl_->comment(); -} - -// Returns true if this test should run. -bool TestInfo::should_run() const { return impl_->should_run(); } - -// Returns true if this test matches the user-specified filter. -bool TestInfo::matches_filter() const { return impl_->matches_filter(); } - -// Returns the result of the test. -const TestResult* TestInfo::result() const { return impl_->result(); } - -// Increments the number of death tests encountered in this test so -// far. -int TestInfo::increment_death_test_count() { - return impl_->result()->increment_death_test_count(); -} - namespace { // A predicate that checks the test name of a TestInfo against a known @@ -2225,70 +2261,54 @@ void UnitTestImpl::RegisterParameterizedTests() { #endif } +} // namespace internal + // Creates the test object, runs it, records its result, and then // deletes it. -void TestInfoImpl::Run() { +void TestInfo::Run() { if (!should_run_) return; // Tells UnitTest where to store test result. - UnitTestImpl* const impl = internal::GetUnitTestImpl(); - impl->set_current_test_info(parent_); + internal::UnitTestImpl* const impl = internal::GetUnitTestImpl(); + impl->set_current_test_info(this); TestEventListener* repeater = UnitTest::GetInstance()->listeners().repeater(); // Notifies the unit test event listeners that a test is about to start. - repeater->OnTestStart(*parent_); + repeater->OnTestStart(*this); - const TimeInMillis start = GetTimeInMillis(); + const TimeInMillis start = internal::GetTimeInMillis(); impl->os_stack_trace_getter()->UponLeavingGTest(); -#if GTEST_HAS_SEH - // Catch SEH-style exceptions. - Test* test = NULL; - - __try { - // Creates the test object. - test = factory_->CreateTest(); - } __except(internal::UnitTestOptions::GTestShouldProcessSEH( - GetExceptionCode())) { - AddExceptionThrownFailure(GetExceptionCode(), - "the test fixture's constructor"); - return; - } -#else // We are on a compiler or platform that doesn't support SEH. - - // TODO(wan): If test->Run() throws, test won't be deleted. This is - // not a problem now as we don't use exceptions. If we were to - // enable exceptions, we should revise the following to be - // exception-safe. // Creates the test object. - Test* test = factory_->CreateTest(); -#endif // GTEST_HAS_SEH + Test* const test = HandleExceptionsInMethodIfSupported( + factory_, &internal::TestFactoryBase::CreateTest, + "the test fixture's constructor"); - // Runs the test only if the constructor of the test fixture didn't + // Runs the test only if the test object was created and its constructor didn't // generate a fatal failure. - if (!Test::HasFatalFailure()) { + if ((test != NULL) && !Test::HasFatalFailure()) { + // This doesn't throw as all user code that can throw are wrapped into + // exception handling code. test->Run(); } // Deletes the test object. impl->os_stack_trace_getter()->UponLeavingGTest(); - delete test; - test = NULL; + HandleExceptionsInMethodIfSupported( + test, &Test::DeleteSelf_, "the test fixture's destructor"); - result_.set_elapsed_time(GetTimeInMillis() - start); + result_.set_elapsed_time(internal::GetTimeInMillis() - start); // Notifies the unit test event listener that a test has just finished. - repeater->OnTestEnd(*parent_); + repeater->OnTestEnd(*this); // Tells UnitTest to stop associating assertion results to this // test. impl->set_current_test_info(NULL); } -} // namespace internal - // class TestCase // Gets the number of successful tests in this test case. @@ -2371,45 +2391,26 @@ void TestCase::Run() { repeater->OnTestCaseStart(*this); impl->os_stack_trace_getter()->UponLeavingGTest(); - set_up_tc_(); + HandleExceptionsInMethodIfSupported( + this, &TestCase::RunSetUpTestCase, "SetUpTestCase()"); const internal::TimeInMillis start = internal::GetTimeInMillis(); for (int i = 0; i < total_test_count(); i++) { - GetMutableTestInfo(i)->impl()->Run(); + GetMutableTestInfo(i)->Run(); } elapsed_time_ = internal::GetTimeInMillis() - start; impl->os_stack_trace_getter()->UponLeavingGTest(); - tear_down_tc_(); + HandleExceptionsInMethodIfSupported( + this, &TestCase::RunTearDownTestCase, "TearDownTestCase()"); + repeater->OnTestCaseEnd(*this); impl->set_current_test_case(NULL); } // Clears the results of all tests in this test case. void TestCase::ClearResult() { - ForEach(test_info_list_, internal::TestInfoImpl::ClearTestResult); -} - -// Returns true iff test passed. -bool TestCase::TestPassed(const TestInfo * test_info) { - const internal::TestInfoImpl* const impl = test_info->impl(); - return impl->should_run() && impl->result()->Passed(); -} - -// Returns true iff test failed. -bool TestCase::TestFailed(const TestInfo * test_info) { - const internal::TestInfoImpl* const impl = test_info->impl(); - return impl->should_run() && impl->result()->Failed(); -} - -// Returns true iff test is disabled. -bool TestCase::TestDisabled(const TestInfo * test_info) { - return test_info->impl()->is_disabled(); -} - -// Returns true if the given test should run. -bool TestCase::ShouldRunTest(const TestInfo *test_info) { - return test_info->impl()->should_run(); + ForEach(test_info_list_, TestInfo::ClearTestResult); } // Shuffles the tests in this test case. @@ -3505,19 +3506,6 @@ Environment* UnitTest::AddEnvironment(Environment* env) { return env; } -#if GTEST_HAS_EXCEPTIONS -// A failed Google Test assertion will throw an exception of this type -// when exceptions are enabled. We derive it from std::runtime_error, -// which is for errors presumably detectable only at run time. Since -// std::runtime_error inherits from std::exception, many testing -// frameworks know how to extract and print the message inside it. -class GoogleTestFailureException : public ::std::runtime_error { - public: - explicit GoogleTestFailureException(const TestPartResult& failure) - : ::std::runtime_error(PrintTestPartResultToString(failure).c_str()) {} -}; -#endif - // Adds a TestPartResult to the current TestResult object. All Google Test // assertion macros (e.g. ASSERT_TRUE, EXPECT_EQ, etc) eventually call // this to report their results. The user code should use the @@ -3640,20 +3628,12 @@ int UnitTest::Run() { _WRITE_ABORT_MSG | _CALL_REPORTFAULT); // pop-up window, core dump. #endif } - - __try { - return impl_->RunAllTests(); - } __except(internal::UnitTestOptions::GTestShouldProcessSEH( - GetExceptionCode())) { - printf("Exception thrown with code 0x%x.\nFAIL\n", GetExceptionCode()); - fflush(stdout); - return 1; - } - -#else // We are on a compiler or platform that doesn't support SEH. - - return impl_->RunAllTests(); #endif // GTEST_HAS_SEH + + return HandleExceptionsInMethodIfSupported( + impl_, + &internal::UnitTestImpl::RunAllTests, + "auxiliary test code (environments or event listeners)") ? 0 : 1; } // Returns the working directory when the first TEST() or TEST_F() was @@ -3890,27 +3870,26 @@ static void SetUpEnvironment(Environment* env) { env->SetUp(); } static void TearDownEnvironment(Environment* env) { env->TearDown(); } // Runs all tests in this UnitTest object, prints the result, and -// returns 0 if all tests are successful, or 1 otherwise. If any -// exception is thrown during a test on Windows, this test is -// considered to be failed, but the rest of the tests will still be -// run. (We disable exceptions on Linux and Mac OS X, so the issue -// doesn't apply there.) +// returns true if all tests are successful. If any exception is +// thrown during a test, the test is considered to be failed, but the +// rest of the tests will still be run. +// // When parameterized tests are enabled, it expands and registers // parameterized tests first in RegisterParameterizedTests(). // All other functions called from RunAllTests() may safely assume that // parameterized tests are ready to be counted and run. -int UnitTestImpl::RunAllTests() { +bool UnitTestImpl::RunAllTests() { // Makes sure InitGoogleTest() was called. if (!GTestIsInitialized()) { printf("%s", "\nThis test program did NOT call ::testing::InitGoogleTest " "before calling RUN_ALL_TESTS(). Please fix it.\n"); - return 1; + return false; } // Do not run any test if the --help flag was specified. if (g_help_flag) - return 0; + return true; // Repeats the call to the post-flag parsing initialization in case the // user didn't call InitGoogleTest. @@ -3942,7 +3921,7 @@ int UnitTestImpl::RunAllTests() { if (GTEST_FLAG(list_tests)) { // This must be called *after* FilterTests() has been called. ListTestsMatchingFilter(); - return 0; + return true; } random_seed_ = GTEST_FLAG(shuffle) ? @@ -4028,8 +4007,7 @@ int UnitTestImpl::RunAllTests() { repeater->OnTestProgramEnd(*parent_); - // Returns 0 if all tests passed, or 1 other wise. - return failed ? 1 : 0; + return !failed; } // Reads the GTEST_SHARD_STATUS_FILE environment variable, and creates the file @@ -4159,12 +4137,12 @@ int UnitTestImpl::FilterTests(ReactionToSharding shard_tests) { kDisableTestFilter) || internal::UnitTestOptions::MatchesFilter(test_name, kDisableTestFilter); - test_info->impl()->set_is_disabled(is_disabled); + test_info->is_disabled_ = is_disabled; const bool matches_filter = internal::UnitTestOptions::FilterMatchesTest(test_case_name, test_name); - test_info->impl()->set_matches_filter(matches_filter); + test_info->matches_filter_ = matches_filter; const bool is_runnable = (GTEST_FLAG(also_run_disabled_tests) || !is_disabled) && @@ -4178,7 +4156,7 @@ int UnitTestImpl::FilterTests(ReactionToSharding shard_tests) { num_runnable_tests += is_runnable; num_selected_tests += is_selected; - test_info->impl()->set_should_run(is_selected); + test_info->should_run_ = is_selected; test_case->set_should_run(test_case->should_run() || is_selected); } } @@ -4194,7 +4172,7 @@ void UnitTestImpl::ListTestsMatchingFilter() { for (size_t j = 0; j < test_case->test_info_list().size(); j++) { const TestInfo* const test_info = test_case->test_info_list()[j]; - if (test_info->matches_filter()) { + if (test_info->matches_filter_) { if (!printed_test_case_name) { printed_test_case_name = true; printf("%s.\n", test_case->name()); @@ -4234,7 +4212,7 @@ OsStackTraceGetterInterface* UnitTestImpl::os_stack_trace_getter() { // the TestResult for the ad hoc test if no test is running. TestResult* UnitTestImpl::current_test_result() { return current_test_info_ ? - current_test_info_->impl()->result() : &ad_hoc_test_result_; + &(current_test_info_->result_) : &ad_hoc_test_result_; } // Shuffles all test cases, and the tests within each test case, @@ -4263,32 +4241,6 @@ void UnitTestImpl::UnshuffleTests() { } } -// TestInfoImpl constructor. The new instance assumes ownership of the test -// factory object. -TestInfoImpl::TestInfoImpl(TestInfo* parent, - const char* a_test_case_name, - const char* a_name, - const char* a_test_case_comment, - const char* a_comment, - TypeId a_fixture_class_id, - internal::TestFactoryBase* factory) : - parent_(parent), - test_case_name_(String(a_test_case_name)), - name_(String(a_name)), - test_case_comment_(String(a_test_case_comment)), - comment_(String(a_comment)), - fixture_class_id_(a_fixture_class_id), - should_run_(false), - is_disabled_(false), - matches_filter_(false), - factory_(factory) { -} - -// TestInfoImpl destructor. -TestInfoImpl::~TestInfoImpl() { - delete factory_; -} - // Returns the current OS stack trace as a String. // // The maximum number of stack frames to be included is specified by @@ -4306,8 +4258,8 @@ String GetCurrentOsStackTraceExceptTop(UnitTest* /*unit_test*/, return GetUnitTestImpl()->CurrentOsStackTraceExceptTop(skip_count + 1); } -// Used by the GTEST_HIDE_UNREACHABLE_CODE_ macro to suppress unreachable -// code warnings. +// Used by the GTEST_SUPPRESS_UNREACHABLE_CODE_WARNING_BELOW_ macro to +// suppress unreachable code warnings. namespace { class ClassUniqueToAlwaysTrue {}; } -- cgit v1.2.3 From a9f380f5c7ff75cd715c58e11885dddc54baef02 Mon Sep 17 00:00:00 2001 From: "zhanyong.wan" Date: Thu, 19 Aug 2010 22:16:00 +0000 Subject: Removes the Windows golden file (by Vlad Losev); implements test result streaming (by Nikhil Jindal and cleaned up by Zhanyong Wan). --- src/gtest-internal-inl.h | 10 ++ src/gtest.cc | 248 ++++++++++++++++++++++++++++++++++++++++++++--- 2 files changed, 242 insertions(+), 16 deletions(-) (limited to 'src') diff --git a/src/gtest-internal-inl.h b/src/gtest-internal-inl.h index d1e0b59a..73920e44 100644 --- a/src/gtest-internal-inl.h +++ b/src/gtest-internal-inl.h @@ -93,6 +93,7 @@ const char kRandomSeedFlag[] = "random_seed"; const char kRepeatFlag[] = "repeat"; const char kShuffleFlag[] = "shuffle"; const char kStackTraceDepthFlag[] = "stack_trace_depth"; +const char kStreamResultToFlag[] = "stream_result_to"; const char kThrowOnFailureFlag[] = "throw_on_failure"; // A valid random seed must be in [1, kMaxRandomSeed]. @@ -165,6 +166,7 @@ class GTestFlagSaver { repeat_ = GTEST_FLAG(repeat); shuffle_ = GTEST_FLAG(shuffle); stack_trace_depth_ = GTEST_FLAG(stack_trace_depth); + stream_result_to_ = GTEST_FLAG(stream_result_to); throw_on_failure_ = GTEST_FLAG(throw_on_failure); } @@ -185,6 +187,7 @@ class GTestFlagSaver { GTEST_FLAG(repeat) = repeat_; GTEST_FLAG(shuffle) = shuffle_; GTEST_FLAG(stack_trace_depth) = stack_trace_depth_; + GTEST_FLAG(stream_result_to) = stream_result_to_; GTEST_FLAG(throw_on_failure) = throw_on_failure_; } private: @@ -205,6 +208,7 @@ class GTestFlagSaver { internal::Int32 repeat_; bool shuffle_; internal::Int32 stack_trace_depth_; + String stream_result_to_; bool throw_on_failure_; } GTEST_ATTRIBUTE_UNUSED_; @@ -741,6 +745,12 @@ class GTEST_API_ UnitTestImpl { // UnitTestOptions. Must not be called before InitGoogleTest. void ConfigureXmlOutput(); +#if GTEST_CAN_STREAM_RESULTS_ + // Initializes the event listener for streaming test results to a socket. + // Must not be called before InitGoogleTest. + void ConfigureStreamingOutput(); +#endif + // Performs initialization dependent upon flag values obtained in // ParseGoogleTestFlagsOnly. Is called from InitGoogleTest after the call to // ParseGoogleTestFlagsOnly. In case a user neglects to call InitGoogleTest diff --git a/src/gtest.cc b/src/gtest.cc index f3768e34..93ab6a8d 100644 --- a/src/gtest.cc +++ b/src/gtest.cc @@ -43,7 +43,7 @@ #include #include -#include +#include // NOLINT #include #include @@ -53,16 +53,15 @@ // gettimeofday(). #define GTEST_HAS_GETTIMEOFDAY_ 1 -#include -#include -#include +#include // NOLINT +#include // NOLINT +#include // NOLINT // Declares vsnprintf(). This header is not available on Windows. -#include -#include -#include -#include +#include // NOLINT +#include // NOLINT +#include // NOLINT +#include // NOLINT #include -#include #elif GTEST_OS_SYMBIAN #define GTEST_HAS_GETTIMEOFDAY_ 1 @@ -119,6 +118,11 @@ #include #endif +#if GTEST_CAN_STREAM_RESULTS_ +#include // NOLINT +#include // NOLINT +#endif + // 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 @@ -258,6 +262,13 @@ GTEST_DEFINE_int32_( "The maximum number of stack frames to print when an " "assertion fails. The valid range is 0 through 100, inclusive."); +GTEST_DEFINE_string_( + stream_result_to, + internal::StringFromGTestEnv("stream_result_to", ""), + "This flag specifies the host name and the port number on which to stream " + "test results. Example: \"localhost:555\". The flag is effective only on " + "Linux."); + GTEST_DEFINE_bool_( throw_on_failure, internal::BoolFromGTestEnv("throw_on_failure", false), @@ -2286,8 +2297,8 @@ void TestInfo::Run() { factory_, &internal::TestFactoryBase::CreateTest, "the test fixture's constructor"); - // Runs the test only if the test object was created and its constructor didn't - // generate a fatal failure. + // Runs the test only if the test object was created and its + // constructor didn't generate a fatal failure. if ((test != NULL) && !Test::HasFatalFailure()) { // This doesn't throw as all user code that can throw are wrapped into // exception handling code. @@ -2800,8 +2811,8 @@ void PrettyUnitTestResultPrinter::PrintFailedTests(const UnitTest& unit_test) { } } - void PrettyUnitTestResultPrinter::OnTestIterationEnd(const UnitTest& unit_test, - int /*iteration*/) { +void PrettyUnitTestResultPrinter::OnTestIterationEnd(const UnitTest& unit_test, + int /*iteration*/) { ColoredPrintf(COLOR_GREEN, "[==========] "); printf("%s from %s ran.", FormatTestCount(unit_test.test_to_run_count()).c_str(), @@ -3266,6 +3277,182 @@ String XmlUnitTestResultPrinter::TestPropertiesAsXmlAttributes( // End XmlUnitTestResultPrinter +#if GTEST_CAN_STREAM_RESULTS_ + +// Streams test results to the given port on the given host machine. +class StreamingListener : public EmptyTestEventListener { + public: + // Escapes '=', '&', '%', and '\n' characters in str as "%xx". + static string UrlEncode(const char* str); + + StreamingListener(const string& host, const string& port) + : sockfd_(-1), host_name_(host), port_num_(port) { + MakeConnection(); + Send("gtest_streaming_protocol_version=1.0\n"); + } + + virtual ~StreamingListener() { + if (sockfd_ != -1) + CloseConnection(); + } + + void OnTestProgramStart(const UnitTest& /* unit_test */) { + Send("event=TestProgramStart\n"); + } + + void OnTestProgramEnd(const UnitTest& unit_test) { + // Note that Google Test current only report elapsed time for each + // test iteration, not for the entire test program. + Send(String::Format("event=TestProgramEnd&passed=%d\n", + unit_test.Passed())); + + // Notify the streaming server to stop. + CloseConnection(); + } + + void OnTestIterationStart(const UnitTest& /* unit_test */, int iteration) { + Send(String::Format("event=TestIterationStart&iteration=%d\n", + iteration)); + } + + void OnTestIterationEnd(const UnitTest& unit_test, int /* iteration */) { + Send(String::Format("event=TestIterationEnd&passed=%d&elapsed_time=%sms\n", + unit_test.Passed(), + StreamableToString(unit_test.elapsed_time()).c_str())); + } + + void OnTestCaseStart(const TestCase& test_case) { + Send(String::Format("event=TestCaseStart&name=%s\n", test_case.name())); + } + + void OnTestCaseEnd(const TestCase& test_case) { + Send(String::Format("event=TestCaseEnd&passed=%d&elapsed_time=%sms\n", + test_case.Passed(), + StreamableToString(test_case.elapsed_time()).c_str())); + } + + void OnTestStart(const TestInfo& test_info) { + Send(String::Format("event=TestStart&name=%s\n", test_info.name())); + } + + void OnTestEnd(const TestInfo& test_info) { + Send(String::Format( + "event=TestEnd&passed=%d&elapsed_time=%sms\n", + (test_info.result())->Passed(), + StreamableToString((test_info.result())->elapsed_time()).c_str())); + } + + void OnTestPartResult(const TestPartResult& test_part_result) { + const char* file_name = test_part_result.file_name(); + if (file_name == NULL) + file_name = ""; + Send(String::Format("event=TestPartResult&file=%s&line=%d&message=", + UrlEncode(file_name).c_str(), + test_part_result.line_number())); + Send(UrlEncode(test_part_result.message()) + "\n"); + } + + private: + // Creates a client socket and connects to the server. + void MakeConnection(); + + // Closes the socket. + void CloseConnection() { + GTEST_CHECK_(sockfd_ != -1) + << "CloseConnection() can be called only when there is a connection."; + + close(sockfd_); + sockfd_ = -1; + } + + // Sends a string to the socket. + void Send(const string& message) { + GTEST_CHECK_(sockfd_ != -1) + << "Send() can be called only when there is a connection."; + + const int len = static_cast(message.length()); + if (write(sockfd_, message.c_str(), len) != len) { + GTEST_LOG_(WARNING) + << "stream_result_to: failed to stream to " + << host_name_ << ":" << port_num_; + } + } + + int sockfd_; // socket file descriptor + const string host_name_; + const string port_num_; + + GTEST_DISALLOW_COPY_AND_ASSIGN_(StreamingListener); +}; // class StreamingListener + +// Checks if str contains '=', '&', '%' or '\n' characters. If yes, +// replaces them by "%xx" where xx is their hexadecimal value. For +// example, replaces "=" with "%3D". This algorithm is O(strlen(str)) +// in both time and space -- important as the input str may contain an +// arbitrarily long test failure message and stack trace. +string StreamingListener::UrlEncode(const char* str) { + string result; + result.reserve(strlen(str) + 1); + for (char ch = *str; ch != '\0'; ch = *++str) { + switch (ch) { + case '%': + case '=': + case '&': + case '\n': + result.append(String::Format("%%%02x", static_cast(ch))); + break; + default: + result.push_back(ch); + break; + } + } + return result; +} + +void StreamingListener::MakeConnection() { + GTEST_CHECK_(sockfd_ == -1) + << "MakeConnection() can't be called when there is already a connection."; + + addrinfo hints; + memset(&hints, 0, sizeof(hints)); + hints.ai_family = AF_UNSPEC; // To allow both IPv4 and IPv6 addresses. + hints.ai_socktype = SOCK_STREAM; + addrinfo* servinfo = NULL; + + // Use the getaddrinfo() to get a linked list of IP addresses for + // the given host name. + const int error_num = getaddrinfo( + host_name_.c_str(), port_num_.c_str(), &hints, &servinfo); + if (error_num != 0) { + GTEST_LOG_(WARNING) << "stream_result_to: getaddrinfo() failed: " + << gai_strerror(error_num); + } + + // Loop through all the results and connect to the first we can. + for (addrinfo* cur_addr = servinfo; sockfd_ == -1 && cur_addr != NULL; + cur_addr = cur_addr->ai_next) { + sockfd_ = socket( + cur_addr->ai_family, cur_addr->ai_socktype, cur_addr->ai_protocol); + if (sockfd_ != -1) { + // Connect the client socket to the server socket. + if (connect(sockfd_, cur_addr->ai_addr, cur_addr->ai_addrlen) == -1) { + close(sockfd_); + sockfd_ = -1; + } + } + } + + freeaddrinfo(servinfo); // all done with this structure + + if (sockfd_ == -1) { + GTEST_LOG_(WARNING) << "stream_result_to: failed to connect to " + << host_name_ << ":" << port_num_; + } +} + +// End of class Streaming Listener +#endif // GTEST_CAN_STREAM_RESULTS__ + // Class ScopedTrace // Pushes the given source file location and message onto a per-thread @@ -3770,6 +3957,25 @@ void UnitTestImpl::ConfigureXmlOutput() { } } +#if GTEST_CAN_STREAM_RESULTS_ +// Initializes event listeners for streaming test results in String form. +// Must not be called before InitGoogleTest. +void UnitTestImpl::ConfigureStreamingOutput() { + const string& target = GTEST_FLAG(stream_result_to); + if (!target.empty()) { + const size_t pos = target.find(':'); + if (pos != string::npos) { + listeners()->Append(new StreamingListener(target.substr(0, pos), + target.substr(pos+1))); + } else { + printf("WARNING: unrecognized streaming target \"%s\" ignored.\n", + target.c_str()); + fflush(stdout); + } + } +} +#endif // GTEST_CAN_STREAM_RESULTS_ + // Performs initialization dependent upon flag values obtained in // ParseGoogleTestFlagsOnly. Is called from InitGoogleTest after the call to // ParseGoogleTestFlagsOnly. In case a user neglects to call InitGoogleTest @@ -3793,6 +3999,11 @@ void UnitTestImpl::PostFlagParsingInit() { // Configures listeners for XML output. This makes it possible for users // to shut down the default XML output before invoking RUN_ALL_TESTS. ConfigureXmlOutput(); + +#if GTEST_CAN_STREAM_RESULTS_ + // Configures listeners for streaming test results to the specified server. + ConfigureStreamingOutput(); +#endif // GTEST_CAN_STREAM_RESULTS_ } } @@ -4471,6 +4682,10 @@ static const char kColorEncodedHelpMessage[] = GTEST_PATH_SEP_ "@Y|@G:@YFILE_PATH]@D\n" " Generate an XML report in the given directory or with the given file\n" " name. @YFILE_PATH@D defaults to @Gtest_details.xml@D.\n" +#if GTEST_CAN_STREAM_RESULTS_ +" @G--" GTEST_FLAG_PREFIX_ "stream_result_to=@YHOST@G:@YPORT@D\n" +" Stream test results to the given server.\n" +#endif // GTEST_CAN_STREAM_RESULTS_ "\n" "Assertion Behavior:\n" #if GTEST_HAS_DEATH_TEST && !GTEST_OS_WINDOWS @@ -4481,10 +4696,8 @@ static const char kColorEncodedHelpMessage[] = " Turn assertion failures into debugger break-points.\n" " @G--" GTEST_FLAG_PREFIX_ "throw_on_failure@D\n" " Turn assertion failures into C++ exceptions.\n" -#if GTEST_OS_WINDOWS " @G--" GTEST_FLAG_PREFIX_ "catch_exceptions@D\n" " Suppress pop-ups caused by exceptions.\n" -#endif // GTEST_OS_WINDOWS "\n" "Except for @G--" GTEST_FLAG_PREFIX_ "list_tests@D, you can alternatively set " "the corresponding\n" @@ -4534,7 +4747,10 @@ void ParseGoogleTestFlagsOnlyImpl(int* argc, CharType** argv) { ParseBoolFlag(arg, kShuffleFlag, >EST_FLAG(shuffle)) || ParseInt32Flag(arg, kStackTraceDepthFlag, >EST_FLAG(stack_trace_depth)) || - ParseBoolFlag(arg, kThrowOnFailureFlag, >EST_FLAG(throw_on_failure)) + ParseStringFlag(arg, kStreamResultToFlag, + >EST_FLAG(stream_result_to)) || + ParseBoolFlag(arg, kThrowOnFailureFlag, + >EST_FLAG(throw_on_failure)) ) { // Yes. Shift the remainder of the argv list left by one. Note // that argv has (*argc + 1) elements, the last one always being -- cgit v1.2.3 From 35c39756495bea5959de5778aaaf33a94f8c1e2e Mon Sep 17 00:00:00 2001 From: "zhanyong.wan" Date: Tue, 31 Aug 2010 18:21:13 +0000 Subject: Casts char to unsigned char before calling isspace() etc to avoid undefined behavior (by Zhanyong Wan); removes conditional #includes keyed on GTEST_HAS_PROTOBUF_ (by Zhanyong Wan); publishes GTEST_HAS_STREAM_REDIRECTION (by Vlad Losev); forward declares some classes properly (by Samuel Benzaquen); honors the --gtest_catch_exceptions flag (by Vlad Losev). --- src/gtest-internal-inl.h | 26 +++++++++++--- src/gtest-port.cc | 30 ++++++++-------- src/gtest-typed-test.cc | 2 +- src/gtest.cc | 93 +++++++++++++++++++++++++++++++----------------- 4 files changed, 98 insertions(+), 53 deletions(-) (limited to 'src') diff --git a/src/gtest-internal-inl.h b/src/gtest-internal-inl.h index 73920e44..fe53c218 100644 --- a/src/gtest-internal-inl.h +++ b/src/gtest-internal-inl.h @@ -771,9 +771,17 @@ class GTEST_API_ UnitTestImpl { // Restores the test cases and tests to their order before the first shuffle. void UnshuffleTests(); + // Returns the value of GTEST_FLAG(catch_exceptions) at the moment + // UnitTest::Run() starts. + bool catch_exceptions() const { return catch_exceptions_; } + private: friend class ::testing::UnitTest; + // Used by UnitTest::Run() to capture the state of + // GTEST_FLAG(catch_exceptions) at the moment it starts. + void set_catch_exceptions(bool value) { catch_exceptions_ = value; } + // The UnitTest object that owns this implementation object. UnitTest* const parent_; @@ -876,6 +884,10 @@ class GTEST_API_ UnitTestImpl { // A per-thread stack of traces created by the SCOPED_TRACE() macro. internal::ThreadLocal > gtest_trace_stack_; + // The value of GTEST_FLAG(catch_exceptions) at the moment RunAllTests() + // starts. + bool catch_exceptions_; + GTEST_DISALLOW_COPY_AND_ASSIGN_(UnitTestImpl); }; // class UnitTestImpl @@ -885,14 +897,16 @@ inline UnitTestImpl* GetUnitTestImpl() { return UnitTest::GetInstance()->impl(); } +#if GTEST_USES_SIMPLE_RE + // Internal helper functions for implementing the simple regular // expression matcher. GTEST_API_ bool IsInSet(char ch, const char* str); -GTEST_API_ bool IsDigit(char ch); -GTEST_API_ bool IsPunct(char ch); +GTEST_API_ bool IsAsciiDigit(char ch); +GTEST_API_ bool IsAsciiPunct(char ch); GTEST_API_ bool IsRepeat(char ch); -GTEST_API_ bool IsWhiteSpace(char ch); -GTEST_API_ bool IsWordChar(char ch); +GTEST_API_ bool IsAsciiWhiteSpace(char ch); +GTEST_API_ bool IsAsciiWordChar(char ch); GTEST_API_ bool IsValidEscape(char ch); GTEST_API_ bool AtomMatchesChar(bool escaped, char pattern, char ch); GTEST_API_ bool ValidateRegex(const char* regex); @@ -901,6 +915,8 @@ GTEST_API_ bool MatchRepetitionAndRegexAtHead( bool escaped, char ch, char repeat, const char* regex, const char* str); GTEST_API_ bool MatchRegexAnywhere(const char* regex, const char* str); +#endif // GTEST_USES_SIMPLE_RE + // Parses the command line for Google Test flags, without initializing // other parts of Google Test. GTEST_API_ void ParseGoogleTestFlagsOnly(int* argc, char** argv); @@ -947,7 +963,7 @@ bool ParseNaturalNumber(const ::std::string& str, Integer* number) { // Fail fast if the given string does not begin with a digit; // this bypasses strtoXXX's "optional leading whitespace and plus // or minus sign" semantics, which are undesirable here. - if (str.empty() || !isdigit(str[0])) { + if (str.empty() || !IsDigit(str[0])) { return false; } errno = 0; diff --git a/src/gtest-port.cc b/src/gtest-port.cc index 5eec8fa7..8a7005f7 100644 --- a/src/gtest-port.cc +++ b/src/gtest-port.cc @@ -181,20 +181,20 @@ bool IsInSet(char ch, const char* str) { // Returns true iff ch belongs to the given classification. Unlike // similar functions in , these aren't affected by the // current locale. -bool IsDigit(char ch) { return '0' <= ch && ch <= '9'; } -bool IsPunct(char ch) { +bool IsAsciiDigit(char ch) { return '0' <= ch && ch <= '9'; } +bool IsAsciiPunct(char ch) { return IsInSet(ch, "^-!\"#$%&'()*+,./:;<=>?@[\\]_`{|}~"); } bool IsRepeat(char ch) { return IsInSet(ch, "?*+"); } -bool IsWhiteSpace(char ch) { return IsInSet(ch, " \f\n\r\t\v"); } -bool IsWordChar(char ch) { +bool IsAsciiWhiteSpace(char ch) { return IsInSet(ch, " \f\n\r\t\v"); } +bool IsAsciiWordChar(char ch) { return ('a' <= ch && ch <= 'z') || ('A' <= ch && ch <= 'Z') || ('0' <= ch && ch <= '9') || ch == '_'; } // Returns true iff "\\c" is a supported escape sequence. bool IsValidEscape(char c) { - return (IsPunct(c) || IsInSet(c, "dDfnrsStvwW")); + return (IsAsciiPunct(c) || IsInSet(c, "dDfnrsStvwW")); } // Returns true iff the given atom (specified by escaped and pattern) @@ -202,19 +202,19 @@ bool IsValidEscape(char c) { bool AtomMatchesChar(bool escaped, char pattern_char, char ch) { if (escaped) { // "\\p" where p is pattern_char. switch (pattern_char) { - case 'd': return IsDigit(ch); - case 'D': return !IsDigit(ch); + case 'd': return IsAsciiDigit(ch); + case 'D': return !IsAsciiDigit(ch); case 'f': return ch == '\f'; case 'n': return ch == '\n'; case 'r': return ch == '\r'; - case 's': return IsWhiteSpace(ch); - case 'S': return !IsWhiteSpace(ch); + case 's': return IsAsciiWhiteSpace(ch); + case 'S': return !IsAsciiWhiteSpace(ch); case 't': return ch == '\t'; case 'v': return ch == '\v'; - case 'w': return IsWordChar(ch); - case 'W': return !IsWordChar(ch); + case 'w': return IsAsciiWordChar(ch); + case 'W': return !IsAsciiWordChar(ch); } - return IsPunct(pattern_char) && pattern_char == ch; + return IsAsciiPunct(pattern_char) && pattern_char == ch; } return (pattern_char == '.' && ch != '\n') || pattern_char == ch; @@ -449,7 +449,7 @@ GTestLog::~GTestLog() { #pragma warning(disable: 4996) #endif // _MSC_VER -#if GTEST_HAS_STREAM_REDIRECTION_ +#if GTEST_HAS_STREAM_REDIRECTION // Object that captures an output stream (stdout/stderr). class CapturedStream { @@ -589,7 +589,7 @@ String GetCapturedStdout() { return GetCapturedStream(&g_captured_stdout); } // Stops capturing stderr and returns the captured string. String GetCapturedStderr() { return GetCapturedStream(&g_captured_stderr); } -#endif // GTEST_HAS_STREAM_REDIRECTION_ +#endif // GTEST_HAS_STREAM_REDIRECTION #if GTEST_HAS_DEATH_TEST @@ -619,7 +619,7 @@ static String FlagToEnvVar(const char* flag) { Message env_var; for (size_t i = 0; i != full_flag.length(); i++) { - env_var << static_cast(toupper(full_flag.c_str()[i])); + env_var << ToUpper(full_flag.c_str()[i]); } return env_var.GetString(); diff --git a/src/gtest-typed-test.cc b/src/gtest-typed-test.cc index 3cc4b5de..f70043e6 100644 --- a/src/gtest-typed-test.cc +++ b/src/gtest-typed-test.cc @@ -40,7 +40,7 @@ namespace internal { // Skips to the first non-space char in str. Returns an empty string if str // contains only whitespace characters. static const char* SkipSpaces(const char* str) { - while (isspace(*str)) + while (IsSpace(*str)) str++; return str; } diff --git a/src/gtest.cc b/src/gtest.cc index 93ab6a8d..287ca88e 100644 --- a/src/gtest.cc +++ b/src/gtest.cc @@ -501,7 +501,7 @@ bool UnitTestOptions::FilterMatchesTest(const String &test_case_name, !MatchesFilter(full_name, negative.c_str())); } -#if GTEST_OS_WINDOWS +#if GTEST_HAS_SEH // Returns EXCEPTION_EXECUTE_HANDLER if Google Test should handle the // given SEH exception, or EXCEPTION_CONTINUE_SEARCH otherwise. // This function is useful as an __except condition. @@ -527,7 +527,7 @@ int UnitTestOptions::GTestShouldProcessSEH(DWORD exception_code) { return should_handle ? EXCEPTION_EXECUTE_HANDLER : EXCEPTION_CONTINUE_SEARCH; } -#endif // GTEST_OS_WINDOWS +#endif // GTEST_HAS_SEH } // namespace internal @@ -1362,7 +1362,7 @@ AssertionResult HRESULTFailureHelper(const char* expr, kBufSize, // buf size NULL); // no arguments for inserts // Trims tailing white space (FormatMessage leaves a trailing cr-lf) - for (; message_length && isspace(error_text[message_length - 1]); + for (; message_length && IsSpace(error_text[message_length - 1]); --message_length) { error_text[message_length - 1] = '\0'; } @@ -1620,9 +1620,9 @@ bool String::CaseInsensitiveCStringEquals(const char * lhs, const char * rhs) { // current locale. bool String::CaseInsensitiveWideCStringEquals(const wchar_t* lhs, const wchar_t* rhs) { - if ( lhs == NULL ) return rhs == NULL; + if (lhs == NULL) return rhs == NULL; - if ( rhs == NULL ) return false; + if (rhs == NULL) return false; #if GTEST_OS_WINDOWS return _wcsicmp(lhs, rhs) == 0; @@ -2096,26 +2096,53 @@ static Result HandleSehExceptionsInMethodIfSupported( template static Result HandleExceptionsInMethodIfSupported( T* object, Result (T::*method)(), const char* location) { + // NOTE: The user code can affect the way in which Google Test handles + // exceptions by setting GTEST_FLAG(catch_exceptions), but only before + // RUN_ALL_TESTS() starts. It is technically possible to check the flag + // after the exception is caught and either report or re-throw the + // exception based on the flag's value: + // + // try { + // // Perform the test method. + // } catch (...) { + // if (GTEST_FLAG(catch_exceptions)) + // // Report the exception as failure. + // else + // throw; // Re-throws the original exception. + // } + // + // However, the purpose of this flag is to allow the program to drop into + // the debugger when the exception is thrown. On most platforms, once the + // control enters the catch block, the exception origin information is + // lost and the debugger will stop the program at the point of the + // re-throw in this function -- instead of at the point of the original + // throw statement in the code under test. For this reason, we perform + // the check early, sacrificing the ability to affect Google Test's + // exception handling in the method where the exception is thrown. + if (internal::GetUnitTestImpl()->catch_exceptions()) { #if GTEST_HAS_EXCEPTIONS - try { - return HandleSehExceptionsInMethodIfSupported(object, method, location); - } catch (const GoogleTestFailureException&) { // NOLINT - // This exception doesn't originate in code under test. It makes no - // sense to report it as a test failure. - throw; - } catch (const std::exception& e) { // NOLINT - internal::ReportFailureInUnknownLocation( - TestPartResult::kFatalFailure, - FormatCxxExceptionMessage(e.what(), location)); - } catch (...) { // NOLINT - internal::ReportFailureInUnknownLocation( - TestPartResult::kFatalFailure, - FormatCxxExceptionMessage(NULL, location)); - } - return static_cast(0); + try { + return HandleSehExceptionsInMethodIfSupported(object, method, location); + } catch (const GoogleTestFailureException&) { // NOLINT + // This exception doesn't originate in code under test. It makes no + // sense to report it as a test failure. + throw; + } catch (const std::exception& e) { // NOLINT + internal::ReportFailureInUnknownLocation( + TestPartResult::kFatalFailure, + FormatCxxExceptionMessage(e.what(), location)); + } catch (...) { // NOLINT + internal::ReportFailureInUnknownLocation( + TestPartResult::kFatalFailure, + FormatCxxExceptionMessage(NULL, location)); + } + return static_cast(0); #else - return HandleSehExceptionsInMethodIfSupported(object, method, location); + return HandleSehExceptionsInMethodIfSupported(object, method, location); #endif // GTEST_HAS_EXCEPTIONS + } else { + return (object->*method)(); + } } // Runs the test and updates the test result. @@ -3773,17 +3800,19 @@ void UnitTest::RecordPropertyForCurrentTest(const char* key, // We don't protect this under mutex_, as we only support calling it // from the main thread. int UnitTest::Run() { -#if GTEST_HAS_SEH - // Catch SEH-style exceptions. + // Captures the value of GTEST_FLAG(catch_exceptions). This value will be + // used for the duration of the program. + impl()->set_catch_exceptions(GTEST_FLAG(catch_exceptions)); +#if GTEST_HAS_SEH const bool in_death_test_child_process = internal::GTEST_FLAG(internal_run_death_test).length() > 0; // Either the user wants Google Test to catch exceptions thrown by the // tests or this is executing in the context of death test child // process. In either case the user does not want to see pop-up dialogs - // about crashes - they are expected.. - if (GTEST_FLAG(catch_exceptions) || in_death_test_child_process) { + // about crashes - they are expected. + if (impl()->catch_exceptions() || in_death_test_child_process) { #if !GTEST_OS_WINDOWS_MOBILE // SetErrorMode doesn't exist on CE. SetErrorMode(SEM_FAILCRITICALERRORS | SEM_NOALIGNMENTFAULTEXCEPT | @@ -3818,7 +3847,7 @@ int UnitTest::Run() { #endif // GTEST_HAS_SEH return HandleExceptionsInMethodIfSupported( - impl_, + impl(), &internal::UnitTestImpl::RunAllTests, "auxiliary test code (environments or event listeners)") ? 0 : 1; } @@ -3914,13 +3943,13 @@ UnitTestImpl::UnitTestImpl(UnitTest* parent) post_flag_parse_init_performed_(false), random_seed_(0), // Will be overridden by the flag before first use. random_(0), // Will be reseeded before first use. -#if GTEST_HAS_DEATH_TEST elapsed_time_(0), +#if GTEST_HAS_DEATH_TEST internal_run_death_test_flag_(NULL), - death_test_factory_(new DefaultDeathTestFactory) { -#else - elapsed_time_(0) { -#endif // GTEST_HAS_DEATH_TEST + death_test_factory_(new DefaultDeathTestFactory), +#endif + // Will be overridden by the flag before first use. + catch_exceptions_(false) { listeners()->SetDefaultResultPrinter(new PrettyUnitTestResultPrinter); } -- cgit v1.2.3 From 88e0df62470fa82e8d3010ef88241cd7565ebe9e Mon Sep 17 00:00:00 2001 From: "zhanyong.wan" Date: Wed, 8 Sep 2010 05:57:37 +0000 Subject: Removes all uses of StrStream; fixes the VC projects and simplifies them by using gtest-all.cc. --- src/gtest.cc | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) (limited to 'src') diff --git a/src/gtest.cc b/src/gtest.cc index 287ca88e..4f0446dd 100644 --- a/src/gtest.cc +++ b/src/gtest.cc @@ -1072,18 +1072,18 @@ AssertionResult FloatingPointLE(const char* expr1, // val2 is NaN, as the IEEE floating-point standard requires that // any predicate involving a NaN must return false. - StrStream val1_ss; + ::std::stringstream val1_ss; val1_ss << std::setprecision(std::numeric_limits::digits10 + 2) << val1; - StrStream val2_ss; + ::std::stringstream val2_ss; val2_ss << std::setprecision(std::numeric_limits::digits10 + 2) << val2; Message msg; msg << "Expected: (" << expr1 << ") <= (" << expr2 << ")\n" - << " Actual: " << StrStreamToString(&val1_ss) << " vs " - << StrStreamToString(&val2_ss); + << " Actual: " << StringStreamToString(&val1_ss) << " vs " + << StringStreamToString(&val2_ss); return AssertionFailure(msg); } @@ -1508,7 +1508,7 @@ String WideStringToUtf8(const wchar_t* str, int num_chars) { if (num_chars == -1) num_chars = static_cast(wcslen(str)); - StrStream stream; + ::std::stringstream stream; for (int i = 0; i < num_chars; ++i) { UInt32 unicode_code_point; @@ -1525,7 +1525,7 @@ String WideStringToUtf8(const wchar_t* str, int num_chars) { char buffer[32]; // CodePointToUtf8 requires a buffer this big. stream << CodePointToUtf8(unicode_code_point, buffer); } - return StrStreamToString(&stream); + return StringStreamToString(&stream); } // Converts a wide C string to a String using the UTF-8 encoding. @@ -1733,16 +1733,16 @@ String String::Format(const char * format, ...) { } } -// Converts the buffer in a StrStream to a String, converting NUL +// Converts the buffer in a stringstream to a String, converting NUL // bytes to "\\0" along the way. -String StrStreamToString(StrStream* ss) { +String StringStreamToString(::std::stringstream* ss) { const ::std::string& str = ss->str(); const char* const start = str.c_str(); const char* const end = start + str.length(); - // We need to use a helper StrStream to do this transformation + // We need to use a helper stringstream to do this transformation // because String doesn't support push_back(). - StrStream helper; + ::std::stringstream helper; for (const char* ch = start; ch != end; ++ch) { if (*ch == '\0') { helper << "\\0"; // Replaces NUL with "\\0"; @@ -3262,9 +3262,9 @@ void XmlUnitTestResultPrinter::PrintXmlTestCase(FILE* out, "errors=\"0\" time=\"%s\">\n", FormatTimeInMillisAsSeconds(test_case.elapsed_time()).c_str()); for (int i = 0; i < test_case.total_test_count(); ++i) { - StrStream stream; + ::std::stringstream stream; OutputXmlTestInfo(&stream, test_case.name(), *test_case.GetTestInfo(i)); - fprintf(out, "%s", StrStreamToString(&stream).c_str()); + fprintf(out, "%s", StringStreamToString(&stream).c_str()); } fprintf(out, " \n"); } -- cgit v1.2.3 From dac3e879c56a50696a36f53e1e5e353e48fa665f Mon Sep 17 00:00:00 2001 From: "zhanyong.wan" Date: Tue, 14 Sep 2010 05:35:59 +0000 Subject: Include gtest headers as user headers instead of system headers. --- src/gtest-all.cc | 2 +- src/gtest-death-test.cc | 8 ++++---- src/gtest-filepath.cc | 6 +++--- src/gtest-internal-inl.h | 6 +++--- src/gtest-port.cc | 8 ++++---- src/gtest-printers.cc | 4 ++-- src/gtest-test-part.cc | 2 +- src/gtest-typed-test.cc | 4 ++-- src/gtest.cc | 4 ++-- src/gtest_main.cc | 2 +- 10 files changed, 23 insertions(+), 23 deletions(-) (limited to 'src') diff --git a/src/gtest-all.cc b/src/gtest-all.cc index f3e22dd7..0a9cee52 100644 --- a/src/gtest-all.cc +++ b/src/gtest-all.cc @@ -36,7 +36,7 @@ // This line ensures that gtest.h can be compiled on its own, even // when it's fused. -#include +#include "gtest/gtest.h" // The following lines pull in the real gtest *.cc files. #include "src/gtest.cc" diff --git a/src/gtest-death-test.cc b/src/gtest-death-test.cc index 66bf1898..ffd9f3a4 100644 --- a/src/gtest-death-test.cc +++ b/src/gtest-death-test.cc @@ -31,8 +31,8 @@ // // This file implements death tests. -#include -#include +#include "gtest/gtest-death-test.h" +#include "gtest/internal/gtest-port.h" #if GTEST_HAS_DEATH_TEST @@ -54,8 +54,8 @@ #endif // GTEST_HAS_DEATH_TEST -#include -#include +#include "gtest/gtest-message.h" +#include "gtest/internal/gtest-string.h" // Indicates that this translation unit is part of Google Test's // implementation. It must come before gtest-internal-inl.h is diff --git a/src/gtest-filepath.cc b/src/gtest-filepath.cc index c1ef9188..96557f38 100644 --- a/src/gtest-filepath.cc +++ b/src/gtest-filepath.cc @@ -29,8 +29,8 @@ // // Authors: keith.ray@gmail.com (Keith Ray) -#include -#include +#include "gtest/internal/gtest-filepath.h" +#include "gtest/internal/gtest-port.h" #include @@ -57,7 +57,7 @@ #define GTEST_PATH_MAX_ _POSIX_PATH_MAX #endif // GTEST_OS_WINDOWS -#include +#include "gtest/internal/gtest-string.h" namespace testing { namespace internal { diff --git a/src/gtest-internal-inl.h b/src/gtest-internal-inl.h index fe53c218..e0f4af5a 100644 --- a/src/gtest-internal-inl.h +++ b/src/gtest-internal-inl.h @@ -56,14 +56,14 @@ #include #include -#include +#include "gtest/internal/gtest-port.h" #if GTEST_OS_WINDOWS #include // For DWORD. #endif // GTEST_OS_WINDOWS -#include // NOLINT -#include +#include "gtest/gtest.h" // NOLINT +#include "gtest/gtest-spi.h" namespace testing { diff --git a/src/gtest-port.cc b/src/gtest-port.cc index 8a7005f7..ae0c663d 100644 --- a/src/gtest-port.cc +++ b/src/gtest-port.cc @@ -29,7 +29,7 @@ // // Author: wan@google.com (Zhanyong Wan) -#include +#include "gtest/internal/gtest-port.h" #include #include @@ -51,9 +51,9 @@ #include #endif // GTEST_OS_MAC -#include -#include -#include +#include "gtest/gtest-spi.h" +#include "gtest/gtest-message.h" +#include "gtest/internal/gtest-string.h" // Indicates that this translation unit is part of Google Test's // implementation. It must come before gtest-internal-inl.h is diff --git a/src/gtest-printers.cc b/src/gtest-printers.cc index 07a0d857..147f8b2a 100644 --- a/src/gtest-printers.cc +++ b/src/gtest-printers.cc @@ -42,12 +42,12 @@ // or void PrintTo(const Foo&, ::std::ostream*) in the namespace that // defines Foo. -#include +#include "gtest/gtest-printers.h" #include #include #include // NOLINT #include -#include +#include "gtest/internal/gtest-port.h" namespace testing { diff --git a/src/gtest-test-part.cc b/src/gtest-test-part.cc index 5d183a44..5ddc67c1 100644 --- a/src/gtest-test-part.cc +++ b/src/gtest-test-part.cc @@ -31,7 +31,7 @@ // // The Google C++ Testing Framework (Google Test) -#include +#include "gtest/gtest-test-part.h" // Indicates that this translation unit is part of Google Test's // implementation. It must come before gtest-internal-inl.h is diff --git a/src/gtest-typed-test.cc b/src/gtest-typed-test.cc index f70043e6..a5cc88f9 100644 --- a/src/gtest-typed-test.cc +++ b/src/gtest-typed-test.cc @@ -29,8 +29,8 @@ // // Author: wan@google.com (Zhanyong Wan) -#include -#include +#include "gtest/gtest-typed-test.h" +#include "gtest/gtest.h" namespace testing { namespace internal { diff --git a/src/gtest.cc b/src/gtest.cc index 4f0446dd..34e56d75 100644 --- a/src/gtest.cc +++ b/src/gtest.cc @@ -31,8 +31,8 @@ // // The Google C++ Testing Framework (Google Test) -#include -#include +#include "gtest/gtest.h" +#include "gtest/gtest-spi.h" #include #include diff --git a/src/gtest_main.cc b/src/gtest_main.cc index 6d4d22d2..a09bbe0c 100644 --- a/src/gtest_main.cc +++ b/src/gtest_main.cc @@ -29,7 +29,7 @@ #include -#include +#include "gtest/gtest.h" GTEST_API_ int main(int argc, char **argv) { std::cout << "Running main() from gtest_main.cc\n"; -- cgit v1.2.3 From b5d3a17805fe0ed2ccde463412ae1fd206c4df21 Mon Sep 17 00:00:00 2001 From: "zhanyong.wan" Date: Mon, 27 Sep 2010 17:42:52 +0000 Subject: Allows EXPECT_FATAL_FAILURE() and friends to accept a string object as the second argument. --- src/gtest.cc | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'src') diff --git a/src/gtest.cc b/src/gtest.cc index 34e56d75..3b2238f4 100644 --- a/src/gtest.cc +++ b/src/gtest.cc @@ -607,7 +607,7 @@ AssertionResult HasOneFailure(const char* /* results_expr */, const char* /* substr_expr */, const TestPartResultArray& results, TestPartResult::Type type, - const char* substr) { + const string& substr) { const String expected(type == TestPartResult::kFatalFailure ? "1 fatal failure" : "1 non-fatal failure"); @@ -629,7 +629,7 @@ AssertionResult HasOneFailure(const char* /* results_expr */, return AssertionFailure(msg); } - if (strstr(r.message(), substr) == NULL) { + if (strstr(r.message(), substr.c_str()) == NULL) { msg << "Expected: " << expected << " containing \"" << substr << "\"\n" << " Actual:\n" @@ -646,7 +646,7 @@ AssertionResult HasOneFailure(const char* /* results_expr */, SingleFailureChecker:: SingleFailureChecker( const TestPartResultArray* results, TestPartResult::Type type, - const char* substr) + const string& substr) : results_(results), type_(type), substr_(substr) {} @@ -656,7 +656,7 @@ SingleFailureChecker:: SingleFailureChecker( // type and contains the given substring. If that's not the case, a // non-fatal failure will be generated. SingleFailureChecker::~SingleFailureChecker() { - EXPECT_PRED_FORMAT3(HasOneFailure, *results_, type_, substr_.c_str()); + EXPECT_PRED_FORMAT3(HasOneFailure, *results_, type_, substr_); } DefaultGlobalTestPartResultReporter::DefaultGlobalTestPartResultReporter( -- cgit v1.2.3 From 2d1835b086e69570e4c3e0ad6197da509bd0a957 Mon Sep 17 00:00:00 2001 From: "zhanyong.wan" Date: Mon, 27 Sep 2010 22:09:42 +0000 Subject: Removes uses of deprecated AssertionFailure() API (by Vlad Losev). --- src/gtest.cc | 70 ++++++++++++++++++++++++------------------------------------ 1 file changed, 28 insertions(+), 42 deletions(-) (limited to 'src') diff --git a/src/gtest.cc b/src/gtest.cc index 3b2238f4..0d41e465 100644 --- a/src/gtest.cc +++ b/src/gtest.cc @@ -618,23 +618,21 @@ AssertionResult HasOneFailure(const char* /* results_expr */, for (int i = 0; i < results.size(); i++) { msg << "\n" << results.GetTestPartResult(i); } - return AssertionFailure(msg); + return AssertionFailure() << msg; } const TestPartResult& r = results.GetTestPartResult(0); if (r.type() != type) { - msg << "Expected: " << expected << "\n" - << " Actual:\n" - << r; - return AssertionFailure(msg); + return AssertionFailure() << "Expected: " << expected << "\n" + << " Actual:\n" + << r; } if (strstr(r.message(), substr.c_str()) == NULL) { - msg << "Expected: " << expected << " containing \"" - << substr << "\"\n" - << " Actual:\n" - << r; - return AssertionFailure(msg); + return AssertionFailure() << "Expected: " << expected << " containing \"" + << substr << "\"\n" + << " Actual:\n" + << r; } return AssertionSuccess(); @@ -1011,7 +1009,7 @@ AssertionResult EqFailure(const char* expected_expression, msg << "\nWhich is: " << expected_value; } - return AssertionFailure(msg); + return AssertionFailure() << msg; } // Constructs a failure message for Boolean assertions such as EXPECT_TRUE. @@ -1041,13 +1039,12 @@ AssertionResult DoubleNearPredFormat(const char* expr1, // TODO(wan): do not print the value of an expression if it's // already a literal. - Message msg; - msg << "The difference between " << expr1 << " and " << expr2 + return AssertionFailure() + << "The difference between " << expr1 << " and " << expr2 << " is " << diff << ", which exceeds " << abs_error_expr << ", where\n" << expr1 << " evaluates to " << val1 << ",\n" << expr2 << " evaluates to " << val2 << ", and\n" << abs_error_expr << " evaluates to " << abs_error << "."; - return AssertionFailure(msg); } @@ -1080,12 +1077,10 @@ AssertionResult FloatingPointLE(const char* expr1, val2_ss << std::setprecision(std::numeric_limits::digits10 + 2) << val2; - Message msg; - msg << "Expected: (" << expr1 << ") <= (" << expr2 << ")\n" + return AssertionFailure() + << "Expected: (" << expr1 << ") <= (" << expr2 << ")\n" << " Actual: " << StringStreamToString(&val1_ss) << " vs " << StringStreamToString(&val2_ss); - - return AssertionFailure(msg); } } // namespace internal @@ -1132,11 +1127,10 @@ AssertionResult CmpHelper##op_name(const char* expr1, const char* expr2, \ if (val1 op val2) {\ return AssertionSuccess();\ } else {\ - Message msg;\ - msg << "Expected: (" << expr1 << ") " #op " (" << expr2\ + return AssertionFailure() \ + << "Expected: (" << expr1 << ") " #op " (" << expr2\ << "), actual: " << FormatForComparisonFailureMessage(val1, val2)\ << " vs " << FormatForComparisonFailureMessage(val2, val1);\ - return AssertionFailure(msg);\ }\ } @@ -1198,11 +1192,9 @@ AssertionResult CmpHelperSTRNE(const char* s1_expression, if (!String::CStringEquals(s1, s2)) { return AssertionSuccess(); } else { - Message msg; - msg << "Expected: (" << s1_expression << ") != (" - << s2_expression << "), actual: \"" - << s1 << "\" vs \"" << s2 << "\""; - return AssertionFailure(msg); + return AssertionFailure() << "Expected: (" << s1_expression << ") != (" + << s2_expression << "), actual: \"" + << s1 << "\" vs \"" << s2 << "\""; } } @@ -1214,11 +1206,10 @@ AssertionResult CmpHelperSTRCASENE(const char* s1_expression, if (!String::CaseInsensitiveCStringEquals(s1, s2)) { return AssertionSuccess(); } else { - Message msg; - msg << "Expected: (" << s1_expression << ") != (" + return AssertionFailure() + << "Expected: (" << s1_expression << ") != (" << s2_expression << ") (ignoring case), actual: \"" << s1 << "\" vs \"" << s2 << "\""; - return AssertionFailure(msg); } } @@ -1267,13 +1258,12 @@ AssertionResult IsSubstringImpl( const bool is_wide_string = sizeof(needle[0]) > 1; const char* const begin_string_quote = is_wide_string ? "L\"" : "\""; - return AssertionFailure( - Message() + return AssertionFailure() << "Value of: " << needle_expr << "\n" << " Actual: " << begin_string_quote << needle << "\"\n" << "Expected: " << (expected_to_be_substring ? "" : "not ") << "a substring of " << haystack_expr << "\n" - << "Which is: " << begin_string_quote << haystack << "\""); + << "Which is: " << begin_string_quote << haystack << "\""; } } // namespace @@ -1369,11 +1359,9 @@ AssertionResult HRESULTFailureHelper(const char* expr, #endif // GTEST_OS_WINDOWS_MOBILE const String error_hex(String::Format("0x%08X ", hr)); - Message msg; - msg << "Expected: " << expr << " " << expected << ".\n" + return ::testing::AssertionFailure() + << "Expected: " << expr << " " << expected << ".\n" << " Actual: " << error_hex << error_text << "\n"; - - return ::testing::AssertionFailure(msg); } } // namespace @@ -1584,12 +1572,10 @@ AssertionResult CmpHelperSTRNE(const char* s1_expression, return AssertionSuccess(); } - Message msg; - msg << "Expected: (" << s1_expression << ") != (" - << s2_expression << "), actual: " - << String::ShowWideCStringQuoted(s1) - << " vs " << String::ShowWideCStringQuoted(s2); - return AssertionFailure(msg); + return AssertionFailure() << "Expected: (" << s1_expression << ") != (" + << s2_expression << "), actual: " + << String::ShowWideCStringQuoted(s1) + << " vs " << String::ShowWideCStringQuoted(s2); } // Compares two C strings, ignoring case. Returns true iff they have -- cgit v1.2.3 From c18438ca2983d4f334cfdbd4453e15c41111fa17 Mon Sep 17 00:00:00 2001 From: "zhanyong.wan" Date: Mon, 11 Oct 2010 06:28:54 +0000 Subject: Makes gtest wokr on MinGW (by Vlad Losev); removes unused linked_ptr::release() method (by Zhanyong Wan). --- src/gtest-death-test.cc | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) (limited to 'src') diff --git a/src/gtest-death-test.cc b/src/gtest-death-test.cc index ffd9f3a4..e11f5041 100644 --- a/src/gtest-death-test.cc +++ b/src/gtest-death-test.cc @@ -526,11 +526,11 @@ bool DeathTestImpl::Passed(bool status_ok) { // class WindowsDeathTest : public DeathTestImpl { public: - WindowsDeathTest(const char* statement, - const RE* regex, + WindowsDeathTest(const char* a_statement, + const RE* a_regex, const char* file, int line) - : DeathTestImpl(statement, regex), file_(file), line_(line) {} + : DeathTestImpl(a_statement, a_regex), file_(file), line_(line) {} // All of these virtual functions are inherited from DeathTest. virtual int Wait(); @@ -587,12 +587,12 @@ int WindowsDeathTest::Wait() { GTEST_DEATH_TEST_CHECK_( WAIT_OBJECT_0 == ::WaitForSingleObject(child_handle_.Get(), INFINITE)); - DWORD status; - GTEST_DEATH_TEST_CHECK_(::GetExitCodeProcess(child_handle_.Get(), &status) - != FALSE); + DWORD status_code; + GTEST_DEATH_TEST_CHECK_( + ::GetExitCodeProcess(child_handle_.Get(), &status_code) != FALSE); child_handle_.Reset(); - set_status(static_cast(status)); - return this->status(); + set_status(static_cast(status_code)); + return status(); } // The AssumeRole process for a Windows death test. It creates a child -- cgit v1.2.3 From 2c8101052343798fe1e2fbcc7f07c27fd3556d1c Mon Sep 17 00:00:00 2001 From: "zhanyong.wan" Date: Thu, 14 Oct 2010 06:50:49 +0000 Subject: Adds a missing #include (by Vlad Losev). --- src/gtest-port.cc | 1 + 1 file changed, 1 insertion(+) (limited to 'src') diff --git a/src/gtest-port.cc b/src/gtest-port.cc index ae0c663d..da62fbab 100644 --- a/src/gtest-port.cc +++ b/src/gtest-port.cc @@ -53,6 +53,7 @@ #include "gtest/gtest-spi.h" #include "gtest/gtest-message.h" +#include "gtest/internal/gtest-internal.h" #include "gtest/internal/gtest-string.h" // Indicates that this translation unit is part of Google Test's -- cgit v1.2.3 From 50f4deb1cf3ef32282c13b7cb84a81b1bf61e0d8 Mon Sep 17 00:00:00 2001 From: vladlosev Date: Mon, 18 Oct 2010 22:09:55 +0000 Subject: Modifies handling of C++ exceptions in death tests to treat exceptions escaping them as failures. --- src/gtest-death-test.cc | 33 +++++++++++++++++++++++---------- 1 file changed, 23 insertions(+), 10 deletions(-) (limited to 'src') diff --git a/src/gtest-death-test.cc b/src/gtest-death-test.cc index e11f5041..3ab9cf9e 100644 --- a/src/gtest-death-test.cc +++ b/src/gtest-death-test.cc @@ -182,15 +182,19 @@ static String DeathTestThreadWarning(size_t thread_count) { // Flag characters for reporting a death test that did not die. static const char kDeathTestLived = 'L'; static const char kDeathTestReturned = 'R'; +static const char kDeathTestThrew = 'T'; static const char kDeathTestInternalError = 'I'; -// An enumeration describing all of the possible ways that a death test -// can conclude. DIED means that the process died while executing the -// test code; LIVED means that process lived beyond the end of the test -// code; and RETURNED means that the test statement attempted a "return," -// which is not allowed. IN_PROGRESS means the test has not yet -// concluded. -enum DeathTestOutcome { IN_PROGRESS, DIED, LIVED, RETURNED }; +// An enumeration describing all of the possible ways that a death test can +// conclude. DIED means that the process died while executing the test +// code; LIVED means that process lived beyond the end of the test code; +// RETURNED means that the test statement attempted to execute a return +// statement, which is not allowed; THREW means that the test statement +// returned control by throwing an exception. IN_PROGRESS means the test +// has not yet concluded. +// TODO(vladl@google.com): Unify names and possibly values for +// AbortReason, DeathTestOutcome, and flag characters above. +enum DeathTestOutcome { IN_PROGRESS, DIED, LIVED, RETURNED, THREW }; // Routine for aborting the program which is safe to call from an // exec-style death test child process, in which case the error @@ -388,6 +392,9 @@ void DeathTestImpl::ReadAndInterpretStatusByte() { case kDeathTestReturned: set_outcome(RETURNED); break; + case kDeathTestThrew: + set_outcome(THREW); + break; case kDeathTestLived: set_outcome(LIVED); break; @@ -416,7 +423,9 @@ void DeathTestImpl::Abort(AbortReason reason) { // it finds any data in our pipe. So, here we write a single flag byte // to the pipe, then exit. const char status_ch = - reason == TEST_DID_NOT_DIE ? kDeathTestLived : kDeathTestReturned; + reason == TEST_DID_NOT_DIE ? kDeathTestLived : + reason == TEST_THREW_EXCEPTION ? kDeathTestThrew : kDeathTestReturned; + GTEST_DEATH_TEST_CHECK_SYSCALL_(posix::Write(write_fd(), &status_ch, 1)); // We are leaking the descriptor here because on some platforms (i.e., // when built as Windows DLL), destructors of global objects will still @@ -434,8 +443,8 @@ void DeathTestImpl::Abort(AbortReason reason) { // // Private data members: // outcome: An enumeration describing how the death test -// concluded: DIED, LIVED, or RETURNED. The death test fails -// in the latter two cases. +// concluded: DIED, LIVED, THREW, or RETURNED. The death test +// fails in the latter three cases. // status: The exit status of the child process. On *nix, it is in the // in the format specified by wait(2). On Windows, this is the // value supplied to the ExitProcess() API or a numeric code @@ -466,6 +475,10 @@ bool DeathTestImpl::Passed(bool status_ok) { buffer << " Result: failed to die.\n" << " Error msg: " << error_message; break; + case THREW: + buffer << " Result: threw an exception.\n" + << " Error msg: " << error_message; + break; case RETURNED: buffer << " Result: illegal return in test statement.\n" << " Error msg: " << error_message; -- cgit v1.2.3 From 25958f3e4c4097caca8347b7937f5f6fb26d6c56 Mon Sep 17 00:00:00 2001 From: vladlosev Date: Fri, 22 Oct 2010 01:33:11 +0000 Subject: Fixes compiler warning when built with -std=c++0x. --- src/gtest.cc | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'src') diff --git a/src/gtest.cc b/src/gtest.cc index 0d41e465..ea3a47c5 100644 --- a/src/gtest.cc +++ b/src/gtest.cc @@ -945,8 +945,8 @@ Message& Message::operator <<(const ::wstring& wstr) { AssertionResult::AssertionResult(const AssertionResult& other) : success_(other.success_), message_(other.message_.get() != NULL ? - new internal::String(*other.message_) : - static_cast(NULL)) { + new ::std::string(*other.message_) : + static_cast< ::std::string*>(NULL)) { } // Returns the assertion's negation. Used with EXPECT/ASSERT_FALSE. -- cgit v1.2.3 From 82cc1d1135879be3b901a10e224dbd827365f8bf Mon Sep 17 00:00:00 2001 From: vladlosev Date: Tue, 26 Oct 2010 23:12:47 +0000 Subject: Changes default of --gtest_catch_exceptions to true. --- src/gtest.cc | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) (limited to 'src') diff --git a/src/gtest.cc b/src/gtest.cc index ea3a47c5..ba27bba0 100644 --- a/src/gtest.cc +++ b/src/gtest.cc @@ -191,7 +191,7 @@ GTEST_DEFINE_bool_( GTEST_DEFINE_bool_( catch_exceptions, - internal::BoolFromGTestEnv("catch_exceptions", false), + internal::BoolFromGTestEnv("catch_exceptions", true), "True iff " GTEST_NAME_ " should catch exceptions and treat them as test failures."); @@ -4711,8 +4711,9 @@ static const char kColorEncodedHelpMessage[] = " Turn assertion failures into debugger break-points.\n" " @G--" GTEST_FLAG_PREFIX_ "throw_on_failure@D\n" " Turn assertion failures into C++ exceptions.\n" -" @G--" GTEST_FLAG_PREFIX_ "catch_exceptions@D\n" -" Suppress pop-ups caused by exceptions.\n" +" @G--" GTEST_FLAG_PREFIX_ "catch_exceptions=0@D\n" +" Do not report exceptions as test failures. Instead, allow them\n" +" to crash the program or throw a pop-up (on Windows).\n" "\n" "Except for @G--" GTEST_FLAG_PREFIX_ "list_tests@D, you can alternatively set " "the corresponding\n" -- cgit v1.2.3 From 42bf979ce7c107bfc214758e4a511232dd9b2e0a Mon Sep 17 00:00:00 2001 From: vladlosev Date: Tue, 30 Nov 2010 22:10:12 +0000 Subject: Adds Google Native Client compatibility (issue 329). --- src/gtest-filepath.cc | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'src') diff --git a/src/gtest-filepath.cc b/src/gtest-filepath.cc index 96557f38..118848a7 100644 --- a/src/gtest-filepath.cc +++ b/src/gtest-filepath.cc @@ -39,8 +39,8 @@ #elif GTEST_OS_WINDOWS #include #include -#elif GTEST_OS_SYMBIAN -// Symbian OpenC has PATH_MAX in sys/syslimits.h +#elif GTEST_OS_SYMBIAN || GTEST_OS_NACL +// Symbian OpenC and NaCl have PATH_MAX in sys/syslimits.h #include #else #include -- cgit v1.2.3 From b5eb6ed9e27b7bf80a406e4a38ffe42db43889cc Mon Sep 17 00:00:00 2001 From: "zhanyong.wan" Date: Thu, 2 Dec 2010 23:28:38 +0000 Subject: Makes gtest print string literals correctly when it contains \x escape sequences. Contributed by Yair Chuchem. --- src/gtest-printers.cc | 41 +++++++++++++++++++++++++++++------------ 1 file changed, 29 insertions(+), 12 deletions(-) (limited to 'src') diff --git a/src/gtest-printers.cc b/src/gtest-printers.cc index 147f8b2a..c85d5822 100644 --- a/src/gtest-printers.cc +++ b/src/gtest-printers.cc @@ -194,25 +194,25 @@ static CharFormat PrintAsCharLiteralTo(Char c, ostream* os) { return kSpecialEscape; } -// Prints a char as if it's part of a string literal, escaping it when -// necessary. -static void PrintAsWideStringLiteralTo(wchar_t c, ostream* os) { +// Prints a char c as if it's part of a string literal, escaping it when +// necessary; returns how c was formatted. +static CharFormat PrintAsWideStringLiteralTo(wchar_t c, ostream* os) { switch (c) { case L'\'': *os << "'"; - break; + return kAsIs; case L'"': *os << "\\\""; - break; + return kSpecialEscape; default: - PrintAsCharLiteralTo(c, os); + return PrintAsCharLiteralTo(c, os); } } -// Prints a char as if it's part of a string literal, escaping it when -// necessary. -static void PrintAsNarrowStringLiteralTo(char c, ostream* os) { - PrintAsWideStringLiteralTo(static_cast(c), os); +// Prints a char c as if it's part of a string literal, escaping it when +// necessary; returns how c was formatted. +static CharFormat PrintAsNarrowStringLiteralTo(char c, ostream* os) { + return PrintAsWideStringLiteralTo(static_cast(c), os); } // Prints a wide or narrow character c and its code. '\0' is printed @@ -263,8 +263,16 @@ void PrintTo(wchar_t wc, ostream* os) { // and may not be null-terminated. static void PrintCharsAsStringTo(const char* begin, size_t len, ostream* os) { *os << "\""; + bool is_previous_hex = false; for (size_t index = 0; index < len; ++index) { - PrintAsNarrowStringLiteralTo(begin[index], os); + const char cur = begin[index]; + if (is_previous_hex && IsXDigit(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 << "\" \""; + } + is_previous_hex = PrintAsNarrowStringLiteralTo(cur, os) == kHexEscape; } *os << "\""; } @@ -280,8 +288,17 @@ void UniversalPrintArray(const char* begin, size_t len, ostream* os) { static void PrintWideCharsAsStringTo(const wchar_t* begin, size_t len, ostream* os) { *os << "L\""; + bool is_previous_hex = false; for (size_t index = 0; index < len; ++index) { - PrintAsWideStringLiteralTo(begin[index], os); + const wchar_t cur = begin[index]; + if (is_previous_hex && 0 <= cur && cur < 128 && + IsXDigit(static_cast(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 << "\""; } -- cgit v1.2.3 From a198966dd349f446f0ab065e5576db7ac1e48e63 Mon Sep 17 00:00:00 2001 From: vladlosev Date: Sat, 29 Jan 2011 16:15:40 +0000 Subject: Renames some internal functions to avoid name clashes. --- src/gtest-printers.cc | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'src') diff --git a/src/gtest-printers.cc b/src/gtest-printers.cc index c85d5822..bfbca9c8 100644 --- a/src/gtest-printers.cc +++ b/src/gtest-printers.cc @@ -308,7 +308,7 @@ void PrintTo(const char* s, ostream* os) { if (s == NULL) { *os << "NULL"; } else { - *os << implicit_cast(s) << " pointing to "; + *os << ImplicitCast_(s) << " pointing to "; PrintCharsAsStringTo(s, strlen(s), os); } } @@ -325,7 +325,7 @@ void PrintTo(const wchar_t* s, ostream* os) { if (s == NULL) { *os << "NULL"; } else { - *os << implicit_cast(s) << " pointing to "; + *os << ImplicitCast_(s) << " pointing to "; PrintWideCharsAsStringTo(s, wcslen(s), os); } } -- cgit v1.2.3 From c8efea670544c86a169f920c567a9dae86227e95 Mon Sep 17 00:00:00 2001 From: vladlosev Date: Sat, 29 Jan 2011 16:19:14 +0000 Subject: template selection error in IBM's xIC_r compiler. --- src/gtest.cc | 26 ++++++++++++++++---------- 1 file changed, 16 insertions(+), 10 deletions(-) (limited to 'src') diff --git a/src/gtest.cc b/src/gtest.cc index ba27bba0..0e89d2bc 100644 --- a/src/gtest.cc +++ b/src/gtest.cc @@ -2047,13 +2047,17 @@ class GoogleTestFailureException : public ::std::runtime_error { }; #endif // GTEST_HAS_EXCEPTIONS +namespace internal { +// We put these helper functions in the internal namespace as IBM's xIC_r +// compiler rejects the code if they were declared static. + // Runs the given method and handles SEH exceptions it throws, when // SEH is supported; returns the 0-value for type Result in case of an // SEH exception. (Microsoft compilers cannot handle SEH and C++ // exceptions in the same function. Therefore, we provide a separate // wrapper function for handling SEH exceptions.) template -static Result HandleSehExceptionsInMethodIfSupported( +Result HandleSehExceptionsInMethodIfSupported( T* object, Result (T::*method)(), const char* location) { #if GTEST_HAS_SEH __try { @@ -2080,7 +2084,7 @@ static Result HandleSehExceptionsInMethodIfSupported( // exceptions, if they are supported; returns the 0-value for type // Result in case of an SEH exception. template -static Result HandleExceptionsInMethodIfSupported( +Result HandleExceptionsInMethodIfSupported( T* object, Result (T::*method)(), const char* location) { // NOTE: The user code can affect the way in which Google Test handles // exceptions by setting GTEST_FLAG(catch_exceptions), but only before @@ -2131,17 +2135,19 @@ static Result HandleExceptionsInMethodIfSupported( } } +} // namespace internal + // Runs the test and updates the test result. void Test::Run() { if (!HasSameFixtureClass()) return; internal::UnitTestImpl* const impl = internal::GetUnitTestImpl(); impl->os_stack_trace_getter()->UponLeavingGTest(); - HandleExceptionsInMethodIfSupported(this, &Test::SetUp, "SetUp()"); + internal::HandleExceptionsInMethodIfSupported(this, &Test::SetUp, "SetUp()"); // We will run the test only if SetUp() was successful. if (!HasFatalFailure()) { impl->os_stack_trace_getter()->UponLeavingGTest(); - HandleExceptionsInMethodIfSupported( + internal::HandleExceptionsInMethodIfSupported( this, &Test::TestBody, "the test body"); } @@ -2149,7 +2155,7 @@ void Test::Run() { // always call TearDown(), even if SetUp() or the test body has // failed. impl->os_stack_trace_getter()->UponLeavingGTest(); - HandleExceptionsInMethodIfSupported( + internal::HandleExceptionsInMethodIfSupported( this, &Test::TearDown, "TearDown()"); } @@ -2306,7 +2312,7 @@ void TestInfo::Run() { impl->os_stack_trace_getter()->UponLeavingGTest(); // Creates the test object. - Test* const test = HandleExceptionsInMethodIfSupported( + Test* const test = internal::HandleExceptionsInMethodIfSupported( factory_, &internal::TestFactoryBase::CreateTest, "the test fixture's constructor"); @@ -2320,7 +2326,7 @@ void TestInfo::Run() { // Deletes the test object. impl->os_stack_trace_getter()->UponLeavingGTest(); - HandleExceptionsInMethodIfSupported( + internal::HandleExceptionsInMethodIfSupported( test, &Test::DeleteSelf_, "the test fixture's destructor"); result_.set_elapsed_time(internal::GetTimeInMillis() - start); @@ -2415,7 +2421,7 @@ void TestCase::Run() { repeater->OnTestCaseStart(*this); impl->os_stack_trace_getter()->UponLeavingGTest(); - HandleExceptionsInMethodIfSupported( + internal::HandleExceptionsInMethodIfSupported( this, &TestCase::RunSetUpTestCase, "SetUpTestCase()"); const internal::TimeInMillis start = internal::GetTimeInMillis(); @@ -2425,7 +2431,7 @@ void TestCase::Run() { elapsed_time_ = internal::GetTimeInMillis() - start; impl->os_stack_trace_getter()->UponLeavingGTest(); - HandleExceptionsInMethodIfSupported( + internal::HandleExceptionsInMethodIfSupported( this, &TestCase::RunTearDownTestCase, "TearDownTestCase()"); repeater->OnTestCaseEnd(*this); @@ -3832,7 +3838,7 @@ int UnitTest::Run() { } #endif // GTEST_HAS_SEH - return HandleExceptionsInMethodIfSupported( + return internal::HandleExceptionsInMethodIfSupported( impl(), &internal::UnitTestImpl::RunAllTests, "auxiliary test code (environments or event listeners)") ? 0 : 1; -- cgit v1.2.3 From 9bcf4d0a654b27732e2fa901fe98c09aba71773a Mon Sep 17 00:00:00 2001 From: "zhanyong.wan" Date: Wed, 2 Feb 2011 00:49:33 +0000 Subject: Adds type_param and value_param as attributes to the XML report; also removes the comment() and test_case_comment() fields of TestInfo. Proposed and initally implemented by Joey Oravec. Re-implemented by Vlad Losev. --- src/gtest-internal-inl.h | 8 ++++-- src/gtest.cc | 73 +++++++++++++++++++++++++++++++----------------- 2 files changed, 52 insertions(+), 29 deletions(-) (limited to 'src') diff --git a/src/gtest-internal-inl.h b/src/gtest-internal-inl.h index e0f4af5a..8629c6fb 100644 --- a/src/gtest-internal-inl.h +++ b/src/gtest-internal-inl.h @@ -607,10 +607,12 @@ class GTEST_API_ UnitTestImpl { // Arguments: // // test_case_name: name of the test case + // type_param: the name of the test's type parameter, or NULL if + // this is not a typed or a type-parameterized test. // set_up_tc: pointer to the function that sets up the test case // tear_down_tc: pointer to the function that tears down the test case TestCase* GetTestCase(const char* test_case_name, - const char* comment, + const char* type_param, Test::SetUpTestCaseFunc set_up_tc, Test::TearDownTestCaseFunc tear_down_tc); @@ -623,7 +625,7 @@ class GTEST_API_ UnitTestImpl { // test_info: the TestInfo object void AddTestInfo(Test::SetUpTestCaseFunc set_up_tc, Test::TearDownTestCaseFunc tear_down_tc, - TestInfo * test_info) { + TestInfo* test_info) { // In order to support thread-safe death tests, we need to // remember the original working directory when the test program // was first invoked. We cannot do this in RUN_ALL_TESTS(), as @@ -638,7 +640,7 @@ class GTEST_API_ UnitTestImpl { } GetTestCase(test_info->test_case_name(), - test_info->test_case_comment(), + test_info->type_param(), set_up_tc, tear_down_tc)->AddTestInfo(test_info); } diff --git a/src/gtest.cc b/src/gtest.cc index 0e89d2bc..575a8a5f 100644 --- a/src/gtest.cc +++ b/src/gtest.cc @@ -2174,16 +2174,18 @@ bool Test::HasNonfatalFailure() { // Constructs a TestInfo object. It assumes ownership of the test factory // object. +// TODO(vladl@google.com): Make a_test_case_name and a_name const string&'s +// to signify they cannot be NULLs. TestInfo::TestInfo(const char* a_test_case_name, const char* a_name, - const char* a_test_case_comment, - const char* a_comment, + const char* a_type_param, + const char* a_value_param, internal::TypeId fixture_class_id, internal::TestFactoryBase* factory) : test_case_name_(a_test_case_name), name_(a_name), - test_case_comment_(a_test_case_comment), - comment_(a_comment), + type_param_(a_type_param ? new std::string(a_type_param) : NULL), + value_param_(a_value_param ? new std::string(a_value_param) : NULL), fixture_class_id_(fixture_class_id), should_run_(false), is_disabled_(false), @@ -2203,10 +2205,10 @@ namespace internal { // // test_case_name: name of the test case // name: name of the test -// test_case_comment: a comment on the test case that will be included in -// the test output -// comment: a comment on the test that will be included in the -// test output +// type_param: the name of the test's type parameter, or NULL if +// this is not a typed or a type-parameterized test. +// value_param: text representation of the test's value parameter, +// or NULL if this is not a value-parameterized test. // fixture_class_id: ID of the test fixture class // set_up_tc: pointer to the function that sets up the test case // tear_down_tc: pointer to the function that tears down the test case @@ -2215,13 +2217,14 @@ namespace internal { // ownership of the factory object. TestInfo* MakeAndRegisterTestInfo( const char* test_case_name, const char* name, - const char* test_case_comment, const char* comment, + const char* type_param, + const char* value_param, TypeId fixture_class_id, SetUpTestCaseFunc set_up_tc, TearDownTestCaseFunc tear_down_tc, TestFactoryBase* factory) { TestInfo* const test_info = - new TestInfo(test_case_name, name, test_case_comment, comment, + new TestInfo(test_case_name, name, type_param, value_param, fixture_class_id, factory); GetUnitTestImpl()->AddTestInfo(set_up_tc, tear_down_tc, test_info); return test_info; @@ -2370,13 +2373,15 @@ int TestCase::total_test_count() const { // Arguments: // // name: name of the test case +// a_type_param: the name of the test case's type parameter, or NULL if +// this is not a typed or a type-parameterized test case. // set_up_tc: pointer to the function that sets up the test case // tear_down_tc: pointer to the function that tears down the test case -TestCase::TestCase(const char* a_name, const char* a_comment, +TestCase::TestCase(const char* a_name, const char* a_type_param, Test::SetUpTestCaseFunc set_up_tc, Test::TearDownTestCaseFunc tear_down_tc) : name_(a_name), - comment_(a_comment), + type_param_(a_type_param ? new std::string(a_type_param) : NULL), set_up_tc_(set_up_tc), tear_down_tc_(tear_down_tc), should_run_(false), @@ -2648,15 +2653,19 @@ void ColoredPrintf(GTestColor color, const char* fmt, ...) { } void PrintFullTestCommentIfPresent(const TestInfo& test_info) { - const char* const comment = test_info.comment(); - const char* const test_case_comment = test_info.test_case_comment(); - - if (test_case_comment[0] != '\0' || comment[0] != '\0') { - printf(", where %s", test_case_comment); - if (test_case_comment[0] != '\0' && comment[0] != '\0') { - printf(" and "); + const char* const type_param = test_info.type_param(); + const char* const value_param = test_info.value_param(); + + if (type_param != NULL || value_param != NULL) { + printf(", where "); + if (type_param != NULL) { + printf("TypeParam = %s", type_param); + if (value_param != NULL) + printf(" and "); + } + if (value_param != NULL) { + printf("GetParam() = %s", value_param); } - printf("%s", comment); } } @@ -2739,10 +2748,10 @@ void PrettyUnitTestResultPrinter::OnTestCaseStart(const TestCase& test_case) { FormatCountableNoun(test_case.test_to_run_count(), "test", "tests"); ColoredPrintf(COLOR_GREEN, "[----------] "); printf("%s from %s", counts.c_str(), test_case_name_.c_str()); - if (test_case.comment()[0] == '\0') { + if (test_case.type_param() == NULL) { printf("\n"); } else { - printf(", where %s\n", test_case.comment()); + printf(", where TypeParam = %s\n", test_case.type_param()); } fflush(stdout); } @@ -3208,8 +3217,18 @@ void XmlUnitTestResultPrinter::OutputXmlTestInfo(::std::ostream* stream, const TestInfo& test_info) { const TestResult& result = *test_info.result(); *stream << " Date: Wed, 2 Feb 2011 01:25:37 +0000 Subject: Add markers to death test messages to make them more recogizable (by Jeff Shute). --- src/gtest-death-test.cc | 29 ++++++++++++++++++++++++----- 1 file changed, 24 insertions(+), 5 deletions(-) (limited to 'src') diff --git a/src/gtest-death-test.cc b/src/gtest-death-test.cc index 3ab9cf9e..3e651939 100644 --- a/src/gtest-death-test.cc +++ b/src/gtest-death-test.cc @@ -438,6 +438,24 @@ void DeathTestImpl::Abort(AbortReason reason) { _exit(1); // Exits w/o any normal exit hooks (we were supposed to crash) } +// Returns an indented copy of stderr output for a death test. +// This makes distinguishing death test output lines from regular log lines +// much easier. +static ::std::string FormatDeathTestOutput(const ::std::string& output) { + ::std::string ret; + for (size_t at = 0; ; ) { + const size_t line_end = output.find('\n', at); + ret += "[ DEATH ] "; + if (line_end == ::std::string::npos) { + ret += output.substr(at); + break; + } + ret += output.substr(at, line_end + 1 - at); + at = line_end + 1; + } + return ret; +} + // Assesses the success or failure of a death test, using both private // members which have previously been set, and one argument: // @@ -473,15 +491,15 @@ bool DeathTestImpl::Passed(bool status_ok) { switch (outcome()) { case LIVED: buffer << " Result: failed to die.\n" - << " Error msg: " << error_message; + << " Error msg:\n" << FormatDeathTestOutput(error_message); break; case THREW: buffer << " Result: threw an exception.\n" - << " Error msg: " << error_message; + << " Error msg:\n" << FormatDeathTestOutput(error_message); break; case RETURNED: buffer << " Result: illegal return in test statement.\n" - << " Error msg: " << error_message; + << " Error msg:\n" << FormatDeathTestOutput(error_message); break; case DIED: if (status_ok) { @@ -491,11 +509,12 @@ bool DeathTestImpl::Passed(bool status_ok) { } else { buffer << " Result: died but not with expected error.\n" << " Expected: " << regex()->pattern() << "\n" - << "Actual msg: " << error_message; + << "Actual msg:\n" << FormatDeathTestOutput(error_message); } } else { buffer << " Result: died but not with expected exit code:\n" - << " " << ExitSummary(status()) << "\n"; + << " " << ExitSummary(status()) << "\n" + << "Actual msg:\n" << FormatDeathTestOutput(error_message); } break; case IN_PROGRESS: -- cgit v1.2.3 From 9d7455f9844e293dff8b7902f0c2553094f2f976 Mon Sep 17 00:00:00 2001 From: vladlosev Date: Wed, 2 Feb 2011 10:07:04 +0000 Subject: Adds null check for file locations in XML output printer. --- src/gtest-port.cc | 32 ++++++++++++++++++++++++++++++++ src/gtest.cc | 5 +++-- 2 files changed, 35 insertions(+), 2 deletions(-) (limited to 'src') diff --git a/src/gtest-port.cc b/src/gtest-port.cc index da62fbab..4310a735 100644 --- a/src/gtest-port.cc +++ b/src/gtest-port.cc @@ -424,6 +424,38 @@ void RE::Init(const char* regex) { #endif // GTEST_USES_POSIX_RE +const char kUnknownFile[] = "unknown file"; + +// Formats a source file path and a line number as they would appear +// in an error message from the compiler used to compile this code. +GTEST_API_ ::std::string FormatFileLocation(const char* file, int line) { + const char* const file_name = file == NULL ? kUnknownFile : file; + + if (line < 0) { + return String::Format("%s:", file_name).c_str(); + } +#ifdef _MSC_VER + return String::Format("%s(%d):", file_name, line).c_str(); +#else + return String::Format("%s:%d:", file_name, line).c_str(); +#endif // _MSC_VER +} + +// Formats a file location for compiler-independent XML output. +// Although this function is not platform dependent, we put it next to +// FormatFileLocation in order to contrast the two functions. +// Note that FormatCompilerIndependentFileLocation() does NOT append colon +// to the file location it produces, unlike FormatFileLocation(). +GTEST_API_ ::std::string FormatCompilerIndependentFileLocation( + const char* file, int line) { + const char* const file_name = file == NULL ? kUnknownFile : file; + + if (line < 0) + return file_name; + else + return String::Format("%s:%d", file_name, line).c_str(); +} + GTestLog::GTestLog(GTestLogSeverity severity, const char* file, int line) : severity_(severity) { diff --git a/src/gtest.cc b/src/gtest.cc index 575a8a5f..1c58c6fd 100644 --- a/src/gtest.cc +++ b/src/gtest.cc @@ -3245,8 +3245,9 @@ void XmlUnitTestResultPrinter::OutputXmlTestInfo(::std::ostream* stream, << EscapeXmlAttribute(part.summary()).c_str() << "\" type=\"\">"; const String message = RemoveInvalidXmlCharacters(String::Format( - "%s:%d\n%s", - part.file_name(), part.line_number(), + "%s\n%s", + internal::FormatCompilerIndependentFileLocation( + part.file_name(), part.line_number()).c_str(), part.message()).c_str()); OutputXmlCDataSection(stream, message.c_str()); *stream << "\n"; -- cgit v1.2.3 From 0980b4bd66b496074d9e34d9f05244e700e9406d Mon Sep 17 00:00:00 2001 From: vladlosev Date: Sat, 12 Feb 2011 07:12:20 +0000 Subject: Fixes off-by-one error in a message about test sharding (by David Glasser). --- src/gtest.cc | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) (limited to 'src') diff --git a/src/gtest.cc b/src/gtest.cc index 1c58c6fd..53a52fbf 100644 --- a/src/gtest.cc +++ b/src/gtest.cc @@ -2716,9 +2716,10 @@ void PrettyUnitTestResultPrinter::OnTestIterationStart( } if (internal::ShouldShard(kTestTotalShards, kTestShardIndex, false)) { + const Int32 shard_index = Int32FromEnvOrDie(kTestShardIndex, -1); ColoredPrintf(COLOR_YELLOW, - "Note: This is test shard %s of %s.\n", - internal::posix::GetEnv(kTestShardIndex), + "Note: This is test shard %d of %s.\n", + static_cast(shard_index) + 1, internal::posix::GetEnv(kTestTotalShards)); } -- cgit v1.2.3 From ffeb11d14a890b902dbb26ff2296cda7bf2d31df Mon Sep 17 00:00:00 2001 From: "zhanyong.wan" Date: Tue, 22 Feb 2011 22:08:59 +0000 Subject: Indents preprocessor directives. --- src/gtest-death-test.cc | 110 ++++++++++++++++++++++++------------------ src/gtest-filepath.cc | 26 +++++----- src/gtest-internal-inl.h | 24 ++++++---- src/gtest-port.cc | 31 ++++++------ src/gtest-printers.cc | 6 +-- src/gtest.cc | 121 ++++++++++++++++++++++++++--------------------- 6 files changed, 179 insertions(+), 139 deletions(-) (limited to 'src') diff --git a/src/gtest-death-test.cc b/src/gtest-death-test.cc index 3e651939..a0ed80d1 100644 --- a/src/gtest-death-test.cc +++ b/src/gtest-death-test.cc @@ -36,21 +36,21 @@ #if GTEST_HAS_DEATH_TEST -#if GTEST_OS_MAC -#include -#endif // GTEST_OS_MAC - -#include -#include -#include -#include - -#if GTEST_OS_WINDOWS -#include -#else -#include -#include -#endif // GTEST_OS_WINDOWS +# if GTEST_OS_MAC +# include +# endif // GTEST_OS_MAC + +# include +# include +# include +# include + +# if GTEST_OS_WINDOWS +# include +# else +# include +# include +# endif // GTEST_OS_WINDOWS #endif // GTEST_HAS_DEATH_TEST @@ -113,14 +113,18 @@ ExitedWithCode::ExitedWithCode(int exit_code) : exit_code_(exit_code) { // ExitedWithCode function-call operator. bool ExitedWithCode::operator()(int exit_status) const { -#if GTEST_OS_WINDOWS +# if GTEST_OS_WINDOWS + return exit_status == exit_code_; -#else + +# else + return WIFEXITED(exit_status) && WEXITSTATUS(exit_status) == exit_code_; -#endif // GTEST_OS_WINDOWS + +# endif // GTEST_OS_WINDOWS } -#if !GTEST_OS_WINDOWS +# if !GTEST_OS_WINDOWS // KilledBySignal constructor. KilledBySignal::KilledBySignal(int signum) : signum_(signum) { } @@ -129,7 +133,7 @@ KilledBySignal::KilledBySignal(int signum) : signum_(signum) { bool KilledBySignal::operator()(int exit_status) const { return WIFSIGNALED(exit_status) && WTERMSIG(exit_status) == signum_; } -#endif // !GTEST_OS_WINDOWS +# endif // !GTEST_OS_WINDOWS namespace internal { @@ -139,20 +143,25 @@ namespace internal { // specified by wait(2). static String ExitSummary(int exit_code) { Message m; -#if GTEST_OS_WINDOWS + +# if GTEST_OS_WINDOWS + m << "Exited with exit status " << exit_code; -#else + +# else + if (WIFEXITED(exit_code)) { m << "Exited with exit status " << WEXITSTATUS(exit_code); } else if (WIFSIGNALED(exit_code)) { m << "Terminated by signal " << WTERMSIG(exit_code); } -#ifdef WCOREDUMP +# ifdef WCOREDUMP if (WCOREDUMP(exit_code)) { m << " (core dumped)"; } -#endif -#endif // GTEST_OS_WINDOWS +# endif +# endif // GTEST_OS_WINDOWS + return m.GetString(); } @@ -162,7 +171,7 @@ bool ExitedUnsuccessfully(int exit_status) { return !ExitedWithCode(0)(exit_status); } -#if !GTEST_OS_WINDOWS +# if !GTEST_OS_WINDOWS // Generates a textual failure message when a death test finds more than // one thread running, or cannot determine the number of threads, prior // to executing the given statement. It is the responsibility of the @@ -177,7 +186,7 @@ static String DeathTestThreadWarning(size_t thread_count) { msg << "detected " << thread_count << " threads."; return msg.GetString(); } -#endif // !GTEST_OS_WINDOWS +# endif // !GTEST_OS_WINDOWS // Flag characters for reporting a death test that did not die. static const char kDeathTestLived = 'L'; @@ -222,7 +231,7 @@ void DeathTestAbort(const String& message) { // A replacement for CHECK that calls DeathTestAbort if the assertion // fails. -#define GTEST_DEATH_TEST_CHECK_(expression) \ +# define GTEST_DEATH_TEST_CHECK_(expression) \ do { \ if (!::testing::internal::IsTrue(expression)) { \ DeathTestAbort(::testing::internal::String::Format( \ @@ -238,7 +247,7 @@ void DeathTestAbort(const String& message) { // evaluates the expression as long as it evaluates to -1 and sets // errno to EINTR. If the expression evaluates to -1 but errno is // something other than EINTR, DeathTestAbort is called. -#define GTEST_DEATH_TEST_CHECK_SYSCALL_(expression) \ +# define GTEST_DEATH_TEST_CHECK_SYSCALL_(expression) \ do { \ int gtest_retval; \ do { \ @@ -527,7 +536,7 @@ bool DeathTestImpl::Passed(bool status_ok) { return success; } -#if GTEST_OS_WINDOWS +# if GTEST_OS_WINDOWS // WindowsDeathTest implements death tests on Windows. Due to the // specifics of starting new processes on Windows, death tests there are // always threadsafe, and Google Test considers the @@ -723,7 +732,7 @@ DeathTest::TestRole WindowsDeathTest::AssumeRole() { set_spawned(true); return OVERSEE_TEST; } -#else // We are not on Windows. +# else // We are not on Windows. // ForkingDeathTest provides implementations for most of the abstract // methods of the DeathTest interface. Only the AssumeRole method is @@ -871,19 +880,19 @@ struct ExecDeathTestArgs { int close_fd; // File descriptor to close; the read end of a pipe }; -#if GTEST_OS_MAC +# if GTEST_OS_MAC inline char** GetEnviron() { // When Google Test is built as a framework on MacOS X, the environ variable // is unavailable. Apple's documentation (man environ) recommends using // _NSGetEnviron() instead. return *_NSGetEnviron(); } -#else +# else // Some POSIX platforms expect you to declare environ. extern "C" makes // it reside in the global namespace. extern "C" char** environ; inline char** GetEnviron() { return environ; } -#endif // GTEST_OS_MAC +# endif // GTEST_OS_MAC // The main function for a threadsafe-style death test child process. // This function is called in a clone()-ed process and thus must avoid @@ -940,7 +949,7 @@ static pid_t ExecDeathTestFork(char* const* argv, int close_fd) { ExecDeathTestArgs args = { argv, close_fd }; pid_t child_pid = -1; -#if GTEST_HAS_CLONE +# if GTEST_HAS_CLONE const bool use_fork = GTEST_FLAG(death_test_use_fork); if (!use_fork) { @@ -957,9 +966,9 @@ static pid_t ExecDeathTestFork(char* const* argv, int close_fd) { GTEST_DEATH_TEST_CHECK_(munmap(stack, stack_size) != -1); } -#else +# else const bool use_fork = true; -#endif // GTEST_HAS_CLONE +# endif // GTEST_HAS_CLONE if (use_fork && (child_pid = fork()) == 0) { ExecDeathTestChildMain(&args); @@ -1020,7 +1029,7 @@ DeathTest::TestRole ExecDeathTest::AssumeRole() { return OVERSEE_TEST; } -#endif // !GTEST_OS_WINDOWS +# endif // !GTEST_OS_WINDOWS // Creates a concrete DeathTest-derived class that depends on the // --gtest_death_test_style flag, and sets the pointer pointed to @@ -1051,18 +1060,23 @@ bool DefaultDeathTestFactory::Create(const char* statement, const RE* regex, } } -#if GTEST_OS_WINDOWS +# if GTEST_OS_WINDOWS + if (GTEST_FLAG(death_test_style) == "threadsafe" || GTEST_FLAG(death_test_style) == "fast") { *test = new WindowsDeathTest(statement, regex, file, line); } -#else + +# else + if (GTEST_FLAG(death_test_style) == "threadsafe") { *test = new ExecDeathTest(statement, regex, file, line); } else if (GTEST_FLAG(death_test_style) == "fast") { *test = new NoExecDeathTest(statement, regex); } -#endif // GTEST_OS_WINDOWS + +# endif // GTEST_OS_WINDOWS + else { // NOLINT - this is more readable than unbalanced brackets inside #if. DeathTest::set_last_death_test_message(String::Format( "Unknown death test style \"%s\" encountered", @@ -1093,7 +1107,7 @@ static void SplitString(const ::std::string& str, char delimiter, dest->swap(parsed); } -#if GTEST_OS_WINDOWS +# if GTEST_OS_WINDOWS // Recreates the pipe and event handles from the provided parameters, // signals the event, and returns a file descriptor wrapped around the pipe // handle. This function is called in the child process only. @@ -1157,7 +1171,7 @@ int GetStatusFileDescriptor(unsigned int parent_process_id, return write_fd; } -#endif // GTEST_OS_WINDOWS +# endif // GTEST_OS_WINDOWS // Returns a newly created InternalRunDeathTestFlag object with fields // initialized from the GTEST_FLAG(internal_run_death_test) flag if @@ -1173,7 +1187,8 @@ InternalRunDeathTestFlag* ParseInternalRunDeathTestFlag() { SplitString(GTEST_FLAG(internal_run_death_test).c_str(), '|', &fields); int write_fd = -1; -#if GTEST_OS_WINDOWS +# if GTEST_OS_WINDOWS + unsigned int parent_process_id = 0; size_t write_handle_as_size_t = 0; size_t event_handle_as_size_t = 0; @@ -1191,7 +1206,8 @@ InternalRunDeathTestFlag* ParseInternalRunDeathTestFlag() { write_fd = GetStatusFileDescriptor(parent_process_id, write_handle_as_size_t, event_handle_as_size_t); -#else +# else + if (fields.size() != 4 || !ParseNaturalNumber(fields[1], &line) || !ParseNaturalNumber(fields[2], &index) @@ -1200,7 +1216,9 @@ InternalRunDeathTestFlag* ParseInternalRunDeathTestFlag() { "Bad --gtest_internal_run_death_test flag: %s", GTEST_FLAG(internal_run_death_test).c_str())); } -#endif // GTEST_OS_WINDOWS + +# endif // GTEST_OS_WINDOWS + return new InternalRunDeathTestFlag(fields[0], line, index, write_fd); } diff --git a/src/gtest-filepath.cc b/src/gtest-filepath.cc index 118848a7..91b25713 100644 --- a/src/gtest-filepath.cc +++ b/src/gtest-filepath.cc @@ -35,26 +35,26 @@ #include #if GTEST_OS_WINDOWS_MOBILE -#include +# include #elif GTEST_OS_WINDOWS -#include -#include +# include +# include #elif GTEST_OS_SYMBIAN || GTEST_OS_NACL // Symbian OpenC and NaCl have PATH_MAX in sys/syslimits.h -#include +# include #else -#include -#include // Some Linux distributions define PATH_MAX here. +# include +# include // Some Linux distributions define PATH_MAX here. #endif // GTEST_OS_WINDOWS_MOBILE #if GTEST_OS_WINDOWS -#define GTEST_PATH_MAX_ _MAX_PATH +# define GTEST_PATH_MAX_ _MAX_PATH #elif defined(PATH_MAX) -#define GTEST_PATH_MAX_ PATH_MAX +# define GTEST_PATH_MAX_ PATH_MAX #elif defined(_XOPEN_PATH_MAX) -#define GTEST_PATH_MAX_ _XOPEN_PATH_MAX +# define GTEST_PATH_MAX_ _XOPEN_PATH_MAX #else -#define GTEST_PATH_MAX_ _POSIX_PATH_MAX +# define GTEST_PATH_MAX_ _POSIX_PATH_MAX #endif // GTEST_OS_WINDOWS #include "gtest/internal/gtest-string.h" @@ -71,16 +71,16 @@ const char kPathSeparator = '\\'; const char kAlternatePathSeparator = '/'; const char kPathSeparatorString[] = "\\"; const char kAlternatePathSeparatorString[] = "/"; -#if GTEST_OS_WINDOWS_MOBILE +# if GTEST_OS_WINDOWS_MOBILE // Windows CE doesn't have a current directory. You should not use // the current directory in tests on Windows CE, but this at least // provides a reasonable fallback. const char kCurrentDirectoryString[] = "\\"; // Windows CE doesn't define INVALID_FILE_ATTRIBUTES const DWORD kInvalidFileAttributes = 0xffffffff; -#else +# else const char kCurrentDirectoryString[] = ".\\"; -#endif // GTEST_OS_WINDOWS_MOBILE +# endif // GTEST_OS_WINDOWS_MOBILE #else const char kPathSeparator = '/'; const char kPathSeparatorString[] = "/"; diff --git a/src/gtest-internal-inl.h b/src/gtest-internal-inl.h index 8629c6fb..e45f452a 100644 --- a/src/gtest-internal-inl.h +++ b/src/gtest-internal-inl.h @@ -41,12 +41,12 @@ // part of Google Test's implementation; otherwise it's undefined. #if !GTEST_IMPLEMENTATION_ // A user is trying to include this from his code - just say no. -#error "gtest-internal-inl.h is part of Google Test's internal implementation." -#error "It must not be included except by Google Test itself." +# error "gtest-internal-inl.h is part of Google Test's internal implementation." +# error "It must not be included except by Google Test itself." #endif // GTEST_IMPLEMENTATION_ #ifndef _WIN32_WCE -#include +# include #endif // !_WIN32_WCE #include #include // For strtoll/_strtoul64/malloc/free. @@ -59,7 +59,7 @@ #include "gtest/internal/gtest-port.h" #if GTEST_OS_WINDOWS -#include // For DWORD. +# include // NOLINT #endif // GTEST_OS_WINDOWS #include "gtest/gtest.h" // NOLINT @@ -930,7 +930,7 @@ GTEST_API_ void ParseGoogleTestFlagsOnly(int* argc, wchar_t** argv); // platform. GTEST_API_ String GetLastErrnoDescription(); -#if GTEST_OS_WINDOWS +# if GTEST_OS_WINDOWS // Provides leak-safe Windows kernel handle ownership. class AutoHandle { public: @@ -954,7 +954,7 @@ class AutoHandle { GTEST_DISALLOW_COPY_AND_ASSIGN_(AutoHandle); }; -#endif // GTEST_OS_WINDOWS +# endif // GTEST_OS_WINDOWS // Attempts to parse a string into a positive integer pointed to by the // number parameter. Returns true if that is possible. @@ -973,14 +973,20 @@ bool ParseNaturalNumber(const ::std::string& str, Integer* number) { char* end; // BiggestConvertible is the largest integer type that system-provided // string-to-number conversion routines can return. -#if GTEST_OS_WINDOWS && !defined(__GNUC__) + +# if GTEST_OS_WINDOWS && !defined(__GNUC__) + // MSVC and C++ Builder define __int64 instead of the standard long long. typedef unsigned __int64 BiggestConvertible; const BiggestConvertible parsed = _strtoui64(str.c_str(), &end, 10); -#else + +# else + typedef unsigned long long BiggestConvertible; // NOLINT const BiggestConvertible parsed = strtoull(str.c_str(), &end, 10); -#endif // GTEST_OS_WINDOWS && !defined(__GNUC__) + +# endif // GTEST_OS_WINDOWS && !defined(__GNUC__) + const bool parse_success = *end == '\0' && errno == 0; // TODO(vladl@google.com): Convert this to compile time assertion when it is diff --git a/src/gtest-port.cc b/src/gtest-port.cc index 4310a735..b860d481 100644 --- a/src/gtest-port.cc +++ b/src/gtest-port.cc @@ -37,18 +37,18 @@ #include #if GTEST_OS_WINDOWS_MOBILE -#include // For TerminateProcess() +# include // For TerminateProcess() #elif GTEST_OS_WINDOWS -#include -#include +# include +# include #else -#include +# include #endif // GTEST_OS_WINDOWS_MOBILE #if GTEST_OS_MAC -#include -#include -#include +# include +# include +# include #endif // GTEST_OS_MAC #include "gtest/gtest-spi.h" @@ -478,8 +478,8 @@ GTestLog::~GTestLog() { // Disable Microsoft deprecation warnings for POSIX functions called from // this class (creat, dup, dup2, and close) #ifdef _MSC_VER -#pragma warning(push) -#pragma warning(disable: 4996) +# pragma warning(push) +# pragma warning(disable: 4996) #endif // _MSC_VER #if GTEST_HAS_STREAM_REDIRECTION @@ -489,7 +489,8 @@ class CapturedStream { public: // The ctor redirects the stream to a temporary file. 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_file_path[MAX_PATH + 1] = { '\0' }; // NOLINT @@ -504,14 +505,14 @@ class CapturedStream { GTEST_CHECK_(captured_fd != -1) << "Unable to open temporary file " << temp_file_path; filename_ = temp_file_path; -#else +# else // There's no guarantee that a test has write access to the // current directory, so we create the temporary file in the /tmp // directory instead. char name_template[] = "/tmp/captured_stream.XXXXXX"; const int captured_fd = mkstemp(name_template); filename_ = name_template; -#endif // GTEST_OS_WINDOWS +# endif // GTEST_OS_WINDOWS fflush(NULL); dup2(captured_fd, fd_); close(captured_fd); @@ -580,9 +581,9 @@ String CapturedStream::ReadEntireFile(FILE* file) { return content; } -#ifdef _MSC_VER -#pragma warning(pop) -#endif // _MSC_VER +# ifdef _MSC_VER +# pragma warning(pop) +# endif // _MSC_VER static CapturedStream* g_captured_stderr = NULL; static CapturedStream* g_captured_stdout = NULL; diff --git a/src/gtest-printers.cc b/src/gtest-printers.cc index bfbca9c8..84a04ab5 100644 --- a/src/gtest-printers.cc +++ b/src/gtest-printers.cc @@ -56,11 +56,11 @@ namespace { using ::std::ostream; #if GTEST_OS_WINDOWS_MOBILE // Windows CE does not define _snprintf_s. -#define snprintf _snprintf +# define snprintf _snprintf #elif _MSC_VER >= 1400 // VC 8.0 and later deprecate snprintf and _snprintf. -#define snprintf _snprintf_s +# define snprintf _snprintf_s #elif _MSC_VER -#define snprintf _snprintf +# define snprintf _snprintf #endif // GTEST_OS_WINDOWS_MOBILE // Prints a segment of bytes in the given object. diff --git a/src/gtest.cc b/src/gtest.cc index 53a52fbf..91057124 100644 --- a/src/gtest.cc +++ b/src/gtest.cc @@ -51,76 +51,76 @@ // TODO(kenton@google.com): Use autoconf to detect availability of // gettimeofday(). -#define GTEST_HAS_GETTIMEOFDAY_ 1 +# define GTEST_HAS_GETTIMEOFDAY_ 1 -#include // NOLINT -#include // NOLINT -#include // NOLINT +# include // NOLINT +# include // NOLINT +# include // NOLINT // Declares vsnprintf(). This header is not available on Windows. -#include // NOLINT -#include // NOLINT -#include // NOLINT -#include // NOLINT -#include +# include // NOLINT +# include // NOLINT +# include // NOLINT +# include // NOLINT +# include #elif GTEST_OS_SYMBIAN -#define GTEST_HAS_GETTIMEOFDAY_ 1 -#include // NOLINT +# define GTEST_HAS_GETTIMEOFDAY_ 1 +# include // NOLINT #elif GTEST_OS_ZOS -#define GTEST_HAS_GETTIMEOFDAY_ 1 -#include // NOLINT +# define GTEST_HAS_GETTIMEOFDAY_ 1 +# include // NOLINT // On z/OS we additionally need strings.h for strcasecmp. -#include // NOLINT +# include // NOLINT #elif GTEST_OS_WINDOWS_MOBILE // We are on Windows CE. -#include // NOLINT +# include // NOLINT #elif GTEST_OS_WINDOWS // We are on Windows proper. -#include // NOLINT -#include // NOLINT -#include // NOLINT -#include // NOLINT +# include // NOLINT +# include // NOLINT +# include // NOLINT +# include // NOLINT -#if GTEST_OS_WINDOWS_MINGW +# if GTEST_OS_WINDOWS_MINGW // MinGW has gettimeofday() but not _ftime64(). // TODO(kenton@google.com): Use autoconf to detect availability of // gettimeofday(). // TODO(kenton@google.com): There are other ways to get the time on // Windows, like GetTickCount() or GetSystemTimeAsFileTime(). MinGW // supports these. consider using them instead. -#define GTEST_HAS_GETTIMEOFDAY_ 1 -#include // NOLINT -#endif // GTEST_OS_WINDOWS_MINGW +# define GTEST_HAS_GETTIMEOFDAY_ 1 +# include // NOLINT +# endif // GTEST_OS_WINDOWS_MINGW // cpplint thinks that the header is already included, so we want to // silence it. -#include // NOLINT +# include // NOLINT #else // Assume other platforms have gettimeofday(). // TODO(kenton@google.com): Use autoconf to detect availability of // gettimeofday(). -#define GTEST_HAS_GETTIMEOFDAY_ 1 +# define GTEST_HAS_GETTIMEOFDAY_ 1 // cpplint thinks that the header is already included, so we want to // silence it. -#include // NOLINT -#include // NOLINT +# include // NOLINT +# include // NOLINT #endif // GTEST_OS_LINUX #if GTEST_HAS_EXCEPTIONS -#include +# include #endif #if GTEST_CAN_STREAM_RESULTS_ -#include // NOLINT -#include // NOLINT +# include // NOLINT +# include // NOLINT #endif // Indicates that this translation unit is part of Google Test's @@ -133,7 +133,7 @@ #undef GTEST_IMPLEMENTATION_ #if GTEST_OS_WINDOWS -#define vsnprintf _vsnprintf +# define vsnprintf _vsnprintf #endif // GTEST_OS_WINDOWS namespace testing { @@ -786,25 +786,30 @@ TimeInMillis GetTimeInMillis() { return 0; #elif GTEST_OS_WINDOWS && !GTEST_HAS_GETTIMEOFDAY_ __timeb64 now; -#ifdef _MSC_VER + +# ifdef _MSC_VER + // MSVC 8 deprecates _ftime64(), so we want to suppress warning 4996 // (deprecated function) there. // TODO(kenton@google.com): Use GetTickCount()? Or use // SystemTimeToFileTime() -#pragma warning(push) // Saves the current warning state. -#pragma warning(disable:4996) // Temporarily disables warning 4996. +# pragma warning(push) // Saves the current warning state. +# pragma warning(disable:4996) // Temporarily disables warning 4996. _ftime64(&now); -#pragma warning(pop) // Restores the warning state. -#else +# pragma warning(pop) // Restores the warning state. +# else + _ftime64(&now); -#endif // _MSC_VER + +# endif // _MSC_VER + return static_cast(now.time) * 1000 + now.millitm; #elif GTEST_HAS_GETTIMEOFDAY_ struct timeval now; gettimeofday(&now, NULL); return static_cast(now.tv_sec) * 1000 + now.tv_usec / 1000; #else -#error "Don't know how to get the current time on your system." +# error "Don't know how to get the current time on your system." #endif } @@ -1332,10 +1337,13 @@ namespace { AssertionResult HRESULTFailureHelper(const char* expr, const char* expected, long hr) { // NOLINT -#if GTEST_OS_WINDOWS_MOBILE +# if GTEST_OS_WINDOWS_MOBILE + // Windows CE doesn't support FormatMessage. const char error_text[] = ""; -#else + +# else + // Looks up the human-readable system message for the HRESULT code // and since we're not passing any params to FormatMessage, we don't // want inserts expanded. @@ -1356,7 +1364,8 @@ AssertionResult HRESULTFailureHelper(const char* expr, --message_length) { error_text[message_length - 1] = '\0'; } -#endif // GTEST_OS_WINDOWS_MOBILE + +# endif // GTEST_OS_WINDOWS_MOBILE const String error_hex(String::Format("0x%08X ", hr)); return ::testing::AssertionFailure() @@ -1698,10 +1707,12 @@ String String::Format(const char * format, ...) { // MSVC 8 deprecates vsnprintf(), so we want to suppress warning // 4996 (deprecated function) there. #ifdef _MSC_VER // We are using MSVC. -#pragma warning(push) // Saves the current warning state. -#pragma warning(disable:4996) // Temporarily disables warning 4996. +# pragma warning(push) // Saves the current warning state. +# pragma warning(disable:4996) // Temporarily disables warning 4996. + const int size = vsnprintf(buffer, kBufferSize, format, args); -#pragma warning(pop) // Restores the warning state. + +# pragma warning(pop) // Restores the warning state. #else // We are not using MSVC. const int size = vsnprintf(buffer, kBufferSize, format, args); #endif // _MSC_VER @@ -3826,20 +3837,21 @@ int UnitTest::Run() { // process. In either case the user does not want to see pop-up dialogs // about crashes - they are expected. 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(SEM_FAILCRITICALERRORS | SEM_NOALIGNMENTFAULTEXCEPT | SEM_NOGPFAULTERRORBOX | SEM_NOOPENFILEERRORBOX); -#endif // !GTEST_OS_WINDOWS_MOBILE +# endif // !GTEST_OS_WINDOWS_MOBILE -#if (defined(_MSC_VER) || GTEST_OS_WINDOWS_MINGW) && !GTEST_OS_WINDOWS_MOBILE +# if (defined(_MSC_VER) || GTEST_OS_WINDOWS_MINGW) && !GTEST_OS_WINDOWS_MOBILE // Death test children can be terminated with _abort(). On Windows, // _abort() can show a dialog with a warning message. This forces the // abort message to go to stderr instead. _set_error_mode(_OUT_TO_STDERR); -#endif +# endif -#if _MSC_VER >= 1400 && !GTEST_OS_WINDOWS_MOBILE +# if _MSC_VER >= 1400 && !GTEST_OS_WINDOWS_MOBILE // In the debug version, Visual Studio pops up a separate dialog // offering a choice to debug the aborted program. We need to suppress // this dialog or it will pop up for every EXPECT/ASSERT_DEATH statement @@ -3855,7 +3867,8 @@ int UnitTest::Run() { _set_abort_behavior( 0x0, // Clear the following flags: _WRITE_ABORT_MSG | _CALL_REPORTFAULT); // pop-up window, core dump. -#endif +# endif + } #endif // GTEST_HAS_SEH @@ -3930,12 +3943,12 @@ namespace internal { UnitTestImpl::UnitTestImpl(UnitTest* parent) : parent_(parent), #ifdef _MSC_VER -#pragma warning(push) // Saves the current warning state. -#pragma warning(disable:4355) // Temporarily disables warning 4355 +# pragma warning(push) // Saves the current warning state. +# pragma warning(disable:4355) // Temporarily disables warning 4355 // (using this in initializer). default_global_test_part_result_reporter_(this), default_per_thread_test_part_result_reporter_(this), -#pragma warning(pop) // Restores the warning state again. +# pragma warning(pop) // Restores the warning state again. #else default_global_test_part_result_reporter_(this), default_per_thread_test_part_result_reporter_(this), @@ -4853,10 +4866,12 @@ void InitGoogleTestImpl(int* argc, CharType** argv) { internal::g_executable_path = internal::StreamableToString(argv[0]); #if GTEST_HAS_DEATH_TEST + g_argvs.clear(); for (int i = 0; i != *argc; i++) { g_argvs.push_back(StreamableToString(argv[i])); } + #endif // GTEST_HAS_DEATH_TEST ParseGoogleTestFlagsOnly(argc, argv); -- cgit v1.2.3 From 603533a0a4dcfc2ef33051b9ae8237568a19adc4 Mon Sep 17 00:00:00 2001 From: "zhanyong.wan" Date: Sat, 5 Mar 2011 08:04:01 +0000 Subject: Fixes compatibility with Borland C++Builder. Original patch by Josh Kelley. Simplified by Zhanyong Wan. --- src/gtest.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src') diff --git a/src/gtest.cc b/src/gtest.cc index 91057124..3859d5ab 100644 --- a/src/gtest.cc +++ b/src/gtest.cc @@ -4349,7 +4349,7 @@ bool ShouldShard(const char* total_shards_env, // Parses the environment variable var as an Int32. If it is unset, // returns default_val. If it is not an Int32, prints an error // and aborts. -Int32 Int32FromEnvOrDie(const char* const var, Int32 default_val) { +Int32 Int32FromEnvOrDie(const char* var, Int32 default_val) { const char* str_val = posix::GetEnv(var); if (str_val == NULL) { return default_val; -- cgit v1.2.3 From 5017fe0090e8902d028ba38753c00d73f16d83f0 Mon Sep 17 00:00:00 2001 From: "zhanyong.wan" Date: Fri, 11 Mar 2011 23:05:00 +0000 Subject: Fixes compatibility with Sun C++ (by Hady Zalek); fixes compatibility with Android (by Zachary Vorhies). --- src/gtest.cc | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'src') diff --git a/src/gtest.cc b/src/gtest.cc index 3859d5ab..a48aea9a 100644 --- a/src/gtest.cc +++ b/src/gtest.cc @@ -1621,11 +1621,11 @@ bool String::CaseInsensitiveWideCStringEquals(const wchar_t* lhs, #if GTEST_OS_WINDOWS return _wcsicmp(lhs, rhs) == 0; -#elif GTEST_OS_LINUX +#elif GTEST_OS_LINUX && !GTEST_OS_LINUX_ANDROID return wcscasecmp(lhs, rhs) == 0; #else - // Mac OS X and Cygwin don't define wcscasecmp. Other unknown OSes - // may not define it either. + // Android, Mac OS X and Cygwin don't define wcscasecmp. + // Other unknown OSes may not define it either. wint_t left, right; do { left = towlower(*lhs++); -- cgit v1.2.3 From 03062e23372fe59b777d793e4ddea0d153925e4d Mon Sep 17 00:00:00 2001 From: vladlosev Date: Wed, 30 Mar 2011 17:45:53 +0000 Subject: Fixes 'formatting error or buffer exceeded' error when outputting long failure messages in XML. --- src/gtest.cc | 30 +++++++++++++----------------- 1 file changed, 13 insertions(+), 17 deletions(-) (limited to 'src') diff --git a/src/gtest.cc b/src/gtest.cc index a48aea9a..fc0f8010 100644 --- a/src/gtest.cc +++ b/src/gtest.cc @@ -3032,7 +3032,7 @@ class XmlUnitTestResultPrinter : public EmptyTestEventListener { static String EscapeXml(const char* str, bool is_attribute); // Returns the given string with all characters invalid in XML removed. - static String RemoveInvalidXmlCharacters(const char* str); + static string RemoveInvalidXmlCharacters(const string& str); // Convenience wrapper around EscapeXml when str is an attribute value. static String EscapeXmlAttribute(const char* str) { @@ -3166,17 +3166,14 @@ String XmlUnitTestResultPrinter::EscapeXml(const char* str, bool is_attribute) { // Returns the given string with all characters invalid in XML removed. // Currently invalid characters are dropped from the string. An // alternative is to replace them with certain characters such as . or ?. -String XmlUnitTestResultPrinter::RemoveInvalidXmlCharacters(const char* str) { - char* const output = new char[strlen(str) + 1]; - char* appender = output; - for (char ch = *str; ch != '\0'; ch = *++str) - if (IsValidXmlCharacter(ch)) - *appender++ = ch; - *appender = '\0'; +string XmlUnitTestResultPrinter::RemoveInvalidXmlCharacters(const string& str) { + string output; + output.reserve(str.size()); + for (string::const_iterator it = str.begin(); it != str.end(); ++it) + if (IsValidXmlCharacter(*it)) + output.push_back(*it); - String ret_value(output); - delete[] output; - return ret_value; + return output; } // The following routines generate an XML representation of a UnitTest @@ -3256,12 +3253,11 @@ void XmlUnitTestResultPrinter::OutputXmlTestInfo(::std::ostream* stream, *stream << " "; - const String message = RemoveInvalidXmlCharacters(String::Format( - "%s\n%s", - internal::FormatCompilerIndependentFileLocation( - part.file_name(), part.line_number()).c_str(), - part.message()).c_str()); - OutputXmlCDataSection(stream, message.c_str()); + const string location = internal::FormatCompilerIndependentFileLocation( + part.file_name(), part.line_number()); + const string message = location + "\n" + part.message(); + OutputXmlCDataSection(stream, + RemoveInvalidXmlCharacters(message).c_str()); *stream << "\n"; } } -- cgit v1.2.3 From 1ea6b31d5debaf2535096b1f511a605a541780ef Mon Sep 17 00:00:00 2001 From: vladlosev Date: Wed, 30 Mar 2011 22:02:47 +0000 Subject: Fixes Windows CE compatibility problem (issue http://code.google.com/p/googletest/issues/detail?id=362). --- src/gtest-death-test.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src') diff --git a/src/gtest-death-test.cc b/src/gtest-death-test.cc index a0ed80d1..603fccc1 100644 --- a/src/gtest-death-test.cc +++ b/src/gtest-death-test.cc @@ -225,7 +225,7 @@ void DeathTestAbort(const String& message) { } else { fprintf(stderr, "%s", message.c_str()); fflush(stderr); - abort(); + posix::Abort(); } } -- cgit v1.2.3 From c7a9cc35121536e44373a2eb5670f7d3a3d5ee28 Mon Sep 17 00:00:00 2001 From: vladlosev Date: Fri, 1 Apr 2011 21:57:36 +0000 Subject: Changes diagnostic output of the question mark from '\?' to '?'. --- src/gtest-printers.cc | 3 --- 1 file changed, 3 deletions(-) (limited to 'src') diff --git a/src/gtest-printers.cc b/src/gtest-printers.cc index 84a04ab5..e576ca45 100644 --- a/src/gtest-printers.cc +++ b/src/gtest-printers.cc @@ -155,9 +155,6 @@ static CharFormat PrintAsCharLiteralTo(Char c, ostream* os) { case L'\'': *os << "\\'"; break; - case L'\?': - *os << "\\?"; - break; case L'\\': *os << "\\\\"; break; -- cgit v1.2.3 From 741d6c0d475664fc48790917cefed455a4307227 Mon Sep 17 00:00:00 2001 From: "zhanyong.wan" Date: Thu, 7 Apr 2011 18:36:50 +0000 Subject: makes gtest compatible with HP UX (by Pasi Valminen); fixes a typo in the name of xlC (by Hady Zalek). --- src/gtest.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src') diff --git a/src/gtest.cc b/src/gtest.cc index fc0f8010..904d9d74 100644 --- a/src/gtest.cc +++ b/src/gtest.cc @@ -2059,7 +2059,7 @@ class GoogleTestFailureException : public ::std::runtime_error { #endif // GTEST_HAS_EXCEPTIONS namespace internal { -// We put these helper functions in the internal namespace as IBM's xIC_r +// We put these helper functions in the internal namespace as IBM's xlC // compiler rejects the code if they were declared static. // Runs the given method and handles SEH exceptions it throws, when -- cgit v1.2.3 From 7d560ed6999b817688cb93633a4b255e7f1e9011 Mon Sep 17 00:00:00 2001 From: vladlosev Date: Fri, 8 Apr 2011 00:42:19 +0000 Subject: Fixes a compiler error when compiling with Visual Age (by Hady Zalek). --- src/gtest-printers.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src') diff --git a/src/gtest-printers.cc b/src/gtest-printers.cc index e576ca45..62ea590d 100644 --- a/src/gtest-printers.cc +++ b/src/gtest-printers.cc @@ -138,7 +138,7 @@ enum CharFormat { // Returns true if c is a printable ASCII character. We test the // value of c directly instead of calling isprint(), which is buggy on // Windows Mobile. -static inline bool IsPrintableAscii(wchar_t c) { +inline bool IsPrintableAscii(wchar_t c) { return 0x20 <= c && c <= 0x7E; } -- cgit v1.2.3 From e9adbcbb56a205dee270842f7d6221c52d508476 Mon Sep 17 00:00:00 2001 From: vladlosev Date: Sat, 9 Apr 2011 00:09:41 +0000 Subject: Simplifies ASCII character detection in gtest-printers.h. This also makes it possible to build Google Test on MinGW. --- src/gtest-printers.cc | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'src') diff --git a/src/gtest-printers.cc b/src/gtest-printers.cc index 62ea590d..ed63c7b3 100644 --- a/src/gtest-printers.cc +++ b/src/gtest-printers.cc @@ -288,8 +288,7 @@ static void PrintWideCharsAsStringTo(const wchar_t* begin, size_t len, bool is_previous_hex = false; for (size_t index = 0; index < len; ++index) { const wchar_t cur = begin[index]; - if (is_previous_hex && 0 <= cur && cur < 128 && - IsXDigit(static_cast(cur))) { + if (is_previous_hex && isascii(cur) && IsXDigit(static_cast(cur))) { // Previous character is of '\x..' form and this character can be // interpreted as another hexadecimal digit in its number. Break string to // disambiguate. -- cgit v1.2.3 From b8c0e16eeb7496f71480c6a060144b0e050edcf5 Mon Sep 17 00:00:00 2001 From: "zhanyong.wan" Date: Tue, 12 Apr 2011 20:36:11 +0000 Subject: Fixes Sun C++ compiler errors (by Pasi Valminen) --- src/gtest-internal-inl.h | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) (limited to 'src') diff --git a/src/gtest-internal-inl.h b/src/gtest-internal-inl.h index e45f452a..65a2101a 100644 --- a/src/gtest-internal-inl.h +++ b/src/gtest-internal-inl.h @@ -271,7 +271,14 @@ GTEST_API_ bool ShouldRunTestOnShard( // the given predicate. template inline int CountIf(const Container& c, Predicate predicate) { - return static_cast(std::count_if(c.begin(), c.end(), predicate)); + // Implemented as an explicit loop since std::count_if() in libCstd on + // Solaris has a non-standard signature. + int count = 0; + for (typename Container::const_iterator it = c.begin(); it != c.end(); ++it) { + if (predicate(*it)) + ++count; + } + return count; } // Applies a function/functor to each element in the container. -- cgit v1.2.3 From c006f8c12bc74131692a2df8fd64dcedeafe6c77 Mon Sep 17 00:00:00 2001 From: "zhanyong.wan" Date: Thu, 14 Apr 2011 19:36:05 +0000 Subject: fixes a problem caused by gcc 4.6 optimization (by Paul Pluzhnikov) --- src/gtest-death-test.cc | 5 +++++ 1 file changed, 5 insertions(+) (limited to 'src') diff --git a/src/gtest-death-test.cc b/src/gtest-death-test.cc index 603fccc1..8b2e4131 100644 --- a/src/gtest-death-test.cc +++ b/src/gtest-death-test.cc @@ -932,6 +932,11 @@ static int ExecDeathTestChildMain(void* child_arg) { // This could be accomplished more elegantly by a single recursive // function, but we want to guard against the unlikely possibility of // a smart compiler optimizing the recursion away. +// +// GTEST_NO_INLINE_ is required to prevent GCC 4.6 from inlining +// StackLowerThanAddress into StackGrowsDown, which then doesn't give +// correct answer. +bool StackLowerThanAddress(const void* ptr) GTEST_NO_INLINE_; bool StackLowerThanAddress(const void* ptr) { int dummy; return &dummy < ptr; -- cgit v1.2.3 From 7e29bb7f7ebc2a1734415cb64395d87fc87d12be Mon Sep 17 00:00:00 2001 From: vladlosev Date: Fri, 20 May 2011 00:38:55 +0000 Subject: Adds support for building Google Mock as a shared library (DLL). --- src/gtest.cc | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'src') diff --git a/src/gtest.cc b/src/gtest.cc index 904d9d74..b6481f7f 100644 --- a/src/gtest.cc +++ b/src/gtest.cc @@ -305,7 +305,7 @@ UInt32 Random::Generate(UInt32 range) { // Test. g_init_gtest_count is set to the number of times // InitGoogleTest() has been called. We don't protect this variable // 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; } // Iterates over a vector of TestCases, keeping a running sum of the @@ -360,7 +360,7 @@ void AssertHelper::operator=(const Message& message) const { } // 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. String g_executable_path; -- cgit v1.2.3 From f3cf0a2316b68cbdc64a00eb61fc8ff955259282 Mon Sep 17 00:00:00 2001 From: vladlosev Date: Mon, 13 Jun 2011 20:09:57 +0000 Subject: Suppresses the tail-call optimization of StackGrowsDown() in GCC4.6 (by Paul Pluzhnikov). --- src/gtest-death-test.cc | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) (limited to 'src') diff --git a/src/gtest-death-test.cc b/src/gtest-death-test.cc index 8b2e4131..44ff6b2f 100644 --- a/src/gtest-death-test.cc +++ b/src/gtest-death-test.cc @@ -936,15 +936,17 @@ static int ExecDeathTestChildMain(void* child_arg) { // GTEST_NO_INLINE_ is required to prevent GCC 4.6 from inlining // StackLowerThanAddress into StackGrowsDown, which then doesn't give // correct answer. -bool StackLowerThanAddress(const void* ptr) GTEST_NO_INLINE_; -bool StackLowerThanAddress(const void* ptr) { +void StackLowerThanAddress(const void* ptr, bool* result) GTEST_NO_INLINE_; +void StackLowerThanAddress(const void* ptr, bool* result) { int dummy; - return &dummy < ptr; + *result = (&dummy < ptr); } bool StackGrowsDown() { int dummy; - return StackLowerThanAddress(&dummy); + bool result; + StackLowerThanAddress(&dummy, &result); + return result; } // A threadsafe implementation of fork(2) for threadsafe-style death tests -- cgit v1.2.3 From 386da2037dc7b1d063ac43bf146889b1edcafe7e Mon Sep 17 00:00:00 2001 From: vladlosev Date: Mon, 20 Jun 2011 21:43:18 +0000 Subject: QNX compatibility patch (by Haruka Iwao). --- src/gtest-death-test.cc | 60 ++++++++++++++++++++++++++++++++++++++++++------- src/gtest-port.cc | 25 +++++++++++++++++++++ 2 files changed, 77 insertions(+), 8 deletions(-) (limited to 'src') diff --git a/src/gtest-death-test.cc b/src/gtest-death-test.cc index 44ff6b2f..fb4a9f9d 100644 --- a/src/gtest-death-test.cc +++ b/src/gtest-death-test.cc @@ -52,6 +52,10 @@ # include # endif // GTEST_OS_WINDOWS +# if GTEST_OS_QNX +# include +# endif // GTEST_OS_QNX + #endif // GTEST_HAS_DEATH_TEST #include "gtest/gtest-message.h" @@ -894,6 +898,7 @@ extern "C" char** environ; inline char** GetEnviron() { return environ; } # endif // GTEST_OS_MAC +# if !GTEST_OS_QNX // The main function for a threadsafe-style death test child process. // This function is called in a clone()-ed process and thus must avoid // any potentially unsafe operations like malloc or libc functions. @@ -926,6 +931,7 @@ static int ExecDeathTestChildMain(void* child_arg) { GetLastErrnoDescription().c_str())); return EXIT_FAILURE; } +# endif // !GTEST_OS_QNX // Two utility routines that together determine the direction the stack // grows. @@ -949,14 +955,51 @@ bool StackGrowsDown() { return result; } -// A threadsafe implementation of fork(2) for threadsafe-style death tests -// that uses clone(2). It dies with an error message if anything goes -// wrong. -static pid_t ExecDeathTestFork(char* const* argv, int close_fd) { +// Spawns a child process with the same executable as the current process in +// a thread-safe manner and instructs it to run the death test. The +// implementation uses fork(2) + exec. On systems where clone(2) is +// 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 }; 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_HAS_CLONE const bool use_fork = GTEST_FLAG(death_test_use_fork); if (!use_fork) { @@ -973,14 +1016,15 @@ static pid_t ExecDeathTestFork(char* const* argv, int close_fd) { GTEST_DEATH_TEST_CHECK_(munmap(stack, stack_size) != -1); } -# else +# else const bool use_fork = true; -# endif // GTEST_HAS_CLONE +# endif // GTEST_HAS_CLONE if (use_fork && (child_pid = fork()) == 0) { ExecDeathTestChildMain(&args); _exit(0); } +# endif // GTEST_OS_QNX GTEST_DEATH_TEST_CHECK_(child_pid != -1); return child_pid; @@ -1028,7 +1072,7 @@ DeathTest::TestRole ExecDeathTest::AssumeRole() { // is necessary. 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])); set_child_pid(child_pid); set_read_fd(pipe_fd[0]); diff --git a/src/gtest-port.cc b/src/gtest-port.cc index b860d481..32069146 100644 --- a/src/gtest-port.cc +++ b/src/gtest-port.cc @@ -51,6 +51,11 @@ # include #endif // GTEST_OS_MAC +#if GTEST_OS_QNX +# include +# include +#endif // GTEST_OS_QNX + #include "gtest/gtest-spi.h" #include "gtest/gtest-message.h" #include "gtest/internal/gtest-internal.h" @@ -98,6 +103,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(process_info.num_threads); + } else { + return 0; + } +} + #else size_t GetThreadCount() { -- cgit v1.2.3 From 4b07d73f4e683d85546d78793a9914a4b5d3d98e Mon Sep 17 00:00:00 2001 From: vladlosev Date: Fri, 9 Sep 2011 05:42:09 +0000 Subject: Ignore SIGPROF signal during clone()/fork() call. clone()/fork() call hangs permanently if it consumes more cpu than the SIGPROF signal timer interval (by Nabeel Mian). --- src/gtest-death-test.cc | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) (limited to 'src') diff --git a/src/gtest-death-test.cc b/src/gtest-death-test.cc index fb4a9f9d..2f0b0e38 100644 --- a/src/gtest-death-test.cc +++ b/src/gtest-death-test.cc @@ -43,6 +43,11 @@ # include # include # include + +# if GTEST_OS_LINUX +# include +# endif // GTEST_OS_LINUX + # include # if GTEST_OS_WINDOWS @@ -998,6 +1003,18 @@ static pid_t ExecDeathTestSpawnChild(char* const* argv, int close_fd) { 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); @@ -1025,6 +1042,10 @@ static pid_t ExecDeathTestSpawnChild(char* const* argv, int close_fd) { _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); return child_pid; -- cgit v1.2.3 From 2ca4d2150048856cc84067163594932064b92267 Mon Sep 17 00:00:00 2001 From: "zhanyong.wan" Date: Fri, 16 Sep 2011 16:43:37 +0000 Subject: Simplifies the implementatoin of the test result printer; by Ulfar Erlingsson --- src/gtest.cc | 12 ++++-------- 1 file changed, 4 insertions(+), 8 deletions(-) (limited to 'src') diff --git a/src/gtest.cc b/src/gtest.cc index b6481f7f..6f7216f9 100644 --- a/src/gtest.cc +++ b/src/gtest.cc @@ -2707,8 +2707,6 @@ class PrettyUnitTestResultPrinter : public TestEventListener { private: static void PrintFailedTests(const UnitTest& unit_test); - - internal::String test_case_name_; }; // Fired before each iteration of tests starts. @@ -2755,11 +2753,10 @@ void PrettyUnitTestResultPrinter::OnEnvironmentsSetUpStart( } void PrettyUnitTestResultPrinter::OnTestCaseStart(const TestCase& test_case) { - test_case_name_ = test_case.name(); const internal::String counts = FormatCountableNoun(test_case.test_to_run_count(), "test", "tests"); 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) { printf("\n"); } else { @@ -2770,7 +2767,7 @@ void PrettyUnitTestResultPrinter::OnTestCaseStart(const TestCase& test_case) { void PrettyUnitTestResultPrinter::OnTestStart(const TestInfo& test_info) { ColoredPrintf(COLOR_GREEN, "[ RUN ] "); - PrintTestName(test_case_name_.c_str(), test_info.name()); + PrintTestName(test_info.test_case_name(), test_info.name()); printf("\n"); fflush(stdout); } @@ -2793,7 +2790,7 @@ void PrettyUnitTestResultPrinter::OnTestEnd(const TestInfo& test_info) { } else { 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()) PrintFullTestCommentIfPresent(test_info); @@ -2809,12 +2806,11 @@ void PrettyUnitTestResultPrinter::OnTestEnd(const TestInfo& test_info) { void PrettyUnitTestResultPrinter::OnTestCaseEnd(const TestCase& test_case) { if (!GTEST_FLAG(print_time)) return; - test_case_name_ = test_case.name(); const internal::String counts = FormatCountableNoun(test_case.test_to_run_count(), "test", "tests"); ColoredPrintf(COLOR_GREEN, "[----------] "); 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()); fflush(stdout); } -- cgit v1.2.3 From f7d58e81c35b37851733a7518c9f7260ba1b8a40 Mon Sep 17 00:00:00 2001 From: vladlosev Date: Mon, 26 Sep 2011 17:54:02 +0000 Subject: Adds a new macro simplifying use of snprinf on MS platforms. --- src/gtest-printers.cc | 10 +--------- 1 file changed, 1 insertion(+), 9 deletions(-) (limited to 'src') diff --git a/src/gtest-printers.cc b/src/gtest-printers.cc index ed63c7b3..cfe9eed3 100644 --- a/src/gtest-printers.cc +++ b/src/gtest-printers.cc @@ -55,14 +55,6 @@ namespace { using ::std::ostream; -#if GTEST_OS_WINDOWS_MOBILE // Windows CE does not define _snprintf_s. -# define snprintf _snprintf -#elif _MSC_VER >= 1400 // VC 8.0 and later deprecate snprintf and _snprintf. -# define snprintf _snprintf_s -#elif _MSC_VER -# define snprintf _snprintf -#endif // GTEST_OS_WINDOWS_MOBILE - // Prints a segment of bytes in the given object. void PrintByteSegmentInObjectTo(const unsigned char* obj_bytes, size_t start, size_t count, ostream* os) { @@ -77,7 +69,7 @@ void PrintByteSegmentInObjectTo(const unsigned char* obj_bytes, size_t start, else *os << '-'; } - snprintf(text, sizeof(text), "%02X", obj_bytes[j]); + GTEST_SNPRINTF_(text, sizeof(text), "%02X", obj_bytes[j]); *os << text; } } -- cgit v1.2.3 From 69a40b7d4ab4171cbe4ef920e7a5171109e2064c Mon Sep 17 00:00:00 2001 From: vladlosev Date: Wed, 5 Oct 2011 05:51:10 +0000 Subject: Adds ability to inject death test child arguments for test purposes. --- src/gtest-death-test.cc | 7 ++++++- src/gtest-port.cc | 18 +++++++++++++++--- 2 files changed, 21 insertions(+), 4 deletions(-) (limited to 'src') diff --git a/src/gtest-death-test.cc b/src/gtest-death-test.cc index 2f0b0e38..76aa1685 100644 --- a/src/gtest-death-test.cc +++ b/src/gtest-death-test.cc @@ -844,6 +844,11 @@ class ExecDeathTest : public ForkingDeathTest { ForkingDeathTest(a_statement, a_regex), file_(file), line_(line) { } virtual TestRole AssumeRole(); private: + static ::std::vector + GetArgvsForDeathTestChildProcess() { + ::std::vector args = GetInjectableArgvs(); + return args; + } // The name of the file in which the death test is located. const char* const file_; // The line number on which the death test is located. @@ -1082,7 +1087,7 @@ DeathTest::TestRole ExecDeathTest::AssumeRole() { GTEST_FLAG_PREFIX_, kInternalRunDeathTestFlag, file_, line_, death_test_index, pipe_fd[1]); Arguments args; - args.AddArguments(GetArgvs()); + args.AddArguments(GetArgvsForDeathTestChildProcess()); args.AddArgument(filter_flag.c_str()); args.AddArgument(internal_flag.c_str()); diff --git a/src/gtest-port.cc b/src/gtest-port.cc index 32069146..6e8dca29 100644 --- a/src/gtest-port.cc +++ b/src/gtest-port.cc @@ -653,11 +653,23 @@ String GetCapturedStderr() { return GetCapturedStream(&g_captured_stderr); } #if GTEST_HAS_DEATH_TEST // A copy of all command line arguments. Set by InitGoogleTest(). -::std::vector g_argvs; +::std::vector g_argvs; -// Returns the command line as a vector of strings. -const ::std::vector& GetArgvs() { return g_argvs; } +static const ::std::vector* g_injected_test_argvs = + NULL; // Owned. +void SetInjectableArgvs(const ::std::vector* argvs) { + if (g_injected_test_argvs != argvs) + delete g_injected_test_argvs; + g_injected_test_argvs = argvs; +} + +const ::std::vector& GetInjectableArgvs() { + if (g_injected_test_argvs != NULL) { + return *g_injected_test_argvs; + } + return g_argvs; +} #endif // GTEST_HAS_DEATH_TEST #if GTEST_OS_WINDOWS_MOBILE -- cgit v1.2.3 From 431a8be1662a3bc9601240914f412b0436d94703 Mon Sep 17 00:00:00 2001 From: vladlosev Date: Wed, 5 Oct 2011 05:52:34 +0000 Subject: Implements the timestamp attribute for the testsuites element in the output XML (external contribution by Dirk Meister). --- src/gtest-internal-inl.h | 14 ++++++++++++++ src/gtest.cc | 38 +++++++++++++++++++++++++++++++++++++- 2 files changed, 51 insertions(+), 1 deletion(-) (limited to 'src') diff --git a/src/gtest-internal-inl.h b/src/gtest-internal-inl.h index 65a2101a..8a85724b 100644 --- a/src/gtest-internal-inl.h +++ b/src/gtest-internal-inl.h @@ -112,6 +112,12 @@ GTEST_API_ bool ShouldUseColor(bool stdout_is_tty); // Formats the given time in milliseconds as seconds. 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". // // On success, stores the value of the flag in *value, and returns @@ -548,6 +554,10 @@ class GTEST_API_ UnitTestImpl { // Gets the number of tests that should run. 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. TimeInMillis elapsed_time() const { return elapsed_time_; } @@ -880,6 +890,10 @@ class GTEST_API_ UnitTestImpl { // Our random number generator. 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. TimeInMillis elapsed_time_; diff --git a/src/gtest.cc b/src/gtest.cc index 6f7216f9..7bdd28a6 100644 --- a/src/gtest.cc +++ b/src/gtest.cc @@ -39,6 +39,7 @@ #include #include #include +#include #include #include @@ -3195,6 +3196,32 @@ std::string FormatTimeInMillisAsSeconds(TimeInMillis ms) { 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(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. void XmlUnitTestResultPrinter::OutputXmlCDataSection(::std::ostream* stream, const char* data) { @@ -3291,10 +3318,11 @@ void XmlUnitTestResultPrinter::PrintXmlUnitTest(FILE* out, fprintf(out, "\n"); fprintf(out, "total_test_count(); } // Gets the number of tests that should run. 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. internal::TimeInMillis UnitTest::elapsed_time() const { return impl()->elapsed_time(); @@ -3961,6 +3995,7 @@ UnitTestImpl::UnitTestImpl(UnitTest* parent) post_flag_parse_init_performed_(false), random_seed_(0), // Will be overridden by the flag before first use. random_(0), // Will be reseeded before first use. + start_timestamp_(0), elapsed_time_(0), #if GTEST_HAS_DEATH_TEST internal_run_death_test_flag_(NULL), @@ -4192,6 +4227,7 @@ bool UnitTestImpl::RunAllTests() { TestEventListener* repeater = listeners()->repeater(); + start_timestamp_ = GetTimeInMillis(); repeater->OnTestProgramStart(*parent_); // How many times to repeat the tests? We don't want to repeat them -- cgit v1.2.3 From 4c11f25f8c972bc5bed6d92abe2a0a3e41f499d7 Mon Sep 17 00:00:00 2001 From: vladlosev Date: Mon, 24 Oct 2011 21:13:56 +0000 Subject: Expressed the thread-safety annotations in code, replacing the existing comment-based system (by Aaron Jacobs). --- src/gtest-internal-inl.h | 6 +++++- src/gtest.cc | 51 ++++++++++++++++++++++++------------------------ 2 files changed, 31 insertions(+), 26 deletions(-) (limited to 'src') diff --git a/src/gtest-internal-inl.h b/src/gtest-internal-inl.h index 8a85724b..d869f0f6 100644 --- a/src/gtest-internal-inl.h +++ b/src/gtest-internal-inl.h @@ -438,8 +438,12 @@ class OsStackTraceGetterInterface { class OsStackTraceGetter : public OsStackTraceGetterInterface { public: OsStackTraceGetter() : caller_frame_(NULL) {} - virtual String CurrentStackTrace(int max_depth, int skip_count); + + 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 // Google Test's implementation. diff --git a/src/gtest.cc b/src/gtest.cc index 7bdd28a6..e407ee9b 100644 --- a/src/gtest.cc +++ b/src/gtest.cc @@ -3528,8 +3528,8 @@ void StreamingListener::MakeConnection() { // Pushes the given source file location and message onto a per-thread // 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; trace.file = file; trace.line = line; @@ -3539,8 +3539,8 @@ ScopedTrace::ScopedTrace(const char* file, int line, const Message& message) { } // Pops the info pushed by the c'tor. -// L < UnitTest::mutex_ -ScopedTrace::~ScopedTrace() { +ScopedTrace::~ScopedTrace() + GTEST_LOCK_EXCLUDED_(UnitTest::mutex_) { UnitTest::GetInstance()->PopGTestTrace(); } @@ -3554,14 +3554,14 @@ ScopedTrace::~ScopedTrace() { // skip_count - the number of top frames to be skipped; doesn't count // against max_depth. // -// L < mutex_ -// We use "L < mutex_" to denote that the function may acquire mutex_. -String OsStackTraceGetter::CurrentStackTrace(int, int) { +String OsStackTraceGetter::CurrentStackTrace(int /* max_depth */, + int /* skip_count */) + GTEST_LOCK_EXCLUDED_(mutex_) { return String(""); } -// L < mutex_ -void OsStackTraceGetter::UponLeavingGTest() { +void OsStackTraceGetter::UponLeavingGTest() + GTEST_LOCK_EXCLUDED_(mutex_) { } const char* const @@ -3774,12 +3774,13 @@ Environment* UnitTest::AddEnvironment(Environment* env) { // assertion macros (e.g. ASSERT_TRUE, EXPECT_EQ, etc) eventually call // this to report their results. The user code should use the // assertion macros instead of calling this directly. -// L < mutex_ -void UnitTest::AddTestPartResult(TestPartResult::Type result_type, - const char* file_name, - int line_number, - const internal::String& message, - const internal::String& os_stack_trace) { +void UnitTest::AddTestPartResult( + TestPartResult::Type result_type, + const char* file_name, + int line_number, + const internal::String& message, + const internal::String& os_stack_trace) + GTEST_LOCK_EXCLUDED_(mutex_) { Message msg; msg << message; @@ -3912,16 +3913,16 @@ const char* UnitTest::original_working_dir() const { // Returns the TestCase object for the test that's currently 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_); return impl_->current_test_case(); } // Returns the TestInfo object for the test that's currently 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_); return impl_->current_test_info(); } @@ -3932,9 +3933,9 @@ int UnitTest::random_seed() const { return impl_->random_seed(); } #if GTEST_HAS_PARAM_TEST // Returns ParameterizedTestCaseRegistry object used to keep track of // value-parameterized tests and instantiate and register them. -// L < mutex_ internal::ParameterizedTestCaseRegistry& - UnitTest::parameterized_test_registry() { + UnitTest::parameterized_test_registry() + GTEST_LOCK_EXCLUDED_(mutex_) { return impl_->parameterized_test_registry(); } #endif // GTEST_HAS_PARAM_TEST @@ -3951,15 +3952,15 @@ UnitTest::~UnitTest() { // Pushes a trace defined by SCOPED_TRACE() on to the per-thread // 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_); impl_->gtest_trace_stack().push_back(trace); } // 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_); impl_->gtest_trace_stack().pop_back(); } -- cgit v1.2.3 From 829402edcffe712ed4c79412ca020525cd8295ad Mon Sep 17 00:00:00 2001 From: vladlosev Date: Fri, 28 Oct 2011 16:19:04 +0000 Subject: Adds support for detection of running in death test child processes. --- src/gtest-death-test.cc | 32 +++++++++++++++++++++++++++++++- 1 file changed, 31 insertions(+), 1 deletion(-) (limited to 'src') diff --git a/src/gtest-death-test.cc b/src/gtest-death-test.cc index 76aa1685..0a0f83b5 100644 --- a/src/gtest-death-test.cc +++ b/src/gtest-death-test.cc @@ -109,13 +109,42 @@ GTEST_DEFINE_string_( "Indicates the file, line number, temporal index of " "the single death test to run, and a file descriptor to " "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 " "death test. FOR INTERNAL USE ONLY."); } // namespace internal #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::ExitedWithCode(int exit_code) : exit_code_(exit_code) { } @@ -825,6 +854,7 @@ DeathTest::TestRole NoExecDeathTest::AssumeRole() { // Event forwarding to the listeners of event listener API mush be shut // down in death test subprocesses. GetUnitTestImpl()->listeners()->SuppressEventForwarding(); + g_in_fast_death_test_child = true; return EXECUTE_TEST; } else { GTEST_DEATH_TEST_CHECK_SYSCALL_(close(pipe_fd[1])); -- cgit v1.2.3 From 8965a6a0d2165f32e6413594bba6367f271f51e7 Mon Sep 17 00:00:00 2001 From: vladlosev Date: Fri, 4 Nov 2011 17:56:23 +0000 Subject: Improves conformance to the Google C++ Style Guide (by Greg Miller). --- src/gtest-death-test.cc | 1 + src/gtest-internal-inl.h | 1 + src/gtest-port.cc | 1 - src/gtest.cc | 2 -- src/gtest_main.cc | 5 ++--- 5 files changed, 4 insertions(+), 6 deletions(-) (limited to 'src') diff --git a/src/gtest-death-test.cc b/src/gtest-death-test.cc index 0a0f83b5..36a2e3a7 100644 --- a/src/gtest-death-test.cc +++ b/src/gtest-death-test.cc @@ -913,6 +913,7 @@ class Arguments { char* const* Argv() { return &args_[0]; } + private: std::vector args_; }; diff --git a/src/gtest-internal-inl.h b/src/gtest-internal-inl.h index d869f0f6..1ea31a15 100644 --- a/src/gtest-internal-inl.h +++ b/src/gtest-internal-inl.h @@ -196,6 +196,7 @@ class GTestFlagSaver { GTEST_FLAG(stream_result_to) = stream_result_to_; GTEST_FLAG(throw_on_failure) = throw_on_failure_; } + private: // Fields for saving the original values of flags. bool also_run_disabled_tests_; diff --git a/src/gtest-port.cc b/src/gtest-port.cc index 6e8dca29..9648eee8 100644 --- a/src/gtest-port.cc +++ b/src/gtest-port.cc @@ -514,7 +514,6 @@ class CapturedStream { public: // The ctor redirects the stream to a temporary file. CapturedStream(int fd) : fd_(fd), uncaptured_fd_(dup(fd)) { - # if GTEST_OS_WINDOWS char temp_dir_path[MAX_PATH + 1] = { '\0' }; // NOLINT char temp_file_path[MAX_PATH + 1] = { '\0' }; // NOLINT diff --git a/src/gtest.cc b/src/gtest.cc index e407ee9b..f2e84af7 100644 --- a/src/gtest.cc +++ b/src/gtest.cc @@ -3864,7 +3864,6 @@ int UnitTest::Run() { // process. In either case the user does not want to see pop-up dialogs // about crashes - they are expected. if (impl()->catch_exceptions() || in_death_test_child_process) { - # if !GTEST_OS_WINDOWS_MOBILE // SetErrorMode doesn't exist on CE. SetErrorMode(SEM_FAILCRITICALERRORS | SEM_NOALIGNMENTFAULTEXCEPT | @@ -3895,7 +3894,6 @@ int UnitTest::Run() { 0x0, // Clear the following flags: _WRITE_ABORT_MSG | _CALL_REPORTFAULT); // pop-up window, core dump. # endif - } #endif // GTEST_HAS_SEH diff --git a/src/gtest_main.cc b/src/gtest_main.cc index a09bbe0c..f3028225 100644 --- a/src/gtest_main.cc +++ b/src/gtest_main.cc @@ -27,13 +27,12 @@ // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -#include +#include #include "gtest/gtest.h" GTEST_API_ int main(int argc, char **argv) { - std::cout << "Running main() from gtest_main.cc\n"; - + printf("Running main() from gtest_main.cc\n"); testing::InitGoogleTest(&argc, argv); return RUN_ALL_TESTS(); } -- cgit v1.2.3 From 69a071bc0d1c87b9b8271e8d7545ade7086be6bb Mon Sep 17 00:00:00 2001 From: vladlosev Date: Mon, 28 Nov 2011 19:52:07 +0000 Subject: Removes spurious semicolon. --- src/gtest-internal-inl.h | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'src') diff --git a/src/gtest-internal-inl.h b/src/gtest-internal-inl.h index 1ea31a15..4e9805d1 100644 --- a/src/gtest-internal-inl.h +++ b/src/gtest-internal-inl.h @@ -443,8 +443,7 @@ class OsStackTraceGetter : public OsStackTraceGetterInterface { virtual String CurrentStackTrace(int max_depth, int skip_count) GTEST_LOCK_EXCLUDED_(mutex_); - virtual void UponLeavingGTest(); - GTEST_LOCK_EXCLUDED_(mutex_); + virtual void UponLeavingGTest() GTEST_LOCK_EXCLUDED_(mutex_); // This string is inserted in place of stack frames that are part of // Google Test's implementation. -- cgit v1.2.3 From 4d6f296e8e5d3f839ef4868390bbec27cb12e068 Mon Sep 17 00:00:00 2001 From: jgm Date: Tue, 17 Jan 2012 15:11:32 +0000 Subject: Adds file and line information to the "message", which is used as the summary of a failure. --- src/gtest-internal-inl.h | 2 +- src/gtest.cc | 15 ++++++++------- 2 files changed, 9 insertions(+), 8 deletions(-) (limited to 'src') diff --git a/src/gtest-internal-inl.h b/src/gtest-internal-inl.h index 4e9805d1..350ade07 100644 --- a/src/gtest-internal-inl.h +++ b/src/gtest-internal-inl.h @@ -620,7 +620,7 @@ class GTEST_API_ UnitTestImpl { // For example, if Foo() calls Bar(), which in turn calls // CurrentOsStackTraceExceptTop(1), Foo() will be included in the // 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 // exist, creates one and returns it. diff --git a/src/gtest.cc b/src/gtest.cc index f2e84af7..56af6469 100644 --- a/src/gtest.cc +++ b/src/gtest.cc @@ -3271,16 +3271,17 @@ void XmlUnitTestResultPrinter::OutputXmlTestInfo(::std::ostream* stream, for (int i = 0; i < result.total_part_count(); ++i) { const TestPartResult& part = result.GetTestPartResult(i); if (part.failed()) { - if (++failures == 1) + if (++failures == 1) { *stream << ">\n"; - *stream << " "; + } const string location = internal::FormatCompilerIndependentFileLocation( part.file_name(), part.line_number()); - const string message = location + "\n" + part.message(); - OutputXmlCDataSection(stream, - RemoveInvalidXmlCharacters(message).c_str()); + const string summary = location + "\n" + part.summary(); + *stream << " "; + const string detail = location + "\n" + part.message(); + OutputXmlCDataSection(stream, RemoveInvalidXmlCharacters(detail).c_str()); *stream << "\n"; } } -- cgit v1.2.3 From f0b86fc3b0f625e1db84f3632cb37bd9eae6ae19 Mon Sep 17 00:00:00 2001 From: jgm Date: Fri, 9 Mar 2012 17:12:39 +0000 Subject: Misc small updates to some debug death code, and to messages streaming to macros --- src/gtest-port.cc | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) (limited to 'src') diff --git a/src/gtest-port.cc b/src/gtest-port.cc index 9648eee8..a0e2d7c7 100644 --- a/src/gtest-port.cc +++ b/src/gtest-port.cc @@ -530,10 +530,15 @@ class CapturedStream { << temp_file_path; filename_ = temp_file_path; # else - // There's no guarantee that a test has write access to the - // current directory, so we create the temporary file in the /tmp - // directory instead. + // There's no guarantee that a test has write access to the current + // directory, so we create the temporary file in the /tmp 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"; +# endif // GTEST_OS_LINUX_ANDROID const int captured_fd = mkstemp(name_template); filename_ = name_template; # endif // GTEST_OS_WINDOWS -- cgit v1.2.3 From a3b859162dd7a4a1798cf8753a03098f2cbdb62e Mon Sep 17 00:00:00 2001 From: "zhanyong.wan" Date: Thu, 31 May 2012 20:37:13 +0000 Subject: Fixes threading annotations and compatibility with C++11, which doesn't allow exepctions to be thrown in a destructor. --- src/gtest.cc | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'src') diff --git a/src/gtest.cc b/src/gtest.cc index 56af6469..78f113e2 100644 --- a/src/gtest.cc +++ b/src/gtest.cc @@ -3530,7 +3530,7 @@ void StreamingListener::MakeConnection() { // Pushes the given source file location and message onto a per-thread // trace stack maintained by Google Test. ScopedTrace::ScopedTrace(const char* file, int line, const Message& message) - GTEST_LOCK_EXCLUDED_(UnitTest::mutex_) { + GTEST_LOCK_EXCLUDED_(&UnitTest::mutex_) { TraceInfo trace; trace.file = file; trace.line = line; @@ -3541,7 +3541,7 @@ ScopedTrace::ScopedTrace(const char* file, int line, const Message& message) // Pops the info pushed by the c'tor. ScopedTrace::~ScopedTrace() - GTEST_LOCK_EXCLUDED_(UnitTest::mutex_) { + GTEST_LOCK_EXCLUDED_(&UnitTest::mutex_) { UnitTest::GetInstance()->PopGTestTrace(); } -- cgit v1.2.3 From a88c9a88e49e90ec414175543b2b7ff2f70866a7 Mon Sep 17 00:00:00 2001 From: "zhanyong.wan" Date: Thu, 7 Jun 2012 20:34:34 +0000 Subject: Improves gtest's failure messages. In particulars, char pointers and char arrays are not escapped properly. --- src/gtest-printers.cc | 84 ++++++++++++++++++++++++++++++--------------------- src/gtest.cc | 36 +++++----------------- 2 files changed, 58 insertions(+), 62 deletions(-) (limited to 'src') diff --git a/src/gtest-printers.cc b/src/gtest-printers.cc index cfe9eed3..898d61d8 100644 --- a/src/gtest-printers.cc +++ b/src/gtest-printers.cc @@ -183,9 +183,9 @@ static CharFormat PrintAsCharLiteralTo(Char c, ostream* os) { 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. -static CharFormat PrintAsWideStringLiteralTo(wchar_t c, ostream* os) { +static CharFormat PrintAsStringLiteralTo(wchar_t c, ostream* os) { switch (c) { case L'\'': *os << "'"; @@ -200,8 +200,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 // necessary; returns how c was formatted. -static CharFormat PrintAsNarrowStringLiteralTo(char c, ostream* os) { - return PrintAsWideStringLiteralTo(static_cast(c), os); +static CharFormat PrintAsStringLiteralTo(char c, ostream* os) { + return PrintAsStringLiteralTo( + static_cast(static_cast(c)), os); } // Prints a wide or narrow character c and its code. '\0' is printed @@ -247,48 +248,63 @@ void PrintTo(wchar_t wc, ostream* os) { PrintCharAndCodeTo(wc, os); } -// Prints the given array of characters to the ostream. -// The array starts at *begin, the length is len, it may include '\0' characters -// and may not be null-terminated. -static void PrintCharsAsStringTo(const char* begin, size_t len, ostream* os) { - *os << "\""; +// Prints the given array of characters to the ostream. CharType must be either +// char or wchar_t. +// The array starts at begin, the length is len, it may include '\0' characters +// and may not be NUL-terminated. +template +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; for (size_t index = 0; index < len; ++index) { - const char cur = begin[index]; + const CharType cur = begin[index]; if (is_previous_hex && IsXDigit(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 << "\" \""; + *os << "\" " << kQuoteBegin; } - is_previous_hex = PrintAsNarrowStringLiteralTo(cur, os) == kHexEscape; + is_previous_hex = PrintAsStringLiteralTo(cur, os) == kHexEscape; } *os << "\""; } +// Prints a (const) char/wchar_t array of 'len' elements, starting at address +// 'begin'. CharType must be either char or wchar_t. +template +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'. 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. -// The array starts at *begin, the length is len, it may include L'\0' -// characters and may not be null-terminated. -static void PrintWideCharsAsStringTo(const wchar_t* begin, size_t len, - 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(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 a (const) wchar_t array of 'len' elements, starting at address +// 'begin'. +void UniversalPrintArray(const wchar_t* begin, size_t len, ostream* os) { + UniversalPrintCharArray(begin, len, os); } // Prints the given C string to the ostream. @@ -314,7 +330,7 @@ void PrintTo(const wchar_t* s, ostream* os) { *os << "NULL"; } else { *os << ImplicitCast_(s) << " pointing to "; - PrintWideCharsAsStringTo(s, wcslen(s), os); + PrintCharsAsStringTo(s, wcslen(s), os); } } #endif // wchar_t is native @@ -333,13 +349,13 @@ void PrintStringTo(const ::std::string& s, ostream* os) { // Prints a ::wstring object. #if GTEST_HAS_GLOBAL_WSTRING void PrintWideStringTo(const ::wstring& s, ostream* os) { - PrintWideCharsAsStringTo(s.data(), s.size(), os); + PrintCharsAsStringTo(s.data(), s.size(), os); } #endif // GTEST_HAS_GLOBAL_WSTRING #if GTEST_HAS_STD_WSTRING 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 diff --git a/src/gtest.cc b/src/gtest.cc index 78f113e2..35e1dbdf 100644 --- a/src/gtest.cc +++ b/src/gtest.cc @@ -818,17 +818,6 @@ TimeInMillis GetTimeInMillis() { // 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 // 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 @@ -1169,8 +1158,8 @@ AssertionResult CmpHelperSTREQ(const char* expected_expression, return EqFailure(expected_expression, actual_expression, - String::ShowCStringQuoted(expected), - String::ShowCStringQuoted(actual), + PrintToString(expected), + PrintToString(actual), false); } @@ -1185,8 +1174,8 @@ AssertionResult CmpHelperSTRCASEEQ(const char* expected_expression, return EqFailure(expected_expression, actual_expression, - String::ShowCStringQuoted(expected), - String::ShowCStringQuoted(actual), + PrintToString(expected), + PrintToString(actual), true); } @@ -1534,15 +1523,6 @@ String String::ShowWideCString(const wchar_t * wide_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 // content. // @@ -1568,8 +1548,8 @@ AssertionResult CmpHelperSTREQ(const char* expected_expression, return EqFailure(expected_expression, actual_expression, - String::ShowWideCStringQuoted(expected), - String::ShowWideCStringQuoted(actual), + PrintToString(expected), + PrintToString(actual), false); } @@ -1584,8 +1564,8 @@ AssertionResult CmpHelperSTRNE(const char* s1_expression, return AssertionFailure() << "Expected: (" << s1_expression << ") != (" << s2_expression << "), actual: " - << String::ShowWideCStringQuoted(s1) - << " vs " << String::ShowWideCStringQuoted(s2); + << PrintToString(s1) + << " vs " << PrintToString(s2); } // Compares two C strings, ignoring case. Returns true iff they have -- cgit v1.2.3 From a1c4b46bc2c12ea7c61108f001a5b5eb4a8ccad0 Mon Sep 17 00:00:00 2001 From: jgm Date: Mon, 9 Jul 2012 13:22:29 +0000 Subject: added defines for iOS --- src/gtest.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src') diff --git a/src/gtest.cc b/src/gtest.cc index 35e1dbdf..3b5a28b0 100644 --- a/src/gtest.cc +++ b/src/gtest.cc @@ -2602,7 +2602,7 @@ void ColoredPrintf(GTestColor color, const char* fmt, ...) { va_list args; va_start(args, fmt); -#if GTEST_OS_WINDOWS_MOBILE || GTEST_OS_SYMBIAN || GTEST_OS_ZOS +#if GTEST_OS_WINDOWS_MOBILE || GTEST_OS_SYMBIAN || GTEST_OS_ZOS || GTEST_OS_IOS const bool use_color = false; #else static const bool in_color_mode = -- cgit v1.2.3 From 4c97512141023985ea849887101d046edb590300 Mon Sep 17 00:00:00 2001 From: jgm Date: Thu, 12 Jul 2012 16:46:50 +0000 Subject: fixes a problem in which we pass the address one byte ~/svn/googletest/trunk after the end of stack space in a call to clone(). According to Linux's man page on clone(), the 'stack' parameter usually points to the topmost address of the memory space set up for the child stack. The existing code points one byte after the end --- src/gtest-death-test.cc | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) (limited to 'src') diff --git a/src/gtest-death-test.cc b/src/gtest-death-test.cc index 36a2e3a7..de50ba74 100644 --- a/src/gtest-death-test.cc +++ b/src/gtest-death-test.cc @@ -1062,8 +1062,19 @@ static pid_t ExecDeathTestSpawnChild(char* const* argv, int close_fd) { void* const stack = mmap(NULL, stack_size, PROT_READ | PROT_WRITE, MAP_ANON | MAP_PRIVATE, -1, 0); GTEST_DEATH_TEST_CHECK_(stack != MAP_FAILED); + + // Maximum stack alignment in bytes: For a downward-growing stack, this + // amount is subtracted from size of the stack space to get an address + // that is within the stack space and is aligned on all systems we care + // about. As far as I know there is no ABI with stack alignment greater + // than 64. We assume stack and stack_size already have alignment of + // kMaxStackAlignment. + const size_t kMaxStackAlignment = 64; void* const stack_top = - static_cast(stack) + (stack_grows_down ? stack_size : 0); + static_cast(stack) + + (stack_grows_down ? stack_size - kMaxStackAlignment : 0); + GTEST_DEATH_TEST_CHECK_(stack_size > kMaxStackAlignment && + reinterpret_cast(stack_top) % kMaxStackAlignment == 0); child_pid = clone(&ExecDeathTestChildMain, stack_top, SIGCHLD, &args); -- cgit v1.2.3 From 2147489625ea8071ca560462f19b1ceb8940a229 Mon Sep 17 00:00:00 2001 From: vladlosev Date: Tue, 14 Aug 2012 15:20:28 +0000 Subject: Fixed Native Client build of gtest when using glibc (by Ben Smith). --- src/gtest-filepath.cc | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'src') diff --git a/src/gtest-filepath.cc b/src/gtest-filepath.cc index 91b25713..9d913b7f 100644 --- a/src/gtest-filepath.cc +++ b/src/gtest-filepath.cc @@ -39,8 +39,8 @@ #elif GTEST_OS_WINDOWS # include # include -#elif GTEST_OS_SYMBIAN || GTEST_OS_NACL -// Symbian OpenC and NaCl have PATH_MAX in sys/syslimits.h +#elif GTEST_OS_SYMBIAN +// Symbian OpenC has PATH_MAX in sys/syslimits.h # include #else # include -- cgit v1.2.3 From 78bf6d5724e733cce313228856e18d5c372b4fb3 Mon Sep 17 00:00:00 2001 From: vladlosev Date: Wed, 19 Sep 2012 17:58:01 +0000 Subject: Improves Android support (by David Turner). --- src/gtest-port.cc | 22 ++++++++++++++++++---- 1 file changed, 18 insertions(+), 4 deletions(-) (limited to 'src') diff --git a/src/gtest-port.cc b/src/gtest-port.cc index a0e2d7c7..9cfe4e95 100644 --- a/src/gtest-port.cc +++ b/src/gtest-port.cc @@ -531,11 +531,25 @@ class CapturedStream { filename_ = temp_file_path; # else // There's no guarantee that a test has write access to the current - // directory, so we create the temporary file in the /tmp directory instead. - // We use /tmp on most systems, and /mnt/sdcard on Android. That's because - // Android doesn't have /tmp. + // directory, so we create the temporary file in the /tmp directory + // instead. We use /tmp on most systems, and /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"; + // Note: Android applications are expected to call the framework's + // Context.getExternalStorageDirectory() method through JNI to get + // the location of the world-writable SD Card directory. However, + // this requires a Context handle, which cannot be retrieved + // globally from native code. Doing so also precludes running the + // code as part of a regular standalone executable, which doesn't + // run in a Dalvik process (e.g. when running it through 'adb shell'). + // + // The location /sdcard is directly accessible from native code + // and is the only location (unofficially) supported by the Android + // team. It's generally a symlink to the real SD Card mount point + // which can be /mnt/sdcard, /mnt/sdcard0, /system/media/sdcard, or + // other OEM-customized locations. Never rely on these, and always + // use /sdcard. + char name_template[] = "/sdcard/gtest_captured_stream.XXXXXX"; # else char name_template[] = "/tmp/captured_stream.XXXXXX"; # endif // GTEST_OS_LINUX_ANDROID -- cgit v1.2.3 From 87fdda2cf24d953f3cbec1e0c266b2db9928f406 Mon Sep 17 00:00:00 2001 From: jgm Date: Thu, 15 Nov 2012 15:47:38 +0000 Subject: Unfortunately, the svn repo is a bit out of date. This commit contains 8 changes that haven't made it to svn. The descriptions of each change are listed below. - Fixes some python shebang lines. - Add ElementsAreArray overloads to gmock. ElementsAreArray now makes a copy of its input elements before the conversion to a Matcher. ElementsAreArray can now take a vector as input. ElementsAreArray can now take an iterator pair as input. - Templatize MatchAndExplain to allow independent string types for the matcher and matchee. I also templatized the ConstCharPointer version of MatchAndExplain to avoid calls with "char*" from using the new templated MatchAndExplain. - Fixes the bug where the constructor of the return type of ElementsAre() saves a reference instead of a copy of the arguments. - Extends ElementsAre() to accept arrays whose sizes aren't known. - Switches gTest's internal FilePath class from testing::internal::String to std::string. testing::internal::String was introduced when gTest couldn't depend on std::string. It's now deprecated. - Switches gTest & gMock from using testing::internal::String objects to std::string. Some static methods of String are still in use. We may be able to remove some but not all of them. In particular, String::Format() should eventually be removed as it truncates the result at 4096 characters, often causing problems. --- src/gtest-death-test.cc | 63 +++++----- src/gtest-filepath.cc | 25 ++-- src/gtest-internal-inl.h | 42 +++---- src/gtest-port.cc | 38 +++--- src/gtest-test-part.cc | 6 +- src/gtest-typed-test.cc | 6 +- src/gtest.cc | 312 ++++++++++++++++++----------------------------- 7 files changed, 209 insertions(+), 283 deletions(-) (limited to 'src') diff --git a/src/gtest-death-test.cc b/src/gtest-death-test.cc index de50ba74..8b52431f 100644 --- a/src/gtest-death-test.cc +++ b/src/gtest-death-test.cc @@ -179,7 +179,7 @@ namespace internal { // Generates a textual description of a given exit code, in the format // specified by wait(2). -static String ExitSummary(int exit_code) { +static std::string ExitSummary(int exit_code) { Message m; # if GTEST_OS_WINDOWS @@ -214,7 +214,7 @@ bool ExitedUnsuccessfully(int exit_status) { // one thread running, or cannot determine the number of threads, prior // to executing the given statement. It is the responsibility of the // caller not to pass a thread_count of 1. -static String DeathTestThreadWarning(size_t thread_count) { +static std::string DeathTestThreadWarning(size_t thread_count) { Message msg; msg << "Death tests use fork(), which is unsafe particularly" << " in a threaded context. For this test, " << GTEST_NAME_ << " "; @@ -248,7 +248,7 @@ enum DeathTestOutcome { IN_PROGRESS, DIED, LIVED, RETURNED, THREW }; // message is propagated back to the parent process. Otherwise, the // message is simply printed to stderr. In either case, the program // then exits with status 1. -void DeathTestAbort(const String& message) { +void DeathTestAbort(const std::string& message) { // On a POSIX system, this function may be called from a threadsafe-style // death test child process, which operates on a very small stack. Use // the heap for any additional non-minuscule memory requirements. @@ -272,7 +272,7 @@ void DeathTestAbort(const String& message) { # define GTEST_DEATH_TEST_CHECK_(expression) \ do { \ if (!::testing::internal::IsTrue(expression)) { \ - DeathTestAbort(::testing::internal::String::Format( \ + DeathTestAbort(::testing::internal::String::Format( \ "CHECK failed: File %s, line %d: %s", \ __FILE__, __LINE__, #expression)); \ } \ @@ -292,15 +292,15 @@ void DeathTestAbort(const String& message) { gtest_retval = (expression); \ } while (gtest_retval == -1 && errno == EINTR); \ if (gtest_retval == -1) { \ - DeathTestAbort(::testing::internal::String::Format( \ + DeathTestAbort(::testing::internal::String::Format( \ "CHECK failed: File %s, line %d: %s != -1", \ __FILE__, __LINE__, #expression)); \ } \ } while (::testing::internal::AlwaysFalse()) // Returns the message describing the last system error in errno. -String GetLastErrnoDescription() { - return String(errno == 0 ? "" : posix::StrError(errno)); +std::string GetLastErrnoDescription() { + return errno == 0 ? "" : posix::StrError(errno); } // This is called from a death test parent process to read a failure @@ -350,11 +350,11 @@ const char* DeathTest::LastMessage() { return last_death_test_message_.c_str(); } -void DeathTest::set_last_death_test_message(const String& message) { +void DeathTest::set_last_death_test_message(const std::string& message) { last_death_test_message_ = message; } -String DeathTest::last_death_test_message_; +std::string DeathTest::last_death_test_message_; // Provides cross platform implementation for some death functionality. class DeathTestImpl : public DeathTest { @@ -529,7 +529,7 @@ bool DeathTestImpl::Passed(bool status_ok) { if (!spawned()) return false; - const String error_message = GetCapturedStderr(); + const std::string error_message = GetCapturedStderr(); bool success = false; Message buffer; @@ -711,15 +711,12 @@ DeathTest::TestRole WindowsDeathTest::AssumeRole() { FALSE, // The initial state is non-signalled. NULL)); // The even is unnamed. GTEST_DEATH_TEST_CHECK_(event_handle_.Get() != NULL); - const String filter_flag = String::Format("--%s%s=%s.%s", - GTEST_FLAG_PREFIX_, kFilterFlag, - info->test_case_name(), - info->name()); - const String internal_flag = String::Format( - "--%s%s=%s|%d|%d|%u|%Iu|%Iu", - GTEST_FLAG_PREFIX_, - kInternalRunDeathTestFlag, - file_, line_, + const std::string filter_flag = + std::string("--") + GTEST_FLAG_PREFIX_ + kFilterFlag + "=" + + info->test_case_name() + "." + info->name(); + const std::string internal_flag = + std::string("--") + GTEST_FLAG_PREFIX_ + kInternalRunDeathTestFlag + + "=" + file_ + "|" + String::Format("%d|%d|%u|%Iu|%Iu", line_, death_test_index, static_cast(::GetCurrentProcessId()), // size_t has the same with as pointers on both 32-bit and 64-bit @@ -734,10 +731,9 @@ DeathTest::TestRole WindowsDeathTest::AssumeRole() { executable_path, _MAX_PATH)); - String command_line = String::Format("%s %s \"%s\"", - ::GetCommandLineA(), - filter_flag.c_str(), - internal_flag.c_str()); + std::string command_line = + std::string(::GetCommandLineA()) + " " + filter_flag + " \"" + + internal_flag + "\""; DeathTest::set_last_death_test_message(""); @@ -954,9 +950,8 @@ static int ExecDeathTestChildMain(void* child_arg) { 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())); + DeathTestAbort(std::string("chdir(\"") + original_dir + "\") failed: " + + GetLastErrnoDescription()); return EXIT_FAILURE; } @@ -966,10 +961,9 @@ static int ExecDeathTestChildMain(void* child_arg) { // invoke the test program via a valid path that contains at least // one path separator. execve(args->argv[0], args->argv, GetEnviron()); - DeathTestAbort(String::Format("execve(%s, ...) in %s failed: %s", - args->argv[0], - original_dir, - GetLastErrnoDescription().c_str())); + DeathTestAbort(std::string("execve(") + args->argv[0] + ", ...) in " + + original_dir + " failed: " + + GetLastErrnoDescription()); return EXIT_FAILURE; } # endif // !GTEST_OS_QNX @@ -1020,9 +1014,8 @@ static pid_t ExecDeathTestSpawnChild(char* const* argv, int close_fd) { 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())); + DeathTestAbort(std::string("chdir(\"") + original_dir + "\") failed: " + + GetLastErrnoDescription()); return EXIT_FAILURE; } @@ -1120,11 +1113,11 @@ DeathTest::TestRole ExecDeathTest::AssumeRole() { // it be closed when the child process does an exec: GTEST_DEATH_TEST_CHECK_(fcntl(pipe_fd[1], F_SETFD, 0) != -1); - const String filter_flag = + const std::string filter_flag = String::Format("--%s%s=%s.%s", GTEST_FLAG_PREFIX_, kFilterFlag, info->test_case_name(), info->name()); - const String internal_flag = + const std::string internal_flag = String::Format("--%s%s=%s|%d|%d|%d", GTEST_FLAG_PREFIX_, kInternalRunDeathTestFlag, file_, line_, death_test_index, pipe_fd[1]); diff --git a/src/gtest-filepath.cc b/src/gtest-filepath.cc index 9d913b7f..4d40cb96 100644 --- a/src/gtest-filepath.cc +++ b/src/gtest-filepath.cc @@ -116,9 +116,10 @@ FilePath FilePath::GetCurrentDir() { // FilePath("dir/file"). If a case-insensitive extension is not // found, returns a copy of the original FilePath. FilePath FilePath::RemoveExtension(const char* extension) const { - String dot_extension(String::Format(".%s", extension)); - if (pathname_.EndsWithCaseInsensitive(dot_extension.c_str())) { - return FilePath(String(pathname_.c_str(), pathname_.length() - 4)); + const std::string dot_extension = std::string(".") + extension; + if (String::EndsWithCaseInsensitive(pathname_, dot_extension)) { + return FilePath(pathname_.substr( + 0, pathname_.length() - dot_extension.length())); } return *this; } @@ -147,7 +148,7 @@ const char* FilePath::FindLastPathSeparator() const { // On Windows platform, '\' is the path separator, otherwise it is '/'. FilePath FilePath::RemoveDirectoryName() const { const char* const last_sep = FindLastPathSeparator(); - return last_sep ? FilePath(String(last_sep + 1)) : *this; + return last_sep ? FilePath(last_sep + 1) : *this; } // RemoveFileName returns the directory path with the filename removed. @@ -158,9 +159,9 @@ FilePath FilePath::RemoveDirectoryName() const { // On Windows platform, '\' is the path separator, otherwise it is '/'. FilePath FilePath::RemoveFileName() const { const char* const last_sep = FindLastPathSeparator(); - String dir; + std::string dir; if (last_sep) { - dir = String(c_str(), last_sep + 1 - c_str()); + dir = std::string(c_str(), last_sep + 1 - c_str()); } else { dir = kCurrentDirectoryString; } @@ -177,11 +178,12 @@ FilePath FilePath::MakeFileName(const FilePath& directory, const FilePath& base_name, int number, const char* extension) { - String file; + std::string file; if (number == 0) { - file = String::Format("%s.%s", base_name.c_str(), extension); + file = base_name.string() + "." + extension; } else { - file = String::Format("%s_%d.%s", base_name.c_str(), number, extension); + file = base_name.string() + "_" + String::Format("%d", number).c_str() + + "." + extension; } return ConcatPaths(directory, FilePath(file)); } @@ -193,8 +195,7 @@ FilePath FilePath::ConcatPaths(const FilePath& directory, if (directory.IsEmpty()) return relative_path; const FilePath dir(directory.RemoveTrailingPathSeparator()); - return FilePath(String::Format("%s%c%s", dir.c_str(), kPathSeparator, - relative_path.c_str())); + return FilePath(dir.string() + kPathSeparator + relative_path.string()); } // Returns true if pathname describes something findable in the file-system, @@ -338,7 +339,7 @@ bool FilePath::CreateFolder() const { // On Windows platform, uses \ as the separator, other platforms use /. FilePath FilePath::RemoveTrailingPathSeparator() const { return IsDirectory() - ? FilePath(String(pathname_.c_str(), pathname_.length() - 1)) + ? FilePath(pathname_.substr(0, pathname_.length() - 1)) : *this; } diff --git a/src/gtest-internal-inl.h b/src/gtest-internal-inl.h index 350ade07..54717c95 100644 --- a/src/gtest-internal-inl.h +++ b/src/gtest-internal-inl.h @@ -202,20 +202,20 @@ class GTestFlagSaver { bool also_run_disabled_tests_; bool break_on_failure_; bool catch_exceptions_; - String color_; - String death_test_style_; + std::string color_; + std::string death_test_style_; bool death_test_use_fork_; - String filter_; - String internal_run_death_test_; + std::string filter_; + std::string internal_run_death_test_; bool list_tests_; - String output_; + std::string output_; bool print_time_; bool pretty_; internal::Int32 random_seed_; internal::Int32 repeat_; bool shuffle_; internal::Int32 stack_trace_depth_; - String stream_result_to_; + std::string stream_result_to_; bool throw_on_failure_; } GTEST_ATTRIBUTE_UNUSED_; @@ -242,7 +242,7 @@ GTEST_API_ char* CodePointToUtf8(UInt32 code_point, char* str); // as '(Invalid Unicode 0xXXXXXXXX)'. If the string is in UTF16 encoding // and contains invalid UTF-16 surrogate pairs, values in those pairs // will be encoded as individual Unicode characters from Basic Normal Plane. -GTEST_API_ String WideStringToUtf8(const wchar_t* str, int num_chars); +GTEST_API_ std::string WideStringToUtf8(const wchar_t* str, int num_chars); // Reads the GTEST_SHARD_STATUS_FILE environment variable, and creates the file // if the variable is present. If a file already exists at this location, this @@ -351,11 +351,11 @@ class TestPropertyKeyIs { // Returns true iff the test name of test property matches on key_. bool operator()(const TestProperty& test_property) const { - return String(test_property.key()).Compare(key_) == 0; + return test_property.key() == key_; } private: - String key_; + std::string key_; }; // Class UnitTestOptions. @@ -373,12 +373,12 @@ class GTEST_API_ UnitTestOptions { // Functions for processing the gtest_output flag. // Returns the output format, or "" for normal printed output. - static String GetOutputFormat(); + static std::string GetOutputFormat(); // Returns the absolute path of the requested output file, or the // default (test_detail.xml in the original working directory) if // none was explicitly specified. - static String GetAbsolutePathToOutputFile(); + static std::string GetAbsolutePathToOutputFile(); // Functions for processing the gtest_filter flag. @@ -391,8 +391,8 @@ class GTEST_API_ UnitTestOptions { // Returns true iff the user-specified filter matches the test case // name and the test name. - static bool FilterMatchesTest(const String &test_case_name, - const String &test_name); + static bool FilterMatchesTest(const std::string &test_case_name, + const std::string &test_name); #if GTEST_OS_WINDOWS // Function for supporting the gtest_catch_exception flag. @@ -405,7 +405,7 @@ class GTEST_API_ UnitTestOptions { // Returns true if "name" matches the ':' separated list of glob-style // filters in "filter". - static bool MatchesFilter(const String& name, const char* filter); + static bool MatchesFilter(const std::string& name, const char* filter); }; // Returns the current application's name, removing directory path if that @@ -418,13 +418,13 @@ class OsStackTraceGetterInterface { OsStackTraceGetterInterface() {} virtual ~OsStackTraceGetterInterface() {} - // Returns the current OS stack trace as a String. Parameters: + // Returns the current OS stack trace as an std::string. Parameters: // // max_depth - the maximum number of stack frames to be included // in the trace. // skip_count - the number of top frames to be skipped; doesn't count // against max_depth. - virtual String CurrentStackTrace(int max_depth, int skip_count) = 0; + virtual string CurrentStackTrace(int max_depth, int skip_count) = 0; // UponLeavingGTest() should be called immediately before Google Test calls // user code. It saves some information about the current stack that @@ -440,7 +440,7 @@ class OsStackTraceGetter : public OsStackTraceGetterInterface { public: OsStackTraceGetter() : caller_frame_(NULL) {} - virtual String CurrentStackTrace(int max_depth, int skip_count) + virtual string CurrentStackTrace(int max_depth, int skip_count) GTEST_LOCK_EXCLUDED_(mutex_); virtual void UponLeavingGTest() GTEST_LOCK_EXCLUDED_(mutex_); @@ -465,7 +465,7 @@ class OsStackTraceGetter : public OsStackTraceGetterInterface { struct TraceInfo { const char* file; int line; - String message; + std::string message; }; // This is the default global test part result reporter used in UnitTestImpl. @@ -610,7 +610,7 @@ class GTEST_API_ UnitTestImpl { // getter, and returns it. OsStackTraceGetterInterface* os_stack_trace_getter(); - // Returns the current OS stack trace as a String. + // Returns the current OS stack trace as an std::string. // // The maximum number of stack frames to be included is specified by // the gtest_stack_trace_depth flag. The skip_count parameter @@ -620,7 +620,7 @@ class GTEST_API_ UnitTestImpl { // For example, if Foo() calls Bar(), which in turn calls // CurrentOsStackTraceExceptTop(1), Foo() will be included in the // trace but Bar() and CurrentOsStackTraceExceptTop() won't. - String CurrentOsStackTraceExceptTop(int skip_count) GTEST_NO_INLINE_; + std::string CurrentOsStackTraceExceptTop(int skip_count) GTEST_NO_INLINE_; // Finds and returns a TestCase with the given name. If one doesn't // exist, creates one and returns it. @@ -953,7 +953,7 @@ GTEST_API_ void ParseGoogleTestFlagsOnly(int* argc, wchar_t** argv); // Returns the message describing the last system error, regardless of the // platform. -GTEST_API_ String GetLastErrnoDescription(); +GTEST_API_ std::string GetLastErrnoDescription(); # if GTEST_OS_WINDOWS // Provides leak-safe Windows kernel handle ownership. diff --git a/src/gtest-port.cc b/src/gtest-port.cc index 9cfe4e95..fa8f29cf 100644 --- a/src/gtest-port.cc +++ b/src/gtest-port.cc @@ -247,7 +247,7 @@ bool AtomMatchesChar(bool escaped, char pattern_char, char ch) { } // Helper function used by ValidateRegex() to format error messages. -String FormatRegexSyntaxError(const char* regex, int index) { +std::string FormatRegexSyntaxError(const char* regex, int index) { return (Message() << "Syntax error at index " << index << " in simple regular expression \"" << regex << "\": ").GetString(); } @@ -513,7 +513,7 @@ GTestLog::~GTestLog() { class CapturedStream { public: // The ctor redirects the stream to a temporary file. - CapturedStream(int fd) : fd_(fd), uncaptured_fd_(dup(fd)) { + explicit CapturedStream(int fd) : fd_(fd), uncaptured_fd_(dup(fd)) { # if GTEST_OS_WINDOWS char temp_dir_path[MAX_PATH + 1] = { '\0' }; // NOLINT char temp_file_path[MAX_PATH + 1] = { '\0' }; // NOLINT @@ -565,7 +565,7 @@ class CapturedStream { remove(filename_.c_str()); } - String GetCapturedString() { + std::string GetCapturedString() { if (uncaptured_fd_ != -1) { // Restores the original stream. fflush(NULL); @@ -575,14 +575,14 @@ class CapturedStream { } FILE* const file = posix::FOpen(filename_.c_str(), "r"); - const String content = ReadEntireFile(file); + const std::string content = ReadEntireFile(file); posix::FClose(file); return content; } private: - // Reads the entire content of a file as a String. - static String ReadEntireFile(FILE* file); + // Reads the entire content of a file as an std::string. + static std::string ReadEntireFile(FILE* file); // Returns the size (in bytes) of a file. static size_t GetFileSize(FILE* file); @@ -602,7 +602,7 @@ size_t CapturedStream::GetFileSize(FILE* file) { } // Reads the entire content of a file as a string. -String CapturedStream::ReadEntireFile(FILE* file) { +std::string CapturedStream::ReadEntireFile(FILE* file) { const size_t file_size = GetFileSize(file); char* const buffer = new char[file_size]; @@ -618,7 +618,7 @@ String CapturedStream::ReadEntireFile(FILE* file) { bytes_read += bytes_last_read; } while (bytes_last_read > 0 && bytes_read < file_size); - const String content(buffer, bytes_read); + const std::string content(buffer, bytes_read); delete[] buffer; return content; @@ -641,8 +641,8 @@ void CaptureStream(int fd, const char* stream_name, CapturedStream** stream) { } // Stops capturing the output stream and returns the captured string. -String GetCapturedStream(CapturedStream** captured_stream) { - const String content = (*captured_stream)->GetCapturedString(); +std::string GetCapturedStream(CapturedStream** captured_stream) { + const std::string content = (*captured_stream)->GetCapturedString(); delete *captured_stream; *captured_stream = NULL; @@ -661,10 +661,14 @@ void CaptureStderr() { } // Stops capturing stdout and returns the captured string. -String GetCapturedStdout() { return GetCapturedStream(&g_captured_stdout); } +std::string GetCapturedStdout() { + return GetCapturedStream(&g_captured_stdout); +} // Stops capturing stderr and returns the captured string. -String GetCapturedStderr() { return GetCapturedStream(&g_captured_stderr); } +std::string GetCapturedStderr() { + return GetCapturedStream(&g_captured_stderr); +} #endif // GTEST_HAS_STREAM_REDIRECTION @@ -702,8 +706,8 @@ void Abort() { // Returns the name of the environment variable corresponding to the // given flag. For example, FlagToEnvVar("foo") will return // "GTEST_FOO" in the open-source version. -static String FlagToEnvVar(const char* flag) { - const String full_flag = +static std::string FlagToEnvVar(const char* flag) { + const std::string full_flag = (Message() << GTEST_FLAG_PREFIX_ << flag).GetString(); Message env_var; @@ -760,7 +764,7 @@ bool ParseInt32(const Message& src_text, const char* str, Int32* value) { // // The value is considered true iff it's not "0". bool BoolFromGTestEnv(const char* flag, bool default_value) { - const String env_var = FlagToEnvVar(flag); + const std::string env_var = FlagToEnvVar(flag); const char* const string_value = posix::GetEnv(env_var.c_str()); return string_value == NULL ? default_value : strcmp(string_value, "0") != 0; @@ -770,7 +774,7 @@ bool BoolFromGTestEnv(const char* flag, bool default_value) { // variable corresponding to the given flag; if it isn't set or // doesn't represent a valid 32-bit integer, returns default_value. Int32 Int32FromGTestEnv(const char* flag, Int32 default_value) { - const String env_var = FlagToEnvVar(flag); + const std::string env_var = FlagToEnvVar(flag); const char* const string_value = posix::GetEnv(env_var.c_str()); if (string_value == NULL) { // The environment variable is not set. @@ -792,7 +796,7 @@ Int32 Int32FromGTestEnv(const char* flag, Int32 default_value) { // Reads and returns the string environment variable corresponding to // the given flag; if it's not set, returns default_value. const char* StringFromGTestEnv(const char* flag, const char* default_value) { - const String env_var = FlagToEnvVar(flag); + const std::string env_var = FlagToEnvVar(flag); const char* const value = posix::GetEnv(env_var.c_str()); return value == NULL ? default_value : value; } diff --git a/src/gtest-test-part.cc b/src/gtest-test-part.cc index 5ddc67c1..c60eef3a 100644 --- a/src/gtest-test-part.cc +++ b/src/gtest-test-part.cc @@ -48,10 +48,10 @@ using internal::GetUnitTestImpl; // Gets the summary of the failure message by omitting the stack trace // in it. -internal::String TestPartResult::ExtractSummary(const char* message) { +std::string TestPartResult::ExtractSummary(const char* message) { const char* const stack_trace = strstr(message, internal::kStackTraceMarker); - return stack_trace == NULL ? internal::String(message) : - internal::String(message, stack_trace - message); + return stack_trace == NULL ? message : + std::string(message, stack_trace); } // Prints a TestPartResult object. diff --git a/src/gtest-typed-test.cc b/src/gtest-typed-test.cc index a5cc88f9..f0079f40 100644 --- a/src/gtest-typed-test.cc +++ b/src/gtest-typed-test.cc @@ -58,10 +58,10 @@ const char* TypedTestCasePState::VerifyRegisteredTestNames( registered_tests = SkipSpaces(registered_tests); Message errors; - ::std::set tests; + ::std::set tests; for (const char* names = registered_tests; names != NULL; names = SkipComma(names)) { - const String name = GetPrefixUntilComma(names); + const std::string name = GetPrefixUntilComma(names); if (tests.count(name) != 0) { errors << "Test " << name << " is listed more than once.\n"; continue; @@ -93,7 +93,7 @@ const char* TypedTestCasePState::VerifyRegisteredTestNames( } } - const String& errors_str = errors.GetString(); + const std::string& errors_str = errors.GetString(); if (errors_str != "") { fprintf(stderr, "%s %s", FormatFileLocation(file, line).c_str(), errors_str.c_str()); diff --git a/src/gtest.cc b/src/gtest.cc index 3b5a28b0..0567e83c 100644 --- a/src/gtest.cc +++ b/src/gtest.cc @@ -364,7 +364,7 @@ void AssertHelper::operator=(const Message& message) const { GTEST_API_ GTEST_DEFINE_STATIC_MUTEX_(g_linked_ptr_mutex); // Application pathname gotten in InitGoogleTest. -String g_executable_path; +std::string g_executable_path; // Returns the current application's name, removing directory path if that // is present. @@ -383,29 +383,29 @@ FilePath GetCurrentExecutableName() { // Functions for processing the gtest_output flag. // Returns the output format, or "" for normal printed output. -String UnitTestOptions::GetOutputFormat() { +std::string UnitTestOptions::GetOutputFormat() { const char* const gtest_output_flag = GTEST_FLAG(output).c_str(); - if (gtest_output_flag == NULL) return String(""); + if (gtest_output_flag == NULL) return std::string(""); const char* const colon = strchr(gtest_output_flag, ':'); return (colon == NULL) ? - String(gtest_output_flag) : - String(gtest_output_flag, colon - gtest_output_flag); + std::string(gtest_output_flag) : + std::string(gtest_output_flag, colon - gtest_output_flag); } // Returns the name of the requested output file, or the default if none // was explicitly specified. -String UnitTestOptions::GetAbsolutePathToOutputFile() { +std::string UnitTestOptions::GetAbsolutePathToOutputFile() { const char* const gtest_output_flag = GTEST_FLAG(output).c_str(); if (gtest_output_flag == NULL) - return String(""); + return ""; const char* const colon = strchr(gtest_output_flag, ':'); if (colon == NULL) - return String(internal::FilePath::ConcatPaths( - internal::FilePath( - UnitTest::GetInstance()->original_working_dir()), - internal::FilePath(kDefaultOutputFile)).ToString() ); + return internal::FilePath::ConcatPaths( + internal::FilePath( + UnitTest::GetInstance()->original_working_dir()), + internal::FilePath(kDefaultOutputFile)).string(); internal::FilePath output_name(colon + 1); if (!output_name.IsAbsolutePath()) @@ -418,12 +418,12 @@ String UnitTestOptions::GetAbsolutePathToOutputFile() { internal::FilePath(colon + 1)); if (!output_name.IsDirectory()) - return output_name.ToString(); + return output_name.string(); internal::FilePath result(internal::FilePath::GenerateUniqueFileName( output_name, internal::GetCurrentExecutableName(), GetOutputFormat().c_str())); - return result.ToString(); + return result.string(); } // Returns true iff the wildcard pattern matches the string. The @@ -448,7 +448,8 @@ bool UnitTestOptions::PatternMatchesString(const char *pattern, } } -bool UnitTestOptions::MatchesFilter(const String& name, const char* filter) { +bool UnitTestOptions::MatchesFilter( + const std::string& name, const char* filter) { const char *cur_pattern = filter; for (;;) { if (PatternMatchesString(cur_pattern, name.c_str())) { @@ -468,28 +469,24 @@ bool UnitTestOptions::MatchesFilter(const String& name, const char* filter) { } } -// TODO(keithray): move String function implementations to gtest-string.cc. - // Returns true iff the user-specified filter matches the test case // name and the test name. -bool UnitTestOptions::FilterMatchesTest(const String &test_case_name, - const String &test_name) { - const String& full_name = String::Format("%s.%s", - test_case_name.c_str(), - test_name.c_str()); +bool UnitTestOptions::FilterMatchesTest(const std::string &test_case_name, + const std::string &test_name) { + const std::string& full_name = test_case_name + "." + test_name.c_str(); // Split --gtest_filter at '-', if there is one, to separate into // positive filter and negative filter portions const char* const p = GTEST_FLAG(filter).c_str(); const char* const dash = strchr(p, '-'); - String positive; - String negative; + std::string positive; + std::string negative; if (dash == NULL) { positive = GTEST_FLAG(filter).c_str(); // Whole string is a positive filter - negative = String(""); + negative = ""; } else { - positive = String(p, dash - p); // Everything up to the dash - negative = String(dash+1); // Everything after the dash + positive = std::string(p, dash); // Everything up to the dash + negative = std::string(dash + 1); // Everything after the dash if (positive.empty()) { // Treat '-test1' as the same as '*-test1' positive = kUniversalFilter; @@ -609,7 +606,7 @@ AssertionResult HasOneFailure(const char* /* results_expr */, const TestPartResultArray& results, TestPartResult::Type type, const string& substr) { - const String expected(type == TestPartResult::kFatalFailure ? + const std::string expected(type == TestPartResult::kFatalFailure ? "1 fatal failure" : "1 non-fatal failure"); Message msg; @@ -747,7 +744,7 @@ int UnitTestImpl::test_to_run_count() const { return SumOverTestCaseList(test_cases_, &TestCase::test_to_run_count); } -// Returns the current OS stack trace as a String. +// Returns the current OS stack trace as an std::string. // // The maximum number of stack frames to be included is specified by // the gtest_stack_trace_depth flag. The skip_count parameter @@ -757,9 +754,9 @@ int UnitTestImpl::test_to_run_count() const { // For example, if Foo() calls Bar(), which in turn calls // CurrentOsStackTraceExceptTop(1), Foo() will be included in the // trace but Bar() and CurrentOsStackTraceExceptTop() won't. -String UnitTestImpl::CurrentOsStackTraceExceptTop(int skip_count) { +std::string UnitTestImpl::CurrentOsStackTraceExceptTop(int skip_count) { (void)skip_count; - return String(""); + return ""; } // Returns the current time in milliseconds. @@ -816,30 +813,7 @@ TimeInMillis GetTimeInMillis() { // Utilities -// class String - -// Copies at most length characters from str into a newly-allocated -// 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 -// is returned. If str is NULL, NULL is returned. -static char* CloneString(const char* str, size_t length) { - if (str == NULL) { - return NULL; - } else { - char* const clone = new char[length + 1]; - posix::StrNCpy(clone, str, length); - clone[length] = '\0'; - return clone; - } -} - -// Clones a 0-terminated C string, allocating memory using new. The -// caller is responsible for deleting[] the return value. Returns the -// cloned string, or NULL if the input is NULL. -const char * String::CloneCString(const char* c_str) { - return (c_str == NULL) ? - NULL : CloneString(c_str, strlen(c_str)); -} +// class String. #if GTEST_OS_WINDOWS_MOBILE // Creates a UTF-16 wide string from the given ANSI string, allocating @@ -896,11 +870,6 @@ bool String::CStringEquals(const char * lhs, const char * rhs) { // encoding, and streams the result to the given Message object. static void StreamWideCharsToMessage(const wchar_t* wstr, size_t length, Message* msg) { - // TODO(wan): consider allowing a testing::String object to - // contain '\0'. This will make it behave more like std::string, - // and will allow ToUtf8String() to return the correct encoding - // for '\0' s.t. we can get rid of the conditional here (and in - // several other places). for (size_t i = 0; i != length; ) { // NOLINT if (wstr[i] != L'\0') { *msg << WideStringToUtf8(wstr + i, static_cast(length - i)); @@ -987,8 +956,8 @@ namespace internal { // be inserted into the message. AssertionResult EqFailure(const char* expected_expression, const char* actual_expression, - const String& expected_value, - const String& actual_value, + const std::string& expected_value, + const std::string& actual_value, bool ignoring_case) { Message msg; msg << "Value of: " << actual_expression; @@ -1008,10 +977,11 @@ AssertionResult EqFailure(const char* expected_expression, } // Constructs a failure message for Boolean assertions such as EXPECT_TRUE. -String GetBoolAssertionFailureMessage(const AssertionResult& assertion_result, - const char* expression_text, - const char* actual_predicate_value, - const char* expected_predicate_value) { +std::string GetBoolAssertionFailureMessage( + const AssertionResult& assertion_result, + const char* expression_text, + const char* actual_predicate_value, + const char* expected_predicate_value) { const char* actual_message = assertion_result.message(); Message msg; msg << "Value of: " << expression_text @@ -1357,7 +1327,7 @@ AssertionResult HRESULTFailureHelper(const char* expr, # endif // GTEST_OS_WINDOWS_MOBILE - const String error_hex(String::Format("0x%08X ", hr)); + const std::string error_hex(String::Format("0x%08X ", hr)); return ::testing::AssertionFailure() << "Expected: " << expr << " " << expected << ".\n" << " Actual: " << error_hex << error_text << "\n"; @@ -1491,7 +1461,7 @@ inline UInt32 CreateCodePointFromUtf16SurrogatePair(wchar_t first, // as '(Invalid Unicode 0xXXXXXXXX)'. If the string is in UTF16 encoding // and contains invalid UTF-16 surrogate pairs, values in those pairs // will be encoded as individual Unicode characters from Basic Normal Plane. -String WideStringToUtf8(const wchar_t* str, int num_chars) { +std::string WideStringToUtf8(const wchar_t* str, int num_chars) { if (num_chars == -1) num_chars = static_cast(wcslen(str)); @@ -1515,12 +1485,12 @@ String WideStringToUtf8(const wchar_t* str, int num_chars) { return StringStreamToString(&stream); } -// Converts a wide C string to a String using the UTF-8 encoding. +// Converts a wide C string to an std::string using the UTF-8 encoding. // NULL will be converted to "(null)". -String String::ShowWideCString(const wchar_t * wide_c_str) { - if (wide_c_str == NULL) return String("(null)"); +std::string String::ShowWideCString(const wchar_t * wide_c_str) { + if (wide_c_str == NULL) return "(null)"; - return String(internal::WideStringToUtf8(wide_c_str, -1).c_str()); + return internal::WideStringToUtf8(wide_c_str, -1); } // Compares two wide C strings. Returns true iff they have the same @@ -1616,59 +1586,18 @@ bool String::CaseInsensitiveWideCStringEquals(const wchar_t* lhs, #endif // OS selector } -// Compares this with another String. -// Returns < 0 if this is less than rhs, 0 if this is equal to rhs, or > 0 -// if this is greater than rhs. -int String::Compare(const String & rhs) const { - const char* const lhs_c_str = c_str(); - const char* const rhs_c_str = rhs.c_str(); - - if (lhs_c_str == NULL) { - return rhs_c_str == NULL ? 0 : -1; // NULL < anything except NULL - } else if (rhs_c_str == NULL) { - return 1; - } - - const size_t shorter_str_len = - length() <= rhs.length() ? length() : rhs.length(); - for (size_t i = 0; i != shorter_str_len; i++) { - if (lhs_c_str[i] < rhs_c_str[i]) { - return -1; - } else if (lhs_c_str[i] > rhs_c_str[i]) { - return 1; - } - } - return (length() < rhs.length()) ? -1 : - (length() > rhs.length()) ? 1 : 0; -} - -// Returns true iff this String ends with the given suffix. *Any* -// String is considered to end with a NULL or empty suffix. -bool String::EndsWith(const char* suffix) const { - if (suffix == NULL || CStringEquals(suffix, "")) return true; - - if (c_str() == NULL) return false; - - const size_t this_len = strlen(c_str()); - const size_t suffix_len = strlen(suffix); - return (this_len >= suffix_len) && - CStringEquals(c_str() + this_len - suffix_len, suffix); +// Returns true iff str ends with the given suffix, ignoring case. +// Any string is considered to end with an empty suffix. +bool String::EndsWithCaseInsensitive( + const std::string& str, const std::string& suffix) { + const size_t str_len = str.length(); + const size_t suffix_len = suffix.length(); + return (str_len >= suffix_len) && + CaseInsensitiveCStringEquals(str.c_str() + str_len - suffix_len, + suffix.c_str()); } -// Returns true iff this String ends with the given suffix, ignoring case. -// Any String is considered to end with a NULL or empty suffix. -bool String::EndsWithCaseInsensitive(const char* suffix) const { - if (suffix == NULL || CStringEquals(suffix, "")) return true; - - if (c_str() == NULL) return false; - - const size_t this_len = strlen(c_str()); - const size_t suffix_len = strlen(suffix); - return (this_len >= suffix_len) && - CaseInsensitiveCStringEquals(c_str() + this_len - suffix_len, suffix); -} - -// Formats a list of arguments to a String, using the same format +// Formats a list of arguments to an std::string, using the same format // spec string as for printf. // // We do not use the StringPrintf class as it is not universally @@ -1678,7 +1607,7 @@ bool String::EndsWithCaseInsensitive(const char* suffix) const { // If 4096 characters are not enough to format the input, or if // there's an error, "" is // returned. -String String::Format(const char * format, ...) { +std::string String::Format(const char * format, ...) { va_list args; va_start(args, format); @@ -1705,46 +1634,42 @@ String String::Format(const char * format, ...) { // always returns a negative value. For simplicity, we lump the two // error cases together. if (size < 0 || size >= kBufferSize) { - return String(""); + return ""; } else { - return String(buffer, size); + return std::string(buffer, size); } } -// Converts the buffer in a stringstream to a String, converting NUL +// Converts the buffer in a stringstream to an std::string, converting NUL // bytes to "\\0" along the way. -String StringStreamToString(::std::stringstream* ss) { +std::string StringStreamToString(::std::stringstream* ss) { const ::std::string& str = ss->str(); const char* const start = str.c_str(); const char* const end = start + str.length(); - // We need to use a helper stringstream to do this transformation - // because String doesn't support push_back(). - ::std::stringstream helper; + std::string result; + result.reserve(2 * (end - start)); for (const char* ch = start; ch != end; ++ch) { if (*ch == '\0') { - helper << "\\0"; // Replaces NUL with "\\0"; + result += "\\0"; // Replaces NUL with "\\0"; } else { - helper.put(*ch); + result += *ch; } } - return String(helper.str().c_str()); + return result; } // Appends the user-supplied message to the Google-Test-generated message. -String AppendUserMessage(const String& gtest_msg, - const Message& user_msg) { +std::string AppendUserMessage(const std::string& gtest_msg, + const Message& user_msg) { // Appends the user message if it's non-empty. - const String user_msg_string = user_msg.GetString(); + const std::string user_msg_string = user_msg.GetString(); if (user_msg_string.empty()) { return gtest_msg; } - Message msg; - msg << gtest_msg << "\n" << user_msg_string; - - return msg.GetString(); + return gtest_msg + "\n" + user_msg_string; } } // namespace internal @@ -1810,7 +1735,7 @@ void TestResult::RecordProperty(const TestProperty& test_property) { // Adds a failure if the key is a reserved attribute of Google Test // testcase tags. Returns true if the property is valid. bool TestResult::ValidateTestProperty(const TestProperty& test_property) { - internal::String key(test_property.key()); + const std::string& key = test_property.key(); if (key == "name" || key == "status" || key == "time" || key == "classname") { ADD_FAILURE() << "Reserved key used in RecordProperty(): " @@ -1911,7 +1836,7 @@ void Test::RecordProperty(const char* key, int value) { namespace internal { void ReportFailureInUnknownLocation(TestPartResult::Type result_type, - const String& message) { + const std::string& message) { // This function is a friend of UnitTest and as such has access to // AddTestPartResult. UnitTest::GetInstance()->AddTestPartResult( @@ -1919,7 +1844,7 @@ void ReportFailureInUnknownLocation(TestPartResult::Type result_type, NULL, // No info about the source file where the exception occurred. -1, // We have no info on which line caused the exception. message, - String()); // No stack trace, either. + ""); // No stack trace, either. } } // namespace internal @@ -1996,13 +1921,13 @@ bool Test::HasSameFixtureClass() { // function returns its result via an output parameter pointer because VC++ // prohibits creation of objects with destructors on stack in functions // using __try (see error C2712). -static internal::String* FormatSehExceptionMessage(DWORD exception_code, - const char* location) { +static std::string* FormatSehExceptionMessage(DWORD exception_code, + const char* location) { Message message; message << "SEH exception with code 0x" << std::setbase(16) << exception_code << std::setbase(10) << " thrown in " << location << "."; - return new internal::String(message.GetString()); + return new std::string(message.GetString()); } #endif // GTEST_HAS_SEH @@ -2010,8 +1935,8 @@ static internal::String* FormatSehExceptionMessage(DWORD exception_code, #if GTEST_HAS_EXCEPTIONS // Adds an "exception thrown" fatal failure to the current test. -static internal::String FormatCxxExceptionMessage(const char* description, - const char* location) { +static std::string FormatCxxExceptionMessage(const char* description, + const char* location) { Message message; if (description != NULL) { message << "C++ exception with description \"" << description << "\""; @@ -2023,7 +1948,7 @@ static internal::String FormatCxxExceptionMessage(const char* description, return message.GetString(); } -static internal::String PrintTestPartResultToString( +static std::string PrintTestPartResultToString( const TestPartResult& test_part_result); // A failed Google Test assertion will throw an exception of this type when @@ -2059,7 +1984,7 @@ Result HandleSehExceptionsInMethodIfSupported( // We create the exception message on the heap because VC++ prohibits // creation of objects with destructors on stack in functions using __try // (see error C2712). - internal::String* exception_message = FormatSehExceptionMessage( + std::string* exception_message = FormatSehExceptionMessage( GetExceptionCode(), location); internal::ReportFailureInUnknownLocation(TestPartResult::kFatalFailure, *exception_message); @@ -2263,11 +2188,11 @@ class TestNameIs { // Returns true iff the test name of test_info matches name_. bool operator()(const TestInfo * test_info) const { - return test_info && internal::String(test_info->name()).Compare(name_) == 0; + return test_info && test_info->name() == name_; } private: - internal::String name_; + std::string name_; }; } // namespace @@ -2457,20 +2382,20 @@ void TestCase::UnshuffleTests() { // // FormatCountableNoun(1, "formula", "formuli") returns "1 formula". // FormatCountableNoun(5, "book", "books") returns "5 books". -static internal::String FormatCountableNoun(int count, - const char * singular_form, - const char * plural_form) { +static std::string FormatCountableNoun(int count, + const char * singular_form, + const char * plural_form) { return internal::String::Format("%d %s", count, count == 1 ? singular_form : plural_form); } // Formats the count of tests. -static internal::String FormatTestCount(int test_count) { +static std::string FormatTestCount(int test_count) { return FormatCountableNoun(test_count, "test", "tests"); } // Formats the count of test cases. -static internal::String FormatTestCaseCount(int test_case_count) { +static std::string FormatTestCaseCount(int test_case_count) { return FormatCountableNoun(test_case_count, "test case", "test cases"); } @@ -2495,8 +2420,8 @@ static const char * TestPartResultTypeToString(TestPartResult::Type type) { } } -// Prints a TestPartResult to a String. -static internal::String PrintTestPartResultToString( +// Prints a TestPartResult to an std::string. +static std::string PrintTestPartResultToString( const TestPartResult& test_part_result) { return (Message() << internal::FormatFileLocation(test_part_result.file_name(), @@ -2507,7 +2432,7 @@ static internal::String PrintTestPartResultToString( // Prints a TestPartResult. static void PrintTestPartResult(const TestPartResult& test_part_result) { - const internal::String& result = + const std::string& result = PrintTestPartResultToString(test_part_result); printf("%s\n", result.c_str()); fflush(stdout); @@ -2700,7 +2625,7 @@ void PrettyUnitTestResultPrinter::OnTestIterationStart( // Prints the filter if it's not *. This reminds the user that some // tests may be skipped. - if (!internal::String::CStringEquals(filter, kUniversalFilter)) { + if (!String::CStringEquals(filter, kUniversalFilter)) { ColoredPrintf(COLOR_YELLOW, "Note: %s filter = %s\n", GTEST_NAME_, filter); } @@ -2734,7 +2659,7 @@ void PrettyUnitTestResultPrinter::OnEnvironmentsSetUpStart( } void PrettyUnitTestResultPrinter::OnTestCaseStart(const TestCase& test_case) { - const internal::String counts = + const std::string counts = FormatCountableNoun(test_case.test_to_run_count(), "test", "tests"); ColoredPrintf(COLOR_GREEN, "[----------] "); printf("%s from %s", counts.c_str(), test_case.name()); @@ -2787,7 +2712,7 @@ void PrettyUnitTestResultPrinter::OnTestEnd(const TestInfo& test_info) { void PrettyUnitTestResultPrinter::OnTestCaseEnd(const TestCase& test_case) { if (!GTEST_FLAG(print_time)) return; - const internal::String counts = + const std::string counts = FormatCountableNoun(test_case.test_to_run_count(), "test", "tests"); ColoredPrintf(COLOR_GREEN, "[----------] "); printf("%s from %s (%s ms total)\n\n", @@ -3006,18 +2931,20 @@ class XmlUnitTestResultPrinter : public EmptyTestEventListener { // is_attribute is true, the text is meant to appear as an attribute // value, and normalizable whitespace is preserved by replacing it // with character references. - static String EscapeXml(const char* str, bool is_attribute); + static std::string EscapeXml(const char* str, bool is_attribute); // Returns the given string with all characters invalid in XML removed. static string RemoveInvalidXmlCharacters(const string& str); // Convenience wrapper around EscapeXml when str is an attribute value. - static String EscapeXmlAttribute(const char* str) { + static std::string EscapeXmlAttribute(const char* str) { return EscapeXml(str, true); } // Convenience wrapper around EscapeXml when str is not an attribute value. - static String EscapeXmlText(const char* str) { return EscapeXml(str, false); } + static std::string EscapeXmlText(const char* str) { + return EscapeXml(str, false); + } // Streams an XML CDATA section, escaping invalid CDATA sequences as needed. static void OutputXmlCDataSection(::std::ostream* stream, const char* data); @@ -3035,12 +2962,12 @@ class XmlUnitTestResultPrinter : public EmptyTestEventListener { // Produces a string representing the test properties in a result as space // delimited XML attributes based on the property key="value" pairs. - // When the String is not empty, it includes a space at the beginning, + // When the std::string is not empty, it includes a space at the beginning, // to delimit this attribute from prior attributes. - static String TestPropertiesAsXmlAttributes(const TestResult& result); + static std::string TestPropertiesAsXmlAttributes(const TestResult& result); // The output file. - const String output_file_; + const std::string output_file_; GTEST_DISALLOW_COPY_AND_ASSIGN_(XmlUnitTestResultPrinter); }; @@ -3098,7 +3025,8 @@ void XmlUnitTestResultPrinter::OnTestIterationEnd(const UnitTest& unit_test, // most invalid characters can be retained using character references. // TODO(wan): It might be nice to have a minimally invasive, human-readable // escaping scheme for invalid characters, rather than dropping them. -String XmlUnitTestResultPrinter::EscapeXml(const char* str, bool is_attribute) { +std::string XmlUnitTestResultPrinter::EscapeXml( + const char* str, bool is_attribute) { Message m; if (str != NULL) { @@ -3316,7 +3244,7 @@ void XmlUnitTestResultPrinter::PrintXmlUnitTest(FILE* out, // Produces a string representing the test properties in a result as space // delimited XML attributes based on the property key="value" pairs. -String XmlUnitTestResultPrinter::TestPropertiesAsXmlAttributes( +std::string XmlUnitTestResultPrinter::TestPropertiesAsXmlAttributes( const TestResult& result) { Message attributes; for (int i = 0; i < result.test_property_count(); ++i) { @@ -3528,17 +3456,17 @@ ScopedTrace::~ScopedTrace() // class OsStackTraceGetter -// Returns the current OS stack trace as a String. Parameters: +// Returns the current OS stack trace as an std::string. Parameters: // // max_depth - the maximum number of stack frames to be included // in the trace. // skip_count - the number of top frames to be skipped; doesn't count // against max_depth. // -String OsStackTraceGetter::CurrentStackTrace(int /* max_depth */, +string OsStackTraceGetter::CurrentStackTrace(int /* max_depth */, int /* skip_count */) GTEST_LOCK_EXCLUDED_(mutex_) { - return String(""); + return ""; } void OsStackTraceGetter::UponLeavingGTest() @@ -3759,8 +3687,8 @@ void UnitTest::AddTestPartResult( TestPartResult::Type result_type, const char* file_name, int line_number, - const internal::String& message, - const internal::String& os_stack_trace) + const std::string& message, + const std::string& os_stack_trace) GTEST_LOCK_EXCLUDED_(mutex_) { Message msg; msg << message; @@ -4008,7 +3936,7 @@ void UnitTestImpl::SuppressTestEventsIfInSubprocess() { // Initializes event listeners performing XML output as specified by // UnitTestOptions. Must not be called before InitGoogleTest. void UnitTestImpl::ConfigureXmlOutput() { - const String& output_format = UnitTestOptions::GetOutputFormat(); + const std::string& output_format = UnitTestOptions::GetOutputFormat(); if (output_format == "xml") { listeners()->SetDefaultXmlGenerator(new XmlUnitTestResultPrinter( UnitTestOptions::GetAbsolutePathToOutputFile().c_str())); @@ -4020,13 +3948,13 @@ void UnitTestImpl::ConfigureXmlOutput() { } #if GTEST_CAN_STREAM_RESULTS_ -// Initializes event listeners for streaming test results in String form. +// Initializes event listeners for streaming test results in string form. // Must not be called before InitGoogleTest. void UnitTestImpl::ConfigureStreamingOutput() { - const string& target = GTEST_FLAG(stream_result_to); + const std::string& target = GTEST_FLAG(stream_result_to); if (!target.empty()) { const size_t pos = target.find(':'); - if (pos != string::npos) { + if (pos != std::string::npos) { listeners()->Append(new StreamingListener(target.substr(0, pos), target.substr(pos+1))); } else { @@ -4080,7 +4008,7 @@ void UnitTestImpl::PostFlagParsingInit() { class TestCaseNameIs { public: // Constructor. - explicit TestCaseNameIs(const String& name) + explicit TestCaseNameIs(const std::string& name) : name_(name) {} // Returns true iff the name of test_case matches name_. @@ -4089,7 +4017,7 @@ class TestCaseNameIs { } private: - String name_; + std::string name_; }; // Finds and returns a TestCase with the given name. If one doesn't @@ -4121,7 +4049,7 @@ TestCase* UnitTestImpl::GetTestCase(const char* test_case_name, new TestCase(test_case_name, type_param, set_up_tc, tear_down_tc); // Is this a death test case? - if (internal::UnitTestOptions::MatchesFilter(String(test_case_name), + if (internal::UnitTestOptions::MatchesFilter(test_case_name, kDeathTestCaseFilter)) { // Yes. Inserts the test case after the last death test case // defined so far. This only works when the test cases haven't @@ -4400,12 +4328,12 @@ int UnitTestImpl::FilterTests(ReactionToSharding shard_tests) { int num_selected_tests = 0; for (size_t i = 0; i < test_cases_.size(); i++) { TestCase* const test_case = test_cases_[i]; - const String &test_case_name = test_case->name(); + const std::string &test_case_name = test_case->name(); test_case->set_should_run(false); for (size_t j = 0; j < test_case->test_info_list().size(); j++) { TestInfo* const test_info = test_case->test_info_list()[j]; - const String test_name(test_info->name()); + const std::string test_name(test_info->name()); // A test is disabled if test case name or test name matches // kDisableTestFilter. const bool is_disabled = @@ -4517,7 +4445,7 @@ void UnitTestImpl::UnshuffleTests() { } } -// Returns the current OS stack trace as a String. +// Returns the current OS stack trace as an std::string. // // The maximum number of stack frames to be included is specified by // the gtest_stack_trace_depth flag. The skip_count parameter @@ -4527,8 +4455,8 @@ void UnitTestImpl::UnshuffleTests() { // For example, if Foo() calls Bar(), which in turn calls // GetCurrentOsStackTraceExceptTop(..., 1), Foo() will be included in // the trace but Bar() and GetCurrentOsStackTraceExceptTop() won't. -String GetCurrentOsStackTraceExceptTop(UnitTest* /*unit_test*/, - int skip_count) { +std::string GetCurrentOsStackTraceExceptTop(UnitTest* /*unit_test*/, + int skip_count) { // We pass skip_count + 1 to skip this wrapper function in addition // to what the user really wants to skip. return GetUnitTestImpl()->CurrentOsStackTraceExceptTop(skip_count + 1); @@ -4576,7 +4504,7 @@ const char* ParseFlagValue(const char* str, if (str == NULL || flag == NULL) return NULL; // The flag must start with "--" followed by GTEST_FLAG_PREFIX_. - const String flag_str = String::Format("--%s%s", GTEST_FLAG_PREFIX_, flag); + const std::string flag_str = std::string("--") + GTEST_FLAG_PREFIX_ + flag; const size_t flag_len = flag_str.length(); if (strncmp(str, flag_str.c_str(), flag_len) != 0) return NULL; @@ -4641,7 +4569,7 @@ bool ParseInt32Flag(const char* str, const char* flag, Int32* value) { // // On success, stores the value of the flag in *value, and returns // true. On failure, returns false without changing *value. -bool ParseStringFlag(const char* str, const char* flag, String* value) { +bool ParseStringFlag(const char* str, const char* flag, std::string* value) { // Gets the value of the flag as a string. const char* const value_str = ParseFlagValue(str, flag, false); @@ -4693,7 +4621,7 @@ static void PrintColorEncoded(const char* str) { return; } - ColoredPrintf(color, "%s", String(str, p - str).c_str()); + ColoredPrintf(color, "%s", std::string(str, p).c_str()); const char ch = p[1]; str = p + 2; @@ -4783,7 +4711,7 @@ static const char kColorEncodedHelpMessage[] = template void ParseGoogleTestFlagsOnlyImpl(int* argc, CharType** argv) { for (int i = 1; i < *argc; i++) { - const String arg_string = StreamableToString(argv[i]); + const std::string arg_string = StreamableToString(argv[i]); const char* const arg = arg_string.c_str(); using internal::ParseBoolFlag; -- cgit v1.2.3 From cc1fdb58caf8d5ac9b858f615d3c42267fc5e258 Mon Sep 17 00:00:00 2001 From: kosak Date: Fri, 22 Feb 2013 20:10:40 +0000 Subject: Removes testing::internal::String::Format(), which causes problems as it truncates the result at 4096 chars. Also update an obsolete link in comment. --- src/gtest-death-test.cc | 85 ++++++++++++----------- src/gtest-filepath.cc | 2 +- src/gtest-internal-inl.h | 8 +-- src/gtest-port.cc | 12 ++-- src/gtest-printers.cc | 7 +- src/gtest.cc | 173 ++++++++++++++++++++--------------------------- 6 files changed, 131 insertions(+), 156 deletions(-) (limited to 'src') diff --git a/src/gtest-death-test.cc b/src/gtest-death-test.cc index 8b52431f..a6023fce 100644 --- a/src/gtest-death-test.cc +++ b/src/gtest-death-test.cc @@ -272,9 +272,10 @@ void DeathTestAbort(const std::string& message) { # define GTEST_DEATH_TEST_CHECK_(expression) \ do { \ if (!::testing::internal::IsTrue(expression)) { \ - DeathTestAbort(::testing::internal::String::Format( \ - "CHECK failed: File %s, line %d: %s", \ - __FILE__, __LINE__, #expression)); \ + DeathTestAbort( \ + ::std::string("CHECK failed: File ") + __FILE__ + ", line " \ + + ::testing::internal::StreamableToString(__LINE__) + ": " \ + + #expression); \ } \ } while (::testing::internal::AlwaysFalse()) @@ -292,9 +293,10 @@ void DeathTestAbort(const std::string& message) { gtest_retval = (expression); \ } while (gtest_retval == -1 && errno == EINTR); \ if (gtest_retval == -1) { \ - DeathTestAbort(::testing::internal::String::Format( \ - "CHECK failed: File %s, line %d: %s != -1", \ - __FILE__, __LINE__, #expression)); \ + DeathTestAbort( \ + ::std::string("CHECK failed: File ") + __FILE__ + ", line " \ + + ::testing::internal::StreamableToString(__LINE__) + ": " \ + + #expression + " != -1"); \ } \ } while (::testing::internal::AlwaysFalse()) @@ -716,14 +718,14 @@ DeathTest::TestRole WindowsDeathTest::AssumeRole() { info->test_case_name() + "." + info->name(); const std::string internal_flag = std::string("--") + GTEST_FLAG_PREFIX_ + kInternalRunDeathTestFlag + - "=" + file_ + "|" + String::Format("%d|%d|%u|%Iu|%Iu", line_, - death_test_index, - static_cast(::GetCurrentProcessId()), - // size_t has the same with as pointers on both 32-bit and 64-bit + "=" + file_ + "|" + StreamableToString(line_) + "|" + + StreamableToString(death_test_index) + "|" + + StreamableToString(static_cast(::GetCurrentProcessId())) + + // size_t has the same width as pointers on both 32-bit and 64-bit // Windows platforms. // See http://msdn.microsoft.com/en-us/library/tcxf1dw6.aspx. - reinterpret_cast(write_handle), - reinterpret_cast(event_handle_.Get())); + "|" + StreamableToString(reinterpret_cast(write_handle)) + + "|" + StreamableToString(reinterpret_cast(event_handle_.Get())); char executable_path[_MAX_PATH + 1]; // NOLINT GTEST_DEATH_TEST_CHECK_( @@ -1114,13 +1116,13 @@ DeathTest::TestRole ExecDeathTest::AssumeRole() { GTEST_DEATH_TEST_CHECK_(fcntl(pipe_fd[1], F_SETFD, 0) != -1); const std::string filter_flag = - String::Format("--%s%s=%s.%s", - GTEST_FLAG_PREFIX_, kFilterFlag, - info->test_case_name(), info->name()); + std::string("--") + GTEST_FLAG_PREFIX_ + kFilterFlag + "=" + + info->test_case_name() + "." + info->name(); const std::string internal_flag = - String::Format("--%s%s=%s|%d|%d|%d", - GTEST_FLAG_PREFIX_, kInternalRunDeathTestFlag, - file_, line_, death_test_index, pipe_fd[1]); + std::string("--") + GTEST_FLAG_PREFIX_ + kInternalRunDeathTestFlag + "=" + + file_ + "|" + StreamableToString(line_) + "|" + + StreamableToString(death_test_index) + "|" + + StreamableToString(pipe_fd[1]); Arguments args; args.AddArguments(GetArgvsForDeathTestChildProcess()); args.AddArgument(filter_flag.c_str()); @@ -1159,9 +1161,10 @@ bool DefaultDeathTestFactory::Create(const char* statement, const RE* regex, if (flag != NULL) { if (death_test_index > flag->index()) { - DeathTest::set_last_death_test_message(String::Format( - "Death test count (%d) somehow exceeded expected maximum (%d)", - death_test_index, flag->index())); + DeathTest::set_last_death_test_message( + "Death test count (" + StreamableToString(death_test_index) + + ") somehow exceeded expected maximum (" + + StreamableToString(flag->index()) + ")"); return false; } @@ -1190,9 +1193,9 @@ bool DefaultDeathTestFactory::Create(const char* statement, const RE* regex, # endif // GTEST_OS_WINDOWS else { // NOLINT - this is more readable than unbalanced brackets inside #if. - DeathTest::set_last_death_test_message(String::Format( - "Unknown death test style \"%s\" encountered", - GTEST_FLAG(death_test_style).c_str())); + DeathTest::set_last_death_test_message( + "Unknown death test style \"" + GTEST_FLAG(death_test_style) + + "\" encountered"); return false; } @@ -1230,8 +1233,8 @@ int GetStatusFileDescriptor(unsigned int parent_process_id, FALSE, // Non-inheritable. parent_process_id)); if (parent_process_handle.Get() == INVALID_HANDLE_VALUE) { - DeathTestAbort(String::Format("Unable to open parent process %u", - parent_process_id)); + DeathTestAbort("Unable to open parent process " + + StreamableToString(parent_process_id)); } // TODO(vladl@google.com): Replace the following check with a @@ -1251,9 +1254,10 @@ int GetStatusFileDescriptor(unsigned int parent_process_id, // DUPLICATE_SAME_ACCESS is used. FALSE, // Request non-inheritable handler. DUPLICATE_SAME_ACCESS)) { - DeathTestAbort(String::Format( - "Unable to duplicate the pipe handle %Iu from the parent process %u", - write_handle_as_size_t, parent_process_id)); + DeathTestAbort("Unable to duplicate the pipe handle " + + StreamableToString(write_handle_as_size_t) + + " from the parent process " + + StreamableToString(parent_process_id)); } const HANDLE event_handle = reinterpret_cast(event_handle_as_size_t); @@ -1264,17 +1268,18 @@ int GetStatusFileDescriptor(unsigned int parent_process_id, 0x0, FALSE, DUPLICATE_SAME_ACCESS)) { - DeathTestAbort(String::Format( - "Unable to duplicate the event handle %Iu from the parent process %u", - event_handle_as_size_t, parent_process_id)); + DeathTestAbort("Unable to duplicate the event handle " + + StreamableToString(event_handle_as_size_t) + + " from the parent process " + + StreamableToString(parent_process_id)); } const int write_fd = ::_open_osfhandle(reinterpret_cast(dup_write_handle), O_APPEND); if (write_fd == -1) { - DeathTestAbort(String::Format( - "Unable to convert pipe handle %Iu to a file descriptor", - write_handle_as_size_t)); + DeathTestAbort("Unable to convert pipe handle " + + StreamableToString(write_handle_as_size_t) + + " to a file descriptor"); } // Signals the parent that the write end of the pipe has been acquired @@ -1311,9 +1316,8 @@ InternalRunDeathTestFlag* ParseInternalRunDeathTestFlag() { || !ParseNaturalNumber(fields[3], &parent_process_id) || !ParseNaturalNumber(fields[4], &write_handle_as_size_t) || !ParseNaturalNumber(fields[5], &event_handle_as_size_t)) { - DeathTestAbort(String::Format( - "Bad --gtest_internal_run_death_test flag: %s", - GTEST_FLAG(internal_run_death_test).c_str())); + DeathTestAbort("Bad --gtest_internal_run_death_test flag: " + + GTEST_FLAG(internal_run_death_test)); } write_fd = GetStatusFileDescriptor(parent_process_id, write_handle_as_size_t, @@ -1324,9 +1328,8 @@ InternalRunDeathTestFlag* ParseInternalRunDeathTestFlag() { || !ParseNaturalNumber(fields[1], &line) || !ParseNaturalNumber(fields[2], &index) || !ParseNaturalNumber(fields[3], &write_fd)) { - DeathTestAbort(String::Format( - "Bad --gtest_internal_run_death_test flag: %s", - GTEST_FLAG(internal_run_death_test).c_str())); + DeathTestAbort("Bad --gtest_internal_run_death_test flag: " + + GTEST_FLAG(internal_run_death_test)); } # endif // GTEST_OS_WINDOWS diff --git a/src/gtest-filepath.cc b/src/gtest-filepath.cc index 4d40cb96..708389d1 100644 --- a/src/gtest-filepath.cc +++ b/src/gtest-filepath.cc @@ -182,7 +182,7 @@ FilePath FilePath::MakeFileName(const FilePath& directory, if (number == 0) { file = base_name.string() + "." + extension; } else { - file = base_name.string() + "_" + String::Format("%d", number).c_str() + file = base_name.string() + "_" + StreamableToString(number) + "." + extension; } return ConcatPaths(directory, FilePath(file)); diff --git a/src/gtest-internal-inl.h b/src/gtest-internal-inl.h index 54717c95..2491eee9 100644 --- a/src/gtest-internal-inl.h +++ b/src/gtest-internal-inl.h @@ -222,12 +222,10 @@ class GTestFlagSaver { // Converts a Unicode code point to a narrow string in UTF-8 encoding. // code_point parameter is of type UInt32 because wchar_t may not be // wide enough to contain a code point. -// The output buffer str must containt at least 32 characters. -// The function returns the address of the output buffer. // If the code_point is not a valid Unicode code point -// (i.e. outside of Unicode range U+0 to U+10FFFF) it will be output -// as '(Invalid Unicode 0xXXXXXXXX)'. -GTEST_API_ char* CodePointToUtf8(UInt32 code_point, char* str); +// (i.e. outside of Unicode range U+0 to U+10FFFF) it will be converted +// to "(Invalid Unicode 0xXXXXXXXX)". +GTEST_API_ std::string CodePointToUtf8(UInt32 code_point); // Converts a wide string to a narrow string in UTF-8 encoding. // The wide string is assumed to have the following encoding: diff --git a/src/gtest-port.cc b/src/gtest-port.cc index fa8f29cf..0c4df5f2 100644 --- a/src/gtest-port.cc +++ b/src/gtest-port.cc @@ -454,15 +454,15 @@ const char kUnknownFile[] = "unknown file"; // Formats a source file path and a line number as they would appear // in an error message from the compiler used to compile this code. GTEST_API_ ::std::string FormatFileLocation(const char* file, int line) { - const char* const file_name = file == NULL ? kUnknownFile : file; + const std::string file_name(file == NULL ? kUnknownFile : file); if (line < 0) { - return String::Format("%s:", file_name).c_str(); + return file_name + ":"; } #ifdef _MSC_VER - return String::Format("%s(%d):", file_name, line).c_str(); + return file_name + "(" + StreamableToString(line) + "):"; #else - return String::Format("%s:%d:", file_name, line).c_str(); + return file_name + ":" + StreamableToString(line) + ":"; #endif // _MSC_VER } @@ -473,12 +473,12 @@ GTEST_API_ ::std::string FormatFileLocation(const char* file, int line) { // to the file location it produces, unlike FormatFileLocation(). GTEST_API_ ::std::string FormatCompilerIndependentFileLocation( const char* file, int line) { - const char* const file_name = file == NULL ? kUnknownFile : file; + const std::string file_name(file == NULL ? kUnknownFile : file); if (line < 0) return file_name; else - return String::Format("%s:%d", file_name, line).c_str(); + return file_name + ":" + StreamableToString(line); } diff --git a/src/gtest-printers.cc b/src/gtest-printers.cc index 898d61d8..75fa4081 100644 --- a/src/gtest-printers.cc +++ b/src/gtest-printers.cc @@ -176,7 +176,7 @@ static CharFormat PrintAsCharLiteralTo(Char c, ostream* os) { *os << static_cast(c); return kAsIs; } else { - *os << String::Format("\\x%X", static_cast(c)); + *os << "\\x" + String::FormatHexInt(static_cast(c)); return kHexEscape; } } @@ -221,7 +221,7 @@ void PrintCharAndCodeTo(Char c, ostream* os) { // obvious). if (c == 0) return; - *os << " (" << String::Format("%d", c).c_str(); + *os << " (" << static_cast(c); // For more convenience, we print c's code again in hexidecimal, // unless c was already printed in the form '\x##' or the code is in @@ -229,8 +229,7 @@ void PrintCharAndCodeTo(Char c, ostream* os) { if (format == kHexEscape || (1 <= c && c <= 9)) { // Do nothing. } else { - *os << String::Format(", 0x%X", - static_cast(c)).c_str(); + *os << ", 0x" << String::FormatHexInt(static_cast(c)); } *os << ")"; } diff --git a/src/gtest.cc b/src/gtest.cc index 0567e83c..8bf4b803 100644 --- a/src/gtest.cc +++ b/src/gtest.cc @@ -1309,7 +1309,7 @@ AssertionResult HRESULTFailureHelper(const char* expr, // want inserts expanded. const DWORD kFlags = FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS; - const DWORD kBufSize = 4096; // String::Format can't exceed this length. + const DWORD kBufSize = 4096; // Gets the system's human readable message string for this HRESULT. char error_text[kBufSize] = { '\0' }; DWORD message_length = ::FormatMessageA(kFlags, @@ -1319,7 +1319,7 @@ AssertionResult HRESULTFailureHelper(const char* expr, error_text, // output buffer kBufSize, // buf size NULL); // no arguments for inserts - // Trims tailing white space (FormatMessage leaves a trailing cr-lf) + // Trims tailing white space (FormatMessage leaves a trailing CR-LF) for (; message_length && IsSpace(error_text[message_length - 1]); --message_length) { error_text[message_length - 1] = '\0'; @@ -1327,10 +1327,10 @@ AssertionResult HRESULTFailureHelper(const char* expr, # endif // GTEST_OS_WINDOWS_MOBILE - const std::string error_hex(String::Format("0x%08X ", hr)); + const std::string error_hex("0x" + String::FormatHexInt(hr)); return ::testing::AssertionFailure() << "Expected: " << expr << " " << expected << ".\n" - << " Actual: " << error_hex << error_text << "\n"; + << " Actual: " << error_hex << " " << error_text << "\n"; } } // namespace @@ -1387,12 +1387,15 @@ inline UInt32 ChopLowBits(UInt32* bits, int n) { // Converts a Unicode code point to a narrow string in UTF-8 encoding. // code_point parameter is of type UInt32 because wchar_t may not be // wide enough to contain a code point. -// The output buffer str must containt at least 32 characters. -// The function returns the address of the output buffer. // If the code_point is not a valid Unicode code point -// (i.e. outside of Unicode range U+0 to U+10FFFF) it will be output -// as '(Invalid Unicode 0xXXXXXXXX)'. -char* CodePointToUtf8(UInt32 code_point, char* str) { +// (i.e. outside of Unicode range U+0 to U+10FFFF) it will be converted +// to "(Invalid Unicode 0xXXXXXXXX)". +std::string CodePointToUtf8(UInt32 code_point) { + if (code_point > kMaxCodePoint4) { + return "(Invalid Unicode 0x" + String::FormatHexInt(code_point) + ")"; + } + + char str[5]; // Big enough for the largest valid code point. if (code_point <= kMaxCodePoint1) { str[1] = '\0'; str[0] = static_cast(code_point); // 0xxxxxxx @@ -1405,22 +1408,12 @@ char* CodePointToUtf8(UInt32 code_point, char* str) { str[2] = static_cast(0x80 | ChopLowBits(&code_point, 6)); // 10xxxxxx str[1] = static_cast(0x80 | ChopLowBits(&code_point, 6)); // 10xxxxxx str[0] = static_cast(0xE0 | code_point); // 1110xxxx - } else if (code_point <= kMaxCodePoint4) { + } else { // code_point <= kMaxCodePoint4 str[4] = '\0'; str[3] = static_cast(0x80 | ChopLowBits(&code_point, 6)); // 10xxxxxx str[2] = static_cast(0x80 | ChopLowBits(&code_point, 6)); // 10xxxxxx str[1] = static_cast(0x80 | ChopLowBits(&code_point, 6)); // 10xxxxxx str[0] = static_cast(0xF0 | code_point); // 11110xxx - } else { - // The longest string String::Format can produce when invoked - // with these parameters is 28 character long (not including - // the terminating nul character). We are asking for 32 character - // buffer just in case. This is also enough for strncpy to - // null-terminate the destination string. - posix::StrNCpy( - str, String::Format("(Invalid Unicode 0x%X)", code_point).c_str(), 32); - str[31] = '\0'; // Makes sure no change in the format to strncpy leaves - // the result unterminated. } return str; } @@ -1479,8 +1472,7 @@ std::string WideStringToUtf8(const wchar_t* str, int num_chars) { unicode_code_point = static_cast(str[i]); } - char buffer[32]; // CodePointToUtf8 requires a buffer this big. - stream << CodePointToUtf8(unicode_code_point, buffer); + stream << CodePointToUtf8(unicode_code_point); } return StringStreamToString(&stream); } @@ -1597,47 +1589,26 @@ bool String::EndsWithCaseInsensitive( suffix.c_str()); } -// Formats a list of arguments to an std::string, using the same format -// spec string as for printf. -// -// We do not use the StringPrintf class as it is not universally -// available. -// -// The result is limited to 4096 characters (including the tailing 0). -// If 4096 characters are not enough to format the input, or if -// there's an error, "" is -// returned. -std::string String::Format(const char * format, ...) { - va_list args; - va_start(args, format); - - char buffer[4096]; - const int kBufferSize = sizeof(buffer)/sizeof(buffer[0]); - - // MSVC 8 deprecates vsnprintf(), so we want to suppress warning - // 4996 (deprecated function) there. -#ifdef _MSC_VER // We are using MSVC. -# pragma warning(push) // Saves the current warning state. -# pragma warning(disable:4996) // Temporarily disables warning 4996. - - const int size = vsnprintf(buffer, kBufferSize, format, args); +// Formats an int value as "%02d". +std::string String::FormatIntWidth2(int value) { + std::stringstream ss; + ss << std::setfill('0') << std::setw(2) << value; + return ss.str(); +} -# pragma warning(pop) // Restores the warning state. -#else // We are not using MSVC. - const int size = vsnprintf(buffer, kBufferSize, format, args); -#endif // _MSC_VER - va_end(args); +// Formats an int value as "%X". +std::string String::FormatHexInt(int value) { + std::stringstream ss; + ss << std::hex << std::uppercase << value; + return ss.str(); +} - // vsnprintf()'s behavior is not portable. When the buffer is not - // big enough, it returns a negative value in MSVC, and returns the - // needed buffer size on Linux. When there is an output error, it - // always returns a negative value. For simplicity, we lump the two - // error cases together. - if (size < 0 || size >= kBufferSize) { - return ""; - } else { - return std::string(buffer, size); - } +// Formats a byte as "%02X". +std::string String::FormatByte(unsigned char value) { + std::stringstream ss; + ss << std::setfill('0') << std::setw(2) << std::hex << std::uppercase + << static_cast(value); + return ss.str(); } // Converts the buffer in a stringstream to an std::string, converting NUL @@ -2091,10 +2062,8 @@ bool Test::HasNonfatalFailure() { // Constructs a TestInfo object. It assumes ownership of the test factory // object. -// TODO(vladl@google.com): Make a_test_case_name and a_name const string&'s -// to signify they cannot be NULLs. -TestInfo::TestInfo(const char* a_test_case_name, - const char* a_name, +TestInfo::TestInfo(const std::string& a_test_case_name, + const std::string& a_name, const char* a_type_param, const char* a_value_param, internal::TypeId fixture_class_id, @@ -2133,7 +2102,8 @@ namespace internal { // The newly created TestInfo instance will assume // ownership of the factory object. TestInfo* MakeAndRegisterTestInfo( - const char* test_case_name, const char* name, + const char* test_case_name, + const char* name, const char* type_param, const char* value_param, TypeId fixture_class_id, @@ -2385,8 +2355,8 @@ void TestCase::UnshuffleTests() { static std::string FormatCountableNoun(int count, const char * singular_form, const char * plural_form) { - return internal::String::Format("%d %s", count, - count == 1 ? singular_form : plural_form); + return internal::StreamableToString(count) + " " + + (count == 1 ? singular_form : plural_form); } // Formats the count of tests. @@ -3056,7 +3026,8 @@ std::string XmlUnitTestResultPrinter::EscapeXml( default: if (IsValidXmlCharacter(*src)) { if (is_attribute && IsNormalizableWhitespace(*src)) - m << String::Format("&#x%02X;", unsigned(*src)); + m << "&#x" << String::FormatByte(static_cast(*src)) + << ";"; else m << *src; } @@ -3121,13 +3092,13 @@ std::string FormatEpochTimeInMillisAsIso8601(TimeInMillis ms) { 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); + // YYYY-MM-DDThh:mm:ss + return StreamableToString(time_struct->tm_year + 1900) + "-" + + String::FormatIntWidth2(time_struct->tm_mon + 1) + "-" + + String::FormatIntWidth2(time_struct->tm_mday) + "T" + + String::FormatIntWidth2(time_struct->tm_hour) + ":" + + String::FormatIntWidth2(time_struct->tm_min) + ":" + + String::FormatIntWidth2(time_struct->tm_sec); } // Streams an XML CDATA section, escaping invalid CDATA sequences as needed. @@ -3268,7 +3239,7 @@ class StreamingListener : public EmptyTestEventListener { StreamingListener(const string& host, const string& port) : sockfd_(-1), host_name_(host), port_num_(port) { MakeConnection(); - Send("gtest_streaming_protocol_version=1.0\n"); + SendLn("gtest_streaming_protocol_version=1.0"); } virtual ~StreamingListener() { @@ -3277,59 +3248,58 @@ class StreamingListener : public EmptyTestEventListener { } void OnTestProgramStart(const UnitTest& /* unit_test */) { - Send("event=TestProgramStart\n"); + SendLn("event=TestProgramStart"); } void OnTestProgramEnd(const UnitTest& unit_test) { // Note that Google Test current only report elapsed time for each // test iteration, not for the entire test program. - Send(String::Format("event=TestProgramEnd&passed=%d\n", - unit_test.Passed())); + SendLn("event=TestProgramEnd&passed=" + + StreamableToString(unit_test.Passed())); // Notify the streaming server to stop. CloseConnection(); } void OnTestIterationStart(const UnitTest& /* unit_test */, int iteration) { - Send(String::Format("event=TestIterationStart&iteration=%d\n", - iteration)); + SendLn("event=TestIterationStart&iteration=" + + StreamableToString(iteration)); } void OnTestIterationEnd(const UnitTest& unit_test, int /* iteration */) { - Send(String::Format("event=TestIterationEnd&passed=%d&elapsed_time=%sms\n", - unit_test.Passed(), - StreamableToString(unit_test.elapsed_time()).c_str())); + SendLn("event=TestIterationEnd&passed=" + + StreamableToString(unit_test.Passed()) + "&elapsed_time=" + + StreamableToString(unit_test.elapsed_time()) + "ms"); } void OnTestCaseStart(const TestCase& test_case) { - Send(String::Format("event=TestCaseStart&name=%s\n", test_case.name())); + SendLn(std::string("event=TestCaseStart&name=") + test_case.name()); } void OnTestCaseEnd(const TestCase& test_case) { - Send(String::Format("event=TestCaseEnd&passed=%d&elapsed_time=%sms\n", - test_case.Passed(), - StreamableToString(test_case.elapsed_time()).c_str())); + SendLn("event=TestCaseEnd&passed=" + StreamableToString(test_case.Passed()) + + "&elapsed_time=" + StreamableToString(test_case.elapsed_time()) + + "ms"); } void OnTestStart(const TestInfo& test_info) { - Send(String::Format("event=TestStart&name=%s\n", test_info.name())); + SendLn(std::string("event=TestStart&name=") + test_info.name()); } void OnTestEnd(const TestInfo& test_info) { - Send(String::Format( - "event=TestEnd&passed=%d&elapsed_time=%sms\n", - (test_info.result())->Passed(), - StreamableToString((test_info.result())->elapsed_time()).c_str())); + SendLn("event=TestEnd&passed=" + + StreamableToString((test_info.result())->Passed()) + + "&elapsed_time=" + + StreamableToString((test_info.result())->elapsed_time()) + "ms"); } void OnTestPartResult(const TestPartResult& test_part_result) { const char* file_name = test_part_result.file_name(); if (file_name == NULL) file_name = ""; - Send(String::Format("event=TestPartResult&file=%s&line=%d&message=", - UrlEncode(file_name).c_str(), - test_part_result.line_number())); - Send(UrlEncode(test_part_result.message()) + "\n"); + SendLn("event=TestPartResult&file=" + UrlEncode(file_name) + + "&line=" + StreamableToString(test_part_result.line_number()) + + "&message=" + UrlEncode(test_part_result.message())); } private: @@ -3358,6 +3328,11 @@ class StreamingListener : public EmptyTestEventListener { } } + // Sends a string and a newline to the socket. + void SendLn(const string& message) { + Send(message + "\n"); + } + int sockfd_; // socket file descriptor const string host_name_; const string port_num_; @@ -3379,7 +3354,7 @@ string StreamingListener::UrlEncode(const char* str) { case '=': case '&': case '\n': - result.append(String::Format("%%%02x", static_cast(ch))); + result.append("%" + String::FormatByte(static_cast(ch))); break; default: result.push_back(ch); -- cgit v1.2.3 From ba072ccca41212e3ac3ac1eca3381d226187c0d1 Mon Sep 17 00:00:00 2001 From: kosak Date: Fri, 22 Feb 2013 20:25:42 +0000 Subject: Fixes gUnit streaming output format. --- src/gtest-internal-inl.h | 153 +++++++++++++++++++++++++++++++++++++++++++++++ src/gtest.cc | 112 +--------------------------------- 2 files changed, 154 insertions(+), 111 deletions(-) (limited to 'src') diff --git a/src/gtest-internal-inl.h b/src/gtest-internal-inl.h index 2491eee9..c96c9411 100644 --- a/src/gtest-internal-inl.h +++ b/src/gtest-internal-inl.h @@ -58,6 +58,11 @@ #include "gtest/internal/gtest-port.h" +#if GTEST_CAN_STREAM_RESULTS_ +# include // NOLINT +# include // NOLINT +#endif + #if GTEST_OS_WINDOWS # include // NOLINT #endif // GTEST_OS_WINDOWS @@ -1048,6 +1053,154 @@ class TestResultAccessor { } }; +#if GTEST_CAN_STREAM_RESULTS_ + +// Streams test results to the given port on the given host machine. +class StreamingListener : public EmptyTestEventListener { + public: + // Abstract base class for writing strings to a socket. + class AbstractSocketWriter { + public: + virtual ~AbstractSocketWriter() {} + + // Sends a string to the socket. + virtual void Send(const string& message) = 0; + + // Closes the socket. + virtual void CloseConnection() {} + + // Sends a string and a newline to the socket. + void SendLn(const string& message) { + Send(message + "\n"); + } + }; + + // Concrete class for actually writing strings to a socket. + class SocketWriter : public AbstractSocketWriter { + public: + SocketWriter(const string& host, const string& port) + : sockfd_(-1), host_name_(host), port_num_(port) { + MakeConnection(); + } + + virtual ~SocketWriter() { + if (sockfd_ != -1) + CloseConnection(); + } + + // Sends a string to the socket. + virtual void Send(const string& message) { + GTEST_CHECK_(sockfd_ != -1) + << "Send() can be called only when there is a connection."; + + const int len = static_cast(message.length()); + if (write(sockfd_, message.c_str(), len) != len) { + GTEST_LOG_(WARNING) + << "stream_result_to: failed to stream to " + << host_name_ << ":" << port_num_; + } + } + + private: + // Creates a client socket and connects to the server. + void MakeConnection(); + + // Closes the socket. + void CloseConnection() { + GTEST_CHECK_(sockfd_ != -1) + << "CloseConnection() can be called only when there is a connection."; + + close(sockfd_); + sockfd_ = -1; + } + + int sockfd_; // socket file descriptor + const string host_name_; + const string port_num_; + + GTEST_DISALLOW_COPY_AND_ASSIGN_(SocketWriter); + }; // class SocketWriter + + // Escapes '=', '&', '%', and '\n' characters in str as "%xx". + static string UrlEncode(const char* str); + + StreamingListener(const string& host, const string& port) + : socket_writer_(new SocketWriter(host, port)) { Start(); } + + explicit StreamingListener(AbstractSocketWriter* socket_writer) + : socket_writer_(socket_writer) { Start(); } + + void OnTestProgramStart(const UnitTest& /* unit_test */) { + SendLn("event=TestProgramStart"); + } + + void OnTestProgramEnd(const UnitTest& unit_test) { + // Note that Google Test current only report elapsed time for each + // test iteration, not for the entire test program. + SendLn("event=TestProgramEnd&passed=" + FormatBool(unit_test.Passed())); + + // Notify the streaming server to stop. + socket_writer_->CloseConnection(); + } + + void OnTestIterationStart(const UnitTest& /* unit_test */, int iteration) { + SendLn("event=TestIterationStart&iteration=" + + StreamableToString(iteration)); + } + + void OnTestIterationEnd(const UnitTest& unit_test, int /* iteration */) { + SendLn("event=TestIterationEnd&passed=" + + FormatBool(unit_test.Passed()) + "&elapsed_time=" + + StreamableToString(unit_test.elapsed_time()) + "ms"); + } + + void OnTestCaseStart(const TestCase& test_case) { + SendLn(std::string("event=TestCaseStart&name=") + test_case.name()); + } + + void OnTestCaseEnd(const TestCase& test_case) { + SendLn("event=TestCaseEnd&passed=" + FormatBool(test_case.Passed()) + + "&elapsed_time=" + StreamableToString(test_case.elapsed_time()) + + "ms"); + } + + void OnTestStart(const TestInfo& test_info) { + SendLn(std::string("event=TestStart&name=") + test_info.name()); + } + + void OnTestEnd(const TestInfo& test_info) { + SendLn("event=TestEnd&passed=" + + FormatBool((test_info.result())->Passed()) + + "&elapsed_time=" + + StreamableToString((test_info.result())->elapsed_time()) + "ms"); + } + + void OnTestPartResult(const TestPartResult& test_part_result) { + const char* file_name = test_part_result.file_name(); + if (file_name == NULL) + file_name = ""; + SendLn("event=TestPartResult&file=" + UrlEncode(file_name) + + "&line=" + StreamableToString(test_part_result.line_number()) + + "&message=" + UrlEncode(test_part_result.message())); + } + + private: + // Sends the given message and a newline to the socket. + void SendLn(const string& message) { socket_writer_->SendLn(message); } + + // Called at the start of streaming to notify the receiver what + // protocol we are using. + void Start() { SendLn("gtest_streaming_protocol_version=1.0"); } + + string FormatBool(bool value) { return value ? "1" : "0"; } + + const scoped_ptr socket_writer_; + + GTEST_DISALLOW_COPY_AND_ASSIGN_(StreamingListener); +}; // class StreamingListener + +#endif // GTEST_CAN_STREAM_RESULTS_ + } // namespace internal } // namespace testing diff --git a/src/gtest.cc b/src/gtest.cc index 8bf4b803..c9bf4581 100644 --- a/src/gtest.cc +++ b/src/gtest.cc @@ -3230,116 +3230,6 @@ std::string XmlUnitTestResultPrinter::TestPropertiesAsXmlAttributes( #if GTEST_CAN_STREAM_RESULTS_ -// Streams test results to the given port on the given host machine. -class StreamingListener : public EmptyTestEventListener { - public: - // Escapes '=', '&', '%', and '\n' characters in str as "%xx". - static string UrlEncode(const char* str); - - StreamingListener(const string& host, const string& port) - : sockfd_(-1), host_name_(host), port_num_(port) { - MakeConnection(); - SendLn("gtest_streaming_protocol_version=1.0"); - } - - virtual ~StreamingListener() { - if (sockfd_ != -1) - CloseConnection(); - } - - void OnTestProgramStart(const UnitTest& /* unit_test */) { - SendLn("event=TestProgramStart"); - } - - void OnTestProgramEnd(const UnitTest& unit_test) { - // Note that Google Test current only report elapsed time for each - // test iteration, not for the entire test program. - SendLn("event=TestProgramEnd&passed=" + - StreamableToString(unit_test.Passed())); - - // Notify the streaming server to stop. - CloseConnection(); - } - - void OnTestIterationStart(const UnitTest& /* unit_test */, int iteration) { - SendLn("event=TestIterationStart&iteration=" + - StreamableToString(iteration)); - } - - void OnTestIterationEnd(const UnitTest& unit_test, int /* iteration */) { - SendLn("event=TestIterationEnd&passed=" + - StreamableToString(unit_test.Passed()) + "&elapsed_time=" + - StreamableToString(unit_test.elapsed_time()) + "ms"); - } - - void OnTestCaseStart(const TestCase& test_case) { - SendLn(std::string("event=TestCaseStart&name=") + test_case.name()); - } - - void OnTestCaseEnd(const TestCase& test_case) { - SendLn("event=TestCaseEnd&passed=" + StreamableToString(test_case.Passed()) - + "&elapsed_time=" + StreamableToString(test_case.elapsed_time()) - + "ms"); - } - - void OnTestStart(const TestInfo& test_info) { - SendLn(std::string("event=TestStart&name=") + test_info.name()); - } - - void OnTestEnd(const TestInfo& test_info) { - SendLn("event=TestEnd&passed=" + - StreamableToString((test_info.result())->Passed()) + - "&elapsed_time=" + - StreamableToString((test_info.result())->elapsed_time()) + "ms"); - } - - void OnTestPartResult(const TestPartResult& test_part_result) { - const char* file_name = test_part_result.file_name(); - if (file_name == NULL) - file_name = ""; - SendLn("event=TestPartResult&file=" + UrlEncode(file_name) + - "&line=" + StreamableToString(test_part_result.line_number()) + - "&message=" + UrlEncode(test_part_result.message())); - } - - private: - // Creates a client socket and connects to the server. - void MakeConnection(); - - // Closes the socket. - void CloseConnection() { - GTEST_CHECK_(sockfd_ != -1) - << "CloseConnection() can be called only when there is a connection."; - - close(sockfd_); - sockfd_ = -1; - } - - // Sends a string to the socket. - void Send(const string& message) { - GTEST_CHECK_(sockfd_ != -1) - << "Send() can be called only when there is a connection."; - - const int len = static_cast(message.length()); - if (write(sockfd_, message.c_str(), len) != len) { - GTEST_LOG_(WARNING) - << "stream_result_to: failed to stream to " - << host_name_ << ":" << port_num_; - } - } - - // Sends a string and a newline to the socket. - void SendLn(const string& message) { - Send(message + "\n"); - } - - int sockfd_; // socket file descriptor - const string host_name_; - const string port_num_; - - GTEST_DISALLOW_COPY_AND_ASSIGN_(StreamingListener); -}; // class StreamingListener - // Checks if str contains '=', '&', '%' or '\n' characters. If yes, // replaces them by "%xx" where xx is their hexadecimal value. For // example, replaces "=" with "%3D". This algorithm is O(strlen(str)) @@ -3364,7 +3254,7 @@ string StreamingListener::UrlEncode(const char* str) { return result; } -void StreamingListener::MakeConnection() { +void StreamingListener::SocketWriter::MakeConnection() { GTEST_CHECK_(sockfd_ == -1) << "MakeConnection() can't be called when there is already a connection."; -- cgit v1.2.3 From 1b89db97058ced81a116d6a03714fec9bd8fc721 Mon Sep 17 00:00:00 2001 From: "zhanyong.wan" Date: Thu, 28 Feb 2013 22:55:25 +0000 Subject: Removes an unused variable; also refactors to support an up-coming googlemock change. --- src/gtest-internal-inl.h | 1 - src/gtest.cc | 31 +++++++++++++------------------ 2 files changed, 13 insertions(+), 19 deletions(-) (limited to 'src') diff --git a/src/gtest-internal-inl.h b/src/gtest-internal-inl.h index c96c9411..d6610430 100644 --- a/src/gtest-internal-inl.h +++ b/src/gtest-internal-inl.h @@ -215,7 +215,6 @@ class GTestFlagSaver { bool list_tests_; std::string output_; bool print_time_; - bool pretty_; internal::Int32 random_seed_; internal::Int32 repeat_; bool shuffle_; diff --git a/src/gtest.cc b/src/gtest.cc index c9bf4581..1ade2691 100644 --- a/src/gtest.cc +++ b/src/gtest.cc @@ -1903,6 +1903,8 @@ static std::string* FormatSehExceptionMessage(DWORD exception_code, #endif // GTEST_HAS_SEH +namespace internal { + #if GTEST_HAS_EXCEPTIONS // Adds an "exception thrown" fatal failure to the current test. @@ -1922,20 +1924,12 @@ static std::string FormatCxxExceptionMessage(const char* description, static std::string PrintTestPartResultToString( const TestPartResult& test_part_result); -// A failed Google Test assertion will throw an exception of this type when -// GTEST_FLAG(throw_on_failure) is true (if exceptions are enabled). We -// derive it from std::runtime_error, which is for errors presumably -// detectable only at run time. Since std::runtime_error inherits from -// std::exception, many testing frameworks know how to extract and print the -// message inside it. -class GoogleTestFailureException : public ::std::runtime_error { - public: - explicit GoogleTestFailureException(const TestPartResult& failure) - : ::std::runtime_error(PrintTestPartResultToString(failure).c_str()) {} -}; +GoogleTestFailureException::GoogleTestFailureException( + const TestPartResult& failure) + : ::std::runtime_error(PrintTestPartResultToString(failure).c_str()) {} + #endif // GTEST_HAS_EXCEPTIONS -namespace internal { // We put these helper functions in the internal namespace as IBM's xlC // compiler rejects the code if they were declared static. @@ -2001,9 +1995,10 @@ Result HandleExceptionsInMethodIfSupported( #if GTEST_HAS_EXCEPTIONS try { return HandleSehExceptionsInMethodIfSupported(object, method, location); - } catch (const GoogleTestFailureException&) { // NOLINT - // This exception doesn't originate in code under test. It makes no - // sense to report it as a test failure. + } catch (const internal::GoogleTestFailureException&) { // NOLINT + // This exception type can only be thrown by a failed Google + // Test assertion with the intention of letting another testing + // framework catch it. Therefore we just re-throw it. throw; } catch (const std::exception& e) { // NOLINT internal::ReportFailureInUnknownLocation( @@ -2390,6 +2385,8 @@ static const char * TestPartResultTypeToString(TestPartResult::Type type) { } } +namespace internal { + // Prints a TestPartResult to an std::string. static std::string PrintTestPartResultToString( const TestPartResult& test_part_result) { @@ -2421,8 +2418,6 @@ static void PrintTestPartResult(const TestPartResult& test_part_result) { // class PrettyUnitTestResultPrinter -namespace internal { - enum GTestColor { COLOR_DEFAULT, COLOR_RED, @@ -3601,7 +3596,7 @@ void UnitTest::AddTestPartResult( #endif // GTEST_OS_WINDOWS } else if (GTEST_FLAG(throw_on_failure)) { #if GTEST_HAS_EXCEPTIONS - throw GoogleTestFailureException(result); + throw internal::GoogleTestFailureException(result); #else // We cannot call abort() as it generates a pop-up in debug mode // that cannot be suppressed in VC 7.1 or below. -- cgit v1.2.3 From 6a036a5c8c7613e888fad39d92fc3fd84a96fbc7 Mon Sep 17 00:00:00 2001 From: "zhanyong.wan" Date: Thu, 28 Feb 2013 23:46:07 +0000 Subject: Fixes a nasty issue in gtest's template instantiation. --- src/gtest-filepath.cc | 1 + src/gtest.cc | 28 ++++++++++++++++++++++++++++ 2 files changed, 29 insertions(+) (limited to 'src') diff --git a/src/gtest-filepath.cc b/src/gtest-filepath.cc index 708389d1..6be58b6f 100644 --- a/src/gtest-filepath.cc +++ b/src/gtest-filepath.cc @@ -29,6 +29,7 @@ // // Authors: keith.ray@gmail.com (Keith Ray) +#include "gtest/gtest-message.h" #include "gtest/internal/gtest-filepath.h" #include "gtest/internal/gtest-port.h" diff --git a/src/gtest.cc b/src/gtest.cc index 1ade2691..8e6db0c7 100644 --- a/src/gtest.cc +++ b/src/gtest.cc @@ -44,6 +44,8 @@ #include #include +#include +#include #include // NOLINT #include #include @@ -886,6 +888,26 @@ static void StreamWideCharsToMessage(const wchar_t* wstr, size_t length, } // namespace internal +// Constructs an empty Message. +// We allocate the stringstream separately because otherwise each use of +// ASSERT/EXPECT in a procedure adds over 200 bytes to the procedure's +// stack frame leading to huge stack frames in some cases; gcc does not reuse +// the stack space. +Message::Message() : ss_(new ::std::stringstream) { + // By default, we want there to be enough precision when printing + // a double to a Message. + *ss_ << std::setprecision(std::numeric_limits::digits10 + 2); +} + +// These two overloads allow streaming a wide C string to a Message +// using the UTF-8 encoding. +Message& Message::operator <<(const wchar_t* wide_c_str) { + return *this << internal::String::ShowWideCString(wide_c_str); +} +Message& Message::operator <<(wchar_t* wide_c_str) { + return *this << internal::String::ShowWideCString(wide_c_str); +} + #if GTEST_HAS_STD_WSTRING // Converts the given wide string to a narrow string using the UTF-8 // encoding, and streams the result to this Message object. @@ -904,6 +926,12 @@ Message& Message::operator <<(const ::wstring& wstr) { } #endif // GTEST_HAS_GLOBAL_WSTRING +// Gets the text streamed to this object so far as an std::string. +// Each '\0' character in the buffer is replaced with "\\0". +std::string Message::GetString() const { + return internal::StringStreamToString(ss_.get()); +} + // AssertionResult constructors. // Used in EXPECT_TRUE/FALSE(assertion_result). AssertionResult::AssertionResult(const AssertionResult& other) -- cgit v1.2.3 From fc01f532a622a7d460a4eff816c56c0e501f20f7 Mon Sep 17 00:00:00 2001 From: "zhanyong.wan" Date: Thu, 28 Feb 2013 23:52:42 +0000 Subject: Fixes unused function warning on Mac, and fixes compatibility with newer GCC. --- src/gtest.cc | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'src') diff --git a/src/gtest.cc b/src/gtest.cc index 8e6db0c7..62b69291 100644 --- a/src/gtest.cc +++ b/src/gtest.cc @@ -3571,13 +3571,13 @@ Environment* UnitTest::AddEnvironment(Environment* env) { // assertion macros (e.g. ASSERT_TRUE, EXPECT_EQ, etc) eventually call // this to report their results. The user code should use the // assertion macros instead of calling this directly. +GTEST_LOCK_EXCLUDED_(mutex_) void UnitTest::AddTestPartResult( TestPartResult::Type result_type, const char* file_name, int line_number, const std::string& message, - const std::string& os_stack_trace) - GTEST_LOCK_EXCLUDED_(mutex_) { + const std::string& os_stack_trace) { Message msg; msg << message; -- cgit v1.2.3 From 6b7a167dca7a9007d14fc95a07f4f6e07fec3162 Mon Sep 17 00:00:00 2001 From: "zhanyong.wan" Date: Mon, 11 Mar 2013 17:52:13 +0000 Subject: Supports colored output on term type screen-256color. Proposed as a one-line patch by Tom Jakubowski (tom@crystae.net); finished by Zhanyong Wan. --- src/gtest.cc | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'src') diff --git a/src/gtest.cc b/src/gtest.cc index 62b69291..911919d8 100644 --- a/src/gtest.cc +++ b/src/gtest.cc @@ -204,7 +204,7 @@ GTEST_DEFINE_string_( "Whether to use colors in the output. Valid values: yes, no, " "and auto. 'auto' means to use colors if the output is " "being sent to a terminal and the TERM environment variable " - "is set to xterm, xterm-color, xterm-256color, linux or cygwin."); + "is set to a terminal type that supports colors."); GTEST_DEFINE_string_( filter, @@ -2497,6 +2497,7 @@ bool ShouldUseColor(bool stdout_is_tty) { String::CStringEquals(term, "xterm-color") || String::CStringEquals(term, "xterm-256color") || String::CStringEquals(term, "screen") || + String::CStringEquals(term, "screen-256color") || String::CStringEquals(term, "linux") || String::CStringEquals(term, "cygwin"); return stdout_is_tty && term_supports_color; -- cgit v1.2.3 From f5fa71f728ce77c5d5c1a940a9bd8bb1d64c9f78 Mon Sep 17 00:00:00 2001 From: vladlosev Date: Fri, 5 Apr 2013 20:50:46 +0000 Subject: Implements support for calling Test::RecordProperty() outside of a test. --- src/gtest-internal-inl.h | 12 +- src/gtest.cc | 370 +++++++++++++++++++++++++++++++++-------------- 2 files changed, 270 insertions(+), 112 deletions(-) (limited to 'src') diff --git a/src/gtest-internal-inl.h b/src/gtest-internal-inl.h index d6610430..302b6cdb 100644 --- a/src/gtest-internal-inl.h +++ b/src/gtest-internal-inl.h @@ -348,8 +348,7 @@ class TestPropertyKeyIs { // Constructor. // // TestPropertyKeyIs has NO default constructor. - explicit TestPropertyKeyIs(const char* key) - : key_(key) {} + explicit TestPropertyKeyIs(const std::string& key) : key_(key) {} // Returns true iff the test name of test property matches on key_. bool operator()(const TestProperty& test_property) const { @@ -712,6 +711,12 @@ class GTEST_API_ UnitTestImpl { ad_hoc_test_result_.Clear(); } + // Adds a TestProperty to the current TestResult object when invoked in a + // context of a test or a test case, or to the global property set. If the + // result already contains a property with the same key, the value will be + // updated. + void RecordProperty(const TestProperty& test_property); + enum ReactionToSharding { HONOR_SHARDING_PROTOCOL, IGNORE_SHARDING_PROTOCOL @@ -1038,8 +1043,9 @@ bool ParseNaturalNumber(const ::std::string& str, Integer* number) { class TestResultAccessor { public: static void RecordProperty(TestResult* test_result, + const std::string& xml_element, const TestProperty& property) { - test_result->RecordProperty(property); + test_result->RecordProperty(xml_element, property); } static void ClearTestPartResults(TestResult* test_result) { diff --git a/src/gtest.cc b/src/gtest.cc index 911919d8..5e96f3ec 100644 --- a/src/gtest.cc +++ b/src/gtest.cc @@ -1716,8 +1716,9 @@ void TestResult::AddTestPartResult(const TestPartResult& test_part_result) { // Adds a test property to the list. If a property with the same key as the // supplied property is already represented, the value of this test_property // replaces the old value for that key. -void TestResult::RecordProperty(const TestProperty& test_property) { - if (!ValidateTestProperty(test_property)) { +void TestResult::RecordProperty(const std::string& xml_element, + const TestProperty& test_property) { + if (!ValidateTestProperty(xml_element, test_property)) { return; } internal::MutexLock lock(&test_properites_mutex_); @@ -1731,21 +1732,94 @@ void TestResult::RecordProperty(const TestProperty& test_property) { property_with_matching_key->SetValue(test_property.value()); } -// Adds a failure if the key is a reserved attribute of Google Test -// testcase tags. Returns true if the property is valid. -bool TestResult::ValidateTestProperty(const TestProperty& test_property) { - const std::string& key = test_property.key(); - if (key == "name" || key == "status" || key == "time" || key == "classname") { - ADD_FAILURE() - << "Reserved key used in RecordProperty(): " - << key - << " ('name', 'status', 'time', and 'classname' are reserved by " - << GTEST_NAME_ << ")"; +// The list of reserved attributes used in the element of XML +// output. +static const char* const kReservedTestSuitesAttributes[] = { + "disabled", + "errors", + "failures", + "name", + "random_seed", + "tests", + "time", + "timestamp" +}; + +// The list of reserved attributes used in the element of XML +// output. +static const char* const kReservedTestSuiteAttributes[] = { + "disabled", + "errors", + "failures", + "name", + "tests", + "time" +}; + +// The list of reserved attributes used in the element of XML output. +static const char* const kReservedTestCaseAttributes[] = { + "classname", + "name", + "status", + "time", + "type_param", + "value_param" +}; + +template +std::vector ArrayAsVector(const char* const (&array)[kSize]) { + return std::vector(array, array + kSize); +} + +static std::vector GetReservedAttributesForElement( + const std::string& xml_element) { + if (xml_element == "testsuites") { + return ArrayAsVector(kReservedTestSuitesAttributes); + } else if (xml_element == "testsuite") { + return ArrayAsVector(kReservedTestSuiteAttributes); + } else if (xml_element == "testcase") { + return ArrayAsVector(kReservedTestCaseAttributes); + } else { + GTEST_CHECK_(false) << "Unrecognized xml_element provided: " << xml_element; + } + // This code is unreachable but some compilers may not realizes that. + return std::vector(); +} + +static std::string FormatWordList(const std::vector& words) { + Message word_list; + for (size_t i = 0; i < words.size(); ++i) { + if (i > 0 && words.size() > 2) { + word_list << ", "; + } + if (i == words.size() - 1) { + word_list << "and "; + } + word_list << "'" << words[i] << "'"; + } + return word_list.GetString(); +} + +bool ValidateTestPropertyName(const std::string& property_name, + const std::vector& reserved_names) { + if (std::find(reserved_names.begin(), reserved_names.end(), property_name) != + reserved_names.end()) { + ADD_FAILURE() << "Reserved key used in RecordProperty(): " << property_name + << " (" << FormatWordList(reserved_names) + << " are reserved by " << GTEST_NAME_ << ")"; return false; } return true; } +// Adds a failure if the key is a reserved attribute of the element named +// xml_element. Returns true if the property is valid. +bool TestResult::ValidateTestProperty(const std::string& xml_element, + const TestProperty& test_property) { + return ValidateTestPropertyName(test_property.key(), + GetReservedAttributesForElement(xml_element)); +} + // Clears the object. void TestResult::Clear() { test_part_results_.clear(); @@ -1821,12 +1895,12 @@ void Test::TearDown() { } // Allows user supplied key value pairs to be recorded for later output. -void Test::RecordProperty(const char* key, const char* value) { - UnitTest::GetInstance()->RecordPropertyForCurrentTest(key, value); +void Test::RecordProperty(const std::string& key, const std::string& value) { + UnitTest::GetInstance()->RecordProperty(key, value); } // Allows user supplied key value pairs to be recorded for later output. -void Test::RecordProperty(const char* key, int value) { +void Test::RecordProperty(const std::string& key, int value) { Message value_message; value_message << value; RecordProperty(key, value_message.GetString().c_str()); @@ -2355,6 +2429,7 @@ void TestCase::Run() { // Clears the results of all tests in this test case. void TestCase::ClearResult() { + ad_hoc_test_result_.Clear(); ForEach(test_info_list_, TestInfo::ClearTestResult); } @@ -2925,13 +3000,13 @@ class XmlUnitTestResultPrinter : public EmptyTestEventListener { // is_attribute is true, the text is meant to appear as an attribute // value, and normalizable whitespace is preserved by replacing it // with character references. - static std::string EscapeXml(const char* str, bool is_attribute); + static std::string EscapeXml(const std::string& str, bool is_attribute); // Returns the given string with all characters invalid in XML removed. - static string RemoveInvalidXmlCharacters(const string& str); + static std::string RemoveInvalidXmlCharacters(const std::string& str); // Convenience wrapper around EscapeXml when str is an attribute value. - static std::string EscapeXmlAttribute(const char* str) { + static std::string EscapeXmlAttribute(const std::string& str) { return EscapeXml(str, true); } @@ -2940,6 +3015,13 @@ class XmlUnitTestResultPrinter : public EmptyTestEventListener { return EscapeXml(str, false); } + // Verifies that the given attribute belongs to the given element and + // streams the attribute as XML. + static void OutputXmlAttribute(std::ostream* stream, + const std::string& element_name, + const std::string& name, + const std::string& value); + // Streams an XML CDATA section, escaping invalid CDATA sequences as needed. static void OutputXmlCDataSection(::std::ostream* stream, const char* data); @@ -2949,10 +3031,12 @@ class XmlUnitTestResultPrinter : public EmptyTestEventListener { const TestInfo& test_info); // Prints an XML representation of a TestCase object - static void PrintXmlTestCase(FILE* out, const TestCase& test_case); + static void PrintXmlTestCase(::std::ostream* stream, + const TestCase& test_case); // Prints an XML summary of unit_test to output stream out. - static void PrintXmlUnitTest(FILE* out, const UnitTest& unit_test); + static void PrintXmlUnitTest(::std::ostream* stream, + const UnitTest& unit_test); // Produces a string representing the test properties in a result as space // delimited XML attributes based on the property key="value" pairs. @@ -3003,7 +3087,9 @@ void XmlUnitTestResultPrinter::OnTestIterationEnd(const UnitTest& unit_test, fflush(stderr); exit(EXIT_FAILURE); } - PrintXmlUnitTest(xmlout, unit_test); + std::stringstream stream; + PrintXmlUnitTest(&stream, unit_test); + fprintf(xmlout, "%s", StringStreamToString(&stream).c_str()); fclose(xmlout); } @@ -3020,43 +3106,42 @@ void XmlUnitTestResultPrinter::OnTestIterationEnd(const UnitTest& unit_test, // TODO(wan): It might be nice to have a minimally invasive, human-readable // escaping scheme for invalid characters, rather than dropping them. std::string XmlUnitTestResultPrinter::EscapeXml( - const char* str, bool is_attribute) { + const std::string& str, bool is_attribute) { Message m; - if (str != NULL) { - for (const char* src = str; *src; ++src) { - switch (*src) { - case '<': - m << "<"; - break; - case '>': - m << ">"; - break; - case '&': - m << "&"; - break; - case '\'': - if (is_attribute) - m << "'"; - else - m << '\''; - break; - case '"': - if (is_attribute) - m << """; + for (size_t i = 0; i < str.size(); ++i) { + const char ch = str[i]; + switch (ch) { + case '<': + m << "<"; + break; + case '>': + m << ">"; + break; + case '&': + m << "&"; + break; + case '\'': + if (is_attribute) + m << "'"; + else + m << '\''; + break; + case '"': + if (is_attribute) + m << """; + else + m << '"'; + break; + default: + if (IsValidXmlCharacter(ch)) { + if (is_attribute && IsNormalizableWhitespace(ch)) + m << "&#x" << String::FormatByte(static_cast(ch)) + << ";"; else - m << '"'; - break; - default: - if (IsValidXmlCharacter(*src)) { - if (is_attribute && IsNormalizableWhitespace(*src)) - m << "&#x" << String::FormatByte(static_cast(*src)) - << ";"; - else - m << *src; - } - break; - } + m << ch; + } + break; } } @@ -3066,10 +3151,11 @@ std::string XmlUnitTestResultPrinter::EscapeXml( // Returns the given string with all characters invalid in XML removed. // Currently invalid characters are dropped from the string. An // alternative is to replace them with certain characters such as . or ?. -string XmlUnitTestResultPrinter::RemoveInvalidXmlCharacters(const string& str) { - string output; +std::string XmlUnitTestResultPrinter::RemoveInvalidXmlCharacters( + const std::string& str) { + std::string output; output.reserve(str.size()); - for (string::const_iterator it = str.begin(); it != str.end(); ++it) + for (std::string::const_iterator it = str.begin(); it != str.end(); ++it) if (IsValidXmlCharacter(*it)) output.push_back(*it); @@ -3145,30 +3231,47 @@ void XmlUnitTestResultPrinter::OutputXmlCDataSection(::std::ostream* stream, *stream << "]]>"; } +void XmlUnitTestResultPrinter::OutputXmlAttribute( + std::ostream* stream, + const std::string& element_name, + const std::string& name, + const std::string& value) { + const std::vector& allowed_names = + GetReservedAttributesForElement(element_name); + + GTEST_CHECK_(std::find(allowed_names.begin(), allowed_names.end(), name) != + allowed_names.end()) + << "Attribute " << name << " is not allowed for element <" << element_name + << ">."; + + *stream << " " << name << "=\"" << EscapeXmlAttribute(value) << "\""; +} + // Prints an XML representation of a TestInfo object. // TODO(wan): There is also value in printing properties with the plain printer. void XmlUnitTestResultPrinter::OutputXmlTestInfo(::std::ostream* stream, const char* test_case_name, const TestInfo& test_info) { const TestResult& result = *test_info.result(); - *stream << " \n", - FormatTimeInMillisAsSeconds(test_case.elapsed_time()).c_str()); - for (int i = 0; i < test_case.total_test_count(); ++i) { - ::std::stringstream stream; - OutputXmlTestInfo(&stream, test_case.name(), *test_case.GetTestInfo(i)); - fprintf(out, "%s", StringStreamToString(&stream).c_str()); - } - fprintf(out, " \n"); + const std::string kTestsuite = "testsuite"; + *stream << " <" << kTestsuite; + OutputXmlAttribute(stream, kTestsuite, "name", test_case.name()); + OutputXmlAttribute(stream, kTestsuite, "tests", + StreamableToString(test_case.total_test_count())); + OutputXmlAttribute(stream, kTestsuite, "failures", + StreamableToString(test_case.failed_test_count())); + OutputXmlAttribute(stream, kTestsuite, "disabled", + StreamableToString(test_case.disabled_test_count())); + OutputXmlAttribute(stream, kTestsuite, "errors", "0"); + OutputXmlAttribute(stream, kTestsuite, "time", + FormatTimeInMillisAsSeconds(test_case.elapsed_time())); + *stream << TestPropertiesAsXmlAttributes(test_case.ad_hoc_test_result()) + << ">\n"; + + for (int i = 0; i < test_case.total_test_count(); ++i) + OutputXmlTestInfo(stream, test_case.name(), *test_case.GetTestInfo(i)); + *stream << " \n"; } // Prints an XML summary of unit_test to output stream out. -void XmlUnitTestResultPrinter::PrintXmlUnitTest(FILE* out, +void XmlUnitTestResultPrinter::PrintXmlUnitTest(std::ostream* stream, const UnitTest& unit_test) { - fprintf(out, "\n"); - fprintf(out, - "\n"; + *stream << "<" << kTestsuites; + + OutputXmlAttribute(stream, kTestsuites, "tests", + StreamableToString(unit_test.total_test_count())); + OutputXmlAttribute(stream, kTestsuites, "failures", + StreamableToString(unit_test.failed_test_count())); + OutputXmlAttribute(stream, kTestsuites, "disabled", + StreamableToString(unit_test.disabled_test_count())); + OutputXmlAttribute(stream, kTestsuites, "errors", "0"); + OutputXmlAttribute( + stream, kTestsuites, "timestamp", + FormatEpochTimeInMillisAsIso8601(unit_test.start_timestamp())); + OutputXmlAttribute(stream, kTestsuites, "time", + FormatTimeInMillisAsSeconds(unit_test.elapsed_time())); + if (GTEST_FLAG(shuffle)) { - fprintf(out, "random_seed=\"%d\" ", unit_test.random_seed()); + OutputXmlAttribute(stream, kTestsuites, "random_seed", + StreamableToString(unit_test.random_seed())); } - fprintf(out, "name=\"AllTests\">\n"); - for (int i = 0; i < unit_test.total_test_case_count(); ++i) - PrintXmlTestCase(out, *unit_test.GetTestCase(i)); - fprintf(out, "\n"); + + *stream << TestPropertiesAsXmlAttributes(unit_test.ad_hoc_test_result()); + + OutputXmlAttribute(stream, kTestsuites, "name", "AllTests"); + *stream << ">\n"; + + + for (int i = 0; i < unit_test.total_test_case_count(); ++i) { + PrintXmlTestCase(stream, *unit_test.GetTestCase(i)); + } + *stream << "\n"; } // Produces a string representing the test properties in a result as space @@ -3452,7 +3574,7 @@ void TestEventListeners::SuppressEventForwarding() { // We don't protect this under mutex_ as a user is not supposed to // call this before main() starts, from which point on the return // value will never change. -UnitTest * UnitTest::GetInstance() { +UnitTest* UnitTest::GetInstance() { // When compiled with MSVC 7.1 in optimized mode, destroying the // UnitTest object upon exiting the program messes up the exit code, // causing successful tests to appear failed. We have to use a @@ -3537,6 +3659,12 @@ const TestCase* UnitTest::GetTestCase(int i) const { return impl()->GetTestCase(i); } +// Returns the TestResult containing information on test failures and +// properties logged outside of individual test cases. +const TestResult& UnitTest::ad_hoc_test_result() const { + return *impl()->ad_hoc_test_result(); +} + // Gets the i-th test case among all the test cases. i can range from 0 to // total_test_case_count() - 1. If i is not in that range, returns NULL. TestCase* UnitTest::GetMutableTestCase(int i) { @@ -3635,12 +3763,14 @@ void UnitTest::AddTestPartResult( } } -// Creates and adds a property to the current TestResult. If a property matching -// the supplied value already exists, updates its value instead. -void UnitTest::RecordPropertyForCurrentTest(const char* key, - const char* value) { - const TestProperty test_property(key, value); - impl_->current_test_result()->RecordProperty(test_property); +// Adds a TestProperty to the current TestResult object when invoked from +// inside a test, to current TestCase's ad_hoc_test_result_ when invoked +// from SetUpTestCase or TearDownTestCase, or to the global property set +// when invoked elsewhere. If the result already contains a property with +// the same key, the value will be updated. +void UnitTest::RecordProperty(const std::string& key, + const std::string& value) { + impl_->RecordProperty(TestProperty(key, value)); } // Runs all tests in this UnitTest object and prints the result. @@ -3813,6 +3943,28 @@ UnitTestImpl::~UnitTestImpl() { delete os_stack_trace_getter_; } +// Adds a TestProperty to the current TestResult object when invoked in a +// context of a test, to current test case's ad_hoc_test_result when invoke +// from SetUpTestCase/TearDownTestCase, or to the global property set +// otherwise. If the result already contains a property with the same key, +// the value will be updated. +void UnitTestImpl::RecordProperty(const TestProperty& test_property) { + std::string xml_element; + TestResult* test_result; // TestResult appropriate for property recording. + + if (current_test_info_ != NULL) { + xml_element = "testcase"; + test_result = &(current_test_info_->result_); + } else if (current_test_case_ != NULL) { + xml_element = "testsuite"; + test_result = &(current_test_case_->ad_hoc_test_result_); + } else { + xml_element = "testsuites"; + test_result = &ad_hoc_test_result_; + } + test_result->RecordProperty(xml_element, test_property); +} + #if GTEST_HAS_DEATH_TEST // Disables event forwarding if the control is currently in a death test // subprocess. Must not be called before InitGoogleTest. -- cgit v1.2.3 From 0fac83390adaf4e80ddee5bc3747079be4234c27 Mon Sep 17 00:00:00 2001 From: "zhanyong.wan" Date: Wed, 10 Apr 2013 04:29:33 +0000 Subject: prints type/value parameters when listing tests --- src/gtest.cc | 54 +++++++++++++++++++++++++++++++++++++++++++++++++----- 1 file changed, 49 insertions(+), 5 deletions(-) (limited to 'src') diff --git a/src/gtest.cc b/src/gtest.cc index 5e96f3ec..b9b44a16 100644 --- a/src/gtest.cc +++ b/src/gtest.cc @@ -2638,6 +2638,11 @@ void ColoredPrintf(GTestColor color, const char* fmt, ...) { va_end(args); } +// Text printed in Google Test's text output and --gunit_list_tests +// output to label the type parameter and value parameter for a test. +static const char kTypeParamLabel[] = "TypeParam"; +static const char kValueParamLabel[] = "GetParam()"; + void PrintFullTestCommentIfPresent(const TestInfo& test_info) { const char* const type_param = test_info.type_param(); const char* const value_param = test_info.value_param(); @@ -2645,12 +2650,12 @@ void PrintFullTestCommentIfPresent(const TestInfo& test_info) { if (type_param != NULL || value_param != NULL) { printf(", where "); if (type_param != NULL) { - printf("TypeParam = %s", type_param); + printf("%s = %s", kTypeParamLabel, type_param); if (value_param != NULL) printf(" and "); } if (value_param != NULL) { - printf("GetParam() = %s", value_param); + printf("%s = %s", kValueParamLabel, value_param); } } } @@ -2735,7 +2740,7 @@ void PrettyUnitTestResultPrinter::OnTestCaseStart(const TestCase& test_case) { if (test_case.type_param() == NULL) { printf("\n"); } else { - printf(", where TypeParam = %s\n", test_case.type_param()); + printf(", where %s = %s\n", kTypeParamLabel, test_case.type_param()); } fflush(stdout); } @@ -4408,8 +4413,33 @@ int UnitTestImpl::FilterTests(ReactionToSharding shard_tests) { return num_selected_tests; } +// Prints the given C-string on a single line by replacing all '\n' +// characters with string "\\n". If the output takes more than +// max_length characters, only prints the first max_length characters +// and "...". +static void PrintOnOneLine(const char* str, int max_length) { + if (str != NULL) { + for (int i = 0; *str != '\0'; ++str) { + if (i >= max_length) { + printf("..."); + break; + } + if (*str == '\n') { + printf("\\n"); + i += 2; + } else { + printf("%c", *str); + ++i; + } + } + } +} + // Prints the names of the tests matching the user-specified filter flag. void UnitTestImpl::ListTestsMatchingFilter() { + // Print at most this many characters for each type/value parameter. + const int kMaxParamLength = 250; + for (size_t i = 0; i < test_cases_.size(); i++) { const TestCase* const test_case = test_cases_[i]; bool printed_test_case_name = false; @@ -4420,9 +4450,23 @@ void UnitTestImpl::ListTestsMatchingFilter() { if (test_info->matches_filter_) { if (!printed_test_case_name) { printed_test_case_name = true; - printf("%s.\n", test_case->name()); + printf("%s.", test_case->name()); + if (test_case->type_param() != NULL) { + printf(" # %s = ", kTypeParamLabel); + // We print the type parameter on a single line to make + // the output easy to parse by a program. + PrintOnOneLine(test_case->type_param(), kMaxParamLength); + } + printf("\n"); + } + printf(" %s", test_info->name()); + if (test_info->value_param() != NULL) { + printf(" # %s = ", kValueParamLabel); + // We print the value parameter on a single line to make the + // output easy to parse by a program. + PrintOnOneLine(test_info->value_param(), kMaxParamLength); } - printf(" %s\n", test_info->name()); + printf("\n"); } } } -- cgit v1.2.3 From c84afbeaf1003ae2d4a0f6d36bbb8938bc73bbc7 Mon Sep 17 00:00:00 2001 From: "zhanyong.wan" Date: Wed, 24 Apr 2013 02:48:07 +0000 Subject: Fixes a thread annotation; updates CHANGES for 1.7.0 --- src/gtest.cc | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'src') diff --git a/src/gtest.cc b/src/gtest.cc index b9b44a16..6b9d75df 100644 --- a/src/gtest.cc +++ b/src/gtest.cc @@ -3705,13 +3705,12 @@ Environment* UnitTest::AddEnvironment(Environment* env) { // assertion macros (e.g. ASSERT_TRUE, EXPECT_EQ, etc) eventually call // this to report their results. The user code should use the // assertion macros instead of calling this directly. -GTEST_LOCK_EXCLUDED_(mutex_) void UnitTest::AddTestPartResult( TestPartResult::Type result_type, const char* file_name, int line_number, const std::string& message, - const std::string& os_stack_trace) { + const std::string& os_stack_trace) GTEST_LOCK_EXCLUDED_(mutex_) { Message msg; msg << message; -- cgit v1.2.3 From c506784b08473f3ba8f37d588fd08d8d3f948245 Mon Sep 17 00:00:00 2001 From: vladlosev Date: Thu, 25 Apr 2013 17:58:52 +0000 Subject: When --gtest_filter is specified, XML report now doesn't contain information about tests that are filtered out (issue 141). --- src/gtest-internal-inl.h | 6 +++++ src/gtest.cc | 59 ++++++++++++++++++++++++++++++++++++++---------- 2 files changed, 53 insertions(+), 12 deletions(-) (limited to 'src') diff --git a/src/gtest-internal-inl.h b/src/gtest-internal-inl.h index 302b6cdb..35df303c 100644 --- a/src/gtest-internal-inl.h +++ b/src/gtest-internal-inl.h @@ -550,9 +550,15 @@ class GTEST_API_ UnitTestImpl { // Gets the number of failed tests. int failed_test_count() const; + // Gets the number of disabled tests that will be reported in the XML report. + int reportable_disabled_test_count() const; + // Gets the number of disabled tests. int disabled_test_count() const; + // Gets the number of tests to be printed in the XML report. + int reportable_test_count() const; + // Gets the number of all tests. int total_test_count() const; diff --git a/src/gtest.cc b/src/gtest.cc index 6b9d75df..57719aa9 100644 --- a/src/gtest.cc +++ b/src/gtest.cc @@ -731,11 +731,22 @@ int UnitTestImpl::failed_test_count() const { return SumOverTestCaseList(test_cases_, &TestCase::failed_test_count); } +// Gets the number of disabled tests that will be reported in the XML report. +int UnitTestImpl::reportable_disabled_test_count() const { + return SumOverTestCaseList(test_cases_, + &TestCase::reportable_disabled_test_count); +} + // Gets the number of disabled tests. int UnitTestImpl::disabled_test_count() const { return SumOverTestCaseList(test_cases_, &TestCase::disabled_test_count); } +// Gets the number of tests to be printed in the XML report. +int UnitTestImpl::reportable_test_count() const { + return SumOverTestCaseList(test_cases_, &TestCase::reportable_test_count); +} + // Gets the number of all tests. int UnitTestImpl::total_test_count() const { return SumOverTestCaseList(test_cases_, &TestCase::total_test_count); @@ -2338,10 +2349,21 @@ int TestCase::failed_test_count() const { return CountIf(test_info_list_, TestFailed); } +// Gets the number of disabled tests that will be reported in the XML report. +int TestCase::reportable_disabled_test_count() const { + return CountIf(test_info_list_, TestReportableDisabled); +} + +// Gets the number of disabled tests in this test case. int TestCase::disabled_test_count() const { return CountIf(test_info_list_, TestDisabled); } +// Gets the number of tests to be printed in the XML report. +int TestCase::reportable_test_count() const { + return CountIf(test_info_list_, TestReportable); +} + // Get the number of tests in this test case that should run. int TestCase::test_to_run_count() const { return CountIf(test_info_list_, ShouldRunTest); @@ -2851,7 +2873,7 @@ void PrettyUnitTestResultPrinter::OnTestIterationEnd(const UnitTest& unit_test, num_failures == 1 ? "TEST" : "TESTS"); } - int num_disabled = unit_test.disabled_test_count(); + int num_disabled = unit_test.reportable_disabled_test_count(); if (num_disabled && !GTEST_FLAG(also_run_disabled_tests)) { if (!num_failures) { printf("\n"); // Add a spacer if no FAILURE banner is displayed. @@ -3310,19 +3332,22 @@ void XmlUnitTestResultPrinter::PrintXmlTestCase(std::ostream* stream, *stream << " <" << kTestsuite; OutputXmlAttribute(stream, kTestsuite, "name", test_case.name()); OutputXmlAttribute(stream, kTestsuite, "tests", - StreamableToString(test_case.total_test_count())); + StreamableToString(test_case.reportable_test_count())); OutputXmlAttribute(stream, kTestsuite, "failures", StreamableToString(test_case.failed_test_count())); - OutputXmlAttribute(stream, kTestsuite, "disabled", - StreamableToString(test_case.disabled_test_count())); + OutputXmlAttribute( + stream, kTestsuite, "disabled", + StreamableToString(test_case.reportable_disabled_test_count())); OutputXmlAttribute(stream, kTestsuite, "errors", "0"); OutputXmlAttribute(stream, kTestsuite, "time", FormatTimeInMillisAsSeconds(test_case.elapsed_time())); *stream << TestPropertiesAsXmlAttributes(test_case.ad_hoc_test_result()) << ">\n"; - for (int i = 0; i < test_case.total_test_count(); ++i) - OutputXmlTestInfo(stream, test_case.name(), *test_case.GetTestInfo(i)); + for (int i = 0; i < test_case.total_test_count(); ++i) { + if (test_case.GetTestInfo(i)->is_reportable()) + OutputXmlTestInfo(stream, test_case.name(), *test_case.GetTestInfo(i)); + } *stream << " \n"; } @@ -3335,11 +3360,12 @@ void XmlUnitTestResultPrinter::PrintXmlUnitTest(std::ostream* stream, *stream << "<" << kTestsuites; OutputXmlAttribute(stream, kTestsuites, "tests", - StreamableToString(unit_test.total_test_count())); + StreamableToString(unit_test.reportable_test_count())); OutputXmlAttribute(stream, kTestsuites, "failures", StreamableToString(unit_test.failed_test_count())); - OutputXmlAttribute(stream, kTestsuites, "disabled", - StreamableToString(unit_test.disabled_test_count())); + OutputXmlAttribute( + stream, kTestsuites, "disabled", + StreamableToString(unit_test.reportable_disabled_test_count())); OutputXmlAttribute(stream, kTestsuites, "errors", "0"); OutputXmlAttribute( stream, kTestsuites, "timestamp", @@ -3357,9 +3383,9 @@ void XmlUnitTestResultPrinter::PrintXmlUnitTest(std::ostream* stream, OutputXmlAttribute(stream, kTestsuites, "name", "AllTests"); *stream << ">\n"; - for (int i = 0; i < unit_test.total_test_case_count(); ++i) { - PrintXmlTestCase(stream, *unit_test.GetTestCase(i)); + if (unit_test.GetTestCase(i)->reportable_test_count() > 0) + PrintXmlTestCase(stream, *unit_test.GetTestCase(i)); } *stream << "\n"; } @@ -3629,11 +3655,21 @@ int UnitTest::successful_test_count() const { // Gets the number of failed tests. int UnitTest::failed_test_count() const { return impl()->failed_test_count(); } +// Gets the number of disabled tests that will be reported in the XML report. +int UnitTest::reportable_disabled_test_count() const { + return impl()->reportable_disabled_test_count(); +} + // Gets the number of disabled tests. int UnitTest::disabled_test_count() const { return impl()->disabled_test_count(); } +// Gets the number of tests to be printed in the XML report. +int UnitTest::reportable_test_count() const { + return impl()->reportable_test_count(); +} + // Gets the number of all tests. int UnitTest::total_test_count() const { return impl()->total_test_count(); } @@ -3929,7 +3965,6 @@ UnitTestImpl::UnitTestImpl(UnitTest* parent) start_timestamp_(0), elapsed_time_(0), #if GTEST_HAS_DEATH_TEST - internal_run_death_test_flag_(NULL), death_test_factory_(new DefaultDeathTestFactory), #endif // Will be overridden by the flag before first use. -- cgit v1.2.3 From 48568d0688d6e330ecf2efadd9d1539c349f6167 Mon Sep 17 00:00:00 2001 From: "zhanyong.wan" Date: Tue, 18 Jun 2013 18:44:25 +0000 Subject: Fixes compatibility with C++11: (1 - 1) is no longer a NULL pointer constant. --- src/gtest.cc | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) (limited to 'src') diff --git a/src/gtest.cc b/src/gtest.cc index 57719aa9..d6552f23 100644 --- a/src/gtest.cc +++ b/src/gtest.cc @@ -182,6 +182,10 @@ bool g_help_flag = false; } // namespace internal +static const char* GetDefaultFilter() { + return kUniversalFilter; +} + GTEST_DEFINE_bool_( also_run_disabled_tests, internal::BoolFromGTestEnv("also_run_disabled_tests", false), @@ -208,7 +212,7 @@ GTEST_DEFINE_string_( GTEST_DEFINE_string_( filter, - internal::StringFromGTestEnv("filter", kUniversalFilter), + internal::StringFromGTestEnv("filter", GetDefaultFilter()), "A colon-separated list of glob (not regex) patterns " "for filtering the tests to run, optionally followed by a " "'-' and a : separated list of negative patterns (tests to " -- cgit v1.2.3 From c306ef2e14483dbf4f047a3e1ca3f86111b800ca Mon Sep 17 00:00:00 2001 From: "zhanyong.wan" Date: Fri, 6 Sep 2013 22:50:25 +0000 Subject: supports a protocol for catching tests that prematurely exit --- src/gtest.cc | 60 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 57 insertions(+), 3 deletions(-) (limited to 'src') diff --git a/src/gtest.cc b/src/gtest.cc index d6552f23..6de53dd0 100644 --- a/src/gtest.cc +++ b/src/gtest.cc @@ -3523,6 +3523,35 @@ const char* const OsStackTraceGetter::kElidedFramesMarker = "... " GTEST_NAME_ " internal frames ..."; +// A helper class that creates the premature-exit file in its +// constructor and deletes the file in its destructor. +class ScopedPrematureExitFile { + public: + explicit ScopedPrematureExitFile(const char* premature_exit_filepath) + : premature_exit_filepath_(premature_exit_filepath) { + // If a path to the premature-exit file is specified... + if (premature_exit_filepath != NULL && *premature_exit_filepath != '\0') { + // create the file with a single "0" character in it. I/O + // errors are ignored as there's nothing better we can do and we + // don't want to fail the test because of this. + FILE* pfile = posix::FOpen(premature_exit_filepath, "w"); + fwrite("0", 1, 1, pfile); + fclose(pfile); + } + } + + ~ScopedPrematureExitFile() { + if (premature_exit_filepath_ != NULL && *premature_exit_filepath_ != '\0') { + remove(premature_exit_filepath_); + } + } + + private: + const char* const premature_exit_filepath_; + + GTEST_DISALLOW_COPY_AND_ASSIGN_(ScopedPrematureExitFile); +}; + } // namespace internal // class TestEventListeners @@ -3823,14 +3852,39 @@ void UnitTest::RecordProperty(const std::string& key, // We don't protect this under mutex_, as we only support calling it // from the main thread. int UnitTest::Run() { + const bool in_death_test_child_process = + internal::GTEST_FLAG(internal_run_death_test).length() > 0; + + // Google Test implements this protocol for catching that a test + // program exits before returning control to Google Test: + // + // 1. Upon start, Google Test creates a file whose absolute path + // is specified by the environment variable + // TEST_PREMATURE_EXIT_FILE. + // 2. When Google Test has finished its work, it deletes the file. + // + // This allows a test runner to set TEST_PREMATURE_EXIT_FILE before + // running a Google-Test-based test program and check the existence + // of the file at the end of the test execution to see if it has + // exited prematurely. + + // If we are in the child process of a death test, don't + // create/delete the premature exit file, as doing so is unnecessary + // and will confuse the parent process. Otherwise, create/delete + // the file upon entering/leaving this function. If the program + // somehow exits before this function has a chance to return, the + // premature-exit file will be left undeleted, causing a test runner + // that understands the premature-exit-file protocol to report the + // test as having failed. + const internal::ScopedPrematureExitFile premature_exit_file( + in_death_test_child_process ? + NULL : internal::posix::GetEnv("TEST_PREMATURE_EXIT_FILE")); + // Captures the value of GTEST_FLAG(catch_exceptions). This value will be // used for the duration of the program. impl()->set_catch_exceptions(GTEST_FLAG(catch_exceptions)); #if GTEST_HAS_SEH - const bool in_death_test_child_process = - internal::GTEST_FLAG(internal_run_death_test).length() > 0; - // Either the user wants Google Test to catch exceptions thrown by the // tests or this is executing in the context of death test child // process. In either case the user does not want to see pop-up dialogs -- cgit v1.2.3 From 37b97d1c93fb8283f8bbf54f5618c1c1e5a4726a Mon Sep 17 00:00:00 2001 From: kosak Date: Tue, 3 Dec 2013 22:38:22 +0000 Subject: Add MemorySanitizer annotations in gtest printers. Also remove unused variable kPathSeparatorString. --- src/gtest-filepath.cc | 2 -- src/gtest-printers.cc | 3 +++ 2 files changed, 3 insertions(+), 2 deletions(-) (limited to 'src') diff --git a/src/gtest-filepath.cc b/src/gtest-filepath.cc index 6be58b6f..d221cfde 100644 --- a/src/gtest-filepath.cc +++ b/src/gtest-filepath.cc @@ -70,7 +70,6 @@ namespace internal { // of them. const char kPathSeparator = '\\'; const char kAlternatePathSeparator = '/'; -const char kPathSeparatorString[] = "\\"; const char kAlternatePathSeparatorString[] = "/"; # if GTEST_OS_WINDOWS_MOBILE // Windows CE doesn't have a current directory. You should not use @@ -84,7 +83,6 @@ const char kCurrentDirectoryString[] = ".\\"; # endif // GTEST_OS_WINDOWS_MOBILE #else const char kPathSeparator = '/'; -const char kPathSeparatorString[] = "/"; const char kCurrentDirectoryString[] = "./"; #endif // GTEST_OS_WINDOWS diff --git a/src/gtest-printers.cc b/src/gtest-printers.cc index 75fa4081..0db5b44a 100644 --- a/src/gtest-printers.cc +++ b/src/gtest-printers.cc @@ -56,6 +56,7 @@ namespace { using ::std::ostream; // Prints a segment of bytes in the given object. +GTEST_ATTRIBUTE_NO_SANITIZE_MEMORY_ void PrintByteSegmentInObjectTo(const unsigned char* obj_bytes, size_t start, size_t count, ostream* os) { char text[5] = ""; @@ -252,6 +253,7 @@ void PrintTo(wchar_t wc, ostream* os) { // The array starts at begin, the length is len, it may include '\0' characters // and may not be NUL-terminated. template +GTEST_ATTRIBUTE_NO_SANITIZE_MEMORY_ static void PrintCharsAsStringTo( const CharType* begin, size_t len, ostream* os) { const char* const kQuoteBegin = sizeof(CharType) == 1 ? "\"" : "L\""; @@ -273,6 +275,7 @@ static void PrintCharsAsStringTo( // Prints a (const) char/wchar_t array of 'len' elements, starting at address // 'begin'. CharType must be either char or wchar_t. template +GTEST_ATTRIBUTE_NO_SANITIZE_MEMORY_ static void UniversalPrintCharArray( const CharType* begin, size_t len, ostream* os) { // The code -- cgit v1.2.3 From 35956659eaaafd4b356acfbabcb48c183d957ff4 Mon Sep 17 00:00:00 2001 From: kosak Date: Wed, 29 Jan 2014 06:34:44 +0000 Subject: Add GTEST_MOVE macro, to support mocking methods with move-only return types. Add GTEST_ATTRIBUTE_NO_SANITIZE_ADDRESS_ --- src/gtest-printers.cc | 3 +++ 1 file changed, 3 insertions(+) (limited to 'src') diff --git a/src/gtest-printers.cc b/src/gtest-printers.cc index 0db5b44a..29c799a5 100644 --- a/src/gtest-printers.cc +++ b/src/gtest-printers.cc @@ -57,6 +57,7 @@ using ::std::ostream; // Prints a segment of bytes in the given object. GTEST_ATTRIBUTE_NO_SANITIZE_MEMORY_ +GTEST_ATTRIBUTE_NO_SANITIZE_ADDRESS_ void PrintByteSegmentInObjectTo(const unsigned char* obj_bytes, size_t start, size_t count, ostream* os) { char text[5] = ""; @@ -254,6 +255,7 @@ void PrintTo(wchar_t wc, ostream* os) { // and may not be NUL-terminated. template GTEST_ATTRIBUTE_NO_SANITIZE_MEMORY_ +GTEST_ATTRIBUTE_NO_SANITIZE_ADDRESS_ static void PrintCharsAsStringTo( const CharType* begin, size_t len, ostream* os) { const char* const kQuoteBegin = sizeof(CharType) == 1 ? "\"" : "L\""; @@ -276,6 +278,7 @@ static void PrintCharsAsStringTo( // 'begin'. CharType must be either char or wchar_t. template GTEST_ATTRIBUTE_NO_SANITIZE_MEMORY_ +GTEST_ATTRIBUTE_NO_SANITIZE_ADDRESS_ static void UniversalPrintCharArray( const CharType* begin, size_t len, ostream* os) { // The code -- cgit v1.2.3 From 134389c0446c786ee1170f7cf60b9ff1dd78d56f Mon Sep 17 00:00:00 2001 From: kosak Date: Wed, 12 Mar 2014 21:03:35 +0000 Subject: Standards compliance changes to fix QNX build. --- src/gtest-port.cc | 1 + src/gtest-printers.cc | 3 ++- 2 files changed, 3 insertions(+), 1 deletion(-) (limited to 'src') diff --git a/src/gtest-port.cc b/src/gtest-port.cc index 0c4df5f2..a43f33d7 100644 --- a/src/gtest-port.cc +++ b/src/gtest-port.cc @@ -53,6 +53,7 @@ #if GTEST_OS_QNX # include +# include # include #endif // GTEST_OS_QNX diff --git a/src/gtest-printers.cc b/src/gtest-printers.cc index 29c799a5..bb794eed 100644 --- a/src/gtest-printers.cc +++ b/src/gtest-printers.cc @@ -45,6 +45,7 @@ #include "gtest/gtest-printers.h" #include #include +#include #include // NOLINT #include #include "gtest/internal/gtest-port.h" @@ -335,7 +336,7 @@ void PrintTo(const wchar_t* s, ostream* os) { *os << "NULL"; } else { *os << ImplicitCast_(s) << " pointing to "; - PrintCharsAsStringTo(s, wcslen(s), os); + PrintCharsAsStringTo(s, std::wcslen(s), os); } } #endif // wchar_t is native -- cgit v1.2.3 From ffea2d604031a8c732cec8f8de9d9f9bcfbbcf70 Mon Sep 17 00:00:00 2001 From: kosak Date: Wed, 12 Mar 2014 22:55:56 +0000 Subject: Add annotations to suppress ThreadSanitizer failures due to gunit/gmock printer. --- src/gtest-printers.cc | 3 +++ 1 file changed, 3 insertions(+) (limited to 'src') diff --git a/src/gtest-printers.cc b/src/gtest-printers.cc index bb794eed..a2df412f 100644 --- a/src/gtest-printers.cc +++ b/src/gtest-printers.cc @@ -59,6 +59,7 @@ using ::std::ostream; // Prints a segment of bytes in the given object. GTEST_ATTRIBUTE_NO_SANITIZE_MEMORY_ GTEST_ATTRIBUTE_NO_SANITIZE_ADDRESS_ +GTEST_ATTRIBUTE_NO_SANITIZE_THREAD_ void PrintByteSegmentInObjectTo(const unsigned char* obj_bytes, size_t start, size_t count, ostream* os) { char text[5] = ""; @@ -257,6 +258,7 @@ void PrintTo(wchar_t wc, ostream* os) { template GTEST_ATTRIBUTE_NO_SANITIZE_MEMORY_ GTEST_ATTRIBUTE_NO_SANITIZE_ADDRESS_ +GTEST_ATTRIBUTE_NO_SANITIZE_THREAD_ static void PrintCharsAsStringTo( const CharType* begin, size_t len, ostream* os) { const char* const kQuoteBegin = sizeof(CharType) == 1 ? "\"" : "L\""; @@ -280,6 +282,7 @@ static void PrintCharsAsStringTo( template GTEST_ATTRIBUTE_NO_SANITIZE_MEMORY_ GTEST_ATTRIBUTE_NO_SANITIZE_ADDRESS_ +GTEST_ATTRIBUTE_NO_SANITIZE_THREAD_ static void UniversalPrintCharArray( const CharType* begin, size_t len, ostream* os) { // The code -- cgit v1.2.3 From a6340420b9cee27f77c5b91bea807121914a5831 Mon Sep 17 00:00:00 2001 From: kosak Date: Mon, 24 Mar 2014 21:58:25 +0000 Subject: Implement threading support for gtest on Windows. Also, stop using localtime(). Instead, use localtime_r() on most systems, localtime_s() on Windows. --- src/gtest-internal-inl.h | 26 ---- src/gtest-port.cc | 391 ++++++++++++++++++++++++++++++++++++++++++++++- src/gtest.cc | 26 ++-- 3 files changed, 398 insertions(+), 45 deletions(-) (limited to 'src') diff --git a/src/gtest-internal-inl.h b/src/gtest-internal-inl.h index 35df303c..41fadb10 100644 --- a/src/gtest-internal-inl.h +++ b/src/gtest-internal-inl.h @@ -968,32 +968,6 @@ GTEST_API_ void ParseGoogleTestFlagsOnly(int* argc, wchar_t** argv); // platform. GTEST_API_ std::string GetLastErrnoDescription(); -# if GTEST_OS_WINDOWS -// Provides leak-safe Windows kernel handle ownership. -class AutoHandle { - public: - AutoHandle() : handle_(INVALID_HANDLE_VALUE) {} - explicit AutoHandle(HANDLE handle) : handle_(handle) {} - - ~AutoHandle() { Reset(); } - - HANDLE Get() const { return handle_; } - void Reset() { Reset(INVALID_HANDLE_VALUE); } - void Reset(HANDLE handle) { - if (handle != handle_) { - if (handle_ != INVALID_HANDLE_VALUE) - ::CloseHandle(handle_); - handle_ = handle; - } - } - - private: - HANDLE handle_; - - GTEST_DISALLOW_COPY_AND_ASSIGN_(AutoHandle); -}; -# endif // GTEST_OS_WINDOWS - // Attempts to parse a string into a positive integer pointed to by the // number parameter. Returns true if that is possible. // GTEST_HAS_DEATH_TEST implies that we have ::std::string, so we can use diff --git a/src/gtest-port.cc b/src/gtest-port.cc index a43f33d7..0d06d6b5 100644 --- a/src/gtest-port.cc +++ b/src/gtest-port.cc @@ -36,14 +36,14 @@ #include #include -#if GTEST_OS_WINDOWS_MOBILE -# include // For TerminateProcess() -#elif GTEST_OS_WINDOWS +#if GTEST_OS_WINDOWS +# include # include # include +# include // Used in ThreadLocal. #else # include -#endif // GTEST_OS_WINDOWS_MOBILE +#endif // GTEST_OS_WINDOWS #if GTEST_OS_MAC # include @@ -134,6 +134,389 @@ size_t GetThreadCount() { #endif // GTEST_OS_MAC +#if GTEST_IS_THREADSAFE && GTEST_OS_WINDOWS + +void SleepMilliseconds(int n) { + ::Sleep(n); +} + +AutoHandle::AutoHandle() + : handle_(INVALID_HANDLE_VALUE) {} + +AutoHandle::AutoHandle(Handle handle) + : handle_(handle) {} + +AutoHandle::~AutoHandle() { + Reset(); +} + +AutoHandle::Handle AutoHandle::Get() const { + return handle_; +} + +void AutoHandle::Reset() { + Reset(INVALID_HANDLE_VALUE); +} + +void AutoHandle::Reset(HANDLE handle) { + // Resetting with the same handle we already own is invalid. + if (handle_ != handle) { + if (IsCloseable()) { + ::CloseHandle(handle_); + } + handle_ = handle; + } else { + GTEST_CHECK_(!IsCloseable()) + << "Resetting a valid handle to itself is likely a programmer error " + "and thus not allowed."; + } +} + +bool AutoHandle::IsCloseable() const { + // Different Windows APIs may use either of these values to represent an + // invalid handle. + return handle_ != NULL && handle_ != INVALID_HANDLE_VALUE; +} + +Notification::Notification() + : event_(::CreateEvent(NULL, // Default security attributes. + TRUE, // Do not reset automatically. + FALSE, // Initially unset. + NULL)) { // Anonymous event. + GTEST_CHECK_(event_.Get() != NULL); +} + +void Notification::Notify() { + GTEST_CHECK_(::SetEvent(event_.Get()) != FALSE); +} + +void Notification::WaitForNotification() { + GTEST_CHECK_( + ::WaitForSingleObject(event_.Get(), INFINITE) == WAIT_OBJECT_0); +} + +Mutex::Mutex() + : type_(kDynamic), + owner_thread_id_(0), + critical_section_init_phase_(0), + critical_section_(new CRITICAL_SECTION) { + ::InitializeCriticalSection(critical_section_); +} + +Mutex::~Mutex() { + // Static mutexes are leaked intentionally. It is not thread-safe to try + // to clean them up. + // TODO(yukawa): Switch to Slim Reader/Writer (SRW) Locks, which requires + // nothing to clean it up but is available only on Vista and later. + // http://msdn.microsoft.com/en-us/library/windows/desktop/aa904937.aspx + if (type_ == kDynamic) { + ::DeleteCriticalSection(critical_section_); + delete critical_section_; + critical_section_ = NULL; + } +} + +void Mutex::Lock() { + ThreadSafeLazyInit(); + ::EnterCriticalSection(critical_section_); + owner_thread_id_ = ::GetCurrentThreadId(); +} + +void Mutex::Unlock() { + ThreadSafeLazyInit(); + // We don't protect writing to owner_thread_id_ here, as it's the + // caller's responsibility to ensure that the current thread holds the + // mutex when this is called. + owner_thread_id_ = 0; + ::LeaveCriticalSection(critical_section_); +} + +// Does nothing if the current thread holds the mutex. Otherwise, crashes +// with high probability. +void Mutex::AssertHeld() { + ThreadSafeLazyInit(); + GTEST_CHECK_(owner_thread_id_ == ::GetCurrentThreadId()) + << "The current thread is not holding the mutex @" << this; +} + +// Initializes owner_thread_id_ and critical_section_ in static mutexes. +void Mutex::ThreadSafeLazyInit() { + // Dynamic mutexes are initialized in the constructor. + if (type_ == kStatic) { + switch ( + ::InterlockedCompareExchange(&critical_section_init_phase_, 1L, 0L)) { + case 0: + // If critical_section_init_phase_ was 0 before the exchange, we + // are the first to test it and need to perform the initialization. + owner_thread_id_ = 0; + critical_section_ = new CRITICAL_SECTION; + ::InitializeCriticalSection(critical_section_); + // Updates the critical_section_init_phase_ to 2 to signal + // initialization complete. + GTEST_CHECK_(::InterlockedCompareExchange( + &critical_section_init_phase_, 2L, 1L) == + 1L); + break; + case 1: + // Somebody else is already initializing the mutex; spin until they + // are done. + while (::InterlockedCompareExchange(&critical_section_init_phase_, + 2L, + 2L) != 2L) { + // Possibly yields the rest of the thread's time slice to other + // threads. + ::Sleep(0); + } + break; + + case 2: + break; // The mutex is already initialized and ready for use. + + default: + GTEST_CHECK_(false) + << "Unexpected value of critical_section_init_phase_ " + << "while initializing a static mutex."; + } + } +} + +namespace { + +class ThreadWithParamSupport : public ThreadWithParamBase { + public: + static HANDLE CreateThread(Runnable* runnable, + Notification* thread_can_start) { + ThreadMainParam* param = new ThreadMainParam(runnable, thread_can_start); + DWORD thread_id; + // TODO(yukawa): Consider to use _beginthreadex instead. + HANDLE thread_handle = ::CreateThread( + NULL, // Default security. + 0, // Default stack size. + &ThreadWithParamSupport::ThreadMain, + param, // Parameter to ThreadMainStatic + 0x0, // Default creation flags. + &thread_id); // Need a valid pointer for the call to work under Win98. + GTEST_CHECK_(thread_handle != NULL) << "CreateThread failed with error " + << ::GetLastError() << "."; + if (thread_handle == NULL) { + delete param; + } + return thread_handle; + } + + private: + struct ThreadMainParam { + ThreadMainParam(Runnable* runnable, Notification* thread_can_start) + : runnable_(runnable), + thread_can_start_(thread_can_start) { + } + scoped_ptr runnable_; + // Does not own. + Notification* thread_can_start_; + }; + + static DWORD WINAPI ThreadMain(void* ptr) { + // Transfers ownership. + scoped_ptr param(static_cast(ptr)); + if (param->thread_can_start_ != NULL) + param->thread_can_start_->WaitForNotification(); + param->runnable_->Run(); + return 0; + } + + // Prohibit instantiation. + ThreadWithParamSupport(); + + GTEST_DISALLOW_COPY_AND_ASSIGN_(ThreadWithParamSupport); +}; + +} // namespace + +ThreadWithParamBase::ThreadWithParamBase(Runnable *runnable, + Notification* thread_can_start) + : thread_(ThreadWithParamSupport::CreateThread(runnable, + thread_can_start)) { +} + +ThreadWithParamBase::~ThreadWithParamBase() { + Join(); +} + +void ThreadWithParamBase::Join() { + GTEST_CHECK_(::WaitForSingleObject(thread_.Get(), INFINITE) == WAIT_OBJECT_0) + << "Failed to join the thread with error " << ::GetLastError() << "."; +} + +// Maps a thread to a set of ThreadIdToThreadLocals that have values +// instantiated on that thread and notifies them when the thread exits. A +// ThreadLocal instance is expected to persist until all threads it has +// values on have terminated. +class ThreadLocalRegistryImpl { + public: + // Registers thread_local_instance as having value on the current thread. + // Returns a value that can be used to identify the thread from other threads. + static ThreadLocalValueHolderBase* GetValueOnCurrentThread( + const ThreadLocalBase* thread_local_instance) { + DWORD current_thread = ::GetCurrentThreadId(); + MutexLock lock(&mutex_); + ThreadIdToThreadLocals* const thread_to_thread_locals = + GetThreadLocalsMapLocked(); + ThreadIdToThreadLocals::iterator thread_local_pos = + thread_to_thread_locals->find(current_thread); + if (thread_local_pos == thread_to_thread_locals->end()) { + thread_local_pos = thread_to_thread_locals->insert( + std::make_pair(current_thread, ThreadLocalValues())).first; + StartWatcherThreadFor(current_thread); + } + ThreadLocalValues& thread_local_values = thread_local_pos->second; + ThreadLocalValues::iterator value_pos = + thread_local_values.find(thread_local_instance); + if (value_pos == thread_local_values.end()) { + value_pos = + thread_local_values + .insert(std::make_pair( + thread_local_instance, + linked_ptr( + thread_local_instance->NewValueForCurrentThread()))) + .first; + } + return value_pos->second.get(); + } + + static void OnThreadLocalDestroyed( + const ThreadLocalBase* thread_local_instance) { + std::vector > value_holders; + // Clean up the ThreadLocalValues data structure while holding the lock, but + // defer the destruction of the ThreadLocalValueHolderBases. + { + MutexLock lock(&mutex_); + ThreadIdToThreadLocals* const thread_to_thread_locals = + GetThreadLocalsMapLocked(); + for (ThreadIdToThreadLocals::iterator it = + thread_to_thread_locals->begin(); + it != thread_to_thread_locals->end(); + ++it) { + ThreadLocalValues& thread_local_values = it->second; + ThreadLocalValues::iterator value_pos = + thread_local_values.find(thread_local_instance); + if (value_pos != thread_local_values.end()) { + value_holders.push_back(value_pos->second); + thread_local_values.erase(value_pos); + // This 'if' can only be successful at most once, so theoretically we + // could break out of the loop here, but we don't bother doing so. + } + } + } + // Outside the lock, let the destructor for 'value_holders' deallocate the + // ThreadLocalValueHolderBases. + } + + static void OnThreadExit(DWORD thread_id) { + GTEST_CHECK_(thread_id != 0) << ::GetLastError(); + std::vector > value_holders; + // Clean up the ThreadIdToThreadLocals data structure while holding the + // lock, but defer the destruction of the ThreadLocalValueHolderBases. + { + MutexLock lock(&mutex_); + ThreadIdToThreadLocals* const thread_to_thread_locals = + GetThreadLocalsMapLocked(); + ThreadIdToThreadLocals::iterator thread_local_pos = + thread_to_thread_locals->find(thread_id); + if (thread_local_pos != thread_to_thread_locals->end()) { + ThreadLocalValues& thread_local_values = thread_local_pos->second; + for (ThreadLocalValues::iterator value_pos = + thread_local_values.begin(); + value_pos != thread_local_values.end(); + ++value_pos) { + value_holders.push_back(value_pos->second); + } + thread_to_thread_locals->erase(thread_local_pos); + } + } + // Outside the lock, let the destructor for 'value_holders' deallocate the + // ThreadLocalValueHolderBases. + } + + private: + // In a particular thread, maps a ThreadLocal object to its value. + typedef std::map > ThreadLocalValues; + // Stores all ThreadIdToThreadLocals having values in a thread, indexed by + // thread's ID. + typedef std::map ThreadIdToThreadLocals; + + // Holds the thread id and thread handle that we pass from + // StartWatcherThreadFor to WatcherThreadFunc. + typedef std::pair ThreadIdAndHandle; + + static void StartWatcherThreadFor(DWORD thread_id) { + // The returned handle will be kept in thread_map and closed by + // watcher_thread in WatcherThreadFunc. + HANDLE thread = ::OpenThread(SYNCHRONIZE | THREAD_QUERY_INFORMATION, + FALSE, + thread_id); + GTEST_CHECK_(thread != NULL); + // We need to to pass a valid thread ID pointer into CreateThread for it + // to work correctly under Win98. + DWORD watcher_thread_id; + HANDLE watcher_thread = ::CreateThread( + NULL, // Default security. + 0, // Default stack size + &ThreadLocalRegistryImpl::WatcherThreadFunc, + reinterpret_cast(new ThreadIdAndHandle(thread_id, thread)), + CREATE_SUSPENDED, + &watcher_thread_id); + GTEST_CHECK_(watcher_thread != NULL); + // Give the watcher thread the same priority as ours to avoid being + // blocked by it. + ::SetThreadPriority(watcher_thread, + ::GetThreadPriority(::GetCurrentThread())); + ::ResumeThread(watcher_thread); + ::CloseHandle(watcher_thread); + } + + // Monitors exit from a given thread and notifies those + // ThreadIdToThreadLocals about thread termination. + static DWORD WINAPI WatcherThreadFunc(LPVOID param) { + const ThreadIdAndHandle* tah = + reinterpret_cast(param); + GTEST_CHECK_( + ::WaitForSingleObject(tah->second, INFINITE) == WAIT_OBJECT_0); + OnThreadExit(tah->first); + ::CloseHandle(tah->second); + delete tah; + return 0; + } + + // Returns map of thread local instances. + static ThreadIdToThreadLocals* GetThreadLocalsMapLocked() { + mutex_.AssertHeld(); + static ThreadIdToThreadLocals* map = new ThreadIdToThreadLocals; + return map; + } + + // Protects access to GetThreadLocalsMapLocked() and its return value. + static Mutex mutex_; + // Protects access to GetThreadMapLocked() and its return value. + static Mutex thread_map_mutex_; +}; + +Mutex ThreadLocalRegistryImpl::mutex_(Mutex::kStaticMutex); +Mutex ThreadLocalRegistryImpl::thread_map_mutex_(Mutex::kStaticMutex); + +ThreadLocalValueHolderBase* ThreadLocalRegistry::GetValueOnCurrentThread( + const ThreadLocalBase* thread_local_instance) { + return ThreadLocalRegistryImpl::GetValueOnCurrentThread( + thread_local_instance); +} + +void ThreadLocalRegistry::OnThreadLocalDestroyed( + const ThreadLocalBase* thread_local_instance) { + ThreadLocalRegistryImpl::OnThreadLocalDestroyed(thread_local_instance); +} + +#endif // GTEST_IS_THREADSAFE && GTEST_OS_WINDOWS + #if GTEST_USES_POSIX_RE // Implements RE. Currently only needed for death tests. diff --git a/src/gtest.cc b/src/gtest.cc index 6de53dd0..3aee9056 100644 --- a/src/gtest.cc +++ b/src/gtest.cc @@ -3219,27 +3219,23 @@ std::string FormatTimeInMillisAsSeconds(TimeInMillis ms) { // 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(ms / 1000); + struct tm time_struct; #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. + if (localtime_s(&time_struct, &seconds) != 0) + return ""; // Invalid ms value #else - const struct tm* const time_struct = localtime(&seconds); // NOLINT -#endif - if (time_struct == NULL) + if (localtime_r(&seconds, &time_struct) == NULL) return ""; // Invalid ms value +#endif // YYYY-MM-DDThh:mm:ss - return StreamableToString(time_struct->tm_year + 1900) + "-" + - String::FormatIntWidth2(time_struct->tm_mon + 1) + "-" + - String::FormatIntWidth2(time_struct->tm_mday) + "T" + - String::FormatIntWidth2(time_struct->tm_hour) + ":" + - String::FormatIntWidth2(time_struct->tm_min) + ":" + - String::FormatIntWidth2(time_struct->tm_sec); + return StreamableToString(time_struct.tm_year + 1900) + "-" + + String::FormatIntWidth2(time_struct.tm_mon + 1) + "-" + + String::FormatIntWidth2(time_struct.tm_mday) + "T" + + String::FormatIntWidth2(time_struct.tm_hour) + ":" + + String::FormatIntWidth2(time_struct.tm_min) + ":" + + String::FormatIntWidth2(time_struct.tm_sec); } // Streams an XML CDATA section, escaping invalid CDATA sequences as needed. -- cgit v1.2.3 From 8120f66c3249e253f03fdb48bee7e528bc038d31 Mon Sep 17 00:00:00 2001 From: billydonahue Date: Thu, 15 May 2014 19:42:15 +0000 Subject: Push upstream to SVN. --- src/gtest-filepath.cc | 2 +- src/gtest-port.cc | 9 ++------- src/gtest.cc | 43 +++++++++++++++++++------------------------ 3 files changed, 22 insertions(+), 32 deletions(-) (limited to 'src') diff --git a/src/gtest-filepath.cc b/src/gtest-filepath.cc index d221cfde..219875cc 100644 --- a/src/gtest-filepath.cc +++ b/src/gtest-filepath.cc @@ -97,7 +97,7 @@ static bool IsPathSeparator(char c) { // Returns the current working directory, or "" if unsuccessful. FilePath FilePath::GetCurrentDir() { -#if GTEST_OS_WINDOWS_MOBILE +#if GTEST_OS_WINDOWS_MOBILE || GTEST_OS_WINDOWS_PHONE || GTEST_OS_WINDOWS_RT // Windows CE doesn't have a current directory, so we just return // something reasonable. return FilePath(kCurrentDirectoryString); diff --git a/src/gtest-port.cc b/src/gtest-port.cc index 0d06d6b5..39e70bb0 100644 --- a/src/gtest-port.cc +++ b/src/gtest-port.cc @@ -886,10 +886,7 @@ GTestLog::~GTestLog() { } // Disable Microsoft deprecation warnings for POSIX functions called from // this class (creat, dup, dup2, and close) -#ifdef _MSC_VER -# pragma warning(push) -# pragma warning(disable: 4996) -#endif // _MSC_VER +GTEST_DISABLE_MSC_WARNINGS_PUSH_(4996) #if GTEST_HAS_STREAM_REDIRECTION @@ -1008,9 +1005,7 @@ std::string CapturedStream::ReadEntireFile(FILE* file) { return content; } -# ifdef _MSC_VER -# pragma warning(pop) -# endif // _MSC_VER +GTEST_DISABLE_MSC_WARNINGS_POP_() static CapturedStream* g_captured_stderr = NULL; static CapturedStream* g_captured_stdout = NULL; diff --git a/src/gtest.cc b/src/gtest.cc index 3aee9056..408e6f2c 100644 --- a/src/gtest.cc +++ b/src/gtest.cc @@ -802,21 +802,13 @@ TimeInMillis GetTimeInMillis() { #elif GTEST_OS_WINDOWS && !GTEST_HAS_GETTIMEOFDAY_ __timeb64 now; -# ifdef _MSC_VER - // MSVC 8 deprecates _ftime64(), so we want to suppress warning 4996 // (deprecated function) there. // TODO(kenton@google.com): Use GetTickCount()? Or use // SystemTimeToFileTime() -# pragma warning(push) // Saves the current warning state. -# pragma warning(disable:4996) // Temporarily disables warning 4996. - _ftime64(&now); -# pragma warning(pop) // Restores the warning state. -# else - + GTEST_DISABLE_MSC_WARNINGS_PUSH_(4996) _ftime64(&now); - -# endif // _MSC_VER + GTEST_DISABLE_MSC_WARNINGS_POP_() return static_cast(now.time) * 1000 + now.millitm; #elif GTEST_HAS_GETTIMEOFDAY_ @@ -956,6 +948,13 @@ AssertionResult::AssertionResult(const AssertionResult& other) static_cast< ::std::string*>(NULL)) { } +// Swaps two AssertionResults. +void AssertionResult::swap(AssertionResult& other) { + using std::swap; + swap(success_, other.success_); + swap(message_, other.message_); +} + // Returns the assertion's negation. Used with EXPECT/ASSERT_FALSE. AssertionResult AssertionResult::operator!() const { AssertionResult negation(!success_); @@ -2554,7 +2553,8 @@ enum GTestColor { COLOR_YELLOW }; -#if GTEST_OS_WINDOWS && !GTEST_OS_WINDOWS_MOBILE +#if GTEST_OS_WINDOWS && !GTEST_OS_WINDOWS_MOBILE && \ + !GTEST_OS_WINDOWS_PHONE && !GTEST_OS_WINDOWS_RT // Returns the character attribute for the given color. WORD GetColorAttribute(GTestColor color) { @@ -2622,7 +2622,8 @@ void ColoredPrintf(GTestColor color, const char* fmt, ...) { va_list args; va_start(args, fmt); -#if GTEST_OS_WINDOWS_MOBILE || GTEST_OS_SYMBIAN || GTEST_OS_ZOS || GTEST_OS_IOS +#if GTEST_OS_WINDOWS_MOBILE || GTEST_OS_SYMBIAN || GTEST_OS_ZOS || \ + GTEST_OS_IOS || GTEST_OS_WINDOWS_PHONE || GTEST_OS_WINDOWS_RT const bool use_color = false; #else static const bool in_color_mode = @@ -2637,7 +2638,8 @@ void ColoredPrintf(GTestColor color, const char* fmt, ...) { return; } -#if GTEST_OS_WINDOWS && !GTEST_OS_WINDOWS_MOBILE +#if GTEST_OS_WINDOWS && !GTEST_OS_WINDOWS_MOBILE && \ + !GTEST_OS_WINDOWS_PHONE && !GTEST_OS_WINDOWS_RT const HANDLE stdout_handle = GetStdHandle(STD_OUTPUT_HANDLE); // Gets the current text color. @@ -3808,7 +3810,7 @@ void UnitTest::AddTestPartResult( // with another testing framework) and specify the former on the // command line for debugging. if (GTEST_FLAG(break_on_failure)) { -#if GTEST_OS_WINDOWS +#if GTEST_OS_WINDOWS && !GTEST_OS_WINDOWS_PHONE && !GTEST_OS_WINDOWS_RT // Using DebugBreak on Windows allows gtest to still break into a debugger // when a failure happens and both the --gtest_break_on_failure and // the --gtest_catch_exceptions flags are specified. @@ -3886,7 +3888,7 @@ int UnitTest::Run() { // process. In either case the user does not want to see pop-up dialogs // about crashes - they are expected. if (impl()->catch_exceptions() || in_death_test_child_process) { -# if !GTEST_OS_WINDOWS_MOBILE +# if !GTEST_OS_WINDOWS_MOBILE && !GTEST_OS_WINDOWS_PHONE && !GTEST_OS_WINDOWS_RT // SetErrorMode doesn't exist on CE. SetErrorMode(SEM_FAILCRITICALERRORS | SEM_NOALIGNMENTFAULTEXCEPT | SEM_NOGPFAULTERRORBOX | SEM_NOOPENFILEERRORBOX); @@ -3989,17 +3991,10 @@ namespace internal { UnitTestImpl::UnitTestImpl(UnitTest* parent) : parent_(parent), -#ifdef _MSC_VER -# pragma warning(push) // Saves the current warning state. -# pragma warning(disable:4355) // Temporarily disables warning 4355 - // (using this in initializer). - default_global_test_part_result_reporter_(this), - default_per_thread_test_part_result_reporter_(this), -# pragma warning(pop) // Restores the warning state again. -#else + GTEST_DISABLE_MSC_WARNINGS_PUSH_(4355 /* using this in initializer */) default_global_test_part_result_reporter_(this), default_per_thread_test_part_result_reporter_(this), -#endif // _MSC_VER + GTEST_DISABLE_MSC_WARNINGS_POP_() global_test_part_result_repoter_( &default_global_test_part_result_reporter_), per_thread_test_part_result_reporter_( -- cgit v1.2.3 From 21ee8a2e72871ca50148657bc217e9b838dcd903 Mon Sep 17 00:00:00 2001 From: kosak Date: Tue, 17 Jun 2014 23:16:37 +0000 Subject: Disable asan instrumentation for StackGrowsDown(). --- src/gtest-death-test.cc | 2 ++ 1 file changed, 2 insertions(+) (limited to 'src') diff --git a/src/gtest-death-test.cc b/src/gtest-death-test.cc index a6023fce..69fe7c1b 100644 --- a/src/gtest-death-test.cc +++ b/src/gtest-death-test.cc @@ -985,6 +985,8 @@ void StackLowerThanAddress(const void* ptr, bool* result) { *result = (&dummy < ptr); } +// Make sure AddressSanitizer does not tamper with the stack here. +GTEST_ATTRIBUTE_NO_SANITIZE_ADDRESS_ bool StackGrowsDown() { int dummy; bool result; -- cgit v1.2.3 From 96ddffe8fdabccb10fb693a54dcb88bd5b71bc09 Mon Sep 17 00:00:00 2001 From: kosak Date: Wed, 18 Jun 2014 00:22:42 +0000 Subject: Reduce the number of occurrences of gendered pronouns in gtest. --- src/gtest-death-test.cc | 6 +++--- src/gtest-internal-inl.h | 2 +- src/gtest-port.cc | 6 +++--- src/gtest-test-part.cc | 6 +++--- src/gtest.cc | 8 ++++---- 5 files changed, 14 insertions(+), 14 deletions(-) (limited to 'src') diff --git a/src/gtest-death-test.cc b/src/gtest-death-test.cc index 69fe7c1b..a0a8c7ba 100644 --- a/src/gtest-death-test.cc +++ b/src/gtest-death-test.cc @@ -68,9 +68,9 @@ // 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. +// included, or there will be a compiler error. This trick exists to +// prevent the accidental inclusion of gtest-internal-inl.h in the +// user's code. #define GTEST_IMPLEMENTATION_ 1 #include "src/gtest-internal-inl.h" #undef GTEST_IMPLEMENTATION_ diff --git a/src/gtest-internal-inl.h b/src/gtest-internal-inl.h index 41fadb10..0ac7a109 100644 --- a/src/gtest-internal-inl.h +++ b/src/gtest-internal-inl.h @@ -40,7 +40,7 @@ // GTEST_IMPLEMENTATION_ is defined to 1 iff the current translation unit is // part of Google Test's implementation; otherwise it's undefined. #if !GTEST_IMPLEMENTATION_ -// A user is trying to include this from his code - just say no. +// If this file is included from the user's code, just say no. # error "gtest-internal-inl.h is part of Google Test's internal implementation." # error "It must not be included except by Google Test itself." #endif // GTEST_IMPLEMENTATION_ diff --git a/src/gtest-port.cc b/src/gtest-port.cc index 39e70bb0..b032745b 100644 --- a/src/gtest-port.cc +++ b/src/gtest-port.cc @@ -64,9 +64,9 @@ // 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. +// included, or there will be a compiler error. This trick exists to +// prevent the accidental inclusion of gtest-internal-inl.h in the +// user's code. #define GTEST_IMPLEMENTATION_ 1 #include "src/gtest-internal-inl.h" #undef GTEST_IMPLEMENTATION_ diff --git a/src/gtest-test-part.cc b/src/gtest-test-part.cc index c60eef3a..fb0e3542 100644 --- a/src/gtest-test-part.cc +++ b/src/gtest-test-part.cc @@ -35,9 +35,9 @@ // 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. +// included, or there will be a compiler error. This trick exists to +// prevent the accidental inclusion of gtest-internal-inl.h in the +// user's code. #define GTEST_IMPLEMENTATION_ 1 #include "src/gtest-internal-inl.h" #undef GTEST_IMPLEMENTATION_ diff --git a/src/gtest.cc b/src/gtest.cc index 408e6f2c..ca3596eb 100644 --- a/src/gtest.cc +++ b/src/gtest.cc @@ -1962,8 +1962,8 @@ bool Test::HasSameFixtureClass() { const bool this_is_TEST = this_fixture_id == internal::GetTestTypeId(); if (first_is_TEST || this_is_TEST) { - // The user mixed TEST and TEST_F in this test case - we'll tell - // him/her how to fix it. + // Both TEST and TEST_F appear in same test case, which is incorrect. + // Tell the user how to fix this. // Gets the name of the TEST and the name of the TEST_F. Note // that first_is_TEST and this_is_TEST cannot both be true, as @@ -1983,8 +1983,8 @@ bool Test::HasSameFixtureClass() { << "want to change the TEST to TEST_F or move it to another test\n" << "case."; } else { - // The user defined two fixture classes with the same name in - // two namespaces - we'll tell him/her how to fix it. + // Two fixture classes with the same name appear in two different + // namespaces, which is not allowed. Tell the user how to fix this. ADD_FAILURE() << "All tests in the same test case must use the same test fixture\n" << "class. However, in test case " -- cgit v1.2.3 From b54098a9abade957ab3c4e94ae5e5225ef0015a4 Mon Sep 17 00:00:00 2001 From: kosak Date: Mon, 28 Jul 2014 21:54:50 +0000 Subject: Expand equality failure messages with a by-line diff. --- src/gtest.cc | 285 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 285 insertions(+) (limited to 'src') diff --git a/src/gtest.cc b/src/gtest.cc index ca3596eb..e4f3df3e 100644 --- a/src/gtest.cc +++ b/src/gtest.cc @@ -46,6 +46,8 @@ #include #include #include +#include +#include #include // NOLINT #include #include @@ -80,6 +82,7 @@ #elif GTEST_OS_WINDOWS_MOBILE // We are on Windows CE. # include // NOLINT +# undef min #elif GTEST_OS_WINDOWS // We are on Windows proper. @@ -102,6 +105,7 @@ // cpplint thinks that the header is already included, so we want to // silence it. # include // NOLINT +# undef min #else @@ -981,6 +985,276 @@ AssertionResult AssertionFailure(const Message& message) { namespace internal { +namespace edit_distance { +std::vector CalculateOptimalEdits(const std::vector& left, + const std::vector& right) { + std::vector > costs( + left.size() + 1, std::vector(right.size() + 1)); + std::vector > best_move( + left.size() + 1, std::vector(right.size() + 1)); + + // Populate for empty right. + for (size_t l_i = 0; l_i < costs.size(); ++l_i) { + costs[l_i][0] = static_cast(l_i); + best_move[l_i][0] = kRemove; + } + // Populate for empty left. + for (size_t r_i = 1; r_i < costs[0].size(); ++r_i) { + costs[0][r_i] = static_cast(r_i); + best_move[0][r_i] = kAdd; + } + + for (size_t l_i = 0; l_i < left.size(); ++l_i) { + for (size_t r_i = 0; r_i < right.size(); ++r_i) { + if (left[l_i] == right[r_i]) { + // Found a match. Consume it. + costs[l_i + 1][r_i + 1] = costs[l_i][r_i]; + best_move[l_i + 1][r_i + 1] = kMatch; + continue; + } + + const double add = costs[l_i + 1][r_i]; + const double remove = costs[l_i][r_i + 1]; + const double replace = costs[l_i][r_i]; + if (add < remove && add < replace) { + costs[l_i + 1][r_i + 1] = add + 1; + best_move[l_i + 1][r_i + 1] = kAdd; + } else if (remove < add && remove < replace) { + costs[l_i + 1][r_i + 1] = remove + 1; + best_move[l_i + 1][r_i + 1] = kRemove; + } else { + // We make replace a little more expensive than add/remove to lower + // their priority. + costs[l_i + 1][r_i + 1] = replace + 1.00001; + best_move[l_i + 1][r_i + 1] = kReplace; + } + } + } + + // Reconstruct the best path. We do it in reverse order. + std::vector best_path; + for (size_t l_i = left.size(), r_i = right.size(); l_i > 0 || r_i > 0;) { + EditType move = best_move[l_i][r_i]; + best_path.push_back(move); + l_i -= move != kAdd; + r_i -= move != kRemove; + } + std::reverse(best_path.begin(), best_path.end()); + return best_path; +} + +namespace { + +// Helper class to convert string into ids with deduplication. +class InternalStrings { + public: + size_t GetId(const std::string& str) { + IdMap::iterator it = ids_.find(str); + if (it != ids_.end()) return it->second; + size_t id = ids_.size(); + return ids_[str] = id; + } + + private: + typedef std::map IdMap; + IdMap ids_; +}; + +} // namespace + +std::vector CalculateOptimalEdits( + const std::vector& left, + const std::vector& right) { + std::vector left_ids, right_ids; + { + InternalStrings intern_table; + for (size_t i = 0; i < left.size(); ++i) { + left_ids.push_back(intern_table.GetId(left[i])); + } + for (size_t i = 0; i < right.size(); ++i) { + right_ids.push_back(intern_table.GetId(right[i])); + } + } + return CalculateOptimalEdits(left_ids, right_ids); +} + +namespace { + +// Helper class that holds the state for one hunk and prints it out to the +// stream. +// It reorders adds/removes when possible to group all removes before all +// adds. It also adds the hunk header before printint into the stream. +class Hunk { + public: + Hunk(size_t left_start, size_t right_start) + : left_start_(left_start), + right_start_(right_start), + adds_(), + removes_(), + common_() {} + + void PushLine(char edit, const char* line) { + switch (edit) { + case ' ': + ++common_; + FlushEdits(); + hunk_.push_back(std::make_pair(' ', line)); + break; + case '-': + ++removes_; + hunk_removes_.push_back(std::make_pair('-', line)); + break; + case '+': + ++adds_; + hunk_adds_.push_back(std::make_pair('+', line)); + break; + } + } + + void PrintTo(std::ostream* os) { + PrintHeader(os); + FlushEdits(); + for (std::list >::const_iterator it = + hunk_.begin(); + it != hunk_.end(); ++it) { + *os << it->first << it->second << "\n"; + } + } + + bool has_edits() const { return adds_ || removes_; } + + private: + void FlushEdits() { + hunk_.splice(hunk_.end(), hunk_removes_); + hunk_.splice(hunk_.end(), hunk_adds_); + } + + // Print a unified diff header for one hunk. + // The format is + // "@@ -, +, @@" + // where the left/right parts are ommitted if unnecessary. + void PrintHeader(std::ostream* ss) const { + *ss << "@@ "; + if (removes_) { + *ss << "-" << left_start_ << "," << (removes_ + common_); + } + if (removes_ && adds_) { + *ss << " "; + } + if (adds_) { + *ss << "+" << right_start_ << "," << (adds_ + common_); + } + *ss << " @@\n"; + } + + size_t left_start_, right_start_; + size_t adds_, removes_, common_; + std::list > hunk_, hunk_adds_, hunk_removes_; +}; + +} // namespace + +// Create a list of diff hunks in Unified diff format. +// Each hunk has a header generated by PrintHeader above plus a body with +// lines prefixed with ' ' for no change, '-' for deletion and '+' for +// addition. +// 'context' represents the desired unchanged prefix/suffix around the diff. +// If two hunks are close enough that their contexts overlap, then they are +// joined into one hunk. +std::string CreateUnifiedDiff(const std::vector& left, + const std::vector& right, + size_t context) { + const std::vector edits = CalculateOptimalEdits(left, right); + + size_t l_i = 0, r_i = 0, edit_i = 0; + std::stringstream ss; + while (edit_i < edits.size()) { + // Find first edit. + while (edit_i < edits.size() && edits[edit_i] == kMatch) { + ++l_i; + ++r_i; + ++edit_i; + } + + // Find the first line to include in the hunk. + const size_t prefix_context = std::min(l_i, context); + Hunk hunk(l_i - prefix_context + 1, r_i - prefix_context + 1); + for (size_t i = prefix_context; i > 0; --i) { + hunk.PushLine(' ', left[l_i - i].c_str()); + } + + // Iterate the edits until we found enough suffix for the hunk or the input + // is over. + size_t n_suffix = 0; + for (; edit_i < edits.size(); ++edit_i) { + if (n_suffix >= context) { + // Continue only if the next hunk is very close. + std::vector::const_iterator it = edits.begin() + edit_i; + while (it != edits.end() && *it == kMatch) ++it; + if (it == edits.end() || (it - edits.begin()) - edit_i >= context) { + // There is no next edit or it is too far away. + break; + } + } + + EditType edit = edits[edit_i]; + // Reset count when a non match is found. + n_suffix = edit == kMatch ? n_suffix + 1 : 0; + + if (edit == kMatch || edit == kRemove || edit == kReplace) { + hunk.PushLine(edit == kMatch ? ' ' : '-', left[l_i].c_str()); + } + if (edit == kAdd || edit == kReplace) { + hunk.PushLine('+', right[r_i].c_str()); + } + + // Advance indices, depending on edit type. + l_i += edit != kAdd; + r_i += edit != kRemove; + } + + if (!hunk.has_edits()) { + // We are done. We don't want this hunk. + break; + } + + hunk.PrintTo(&ss); + } + return ss.str(); +} + +} // namespace edit_distance + +namespace { + +// The string representation of the values received in EqFailure() are already +// escaped. Split them on escaped '\n' boundaries. Leave all other escaped +// characters the same. +std::vector SplitEscapedString(const std::string& str) { + std::vector lines; + size_t start = 0, end = str.size(); + if (end > 2 && str[0] == '"' && str[end - 1] == '"') { + ++start; + --end; + } + bool escaped = false; + for (size_t i = start; i + 1 < end; ++i) { + if (escaped) { + escaped = false; + if (str[i] == 'n') { + lines.push_back(str.substr(start, i - start - 1)); + start = i + 1; + } + } else { + escaped = str[i] == '\\'; + } + } + lines.push_back(str.substr(start, end - start)); + return lines; +} + +} // namespace + // Constructs and returns the message for an equality assertion // (e.g. ASSERT_EQ, EXPECT_STREQ, etc) failure. // @@ -1015,6 +1289,17 @@ AssertionResult EqFailure(const char* expected_expression, msg << "\nWhich is: " << expected_value; } + if (!expected_value.empty() && !actual_value.empty()) { + const std::vector expected_lines = + SplitEscapedString(expected_value); + const std::vector actual_lines = + SplitEscapedString(actual_value); + if (expected_lines.size() > 1 || actual_lines.size() > 1) { + msg << "\nWith diff:\n" + << edit_distance::CreateUnifiedDiff(expected_lines, actual_lines); + } + } + return AssertionFailure() << msg; } -- cgit v1.2.3 From 64df8e349f20f0552176e146312c589efe754925 Mon Sep 17 00:00:00 2001 From: kosak Date: Tue, 29 Jul 2014 00:30:10 +0000 Subject: Mock out GetCurrentDir in NaCl. --- src/gtest-filepath.cc | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) (limited to 'src') diff --git a/src/gtest-filepath.cc b/src/gtest-filepath.cc index 219875cc..0292dc11 100644 --- a/src/gtest-filepath.cc +++ b/src/gtest-filepath.cc @@ -106,7 +106,14 @@ FilePath FilePath::GetCurrentDir() { return FilePath(_getcwd(cwd, sizeof(cwd)) == NULL ? "" : cwd); #else char cwd[GTEST_PATH_MAX_ + 1] = { '\0' }; - return FilePath(getcwd(cwd, sizeof(cwd)) == NULL ? "" : cwd); + char* result = getcwd(cwd, sizeof(cwd)); +# if GTEST_OS_NACL + // getcwd will likely fail in NaCl due to the sandbox, so return something + // reasonable. The user may have provided a shim implementation for getcwd, + // however, so fallback only when failure is detected. + return FilePath(result == NULL ? kCurrentDirectoryString : cwd); +# endif // GTEST_OS_NACL + return FilePath(result == NULL ? "" : cwd); #endif // GTEST_OS_WINDOWS_MOBILE } -- cgit v1.2.3 From e330b754cbd4b23a160521e05ff1014ed576378b Mon Sep 17 00:00:00 2001 From: kosak Date: Mon, 17 Nov 2014 02:28:09 +0000 Subject: Strip trailing whitespace when stringifying type lists. --- src/gtest-typed-test.cc | 22 +++++++++++++++------- 1 file changed, 15 insertions(+), 7 deletions(-) (limited to 'src') diff --git a/src/gtest-typed-test.cc b/src/gtest-typed-test.cc index f0079f40..e11d050a 100644 --- a/src/gtest-typed-test.cc +++ b/src/gtest-typed-test.cc @@ -45,6 +45,15 @@ static const char* SkipSpaces(const char* str) { return str; } +static std::vector SplitIntoTestNames(const char* src) { + std::vector name_vec; + src = SkipSpaces(src); + for (; src != NULL; src = SkipComma(src)) { + name_vec.push_back(StripTrailingSpaces(GetPrefixUntilComma(src))); + } + return name_vec; +} + // Verifies that registered_tests match the test names in // defined_test_names_; returns registered_tests if successful, or // aborts the program otherwise. @@ -53,15 +62,14 @@ const char* TypedTestCasePState::VerifyRegisteredTestNames( typedef ::std::set::const_iterator DefinedTestIter; registered_ = true; - // Skip initial whitespace in registered_tests since some - // preprocessors prefix stringizied literals with whitespace. - registered_tests = SkipSpaces(registered_tests); + std::vector name_vec = SplitIntoTestNames(registered_tests); Message errors; - ::std::set tests; - for (const char* names = registered_tests; names != NULL; - names = SkipComma(names)) { - const std::string name = GetPrefixUntilComma(names); + + std::set tests; + for (std::vector::const_iterator name_it = name_vec.begin(); + name_it != name_vec.end(); ++name_it) { + const std::string& name = *name_it; if (tests.count(name) != 0) { errors << "Test " << name << " is listed more than once.\n"; continue; -- cgit v1.2.3 From 102b50483a4b515a94a5b1c75db468eb071cf172 Mon Sep 17 00:00:00 2001 From: kosak Date: Mon, 17 Nov 2014 02:56:14 +0000 Subject: Noop changes to suppress compile-time warnings in WINDOWS code paths. --- src/gtest.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src') diff --git a/src/gtest.cc b/src/gtest.cc index e4f3df3e..dc06e022 100644 --- a/src/gtest.cc +++ b/src/gtest.cc @@ -2909,7 +2909,7 @@ void ColoredPrintf(GTestColor color, const char* fmt, ...) { #if GTEST_OS_WINDOWS_MOBILE || GTEST_OS_SYMBIAN || GTEST_OS_ZOS || \ GTEST_OS_IOS || GTEST_OS_WINDOWS_PHONE || GTEST_OS_WINDOWS_RT - const bool use_color = false; + const bool use_color = AlwaysFalse(); #else static const bool in_color_mode = ShouldUseColor(posix::IsATTY(posix::FileNo(stdout)) != 0); -- cgit v1.2.3 From c2101c28771d8abd0f2e057cdbdc26b7a05fad2d Mon Sep 17 00:00:00 2001 From: kosak Date: Thu, 8 Jan 2015 02:35:11 +0000 Subject: Change an example to use 'override' rather than 'virtual'. Add missing headers for 'connect' and 'socket'. --- src/gtest.cc | 2 ++ 1 file changed, 2 insertions(+) (limited to 'src') diff --git a/src/gtest.cc b/src/gtest.cc index dc06e022..64ab7670 100644 --- a/src/gtest.cc +++ b/src/gtest.cc @@ -128,6 +128,8 @@ #if GTEST_CAN_STREAM_RESULTS_ # include // NOLINT # include // NOLINT +# include // NOLINT +# include // NOLINT #endif // Indicates that this translation unit is part of Google Test's -- cgit v1.2.3 From 12ab6bb16fe055087dd64bb41f20a74dd356a5f0 Mon Sep 17 00:00:00 2001 From: kosak Date: Thu, 8 Jan 2015 03:12:18 +0000 Subject: Small Mingw localtime() fix. Thanks tberghammer for pointing it out. https://codereview.appspot.com/185420043/ --- src/gtest.cc | 27 ++++++++++++++++++--------- 1 file changed, 18 insertions(+), 9 deletions(-) (limited to 'src') diff --git a/src/gtest.cc b/src/gtest.cc index 64ab7670..7fd5f298 100644 --- a/src/gtest.cc +++ b/src/gtest.cc @@ -3505,19 +3505,28 @@ std::string FormatTimeInMillisAsSeconds(TimeInMillis ms) { return ss.str(); } +static bool PortableLocaltime(time_t seconds, struct tm* out) { +#if defined(_MSC_VER) + return localtime_s(out, &seconds) == 0; +#elif defined(__MINGW32__) || defined(__MINGW64__) + // MINGW provides neither localtime_r nor localtime_s, but uses + // Windows' localtime(), which has a thread-local tm buffer. + struct tm* tm_ptr = localtime(&seconds); // NOLINT + if (tm_ptr == NULL) + return false; + *out = *tm_ptr; + return true; +#else + return localtime_r(&seconds, out) != NULL; +#endif +} + // 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) { - time_t seconds = static_cast(ms / 1000); struct tm time_struct; -#ifdef _MSC_VER - if (localtime_s(&time_struct, &seconds) != 0) - return ""; // Invalid ms value -#else - if (localtime_r(&seconds, &time_struct) == NULL) - return ""; // Invalid ms value -#endif - + if (!PortableLocaltime(static_cast(ms / 1000), &time_struct)) + return ""; // YYYY-MM-DDThh:mm:ss return StreamableToString(time_struct.tm_year + 1900) + "-" + String::FormatIntWidth2(time_struct.tm_mon + 1) + "-" + -- cgit v1.2.3 From 5c996c64665ff9826100f0f0fb055b7c883277bb Mon Sep 17 00:00:00 2001 From: kosak Date: Tue, 28 Apr 2015 21:43:13 +0000 Subject: Make an int64->double conversion explicit to silence -Wconversion. Addresses issue #173: https://code.google.com/p/googlemock/issues/detail?id=173 --- src/gtest.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src') diff --git a/src/gtest.cc b/src/gtest.cc index 7fd5f298..bcbbf53a 100644 --- a/src/gtest.cc +++ b/src/gtest.cc @@ -3501,7 +3501,7 @@ std::string XmlUnitTestResultPrinter::RemoveInvalidXmlCharacters( // Formats the given time in milliseconds as seconds. std::string FormatTimeInMillisAsSeconds(TimeInMillis ms) { ::std::stringstream ss; - ss << ms/1000.0; + ss << (static_cast(ms) * 1e-3); return ss.str(); } -- cgit v1.2.3 From 1197daf3571161590dce2bc4879512ef7bc1ba67 Mon Sep 17 00:00:00 2001 From: kosak Date: Tue, 28 Apr 2015 22:04:35 +0000 Subject: urxvt supports colors --- src/gtest.cc | 2 ++ 1 file changed, 2 insertions(+) (limited to 'src') diff --git a/src/gtest.cc b/src/gtest.cc index bcbbf53a..8b767074 100644 --- a/src/gtest.cc +++ b/src/gtest.cc @@ -2886,6 +2886,8 @@ bool ShouldUseColor(bool stdout_is_tty) { String::CStringEquals(term, "xterm-256color") || String::CStringEquals(term, "screen") || String::CStringEquals(term, "screen-256color") || + String::CStringEquals(term, "rxvt-unicode") || + String::CStringEquals(term, "rxvt-unicode-256color") || String::CStringEquals(term, "linux") || String::CStringEquals(term, "cygwin"); return stdout_is_tty && term_supports_color; -- cgit v1.2.3 From 38dd7485c0bec2720c75789f26f5d549e9b4a541 Mon Sep 17 00:00:00 2001 From: kosak Date: Tue, 14 Jul 2015 21:49:27 +0000 Subject: Change GetDefaultFilter to allow for the injection of a custom filter. --- src/gtest.cc | 6 ++++++ 1 file changed, 6 insertions(+) (limited to 'src') diff --git a/src/gtest.cc b/src/gtest.cc index 8b767074..6dea6c6a 100644 --- a/src/gtest.cc +++ b/src/gtest.cc @@ -189,6 +189,12 @@ bool g_help_flag = false; } // namespace internal static const char* GetDefaultFilter() { +#ifdef GTEST_TEST_FILTER_ENV_VAR_ + const char* const testbridge_test_only = getenv(GTEST_TEST_FILTER_ENV_VAR_); + if (testbridge_test_only != NULL) { + return testbridge_test_only; + } +#endif // GTEST_TEST_FILTER_ENV_VAR_ return kUniversalFilter; } -- cgit v1.2.3 From 0928adbfea9b7645e884bd95fee23cfd669729cd Mon Sep 17 00:00:00 2001 From: kosak Date: Tue, 14 Jul 2015 22:44:39 +0000 Subject: Move the selection of the flag saver implementation into gtest-port.h and custom/gtest-port.h. --- src/gtest.cc | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) (limited to 'src') diff --git a/src/gtest.cc b/src/gtest.cc index 6dea6c6a..bb00879d 100644 --- a/src/gtest.cc +++ b/src/gtest.cc @@ -2179,14 +2179,15 @@ int TestResult::test_property_count() const { // Creates a Test object. -// The c'tor saves the values of all Google Test flags. +// The c'tor saves the states of all flags. Test::Test() - : gtest_flag_saver_(new internal::GTestFlagSaver) { + : gtest_flag_saver_(new GTEST_FLAG_SAVER_) { } -// The d'tor restores the values of all Google Test flags. +// The d'tor restores the states of all flags. The actual work is +// done by the d'tor of the gtest_flag_saver_ field, and thus not +// visible here. Test::~Test() { - delete gtest_flag_saver_; } // Sets up the test fixture. -- cgit v1.2.3 From 195610d30c2234b76bef70a85426ac8d7dbdf9f3 Mon Sep 17 00:00:00 2001 From: kosak Date: Fri, 17 Jul 2015 21:56:19 +0000 Subject: Add support for --gtest_flagfile --- src/gtest-death-test.cc | 20 -------- src/gtest-internal-inl.h | 1 + src/gtest-port.cc | 80 ++++++++++++++++-------------- src/gtest.cc | 123 +++++++++++++++++++++++++++++++++-------------- 4 files changed, 134 insertions(+), 90 deletions(-) (limited to 'src') diff --git a/src/gtest-death-test.cc b/src/gtest-death-test.cc index a0a8c7ba..b049eb07 100644 --- a/src/gtest-death-test.cc +++ b/src/gtest-death-test.cc @@ -1204,26 +1204,6 @@ bool DefaultDeathTestFactory::Create(const char* statement, const RE* regex, return true; } -// Splits a given string on a given delimiter, populating a given -// vector with the fields. GTEST_HAS_DEATH_TEST implies that we have -// ::std::string, so we can use it here. -static void SplitString(const ::std::string& str, char delimiter, - ::std::vector< ::std::string>* dest) { - ::std::vector< ::std::string> parsed; - ::std::string::size_type pos = 0; - while (::testing::internal::AlwaysTrue()) { - const ::std::string::size_type colon = str.find(delimiter, pos); - if (colon == ::std::string::npos) { - parsed.push_back(str.substr(pos)); - break; - } else { - parsed.push_back(str.substr(pos, colon - pos)); - pos = colon + 1; - } - } - dest->swap(parsed); -} - # if GTEST_OS_WINDOWS // Recreates the pipe and event handles from the provided parameters, // signals the event, and returns a file descriptor wrapped around the pipe diff --git a/src/gtest-internal-inl.h b/src/gtest-internal-inl.h index 0ac7a109..6a7e2533 100644 --- a/src/gtest-internal-inl.h +++ b/src/gtest-internal-inl.h @@ -100,6 +100,7 @@ const char kShuffleFlag[] = "shuffle"; const char kStackTraceDepthFlag[] = "stack_trace_depth"; const char kStreamResultToFlag[] = "stream_result_to"; const char kThrowOnFailureFlag[] = "throw_on_failure"; +const char kFlagfileFlag[] = "flagfile"; // A valid random seed must be in [1, kMaxRandomSeed]. const int kMaxRandomSeed = 99999; diff --git a/src/gtest-port.cc b/src/gtest-port.cc index b032745b..448a807f 100644 --- a/src/gtest-port.cc +++ b/src/gtest-port.cc @@ -962,12 +962,6 @@ class CapturedStream { } private: - // Reads the entire content of a file as an std::string. - static std::string ReadEntireFile(FILE* file); - - // Returns the size (in bytes) of a file. - static size_t GetFileSize(FILE* file); - const int fd_; // A stream to capture. int uncaptured_fd_; // Name of the temporary file holding the stderr output. @@ -976,35 +970,6 @@ class CapturedStream { GTEST_DISALLOW_COPY_AND_ASSIGN_(CapturedStream); }; -// Returns the size (in bytes) of a file. -size_t CapturedStream::GetFileSize(FILE* file) { - fseek(file, 0, SEEK_END); - return static_cast(ftell(file)); -} - -// Reads the entire content of a file as a string. -std::string CapturedStream::ReadEntireFile(FILE* file) { - const size_t file_size = GetFileSize(file); - char* const buffer = new char[file_size]; - - size_t bytes_last_read = 0; // # of bytes read in the last fread() - size_t bytes_read = 0; // # of bytes read so far - - fseek(file, 0, SEEK_SET); - - // Keeps reading the file until we cannot read further or the - // pre-determined file size is reached. - do { - bytes_last_read = fread(buffer+bytes_read, 1, file_size-bytes_read, file); - bytes_read += bytes_last_read; - } while (bytes_last_read > 0 && bytes_read < file_size); - - const std::string content(buffer, bytes_read); - delete[] buffer; - - return content; -} - GTEST_DISABLE_MSC_WARNINGS_POP_() static CapturedStream* g_captured_stderr = NULL; @@ -1051,6 +1016,51 @@ std::string GetCapturedStderr() { #endif // GTEST_HAS_STREAM_REDIRECTION +std::string TempDir() { +#if GTEST_OS_WINDOWS_MOBILE + return "\\temp\\"; +#elif GTEST_OS_WINDOWS + const char* temp_dir = posix::GetEnv("TEMP"); + if (temp_dir == NULL || temp_dir[0] == '\0') + return "\\temp\\"; + else if (temp_dir[strlen(temp_dir) - 1] == '\\') + return temp_dir; + else + return std::string(temp_dir) + "\\"; +#elif GTEST_OS_LINUX_ANDROID + return "/sdcard/"; +#else + return "/tmp/"; +#endif // GTEST_OS_WINDOWS_MOBILE +} + +size_t GetFileSize(FILE* file) { + fseek(file, 0, SEEK_END); + return static_cast(ftell(file)); +} + +std::string ReadEntireFile(FILE* file) { + const size_t file_size = GetFileSize(file); + char* const buffer = new char[file_size]; + + size_t bytes_last_read = 0; // # of bytes read in the last fread() + size_t bytes_read = 0; // # of bytes read so far + + fseek(file, 0, SEEK_SET); + + // Keeps reading the file until we cannot read further or the + // pre-determined file size is reached. + do { + bytes_last_read = fread(buffer+bytes_read, 1, file_size-bytes_read, file); + bytes_read += bytes_last_read; + } while (bytes_last_read > 0 && bytes_read < file_size); + + const std::string content(buffer, bytes_read); + delete[] buffer; + + return content; +} + #if GTEST_HAS_DEATH_TEST // A copy of all command line arguments. Set by InitGoogleTest(). diff --git a/src/gtest.cc b/src/gtest.cc index bb00879d..71784f92 100644 --- a/src/gtest.cc +++ b/src/gtest.cc @@ -295,6 +295,11 @@ GTEST_DEFINE_bool_( "if exceptions are enabled or exit the program with a non-zero code " "otherwise."); +GTEST_DEFINE_string_( + flagfile, + internal::StringFromGTestEnv("flagfile", ""), + "This flag specifies the flagfile to read command-line flags from."); + namespace internal { // Generates a random number from [0, range), using a Linear @@ -905,6 +910,23 @@ static void StreamWideCharsToMessage(const wchar_t* wstr, size_t length, #endif // GTEST_HAS_STD_WSTRING || GTEST_HAS_GLOBAL_WSTRING +void SplitString(const ::std::string& str, char delimiter, + ::std::vector< ::std::string>* dest) { + ::std::vector< ::std::string> parsed; + ::std::string::size_type pos = 0; + while (::testing::internal::AlwaysTrue()) { + const ::std::string::size_type colon = str.find(delimiter, pos); + if (colon == ::std::string::npos) { + parsed.push_back(str.substr(pos)); + break; + } else { + parsed.push_back(str.substr(pos, colon - pos)); + pos = colon + 1; + } + } + dest->swap(parsed); +} + } // namespace internal // Constructs an empty Message. @@ -5178,6 +5200,56 @@ static const char kColorEncodedHelpMessage[] = "(not one in your own code or tests), please report it to\n" "@G<" GTEST_DEV_EMAIL_ ">@D.\n"; +bool ParseGoogleTestFlag(const char* const arg) { + return ParseBoolFlag(arg, kAlsoRunDisabledTestsFlag, + >EST_FLAG(also_run_disabled_tests)) || + ParseBoolFlag(arg, kBreakOnFailureFlag, + >EST_FLAG(break_on_failure)) || + ParseBoolFlag(arg, kCatchExceptionsFlag, + >EST_FLAG(catch_exceptions)) || + ParseStringFlag(arg, kColorFlag, >EST_FLAG(color)) || + ParseStringFlag(arg, kDeathTestStyleFlag, + >EST_FLAG(death_test_style)) || + ParseBoolFlag(arg, kDeathTestUseFork, + >EST_FLAG(death_test_use_fork)) || + ParseStringFlag(arg, kFilterFlag, >EST_FLAG(filter)) || + ParseStringFlag(arg, kInternalRunDeathTestFlag, + >EST_FLAG(internal_run_death_test)) || + ParseBoolFlag(arg, kListTestsFlag, >EST_FLAG(list_tests)) || + ParseStringFlag(arg, kOutputFlag, >EST_FLAG(output)) || + ParseBoolFlag(arg, kPrintTimeFlag, >EST_FLAG(print_time)) || + ParseInt32Flag(arg, kRandomSeedFlag, >EST_FLAG(random_seed)) || + ParseInt32Flag(arg, kRepeatFlag, >EST_FLAG(repeat)) || + ParseBoolFlag(arg, kShuffleFlag, >EST_FLAG(shuffle)) || + ParseInt32Flag(arg, kStackTraceDepthFlag, + >EST_FLAG(stack_trace_depth)) || + ParseStringFlag(arg, kStreamResultToFlag, + >EST_FLAG(stream_result_to)) || + ParseBoolFlag(arg, kThrowOnFailureFlag, + >EST_FLAG(throw_on_failure)); +} + +void LoadFlagsFromFile(const std::string& path) { + FILE* flagfile = posix::FOpen(path.c_str(), "r"); + if (!flagfile) { + fprintf(stderr, + "Unable to open file \"%s\"\n", + GTEST_FLAG(flagfile).c_str()); + fflush(stderr); + exit(EXIT_FAILURE); + } + std::string contents(ReadEntireFile(flagfile)); + posix::FClose(flagfile); + std::vector lines; + SplitString(contents, '\n', &lines); + for (size_t i = 0; i < lines.size(); ++i) { + if (lines[i].empty()) + continue; + if (!ParseGoogleTestFlag(lines[i].c_str())) + g_help_flag = true; + } +} + // Parses the command line for Google Test flags, without initializing // other parts of Google Test. The type parameter CharType can be // instantiated to either char or wchar_t. @@ -5191,35 +5263,22 @@ void ParseGoogleTestFlagsOnlyImpl(int* argc, CharType** argv) { using internal::ParseInt32Flag; using internal::ParseStringFlag; - // Do we see a Google Test flag? - if (ParseBoolFlag(arg, kAlsoRunDisabledTestsFlag, - >EST_FLAG(also_run_disabled_tests)) || - ParseBoolFlag(arg, kBreakOnFailureFlag, - >EST_FLAG(break_on_failure)) || - ParseBoolFlag(arg, kCatchExceptionsFlag, - >EST_FLAG(catch_exceptions)) || - ParseStringFlag(arg, kColorFlag, >EST_FLAG(color)) || - ParseStringFlag(arg, kDeathTestStyleFlag, - >EST_FLAG(death_test_style)) || - ParseBoolFlag(arg, kDeathTestUseFork, - >EST_FLAG(death_test_use_fork)) || - ParseStringFlag(arg, kFilterFlag, >EST_FLAG(filter)) || - ParseStringFlag(arg, kInternalRunDeathTestFlag, - >EST_FLAG(internal_run_death_test)) || - ParseBoolFlag(arg, kListTestsFlag, >EST_FLAG(list_tests)) || - ParseStringFlag(arg, kOutputFlag, >EST_FLAG(output)) || - ParseBoolFlag(arg, kPrintTimeFlag, >EST_FLAG(print_time)) || - ParseInt32Flag(arg, kRandomSeedFlag, >EST_FLAG(random_seed)) || - ParseInt32Flag(arg, kRepeatFlag, >EST_FLAG(repeat)) || - ParseBoolFlag(arg, kShuffleFlag, >EST_FLAG(shuffle)) || - ParseInt32Flag(arg, kStackTraceDepthFlag, - >EST_FLAG(stack_trace_depth)) || - ParseStringFlag(arg, kStreamResultToFlag, - >EST_FLAG(stream_result_to)) || - ParseBoolFlag(arg, kThrowOnFailureFlag, - >EST_FLAG(throw_on_failure)) - ) { - // Yes. Shift the remainder of the argv list left by one. Note + bool remove_flag = false; + if (ParseGoogleTestFlag(arg)) { + remove_flag = true; + } else if (ParseStringFlag(arg, kFlagfileFlag, >EST_FLAG(flagfile))) { + LoadFlagsFromFile(GTEST_FLAG(flagfile)); + remove_flag = true; + } else if (arg_string == "--help" || arg_string == "-h" || + arg_string == "-?" || arg_string == "/?" || + HasGoogleTestFlagPrefix(arg)) { + // Both help flag and unrecognized Google Test flags (excluding + // internal ones) trigger help display. + g_help_flag = true; + } + + if (remove_flag) { + // Shift the remainder of the argv list left by one. Note // that argv has (*argc + 1) elements, the last one always being // NULL. The following loop moves the trailing NULL element as // well. @@ -5233,12 +5292,6 @@ void ParseGoogleTestFlagsOnlyImpl(int* argc, CharType** argv) { // We also need to decrement the iterator as we just removed // an element. i--; - } else if (arg_string == "--help" || arg_string == "-h" || - arg_string == "-?" || arg_string == "/?" || - HasGoogleTestFlagPrefix(arg)) { - // Both help flag and unrecognized Google Test flags (excluding - // internal ones) trigger help display. - g_help_flag = true; } } -- cgit v1.2.3 From 4f8dc917ebce062f75defee3d4890bbcd07e277b Mon Sep 17 00:00:00 2001 From: kosak Date: Fri, 17 Jul 2015 22:11:58 +0000 Subject: Add support for --gtest_flagfile. --- src/gtest-typed-test.cc | 18 +++++++++--------- src/gtest.cc | 12 +++++++++--- 2 files changed, 18 insertions(+), 12 deletions(-) (limited to 'src') diff --git a/src/gtest-typed-test.cc b/src/gtest-typed-test.cc index e11d050a..df1eef47 100644 --- a/src/gtest-typed-test.cc +++ b/src/gtest-typed-test.cc @@ -55,11 +55,11 @@ static std::vector SplitIntoTestNames(const char* src) { } // Verifies that registered_tests match the test names in -// defined_test_names_; returns registered_tests if successful, or +// registered_tests_; returns registered_tests if successful, or // aborts the program otherwise. const char* TypedTestCasePState::VerifyRegisteredTestNames( const char* file, int line, const char* registered_tests) { - typedef ::std::set::const_iterator DefinedTestIter; + typedef RegisteredTestsMap::const_iterator RegisteredTestIter; registered_ = true; std::vector name_vec = SplitIntoTestNames(registered_tests); @@ -76,10 +76,10 @@ const char* TypedTestCasePState::VerifyRegisteredTestNames( } bool found = false; - for (DefinedTestIter it = defined_test_names_.begin(); - it != defined_test_names_.end(); + for (RegisteredTestIter it = registered_tests_.begin(); + it != registered_tests_.end(); ++it) { - if (name == *it) { + if (name == it->first) { found = true; break; } @@ -93,11 +93,11 @@ const char* TypedTestCasePState::VerifyRegisteredTestNames( } } - for (DefinedTestIter it = defined_test_names_.begin(); - it != defined_test_names_.end(); + for (RegisteredTestIter it = registered_tests_.begin(); + it != registered_tests_.end(); ++it) { - if (tests.count(*it) == 0) { - errors << "You forgot to list test " << *it << ".\n"; + if (tests.count(it->first) == 0) { + errors << "You forgot to list test " << it->first << ".\n"; } } diff --git a/src/gtest.cc b/src/gtest.cc index 71784f92..aa508bb2 100644 --- a/src/gtest.cc +++ b/src/gtest.cc @@ -2493,12 +2493,14 @@ TestInfo::TestInfo(const std::string& a_test_case_name, const std::string& a_name, const char* a_type_param, const char* a_value_param, + internal::CodeLocation a_code_location, internal::TypeId fixture_class_id, internal::TestFactoryBase* factory) : test_case_name_(a_test_case_name), name_(a_name), type_param_(a_type_param ? new std::string(a_type_param) : NULL), value_param_(a_value_param ? new std::string(a_value_param) : NULL), + location_(a_code_location), fixture_class_id_(fixture_class_id), should_run_(false), is_disabled_(false), @@ -2522,6 +2524,7 @@ namespace internal { // this is not a typed or a type-parameterized test. // value_param: text representation of the test's value parameter, // or NULL if this is not a value-parameterized test. +// code_location: code location where the test is defined // fixture_class_id: ID of the test fixture class // set_up_tc: pointer to the function that sets up the test case // tear_down_tc: pointer to the function that tears down the test case @@ -2533,20 +2536,21 @@ TestInfo* MakeAndRegisterTestInfo( const char* name, const char* type_param, const char* value_param, + CodeLocation code_location, TypeId fixture_class_id, SetUpTestCaseFunc set_up_tc, TearDownTestCaseFunc tear_down_tc, TestFactoryBase* factory) { TestInfo* const test_info = new TestInfo(test_case_name, name, type_param, value_param, - fixture_class_id, factory); + code_location, fixture_class_id, factory); GetUnitTestImpl()->AddTestInfo(set_up_tc, tear_down_tc, test_info); return test_info; } #if GTEST_HAS_PARAM_TEST void ReportInvalidTestCaseType(const char* test_case_name, - const char* file, int line) { + CodeLocation code_location) { Message errors; errors << "Attempted redefinition of test case " << test_case_name << ".\n" @@ -2558,7 +2562,9 @@ void ReportInvalidTestCaseType(const char* test_case_name, << "probably rename one of the classes to put the tests into different\n" << "test cases."; - fprintf(stderr, "%s %s", FormatFileLocation(file, line).c_str(), + fprintf(stderr, "%s %s", + FormatFileLocation(code_location.file.c_str(), + code_location.line).c_str(), errors.GetString().c_str()); } #endif // GTEST_HAS_PARAM_TEST -- cgit v1.2.3 From 060b7452ec0f3f0a7fa09914e4044349dc9990c6 Mon Sep 17 00:00:00 2001 From: kosak Date: Fri, 17 Jul 2015 22:53:00 +0000 Subject: Implement GetThreadCount for Linux. --- src/gtest-port.cc | 30 ++++++++++++++++++++++++++---- 1 file changed, 26 insertions(+), 4 deletions(-) (limited to 'src') diff --git a/src/gtest-port.cc b/src/gtest-port.cc index 448a807f..19fa0280 100644 --- a/src/gtest-port.cc +++ b/src/gtest-port.cc @@ -35,6 +35,7 @@ #include #include #include +#include #if GTEST_OS_WINDOWS # include @@ -83,10 +84,31 @@ const int kStdOutFileno = STDOUT_FILENO; const int kStdErrFileno = STDERR_FILENO; #endif // _MSC_VER -#if GTEST_OS_MAC +#if GTEST_OS_LINUX + +namespace { +template +T ReadProcFileField(const string& filename, int field) { + std::string dummy; + std::ifstream file(filename.c_str()); + while (field-- > 0) { + file >> dummy; + } + T output = 0; + file >> output; + return output; +} +} // namespace + +// Returns the number of active threads, or 0 when there is an error. +size_t GetThreadCount() { + const string filename = + (Message() << "/proc/" << getpid() << "/stat").GetString(); + return ReadProcFileField(filename, 19); +} + +#elif GTEST_OS_MAC -// Returns the number of threads running in the process, or 0 to indicate that -// we cannot detect it. size_t GetThreadCount() { const task_t task = mach_task_self(); mach_msg_type_number_t thread_count; @@ -132,7 +154,7 @@ size_t GetThreadCount() { return 0; } -#endif // GTEST_OS_MAC +#endif // GTEST_OS_LINUX #if GTEST_IS_THREADSAFE && GTEST_OS_WINDOWS -- cgit v1.2.3 From fe95bc332d92c6e3f5c2e07fd681bd3549b77374 Mon Sep 17 00:00:00 2001 From: kosak Date: Fri, 17 Jul 2015 23:08:48 +0000 Subject: Determine the existence of hash_map/hash_set in gtest-port.h. --- src/gtest-port.cc | 1 - 1 file changed, 1 deletion(-) (limited to 'src') diff --git a/src/gtest-port.cc b/src/gtest-port.cc index 19fa0280..cd3ac9a5 100644 --- a/src/gtest-port.cc +++ b/src/gtest-port.cc @@ -887,7 +887,6 @@ GTEST_API_ ::std::string FormatCompilerIndependentFileLocation( return file_name + ":" + StreamableToString(line); } - GTestLog::GTestLog(GTestLogSeverity severity, const char* file, int line) : severity_(severity) { const char* const marker = -- cgit v1.2.3 From e7dbfde8ce49c5989d6e44715cfc1910a95990fe Mon Sep 17 00:00:00 2001 From: kosak Date: Fri, 17 Jul 2015 23:57:03 +0000 Subject: Move stack trace logic into custom/ and add a macro to inject it. --- src/gtest-internal-inl.h | 24 +++++++----------------- src/gtest.cc | 36 +++++++++++++++++------------------- 2 files changed, 24 insertions(+), 36 deletions(-) (limited to 'src') diff --git a/src/gtest-internal-inl.h b/src/gtest-internal-inl.h index 6a7e2533..56c8a20c 100644 --- a/src/gtest-internal-inl.h +++ b/src/gtest-internal-inl.h @@ -433,6 +433,10 @@ class OsStackTraceGetterInterface { // CurrentStackTrace() will use to find and hide Google Test stack frames. virtual void UponLeavingGTest() = 0; + // This string is inserted in place of stack frames that are part of + // Google Test's implementation. + static const char* const kElidedFramesMarker; + private: GTEST_DISALLOW_COPY_AND_ASSIGN_(OsStackTraceGetterInterface); }; @@ -440,26 +444,12 @@ class OsStackTraceGetterInterface { // A working implementation of the OsStackTraceGetterInterface interface. class OsStackTraceGetter : public OsStackTraceGetterInterface { public: - OsStackTraceGetter() : caller_frame_(NULL) {} - - virtual string CurrentStackTrace(int max_depth, int skip_count) - GTEST_LOCK_EXCLUDED_(mutex_); + OsStackTraceGetter() {} - virtual void UponLeavingGTest() GTEST_LOCK_EXCLUDED_(mutex_); - - // This string is inserted in place of stack frames that are part of - // Google Test's implementation. - static const char* const kElidedFramesMarker; + virtual string CurrentStackTrace(int max_depth, int skip_count); + virtual void UponLeavingGTest(); private: - Mutex mutex_; // protects all internal state - - // We save the stack frame below the frame that calls user code. - // We do this because the address of the frame immediately below - // the user code changes between the call to UponLeavingGTest() - // and any calls to CurrentStackTrace() from within the user code. - void* caller_frame_; - GTEST_DISALLOW_COPY_AND_ASSIGN_(OsStackTraceGetter); }; diff --git a/src/gtest.cc b/src/gtest.cc index aa508bb2..1c5117d3 100644 --- a/src/gtest.cc +++ b/src/gtest.cc @@ -32,6 +32,7 @@ // The Google C++ Testing Framework (Google Test) #include "gtest/gtest.h" +#include "gtest/internal/custom/gtest.h" #include "gtest/gtest-spi.h" #include @@ -789,8 +790,12 @@ int UnitTestImpl::test_to_run_count() const { // CurrentOsStackTraceExceptTop(1), Foo() will be included in the // trace but Bar() and CurrentOsStackTraceExceptTop() won't. std::string UnitTestImpl::CurrentOsStackTraceExceptTop(int skip_count) { - (void)skip_count; - return ""; + return os_stack_trace_getter()->CurrentStackTrace( + static_cast(GTEST_FLAG(stack_trace_depth)), + skip_count + 1 + // Skips the user-specified number of frames plus this function + // itself. + ); // NOLINT } // Returns the current time in milliseconds. @@ -3833,26 +3838,15 @@ ScopedTrace::~ScopedTrace() // class OsStackTraceGetter -// Returns the current OS stack trace as an std::string. Parameters: -// -// max_depth - the maximum number of stack frames to be included -// in the trace. -// skip_count - the number of top frames to be skipped; doesn't count -// against max_depth. -// -string OsStackTraceGetter::CurrentStackTrace(int /* max_depth */, - int /* skip_count */) - GTEST_LOCK_EXCLUDED_(mutex_) { - return ""; -} +const char* const OsStackTraceGetterInterface::kElidedFramesMarker = + "... " GTEST_NAME_ " internal frames ..."; -void OsStackTraceGetter::UponLeavingGTest() - GTEST_LOCK_EXCLUDED_(mutex_) { +string OsStackTraceGetter::CurrentStackTrace(int /*max_depth*/, + int /*skip_count*/) { + return ""; } -const char* const -OsStackTraceGetter::kElidedFramesMarker = - "... " GTEST_NAME_ " internal frames ..."; +void OsStackTraceGetter::UponLeavingGTest() {} // A helper class that creates the premature-exit file in its // constructor and deletes the file in its destructor. @@ -4907,7 +4901,11 @@ void UnitTestImpl::set_os_stack_trace_getter( // getter, and returns it. OsStackTraceGetterInterface* UnitTestImpl::os_stack_trace_getter() { if (os_stack_trace_getter_ == NULL) { +#ifdef GTEST_OS_STACK_TRACE_GETTER_ + os_stack_trace_getter_ = new GTEST_OS_STACK_TRACE_GETTER_; +#else os_stack_trace_getter_ = new OsStackTraceGetter; +#endif // GTEST_OS_STACK_TRACE_GETTER_ } return os_stack_trace_getter_; -- cgit v1.2.3 From 4d69b1607a876a77b8719f035b23254677617a47 Mon Sep 17 00:00:00 2001 From: kosak Date: Sun, 19 Jul 2015 21:50:45 +0000 Subject: GTEST_USE_OWN_FLAGFILE support --- src/gtest.cc | 6 ++++++ 1 file changed, 6 insertions(+) (limited to 'src') diff --git a/src/gtest.cc b/src/gtest.cc index 1c5117d3..08393897 100644 --- a/src/gtest.cc +++ b/src/gtest.cc @@ -296,10 +296,12 @@ GTEST_DEFINE_bool_( "if exceptions are enabled or exit the program with a non-zero code " "otherwise."); +#if GTEST_USE_OWN_FLAGFILE_FLAG_ GTEST_DEFINE_string_( flagfile, internal::StringFromGTestEnv("flagfile", ""), "This flag specifies the flagfile to read command-line flags from."); +#endif // GTEST_USE_OWN_FLAGFILE_FLAG_ namespace internal { @@ -5233,6 +5235,7 @@ bool ParseGoogleTestFlag(const char* const arg) { >EST_FLAG(throw_on_failure)); } +#if GTEST_USE_OWN_FLAGFILE_FLAG_ void LoadFlagsFromFile(const std::string& path) { FILE* flagfile = posix::FOpen(path.c_str(), "r"); if (!flagfile) { @@ -5253,6 +5256,7 @@ void LoadFlagsFromFile(const std::string& path) { g_help_flag = true; } } +#endif // GTEST_USE_OWN_FLAGFILE_FLAG_ // Parses the command line for Google Test flags, without initializing // other parts of Google Test. The type parameter CharType can be @@ -5270,9 +5274,11 @@ void ParseGoogleTestFlagsOnlyImpl(int* argc, CharType** argv) { bool remove_flag = false; if (ParseGoogleTestFlag(arg)) { remove_flag = true; +#if GTEST_USE_OWN_FLAGFILE_FLAG_ } else if (ParseStringFlag(arg, kFlagfileFlag, >EST_FLAG(flagfile))) { LoadFlagsFromFile(GTEST_FLAG(flagfile)); remove_flag = true; +#endif // GTEST_USE_OWN_FLAGFILE_FLAG_ } else if (arg_string == "--help" || arg_string == "-h" || arg_string == "-?" || arg_string == "/?" || HasGoogleTestFlagPrefix(arg)) { -- cgit v1.2.3 From c6b9fcd60ab2b9c08c01c641d5b41fb13c577ce2 Mon Sep 17 00:00:00 2001 From: kosak Date: Sun, 19 Jul 2015 22:42:00 +0000 Subject: Add injection point for GTEST_KILLED_BY_SIGNAL_OVERRIDE. --- src/gtest-death-test.cc | 8 ++++++++ 1 file changed, 8 insertions(+) (limited to 'src') diff --git a/src/gtest-death-test.cc b/src/gtest-death-test.cc index b049eb07..a6144074 100644 --- a/src/gtest-death-test.cc +++ b/src/gtest-death-test.cc @@ -169,6 +169,14 @@ KilledBySignal::KilledBySignal(int signum) : signum_(signum) { // KilledBySignal function-call operator. bool KilledBySignal::operator()(int exit_status) const { +# if defined(GTEST_KILLED_BY_SIGNAL_OVERRIDE_) + { + bool result; + if (GTEST_KILLED_BY_SIGNAL_OVERRIDE_(signum_, exit_status, &result)) { + return result; + } + } +# endif // defined(GTEST_KILLED_BY_SIGNAL_OVERRIDE_) return WIFSIGNALED(exit_status) && WTERMSIG(exit_status) == signum_; } # endif // !GTEST_OS_WINDOWS -- cgit v1.2.3 From 41b5b28d4858530a94078a5204c9d393f520159d Mon Sep 17 00:00:00 2001 From: kosak Date: Fri, 24 Jul 2015 19:07:10 +0000 Subject: Inject implementation of *FromGTestEnv using macros. --- src/gtest-port.cc | 9 +++++++++ 1 file changed, 9 insertions(+) (limited to 'src') diff --git a/src/gtest-port.cc b/src/gtest-port.cc index cd3ac9a5..3bc404bd 100644 --- a/src/gtest-port.cc +++ b/src/gtest-port.cc @@ -1174,6 +1174,9 @@ bool ParseInt32(const Message& src_text, const char* str, Int32* value) { // // The value is considered true iff it's not "0". bool BoolFromGTestEnv(const char* flag, bool default_value) { +#if defined(GTEST_GET_BOOL_FROM_ENV_) + return GTEST_GET_BOOL_FROM_ENV_(flag, default_value); +#endif // defined(GTEST_GET_BOOL_FROM_ENV_) const std::string env_var = FlagToEnvVar(flag); const char* const string_value = posix::GetEnv(env_var.c_str()); return string_value == NULL ? @@ -1184,6 +1187,9 @@ bool BoolFromGTestEnv(const char* flag, bool default_value) { // variable corresponding to the given flag; if it isn't set or // doesn't represent a valid 32-bit integer, returns default_value. Int32 Int32FromGTestEnv(const char* flag, Int32 default_value) { +#if defined(GTEST_GET_INT32_FROM_ENV_) + return GTEST_GET_INT32_FROM_ENV_(flag, default_value); +#endif // defined(GTEST_GET_INT32_FROM_ENV_) const std::string env_var = FlagToEnvVar(flag); const char* const string_value = posix::GetEnv(env_var.c_str()); if (string_value == NULL) { @@ -1206,6 +1212,9 @@ Int32 Int32FromGTestEnv(const char* flag, Int32 default_value) { // Reads and returns the string environment variable corresponding to // the given flag; if it's not set, returns default_value. const char* StringFromGTestEnv(const char* flag, const char* default_value) { +#if defined(GTEST_GET_STRING_FROM_ENV_) + return GTEST_GET_STRING_FROM_ENV_(flag, default_value); +#endif // defined(GTEST_GET_STRING_FROM_ENV_) const std::string env_var = FlagToEnvVar(flag); const char* const value = posix::GetEnv(env_var.c_str()); return value == NULL ? default_value : value; -- cgit v1.2.3 From 40bba6c9ec1a258ff450a99d7f6b8e8a1f9fee73 Mon Sep 17 00:00:00 2001 From: kosak Date: Fri, 24 Jul 2015 20:26:10 +0000 Subject: Inject GTEST_EXTRA_DEATH_TEST_COMMAND_LINE_ARGS_ --- src/gtest-death-test.cc | 6 ++++++ 1 file changed, 6 insertions(+) (limited to 'src') diff --git a/src/gtest-death-test.cc b/src/gtest-death-test.cc index a6144074..c076d072 100644 --- a/src/gtest-death-test.cc +++ b/src/gtest-death-test.cc @@ -33,6 +33,7 @@ #include "gtest/gtest-death-test.h" #include "gtest/internal/gtest-port.h" +#include "gtest/internal/custom/gtest.h" #if GTEST_HAS_DEATH_TEST @@ -883,6 +884,11 @@ class ExecDeathTest : public ForkingDeathTest { static ::std::vector GetArgvsForDeathTestChildProcess() { ::std::vector args = GetInjectableArgvs(); +# if defined(GTEST_EXTRA_DEATH_TEST_COMMAND_LINE_ARGS_) + ::std::vector extra_args = + GTEST_EXTRA_DEATH_TEST_COMMAND_LINE_ARGS_(); + args.insert(args.end(), extra_args.begin(), extra_args.end()); +# endif // defined(GTEST_EXTRA_DEATH_TEST_COMMAND_LINE_ARGS_) return args; } // The name of the file in which the death test is located. -- cgit v1.2.3 From f972f1680aa5de3230dac197b223336f30210f69 Mon Sep 17 00:00:00 2001 From: kosak Date: Fri, 24 Jul 2015 20:43:09 +0000 Subject: Inject GetArgvs() with a macro from custom/gtest-port.h. --- src/gtest-port.cc | 5 +---- src/gtest.cc | 34 ++++++++++++++-------------------- 2 files changed, 15 insertions(+), 24 deletions(-) (limited to 'src') diff --git a/src/gtest-port.cc b/src/gtest-port.cc index 3bc404bd..7c936f08 100644 --- a/src/gtest-port.cc +++ b/src/gtest-port.cc @@ -1084,9 +1084,6 @@ std::string ReadEntireFile(FILE* file) { #if GTEST_HAS_DEATH_TEST -// A copy of all command line arguments. Set by InitGoogleTest(). -::std::vector g_argvs; - static const ::std::vector* g_injected_test_argvs = NULL; // Owned. @@ -1100,7 +1097,7 @@ const ::std::vector& GetInjectableArgvs() { if (g_injected_test_argvs != NULL) { return *g_injected_test_argvs; } - return g_argvs; + return GetArgvs(); } #endif // GTEST_HAS_DEATH_TEST diff --git a/src/gtest.cc b/src/gtest.cc index 08393897..fb65bc17 100644 --- a/src/gtest.cc +++ b/src/gtest.cc @@ -327,13 +327,7 @@ UInt32 Random::Generate(UInt32 range) { // GTestIsInitialized() returns true iff the user has initialized // Google Test. Useful for catching the user mistake of not initializing // Google Test before calling RUN_ALL_TESTS(). -// -// A user must call testing::InitGoogleTest() to initialize Google -// Test. g_init_gtest_count is set to the number of times -// InitGoogleTest() has been called. We don't protect this variable -// under a mutex as it is only accessed in the main thread. -GTEST_API_ int g_init_gtest_count = 0; -static bool GTestIsInitialized() { return g_init_gtest_count != 0; } +static bool GTestIsInitialized() { return GetArgvs().size() > 0; } // Iterates over a vector of TestCases, keeping a running sum of the // results of calling a given int-returning method on each. @@ -389,8 +383,16 @@ void AssertHelper::operator=(const Message& message) const { // Mutex for linked pointers. GTEST_API_ GTEST_DEFINE_STATIC_MUTEX_(g_linked_ptr_mutex); -// Application pathname gotten in InitGoogleTest. -std::string g_executable_path; +// A copy of all command line arguments. Set by InitGoogleTest(). +::std::vector g_argvs; + +const ::std::vector& GetArgvs() { +#if defined(GTEST_CUSTOM_GET_ARGVS_) + return GTEST_CUSTOM_GET_ARGVS_(); +#else // defined(GTEST_CUSTOM_GET_ARGVS_) + return g_argvs; +#endif // defined(GTEST_CUSTOM_GET_ARGVS_) +} // Returns the current application's name, removing directory path if that // is present. @@ -398,9 +400,9 @@ FilePath GetCurrentExecutableName() { FilePath result; #if GTEST_OS_WINDOWS - result.Set(FilePath(g_executable_path).RemoveExtension("exe")); + result.Set(FilePath(GetArgvs()[0]).RemoveExtension("exe")); #else - result.Set(FilePath(g_executable_path)); + result.Set(FilePath(GetArgvs()[0])); #endif // GTEST_OS_WINDOWS return result.RemoveDirectoryName(); @@ -5328,24 +5330,16 @@ void ParseGoogleTestFlagsOnly(int* argc, wchar_t** argv) { // wchar_t. template void InitGoogleTestImpl(int* argc, CharType** argv) { - g_init_gtest_count++; - // We don't want to run the initialization code twice. - if (g_init_gtest_count != 1) return; + if (GTestIsInitialized()) return; if (*argc <= 0) return; - internal::g_executable_path = internal::StreamableToString(argv[0]); - -#if GTEST_HAS_DEATH_TEST - g_argvs.clear(); for (int i = 0; i != *argc; i++) { g_argvs.push_back(StreamableToString(argv[i])); } -#endif // GTEST_HAS_DEATH_TEST - ParseGoogleTestFlagsOnly(argc, argv); GetUnitTestImpl()->PostFlagParsingInit(); } -- cgit v1.2.3 From 4188ec35292595660c1bc5b6f35cefe17188e1ab Mon Sep 17 00:00:00 2001 From: kosak Date: Fri, 24 Jul 2015 21:16:59 +0000 Subject: Inject GTEST_CUSTOM_TEST_EVENT_LISTENER_ --- src/gtest.cc | 5 +++++ 1 file changed, 5 insertions(+) (limited to 'src') diff --git a/src/gtest.cc b/src/gtest.cc index fb65bc17..bfc4f4fe 100644 --- a/src/gtest.cc +++ b/src/gtest.cc @@ -4436,6 +4436,11 @@ void UnitTestImpl::PostFlagParsingInit() { if (!post_flag_parse_init_performed_) { post_flag_parse_init_performed_ = true; +#if defined(GTEST_CUSTOM_TEST_EVENT_LISTENER_) + // Register to send notifications about key process state changes. + listeners()->Append(new GTEST_CUSTOM_TEST_EVENT_LISTENER_()); +#endif // defined(GTEST_CUSTOM_TEST_EVENT_LISTENER_) + #if GTEST_HAS_DEATH_TEST InitDeathTestSubprocessControlInfo(); SuppressTestEventsIfInSubprocess(); -- cgit v1.2.3 From c33ce7c159055c956d97dbdb40532f20d71351d8 Mon Sep 17 00:00:00 2001 From: kosak Date: Mon, 27 Jul 2015 21:36:08 +0000 Subject: Inject the custom InitGoogleTest function using a macro. --- src/gtest.cc | 8 ++++++++ 1 file changed, 8 insertions(+) (limited to 'src') diff --git a/src/gtest.cc b/src/gtest.cc index bfc4f4fe..487592a6 100644 --- a/src/gtest.cc +++ b/src/gtest.cc @@ -5361,13 +5361,21 @@ void InitGoogleTestImpl(int* argc, CharType** argv) { // // Calling the function for the second time has no user-visible effect. void InitGoogleTest(int* argc, char** argv) { +#if defined(GTEST_CUSTOM_INIT_GOOGLE_TEST_FUNCTION_) + GTEST_CUSTOM_INIT_GOOGLE_TEST_FUNCTION_(argc, argv); +#else // defined(GTEST_CUSTOM_INIT_GOOGLE_TEST_FUNCTION_) internal::InitGoogleTestImpl(argc, argv); +#endif // defined(GTEST_CUSTOM_INIT_GOOGLE_TEST_FUNCTION_) } // This overloaded version can be used in Windows programs compiled in // UNICODE mode. void InitGoogleTest(int* argc, wchar_t** argv) { +#if defined(GTEST_CUSTOM_INIT_GOOGLE_TEST_FUNCTION_) + GTEST_CUSTOM_INIT_GOOGLE_TEST_FUNCTION_(argc, argv); +#else // defined(GTEST_CUSTOM_INIT_GOOGLE_TEST_FUNCTION_) internal::InitGoogleTestImpl(argc, argv); +#endif // defined(GTEST_CUSTOM_INIT_GOOGLE_TEST_FUNCTION_) } } // namespace testing -- cgit v1.2.3 From 1e86cae1d64b9dd25f5ca0db09a2d17aad30593c Mon Sep 17 00:00:00 2001 From: kosak Date: Mon, 27 Jul 2015 21:42:24 +0000 Subject: Inject GTEST_EXTRA_DEATH_TEST_CHILD_SETUP --- src/gtest.cc | 5 +++++ 1 file changed, 5 insertions(+) (limited to 'src') diff --git a/src/gtest.cc b/src/gtest.cc index 487592a6..4170e5c7 100644 --- a/src/gtest.cc +++ b/src/gtest.cc @@ -4574,6 +4574,11 @@ bool UnitTestImpl::RunAllTests() { #if GTEST_HAS_DEATH_TEST in_subprocess_for_death_test = (internal_run_death_test_flag_.get() != NULL); +# if defined(GTEST_EXTRA_DEATH_TEST_CHILD_SETUP_) + if (in_subprocess_for_death_test) { + GTEST_EXTRA_DEATH_TEST_CHILD_SETUP_(); + } +# endif // defined(GTEST_EXTRA_DEATH_TEST_CHILD_SETUP_) #endif // GTEST_HAS_DEATH_TEST const bool should_shard = ShouldShard(kTestTotalShards, kTestShardIndex, -- cgit v1.2.3 From 33307529412166cd7633eee9bf0b0aff21b5cf52 Mon Sep 17 00:00:00 2001 From: kosak Date: Mon, 27 Jul 2015 22:00:58 +0000 Subject: Order the initializers correctly. --- src/gtest-port.cc | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'src') diff --git a/src/gtest-port.cc b/src/gtest-port.cc index 7c936f08..3842c415 100644 --- a/src/gtest-port.cc +++ b/src/gtest-port.cc @@ -218,8 +218,8 @@ void Notification::WaitForNotification() { } Mutex::Mutex() - : type_(kDynamic), - owner_thread_id_(0), + : owner_thread_id_(0), + type_(kDynamic), critical_section_init_phase_(0), critical_section_(new CRITICAL_SECTION) { ::InitializeCriticalSection(critical_section_); -- cgit v1.2.3