diff options
author | rch@chromium.org <rch@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2014-01-25 20:31:10 +0000 |
---|---|---|
committer | rch@chromium.org <rch@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2014-01-25 20:31:10 +0000 |
commit | be8cff83b5fdd35792ff5612043972182fa9c67d (patch) | |
tree | 5d248e488e15fea31969878bc40c5ad5f72ba68f /net/test | |
parent | 8e89b03ada36070a5f22791ff51a23539b471798 (diff) | |
download | chromium_src-be8cff83b5fdd35792ff5612043972182fa9c67d.zip chromium_src-be8cff83b5fdd35792ff5612043972182fa9c67d.tar.gz chromium_src-be8cff83b5fdd35792ff5612043972182fa9c67d.tar.bz2 |
Use EXPECT_DFATAL instead of EXPECT_DEBUG_DEATH in spdy_protocol_test.cc.
Switch the associated DCHECK to a LOG_IF(DFATAL).
Move EXPECT_DFATAL, and friends, from net/quic/test_tools/ to net/test/.
Merge internal change: 60170975
Review URL: https://codereview.chromium.org/134193004
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@247136 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'net/test')
-rw-r--r-- | net/test/gtest_util.h | 99 | ||||
-rw-r--r-- | net/test/scoped_disable_exit_on_dfatal.cc | 33 | ||||
-rw-r--r-- | net/test/scoped_disable_exit_on_dfatal.h | 39 | ||||
-rw-r--r-- | net/test/scoped_mock_log.cc | 58 | ||||
-rw-r--r-- | net/test/scoped_mock_log.h | 98 |
5 files changed, 327 insertions, 0 deletions
diff --git a/net/test/gtest_util.h b/net/test/gtest_util.h new file mode 100644 index 0000000..14492c2 --- /dev/null +++ b/net/test/gtest_util.h @@ -0,0 +1,99 @@ +// Copyright 2014 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// +// Testing utilities that extend gtest. + +#ifndef NET_QUIC_TEST_TOOLS_GTEST_UTIL_H_ +#define NET_QUIC_TEST_TOOLS_GTEST_UTIL_H_ + +#include "net/test/scoped_disable_exit_on_dfatal.h" +#include "net/test/scoped_mock_log.h" +#include "testing/gmock/include/gmock/gmock.h" +#include "testing/gtest/include/gtest/gtest.h" + +namespace net { +namespace test { + +// Internal implementation for the EXPECT_DFATAL and ASSERT_DFATAL +// macros. Do not use this directly. +#define GTEST_DFATAL_(statement, matcher, fail) \ + GTEST_AMBIGUOUS_ELSE_BLOCKER_ \ + if (true) { \ + ::net::test::ScopedMockLog gtest_log; \ + ::net::test::ScopedDisableExitOnDFatal gtest_disable_exit; \ + using ::testing::_; \ + EXPECT_CALL(gtest_log, Log(_, _, _, _, _)) \ + .WillRepeatedly(::testing::Return(false)); \ + EXPECT_CALL(gtest_log, Log(logging::LOG_DFATAL, _, _, _, matcher)) \ + .Times(::testing::AtLeast(1)) \ + .WillOnce(::testing::Return(false)); \ + gtest_log.StartCapturingLogs(); \ + { statement; } \ + gtest_log.StopCapturingLogs(); \ + if (!testing::Mock::VerifyAndClear(>est_log)) { \ + goto GTEST_CONCAT_TOKEN_(gtest_label_dfatal_, __LINE__); \ + } \ + } else \ + GTEST_CONCAT_TOKEN_(gtest_label_dfatal_, __LINE__): \ + fail("") + +// The EXPECT_DFATAL and ASSERT_DFATAL macros are lightweight +// alternatives to EXPECT_DEBUG_DEATH and ASSERT_DEBUG_DEATH. They +// are appropriate for testing that your code logs a message at the +// DFATAL level. +// +// Unlike EXPECT_DEBUG_DEATH and ASSERT_DEBUG_DEATH, these macros +// execute the given statement in the current process, not a forked +// one. This works because we disable exiting the program for +// LOG(DFATAL). This makes the tests run more quickly. +// +// The _WITH() variants allow one to specify any matcher for the +// DFATAL log message, whereas the other variants assume a regex. + +#define EXPECT_DFATAL_WITH(statement, matcher) \ + GTEST_DFATAL_(statement, matcher, GTEST_NONFATAL_FAILURE_) + +#define ASSERT_DFATAL_WITH(statement, matcher) \ + GTEST_DFATAL_(statement, matcher, GTEST_FATAL_FAILURE_) + +#define EXPECT_DFATAL(statement, regex) \ + EXPECT_DFATAL_WITH(statement, ::testing::ContainsRegex(regex)) + +#define ASSERT_DFATAL(statement, regex) \ + ASSERT_DFATAL_WITH(statement, ::testing::ContainsRegex(regex)) + +// The EXPECT_DEBUG_DFATAL and ASSERT_DEBUG_DFATAL macros are similar to +// EXPECT_DFATAL and ASSERT_DFATAL. Use them in conjunction with DLOG(DFATAL) +// or similar macros that produce no-op in opt build and DFATAL in dbg build. + +#ifndef NDEBUG + +#define EXPECT_DEBUG_DFATAL(statement, regex) \ + EXPECT_DFATAL(statement, regex) +#define ASSERT_DEBUG_DFATAL(statement, regex) \ + ASSERT_DFATAL(statement, regex) + +#else // NDEBUG + +#define EXPECT_DEBUG_DFATAL(statement, regex) \ + GTEST_AMBIGUOUS_ELSE_BLOCKER_ \ + if (true) { \ + (void)(regex); \ + statement; \ + } else \ + GTEST_NONFATAL_FAILURE_("") +#define ASSERT_DEBUG_DFATAL(statement, regex) \ + GTEST_AMBIGUOUS_ELSE_BLOCKER_ \ + if (true) { \ + (void)(regex); \ + statement; \ + } else \ + GTEST_NONFATAL_FAILURE_("") + +#endif // NDEBUG + +} // namespace test +} // namespace net + +#endif // NET_QUIC_TEST_TOOLS_GTEST_UTIL_H_ diff --git a/net/test/scoped_disable_exit_on_dfatal.cc b/net/test/scoped_disable_exit_on_dfatal.cc new file mode 100644 index 0000000..f909126 --- /dev/null +++ b/net/test/scoped_disable_exit_on_dfatal.cc @@ -0,0 +1,33 @@ +// Copyright 2014 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "net/test/scoped_disable_exit_on_dfatal.h" + +#include "base/logging.h" + +namespace net { +namespace test { + +// static +ScopedDisableExitOnDFatal* ScopedDisableExitOnDFatal::g_instance_ = NULL; + +ScopedDisableExitOnDFatal::ScopedDisableExitOnDFatal() { + CHECK(!g_instance_); + g_instance_ = this; + logging::SetLogAssertHandler(LogAssertHandler); +} + +ScopedDisableExitOnDFatal::~ScopedDisableExitOnDFatal() { + CHECK_EQ(g_instance_, this); + logging::SetLogAssertHandler(NULL); + g_instance_ = NULL; +} + +// static +void ScopedDisableExitOnDFatal::LogAssertHandler(const std::string& str) { + // Simply swallow the assert. +} + +} // namespace test +} // namespace net diff --git a/net/test/scoped_disable_exit_on_dfatal.h b/net/test/scoped_disable_exit_on_dfatal.h new file mode 100644 index 0000000..5df8ff7 --- /dev/null +++ b/net/test/scoped_disable_exit_on_dfatal.h @@ -0,0 +1,39 @@ +// Copyright 2014 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef NET_QUIC_TEST_TOOLS_SCOPED_DISABLE_EXIT_ON_DFATAL_H_ +#define NET_QUIC_TEST_TOOLS_SCOPED_DISABLE_EXIT_ON_DFATAL_H_ + +#include "base/logging.h" +#include "testing/gmock/include/gmock/gmock.h" +#include "testing/gtest/include/gtest/gtest.h" + +namespace net { +namespace test { + + +// The ScopedDisableExitOnDFatal class is used to disable exiting the +// program when we encounter a LOG(DFATAL) within the current block. +// After we leave the current block, the default behavior is +// restored. +class ScopedDisableExitOnDFatal { + public: + ScopedDisableExitOnDFatal(); + ~ScopedDisableExitOnDFatal(); + + private: + // Currently active instance. + static ScopedDisableExitOnDFatal* g_instance_; + + // Static function which is set as the logging assert handler. + // Called when there is a check failure. + static void LogAssertHandler(const std::string& msg); + + DISALLOW_COPY_AND_ASSIGN(ScopedDisableExitOnDFatal); +}; + +} // namespace test +} // namespace net + +#endif // NET_QUIC_TEST_TOOLS_SCOPED_DISABLE_EXIT_ON_DFATAL_H_ diff --git a/net/test/scoped_mock_log.cc b/net/test/scoped_mock_log.cc new file mode 100644 index 0000000..3bc99cb --- /dev/null +++ b/net/test/scoped_mock_log.cc @@ -0,0 +1,58 @@ +// Copyright 2014 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "net/test/scoped_mock_log.h" + +#include "base/logging.h" + +namespace net { +namespace test { + +// static +ScopedMockLog* ScopedMockLog::g_instance_ = NULL; + +ScopedMockLog::ScopedMockLog() : is_capturing_logs_(false) {} + +ScopedMockLog::~ScopedMockLog() { + if (is_capturing_logs_) { + StopCapturingLogs(); + } +} + +void ScopedMockLog::StartCapturingLogs() { + // We don't use CHECK(), which can generate a new LOG message, and + // thus can confuse ScopedMockLog objects or other registered + // LogSinks. + RAW_CHECK(!is_capturing_logs_); + RAW_CHECK(!g_instance_); + + is_capturing_logs_ = true; + g_instance_ = this; + previous_handler_ = logging::GetLogMessageHandler(); + logging::SetLogMessageHandler(LogMessageHandler); +} + +void ScopedMockLog::StopCapturingLogs() { + // We don't use CHECK(), which can generate a new LOG message, and + // thus can confuse ScopedMockLog objects or other registered + // LogSinks. + RAW_CHECK(is_capturing_logs_); + RAW_CHECK(g_instance_ == this); + + is_capturing_logs_ = false; + logging::SetLogMessageHandler(previous_handler_); + g_instance_ = NULL; +} + +// static +bool ScopedMockLog::LogMessageHandler(int severity, + const char* file, + int line, + size_t message_start, + const std::string& str) { + return g_instance_->Log(severity, file, line, message_start, str); +} + +} // namespace test +} // namespace net diff --git a/net/test/scoped_mock_log.h b/net/test/scoped_mock_log.h new file mode 100644 index 0000000..e1edfcc --- /dev/null +++ b/net/test/scoped_mock_log.h @@ -0,0 +1,98 @@ +// Copyright 2014 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef NET_QUIC_TEST_TOOLS_SCOPED_MOCK_LOG_H_ +#define NET_QUIC_TEST_TOOLS_SCOPED_MOCK_LOG_H_ + +#include "base/logging.h" +#include "testing/gmock/include/gmock/gmock.h" +#include "testing/gtest/include/gtest/gtest.h" + +namespace net { +namespace test { + +// A ScopedMockLog object intercepts LOG() messages issued during its +// lifespan. Using this together with gMock, it's very easy to test +// how a piece of code calls LOG(). The typical usage: +// +// TEST(FooTest, LogsCorrectly) { +// ScopedMockLog log; +// +// // We expect the WARNING "Something bad!" exactly twice. +// EXPECT_CALL(log, Log(WARNING, _, "Something bad!")) +// .Times(2); +// +// // We allow foo.cc to call LOG(INFO) any number of times. +// EXPECT_CALL(log, Log(INFO, HasSubstr("/foo.cc"), _)) +// .Times(AnyNumber()); +// +// log.StartCapturingLogs(); // Call this after done setting expectations. +// Foo(); // Exercises the code under test. +// } +// +// CAVEAT: base/logging does not allow a thread to call LOG() again +// when it's already inside a LOG() call. Doing so will cause a +// deadlock. Therefore, it's the user's responsibility to not call +// LOG() in an action triggered by ScopedMockLog::Log(). You may call +// RAW_LOG() instead. +class ScopedMockLog { + public: + // Creates a ScopedMockLog object that is not capturing logs. + // If it were to start to capture logs, it could be a problem if + // some other threads already exist and are logging, as the user + // hasn't had a chance to set up expectation on this object yet + // (calling a mock method before setting the expectation is + // UNDEFINED behavior). + ScopedMockLog(); + + // When the object is destructed, it stops intercepting logs. + ~ScopedMockLog(); + + // Starts log capturing if the object isn't already doing so. + // Otherwise crashes. Usually this method is called in the same + // thread that created this object. It is the user's responsibility + // to not call this method if another thread may be calling it or + // StopCapturingLogs() at the same time. + void StartCapturingLogs(); + + // Stops log capturing if the object is capturing logs. Otherwise + // crashes. Usually this method is called in the same thread that + // created this object. It is the user's responsibility to not call + // this method if another thread may be calling it or + // StartCapturingLogs() at the same time. + void StopCapturingLogs(); + + // Sets the Log Message Handler that gets passed every log message before + // it's sent to other log destinations (if any). + // Returns true to signal that it handled the message and the message + // should not be sent to other log destinations. + MOCK_METHOD5(Log, bool(int severity, + const char* file, + int line, + size_t message_start, + const std::string& str)); + + private: + // The currently active scoped mock log. + static ScopedMockLog* g_instance_; + + // Static function which is set as the logging message handler. + // Called once for each message. + static bool LogMessageHandler(int severity, + const char* file, + int line, + size_t message_start, + const std::string& str); + + // True if this object is currently capturing logs. + bool is_capturing_logs_; + + // The previous handler to restore when the ScopedMockLog is destroyed. + logging::LogMessageHandlerFunction previous_handler_; +}; + +} // namespace test +} // namespace net + +#endif // NET_QUIC_TEST_TOOLS_SCOPED_MOCK_LOG_H_ |