summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorGennadiy Civil <gennadiycivil@users.noreply.github.com>2018-05-07 14:43:09 -0400
committerGitHub <noreply@github.com>2018-05-07 14:43:09 -0400
commit045e7f9ee4f969ac1a3fe428f79c4b880f0aff43 (patch)
tree9a8933a3a820211ac2e1b75cc8a4ee0ec6c47f84
parent278aba369c41e90e9e77a6f51443beb3692919cf (diff)
parent960149f913c8c754e4c73da186b8d61c7c78409b (diff)
downloadgoogletest-045e7f9ee4f969ac1a3fe428f79c4b880f0aff43.tar.gz
googletest-045e7f9ee4f969ac1a3fe428f79c4b880f0aff43.zip
Merge pull request #1593 from Steelskin/fuchsia_death_test
Add death test support for Fuchsia.
-rw-r--r--googletest/include/gtest/gtest-death-test.h2
-rw-r--r--googletest/include/gtest/gtest.h2
-rw-r--r--googletest/include/gtest/internal/gtest-port.h3
-rw-r--r--googletest/src/gtest-death-test.cc213
-rw-r--r--googletest/src/gtest-port.cc24
-rw-r--r--googletest/test/gtest-death-test_test.cc7
-rw-r--r--googletest/test/gtest-options_test.cc6
-rw-r--r--googletest/test/gtest-port_test.cc4
8 files changed, 243 insertions, 18 deletions
diff --git a/googletest/include/gtest/gtest-death-test.h b/googletest/include/gtest/gtest-death-test.h
index 6a216bcb..3834292f 100644
--- a/googletest/include/gtest/gtest-death-test.h
+++ b/googletest/include/gtest/gtest-death-test.h
@@ -198,7 +198,7 @@ class GTEST_API_ ExitedWithCode {
const int exit_code_;
};
-# if !GTEST_OS_WINDOWS
+# if !GTEST_OS_WINDOWS && !GTEST_OS_FUCHSIA
// Tests that an exit code describes an exit due to termination by a
// given signal.
class GTEST_API_ KilledBySignal {
diff --git a/googletest/include/gtest/gtest.h b/googletest/include/gtest/gtest.h
index a0592a82..e1e9c1bb 100644
--- a/googletest/include/gtest/gtest.h
+++ b/googletest/include/gtest/gtest.h
@@ -172,6 +172,7 @@ class TestEventListenersAccessor;
class TestEventRepeater;
class UnitTestRecordPropertyTestHelper;
class WindowsDeathTest;
+class FuchsiaDeathTest;
class UnitTestImpl* GetUnitTestImpl();
void ReportFailureInUnknownLocation(TestPartResult::Type result_type,
const std::string& message);
@@ -593,6 +594,7 @@ class GTEST_API_ TestResult {
friend class internal::TestResultAccessor;
friend class internal::UnitTestImpl;
friend class internal::WindowsDeathTest;
+ friend class internal::FuchsiaDeathTest;
// Gets the vector of TestPartResults.
const std::vector<TestPartResult>& test_part_results() const {
diff --git a/googletest/include/gtest/internal/gtest-port.h b/googletest/include/gtest/internal/gtest-port.h
index e677cd97..fafb134b 100644
--- a/googletest/include/gtest/internal/gtest-port.h
+++ b/googletest/include/gtest/internal/gtest-port.h
@@ -813,7 +813,8 @@ typedef struct _RTL_CRITICAL_SECTION GTEST_CRITICAL_SECTION;
(GTEST_OS_MAC && !GTEST_OS_IOS) || \
(GTEST_OS_WINDOWS_DESKTOP && _MSC_VER >= 1400) || \
GTEST_OS_WINDOWS_MINGW || GTEST_OS_AIX || GTEST_OS_HPUX || \
- GTEST_OS_OPENBSD || GTEST_OS_QNX || GTEST_OS_FREEBSD || GTEST_OS_NETBSD)
+ GTEST_OS_OPENBSD || GTEST_OS_QNX || GTEST_OS_FREEBSD || \
+ GTEST_OS_NETBSD || GTEST_OS_FUCHSIA)
# define GTEST_HAS_DEATH_TEST 1
#endif
diff --git a/googletest/src/gtest-death-test.cc b/googletest/src/gtest-death-test.cc
index 9ecab8f9..792fe46a 100644
--- a/googletest/src/gtest-death-test.cc
+++ b/googletest/src/gtest-death-test.cc
@@ -62,6 +62,12 @@
# include <spawn.h>
# endif // GTEST_OS_QNX
+# if GTEST_OS_FUCHSIA
+# include <fdio/io.h>
+# include <launchpad/launchpad.h>
+# include <zircon/syscalls.h>
+# endif // GTEST_OS_FUCHSIA
+
#endif // GTEST_HAS_DEATH_TEST
#include "gtest/gtest-message.h"
@@ -127,10 +133,10 @@ 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.
+ // On Windows and Fuchsia, death tests are thread-safe regardless of the value
+ // of the death_test_style flag.
return !GTEST_FLAG(internal_run_death_test).empty();
# else
@@ -150,7 +156,7 @@ 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 || GTEST_OS_FUCHSIA
return exit_status == exit_code_;
@@ -158,10 +164,10 @@ bool ExitedWithCode::operator()(int exit_status) const {
return WIFEXITED(exit_status) && WEXITSTATUS(exit_status) == exit_code_;
-# endif // GTEST_OS_WINDOWS
+# endif // GTEST_OS_WINDOWS || GTEST_OS_FUCHSIA
}
-# if !GTEST_OS_WINDOWS
+# if !GTEST_OS_WINDOWS && !GTEST_OS_FUCHSIA
// KilledBySignal constructor.
KilledBySignal::KilledBySignal(int signum) : signum_(signum) {
}
@@ -189,7 +195,7 @@ namespace internal {
static std::string ExitSummary(int exit_code) {
Message m;
-# if GTEST_OS_WINDOWS
+# if GTEST_OS_WINDOWS || GTEST_OS_FUCHSIA
m << "Exited with exit status " << exit_code;
@@ -205,7 +211,7 @@ static std::string ExitSummary(int exit_code) {
m << " (core dumped)";
}
# endif
-# endif // GTEST_OS_WINDOWS
+# endif // GTEST_OS_WINDOWS || GTEST_OS_FUCHSIA
return m.GetString();
}
@@ -216,7 +222,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
@@ -231,7 +237,7 @@ static std::string DeathTestThreadWarning(size_t thread_count) {
msg << "detected " << thread_count << " threads.";
return msg.GetString();
}
-# endif // !GTEST_OS_WINDOWS
+# endif // !GTEST_OS_WINDOWS && !GTEST_OS_FUCHSIA
// Flag characters for reporting a death test that did not die.
static const char kDeathTestLived = 'L';
@@ -239,6 +245,13 @@ static const char kDeathTestReturned = 'R';
static const char kDeathTestThrew = 'T';
static const char kDeathTestInternalError = 'I';
+#if GTEST_OS_FUCHSIA
+
+// File descriptor used for the pipe in the child process.
+static const int kFuchsiaReadPipeFd = 3;
+
+#endif
+
// 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;
@@ -781,7 +794,168 @@ 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_;
+};
+
+// 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];
+ }
+
+ int size() {
+ return args_.size() - 1;
+ }
+
+ 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;
+
+ // 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);
+
+ ReadAndInterpretStatusByte();
+
+ zx_info_process_t buffer;
+ status_zx = zx_object_get_info(
+ child_process_,
+ ZX_INFO_PROCESS,
+ &buffer,
+ sizeof(buffer),
+ nullptr,
+ nullptr);
+ 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(kFuchsiaReadPipeFd);
+ return EXECUTE_TEST;
+ }
+
+ CaptureStderr();
+ // Flush the log buffers since the log streams are shared with the child.
+ FlushInfoLog();
+
+ // Build the child process 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);
+ Arguments args;
+ args.AddArguments(GetInjectableArgvs());
+ args.AddArgument(filter_flag.c_str());
+ args.AddArgument(internal_flag.c_str());
+
+ // Build the child process launcher.
+ zx_status_t status;
+ launchpad_t* lp;
+ status = launchpad_create(ZX_HANDLE_INVALID, args.Argv()[0], &lp);
+ GTEST_DEATH_TEST_CHECK_(status == ZX_OK);
+
+ // Build the pipe for communication with the child.
+ int read_fd;
+ status = launchpad_add_pipe(lp, &read_fd, kFuchsiaReadPipeFd);
+ GTEST_DEATH_TEST_CHECK_(status == ZX_OK);
+ set_read_fd(read_fd);
+
+ // Set the command line arguments.
+ status = launchpad_load_from_file(lp, args.Argv()[0]);
+ GTEST_DEATH_TEST_CHECK_(status == ZX_OK);
+ status = launchpad_set_args(lp, args.size(), args.Argv());
+ GTEST_DEATH_TEST_CHECK_(status == ZX_OK);
+
+ // Clone all the things (environment, stdio, namespace, ...).
+ launchpad_clone(lp, LP_CLONE_ALL);
+
+ // Launch the child process.
+ status = launchpad_go(lp, &child_process_, nullptr);
+ 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 +1378,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") {
@@ -1324,6 +1505,16 @@ InternalRunDeathTestFlag* ParseInternalRunDeathTestFlag() {
write_fd = GetStatusFileDescriptor(parent_process_id,
write_handle_as_size_t,
event_handle_as_size_t);
+
+# elif GTEST_OS_FUCHSIA
+
+ if (fields.size() != 3
+ || !ParseNaturalNumber(fields[1], &line)
+ || !ParseNaturalNumber(fields[2], &index)) {
+ DeathTestAbort("Bad --gtest_internal_run_death_test flag: "
+ + GTEST_FLAG(internal_run_death_test));
+ }
+
# else
if (fields.size() != 4
diff --git a/googletest/src/gtest-port.cc b/googletest/src/gtest-port.cc
index d32afb1f..f8a0ad65 100644
--- a/googletest/src/gtest-port.cc
+++ b/googletest/src/gtest-port.cc
@@ -63,6 +63,11 @@
# include <sys/types.h>
#endif // GTEST_OS_AIX
+#if GTEST_OS_FUCHSIA
+# include <zircon/process.h>
+# include <zircon/syscalls.h>
+#endif // GTEST_OS_FUCHSIA
+
#include "gtest/gtest-spi.h"
#include "gtest/gtest-message.h"
#include "gtest/internal/gtest-internal.h"
@@ -156,6 +161,25 @@ size_t GetThreadCount() {
}
}
+#elif GTEST_OS_FUCHSIA
+
+size_t GetThreadCount() {
+ int dummy_buffer;
+ size_t avail;
+ zx_status_t status = zx_object_get_info(
+ zx_process_self(),
+ ZX_INFO_PROCESS_THREADS,
+ &dummy_buffer,
+ 0,
+ nullptr,
+ &avail);
+ if (status == ZX_OK) {
+ return avail;
+ } else {
+ return 0;
+ }
+}
+
#else
size_t GetThreadCount() {
diff --git a/googletest/test/gtest-death-test_test.cc b/googletest/test/gtest-death-test_test.cc
index 21573c77..37261cb6 100644
--- a/googletest/test/gtest-death-test_test.cc
+++ b/googletest/test/gtest-death-test_test.cc
@@ -200,7 +200,7 @@ int DieInDebugElse12(int* sideeffect) {
return 12;
}
-# if GTEST_OS_WINDOWS
+# if GTEST_OS_WINDOWS || GTEST_OS_FUCHSIA
// Tests the ExitedWithCode predicate.
TEST(ExitStatusPredicateTest, ExitedWithCode) {
@@ -272,7 +272,7 @@ TEST(ExitStatusPredicateTest, KilledBySignal) {
EXPECT_FALSE(pred_kill(status_segv));
}
-# endif // GTEST_OS_WINDOWS
+# endif // GTEST_OS_WINDOWS || GTEST_OS_FUCHSIA
// Tests that the death test macros expand to code which may or may not
// be followed by operator<<, and that in either case the complete text
@@ -787,8 +787,9 @@ static void TestExitMacros() {
// See http://msdn.microsoft.com/en-us/library/dwwzkt4c(VS.71).aspx.
EXPECT_EXIT(raise(SIGABRT), testing::ExitedWithCode(3), "") << "b_ar";
-# else
+# elif !GTEST_OS_FUCHSIA
+ // Fuchsia has no unix signals.
EXPECT_EXIT(raise(SIGKILL), testing::KilledBySignal(SIGKILL), "") << "foo";
ASSERT_EXIT(raise(SIGUSR2), testing::KilledBySignal(SIGUSR2), "") << "bar";
diff --git a/googletest/test/gtest-options_test.cc b/googletest/test/gtest-options_test.cc
index 25c9f394..10cb1df7 100644
--- a/googletest/test/gtest-options_test.cc
+++ b/googletest/test/gtest-options_test.cc
@@ -103,6 +103,8 @@ TEST(OutputFileHelpersTest, GetCurrentExecutableName) {
_strcmpi("gtest-options-ex_test", exe_str.c_str()) == 0 ||
_strcmpi("gtest_all_test", exe_str.c_str()) == 0 ||
_strcmpi("gtest_dll_test", exe_str.c_str()) == 0;
+#elif GTEST_OS_FUCHSIA
+ const bool success = exe_str == "app";
#else
// TODO(wan@google.com): remove the hard-coded "lt-" prefix when
// Chandler Carruth's libtool replacement is ready.
@@ -116,6 +118,8 @@ TEST(OutputFileHelpersTest, GetCurrentExecutableName) {
FAIL() << "GetCurrentExecutableName() returns " << exe_str;
}
+#if !GTEST_OS_FUCHSIA
+
class XmlOutputChangeDirTest : public Test {
protected:
virtual void SetUp() {
@@ -202,6 +206,8 @@ TEST_F(XmlOutputChangeDirTest, PreserveOriginalWorkingDirWithAbsolutePath) {
#endif
}
+#endif // !GTEST_OS_FUCHSIA
+
} // namespace
} // namespace internal
} // namespace testing
diff --git a/googletest/test/gtest-port_test.cc b/googletest/test/gtest-port_test.cc
index 51956f05..3801e5ee 100644
--- a/googletest/test/gtest-port_test.cc
+++ b/googletest/test/gtest-port_test.cc
@@ -296,7 +296,7 @@ TEST(FormatCompilerIndependentFileLocationTest, FormatsUknownFileAndLine) {
EXPECT_EQ("unknown file", FormatCompilerIndependentFileLocation(NULL, -1));
}
-#if GTEST_OS_LINUX || GTEST_OS_MAC || GTEST_OS_QNX
+#if GTEST_OS_LINUX || GTEST_OS_MAC || GTEST_OS_QNX || GTEST_OS_FUCHSIA
void* ThreadFunc(void* data) {
internal::Mutex* mutex = static_cast<internal::Mutex*>(data);
mutex->Lock();
@@ -340,7 +340,7 @@ TEST(GetThreadCountTest, ReturnsCorrectValue) {
TEST(GetThreadCountTest, ReturnsZeroWhenUnableToCountThreads) {
EXPECT_EQ(0U, GetThreadCount());
}
-#endif // GTEST_OS_LINUX || GTEST_OS_MAC || GTEST_OS_QNX
+#endif // GTEST_OS_LINUX || GTEST_OS_MAC || GTEST_OS_QNX || GTEST_OS_FUCHSIA
TEST(GtestCheckDeathTest, DiesWithCorrectOutputOnFailure) {
const bool a_false_condition = false;
OpenPOWER on IntegriCloud