summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
author <shinichiro.hamaji@gmail.com>2009-01-13 11:49:10 +0000
committer <shinichiro.hamaji@gmail.com>2009-01-13 11:49:10 +0000
commiteecffc5aa5501b69e9d493ebe8b4e19699d62fb2 (patch)
tree63c0e61ee0953ea95d554a7bb1a180134d06688a /src
parent9de1077eeddbb722714315ebca819ea4288ebb3e (diff)
downloadglog-eecffc5aa5501b69e9d493ebe8b4e19699d62fb2.tar.gz
glog-eecffc5aa5501b69e9d493ebe8b4e19699d62fb2.tar.bz2
glog-eecffc5aa5501b69e9d493ebe8b4e19699d62fb2.zip
Introduce mock-log.h for unittests.
git-svn-id: https://google-glog.googlecode.com/svn/trunk@28 eb4d4688-79bd-11dd-afb4-1d65580434c0
Diffstat (limited to 'src')
-rw-r--r--src/mock-log.h155
-rw-r--r--src/mock-log_test.cc106
2 files changed, 261 insertions, 0 deletions
diff --git a/src/mock-log.h b/src/mock-log.h
new file mode 100644
index 0000000..5b21811
--- /dev/null
+++ b/src/mock-log.h
@@ -0,0 +1,155 @@
+// Copyright (c) 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: Zhanyong Wan
+//
+// Defines the ScopedMockLog class (using Google C++ Mocking
+// Framework), which is convenient for testing code that uses LOG().
+
+#ifndef GLOG_SRC_MOCK_LOG_H_
+#define GLOG_SRC_MOCK_LOG_H_
+
+// For GOOGLE_NAMESPACE. This must go first so we get _XOPEN_SOURCE.
+#include "utilities.h"
+
+#include <string>
+
+#include <gmock/gmock.h>
+
+#include "glog/logging.h"
+
+_START_GOOGLE_NAMESPACE_
+namespace glog_testing {
+
+// A ScopedMockLog object intercepts LOG() messages issued during its
+// lifespan. Using this together with Google C++ Mocking Framework,
+// 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());
+//
+// Foo(); // Exercises the code under test.
+// }
+class ScopedMockLog : public GOOGLE_NAMESPACE::LogSink {
+ public:
+ // When a ScopedMockLog object is constructed, it starts to
+ // intercept logs.
+ ScopedMockLog() { AddLogSink(this); }
+
+ // When the object is destructed, it stops intercepting logs.
+ virtual ~ScopedMockLog() { RemoveLogSink(this); }
+
+ // Implements the mock method:
+ //
+ // void Log(LogSeverity severity, const string& file_path,
+ // const string& message);
+ //
+ // The second argument to Send() is the full path of the source file
+ // in which the LOG() was issued.
+ //
+ // Note, that in a multi-threaded environment, all LOG() messages from a
+ // single thread will be handled in sequence, but that cannot be guaranteed
+ // for messages from different threads. In fact, if the same or multiple
+ // expectations are matched on two threads concurrently, their actions will
+ // be executed concurrently as well and may interleave.
+ MOCK_METHOD3(Log, void(GOOGLE_NAMESPACE::LogSeverity severity,
+ const std::string& file_path,
+ const std::string& message));
+
+ private:
+ // Implements the send() virtual function in class LogSink.
+ // Whenever a LOG() statement is executed, this function will be
+ // invoked with information presented in the LOG().
+ //
+ // The method argument list is long and carries much information a
+ // test usually doesn't care about, so we trim the list before
+ // forwarding the call to Log(), which is much easier to use in
+ // tests.
+ //
+ // We still cannot call Log() directly, as it may invoke other LOG()
+ // messages, either due to Invoke, or due to an error logged in
+ // Google C++ Mocking Framework code, which would trigger a deadlock
+ // since a lock is held during send().
+ //
+ // Hence, we save the message for WaitTillSent() which will be called after
+ // the lock on send() is released, and we'll call Log() inside
+ // WaitTillSent(). Since while a single send() call may be running at a
+ // time, multiple WaitTillSent() calls (along with the one send() call) may
+ // be running simultaneously, we ensure thread-safety of the exchange between
+ // send() and WaitTillSent(), and that for each message, LOG(), send(),
+ // WaitTillSent() and Log() are executed in the same thread.
+ virtual void send(GOOGLE_NAMESPACE::LogSeverity severity,
+ const char* full_filename,
+ const char* base_filename, int line, const tm* tm_time,
+ const char* message, size_t message_len) {
+ // We are only interested in the log severity, full file name, and
+ // log message.
+ message_info_.severity = severity;
+ message_info_.file_path = full_filename;
+ message_info_.message = std::string(message, message_len);
+ }
+
+ // Implements the WaitTillSent() virtual function in class LogSink.
+ // It will be executed after send() and after the global logging lock is
+ // released, so calls within it (or rather within the Log() method called
+ // within) may also issue LOG() statements.
+ //
+ // LOG(), send(), WaitTillSent() and Log() will occur in the same thread for
+ // a given log message.
+ virtual void WaitTillSent() {
+ // First, and very importantly, we save a copy of the message being
+ // processed before calling Log(), since Log() may indirectly call send()
+ // and WaitTillSent() in the same thread again.
+ MessageInfo message_info = message_info_;
+ Log(message_info.severity, message_info.file_path, message_info.message);
+ }
+
+ // All relevant information about a logged message that needs to be passed
+ // from send() to WaitTillSent().
+ struct MessageInfo {
+ GOOGLE_NAMESPACE::LogSeverity severity;
+ std::string file_path;
+ std::string message;
+ };
+ MessageInfo message_info_;
+};
+
+} // namespace glog_testing
+_END_GOOGLE_NAMESPACE_
+
+#endif // GLOG_SRC_MOCK_LOG_H_
diff --git a/src/mock-log_test.cc b/src/mock-log_test.cc
new file mode 100644
index 0000000..7d58a30
--- /dev/null
+++ b/src/mock-log_test.cc
@@ -0,0 +1,106 @@
+// Copyright (c) 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: Zhanyong Wan
+
+// Tests the ScopedMockLog class.
+
+#include "mock-log.h"
+
+#include <string>
+
+#include <gmock/gmock.h>
+#include <gtest/gtest.h>
+
+namespace {
+
+using GOOGLE_NAMESPACE::INFO;
+using GOOGLE_NAMESPACE::WARNING;
+using GOOGLE_NAMESPACE::ERROR;
+using GOOGLE_NAMESPACE::glog_testing::ScopedMockLog;
+using std::string;
+using testing::_;
+using testing::HasSubstr;
+using testing::InSequence;
+using testing::InvokeWithoutArgs;
+
+// Tests that ScopedMockLog intercepts LOG()s when it's alive.
+TEST(ScopedMockLogTest, InterceptsLog) {
+ ScopedMockLog log;
+
+ InSequence s;
+ EXPECT_CALL(log, Log(WARNING, HasSubstr("/mock-log_test.cc"), "Fishy."));
+ EXPECT_CALL(log, Log(INFO, _, "Working..."))
+ .Times(2);
+ EXPECT_CALL(log, Log(ERROR, _, "Bad!!"));
+
+ LOG(WARNING) << "Fishy.";
+ LOG(INFO) << "Working...";
+ LOG(INFO) << "Working...";
+ LOG(ERROR) << "Bad!!";
+}
+
+void LogBranch() {
+ LOG(INFO) << "Logging a branch...";
+}
+
+void LogTree() {
+ LOG(INFO) << "Logging the whole tree...";
+}
+
+void LogForest() {
+ LOG(INFO) << "Logging the entire forest.";
+ LOG(INFO) << "Logging the entire forest..";
+ LOG(INFO) << "Logging the entire forest...";
+}
+
+// The purpose of the following test is to verify that intercepting logging
+// continues to work properly if a LOG statement is executed within the scope
+// of a mocked call.
+TEST(ScopedMockLogTest, LogDuringIntercept) {
+ ScopedMockLog log;
+ InSequence s;
+ EXPECT_CALL(log, Log(INFO, __FILE__, "Logging a branch..."))
+ .WillOnce(InvokeWithoutArgs(LogTree));
+ EXPECT_CALL(log, Log(INFO, __FILE__, "Logging the whole tree..."))
+ .WillOnce(InvokeWithoutArgs(LogForest));
+ EXPECT_CALL(log, Log(INFO, __FILE__, "Logging the entire forest."));
+ EXPECT_CALL(log, Log(INFO, __FILE__, "Logging the entire forest.."));
+ EXPECT_CALL(log, Log(INFO, __FILE__, "Logging the entire forest..."));
+ LogBranch();
+}
+
+} // namespace
+
+int main(int argc, char **argv) {
+ GOOGLE_NAMESPACE::InitGoogleLogging(argv[0]);
+ testing::InitGoogleMock(&argc, argv);
+
+ return RUN_ALL_TESTS();
+}