diff options
Diffstat (limited to 'googletest/src/gtest-death-test.cc')
-rw-r--r-- | googletest/src/gtest-death-test.cc | 189 |
1 files changed, 186 insertions, 3 deletions
diff --git a/googletest/src/gtest-death-test.cc b/googletest/src/gtest-death-test.cc index 9ecab8f..eef6ed2 100644 --- a/googletest/src/gtest-death-test.cc +++ b/googletest/src/gtest-death-test.cc @@ -62,6 +62,11 @@ # include <spawn.h> # endif // GTEST_OS_QNX +# if GTEST_OS_FUCHSIA +# include <launchpad/launchpad.h> +# include <zircon/syscalls.h> +# endif // GTEST_OS_FUCHSIA + #endif // GTEST_HAS_DEATH_TEST #include "gtest/gtest-message.h" @@ -127,7 +132,7 @@ static bool g_in_fast_death_test_child = false; // 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 +# if GTEST_OS_WINDOWS || GTEST_OS_FUCHSIA // On Windows, death tests are thread-safe regardless of the value of the // death_test_style flag. @@ -216,7 +221,7 @@ bool ExitedUnsuccessfully(int exit_status) { return !ExitedWithCode(0)(exit_status); } -# if !GTEST_OS_WINDOWS +# if !GTEST_OS_WINDOWS && !GTEST_OS_FUCHSIA // 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 @@ -781,7 +786,178 @@ DeathTest::TestRole WindowsDeathTest::AssumeRole() { set_spawned(true); return OVERSEE_TEST; } -# else // We are not on Windows. + +# elif GTEST_OS_FUCHSIA + +class FuchsiaDeathTest : public DeathTestImpl { + public: + FuchsiaDeathTest(const char* a_statement, + const RE* a_regex, + const char* file, + int line) + : DeathTestImpl(a_statement, a_regex), file_(file), line_(line) {} + + // All of these virtual functions are inherited from DeathTest. + virtual int Wait(); + 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_; + + zx_handle_t child_process_; + // zx_handle_t crash_port_; +}; + +// Utility class for accumulating command-line arguments. +class Arguments { + public: + Arguments() { + args_.push_back(NULL); + } + + ~Arguments() { + for (std::vector<char*>::iterator i = args_.begin(); i != args_.end(); + ++i) { + free(*i); + } + } + void AddArgument(const char* argument) { + args_.insert(args_.end() - 1, posix::StrDup(argument)); + } + + template <typename Str> + void AddArguments(const ::std::vector<Str>& arguments) { + for (typename ::std::vector<Str>::const_iterator i = arguments.begin(); + i != arguments.end(); + ++i) { + args_.insert(args_.end() - 1, posix::StrDup(i->c_str())); + } + } + char* const* Argv() { + return &args_[0]; + } + + private: + std::vector<char*> args_; +}; + +// 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 FuchsiaDeathTest::Wait() { + if (!spawned()) + return 0; + + ReadAndInterpretStatusByte(); + + // Wait for child process to terminate. + zx_status_t status_zx; + zx_signals_t signals; + status_zx = zx_object_wait_one( + child_process_, + ZX_PROCESS_TERMINATED, + ZX_TIME_INFINITE, + &signals); + GTEST_DEATH_TEST_CHECK_(status_zx == ZX_OK); + + // Do we need this? + // // Attempt to read the crash port. + // zx_port_packet_t packet; + // status = zx_port_wait(crash_port_, past, &packet, 1) + // if (status == ZX_ERR_TIMED_OUT) { + // // Process did not crash. + // set_outcome(LIVED); + // return status(); + // } + + zx_info_process_t buffer; + size_t actual; + size_t avail; + status_zx = zx_object_get_info(child_process_, ZX_INFO_PROCESS, &buffer, sizeof(buffer), &actual, &avail); + GTEST_DEATH_TEST_CHECK_(status_zx == ZX_OK); + + GTEST_DEATH_TEST_CHECK_(buffer.exited); + set_status(buffer.return_code); + return status(); +} + +// The AssumeRole process for a Fuchsia 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 FuchsiaDeathTest::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. + set_write_fd(flag->write_fd()); + return EXECUTE_TEST; + } + + // Create the crash port to report on. + // zx_status_t status = zx_port_create(0, &crash_port_); + // GTEST_DEATH_TEST_CHECK_(status == ZX_OK); + + CaptureStderr(); + // Flush the log buffers since the log streams are shared with the child. + FlushInfoLog(); + + // Build the child process launcher. + launchpad_t* lp; + zx_status_t status; + status = launchpad_create(ZX_HANDLE_INVALID, "processname", &lp); + GTEST_DEATH_TEST_CHECK_(status == ZX_OK); + + // Build the writing pipe for the child. + int write_fd; + status = launchpad_add_pipe(lp, &write_fd, read_fd()); + GTEST_DEATH_TEST_CHECK_(status == ZX_OK); + + // Build the child command 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_ + "|" + StreamableToString(line_) + "|" + + StreamableToString(death_test_index) + "|" + + StreamableToString(write_fd); + Arguments args; + args.AddArguments(GetInjectableArgvs()); + args.AddArgument(filter_flag.c_str()); + args.AddArgument(internal_flag.c_str()); + + status = launchpad_load_from_file(lp, args.Argv()[0]); + GTEST_DEATH_TEST_CHECK_(status == ZX_OK); + status = launchpad_set_args(lp, GetArgvs().size() + 2, args.Argv()); + GTEST_DEATH_TEST_CHECK_(status == ZX_OK); + + // Launch the child process. + zx_handle_t proc; + const char* errmsg; + status = launchpad_go(lp, &proc, &errmsg); + GTEST_DEATH_TEST_CHECK_(status == ZX_OK); + child_process_ = proc; + + // bind the crash port. This should be moved to before launching the process. + // FIXME: I don't think this is necessary + // status = zx_task_bind_exception_port(child_process_, crash_port_, 0xabcabc, 0); + // GTEST_DEATH_TEST_CHECK_(status == ZX_OK); + + set_spawned(true); + return OVERSEE_TEST; +} + +#else // We are neither on Windows, nor on Fuchsia. // ForkingDeathTest provides implementations for most of the abstract // methods of the DeathTest interface. Only the AssumeRole method is @@ -1204,6 +1380,13 @@ bool DefaultDeathTestFactory::Create(const char* statement, const RE* regex, *test = new WindowsDeathTest(statement, regex, file, line); } +# elif GTEST_OS_FUCHSIA + + if (GTEST_FLAG(death_test_style) == "threadsafe" || + GTEST_FLAG(death_test_style) == "fast") { + *test = new FuchsiaDeathTest(statement, regex, file, line); + } + # else if (GTEST_FLAG(death_test_style) == "threadsafe") { |