blob: 34bcdd19463d27e7a81f3d58f17e80b46b9143d8 [file] [log] [blame]
Brian Silvermanf665d692013-02-17 22:11:39 -08001#include <string>
2
3#include "gtest/gtest.h"
4
5#include "aos/common/logging/logging_impl.h"
6#include "aos/common/time.h"
Brian4a424a22014-04-02 11:52:45 -07007#include <inttypes.h>
Brian Silvermanf665d692013-02-17 22:11:39 -08008
9using ::testing::AssertionResult;
10using ::testing::AssertionSuccess;
11using ::testing::AssertionFailure;
12
13namespace aos {
14namespace logging {
15namespace testing {
16
17class TestLogImplementation : public LogImplementation {
Brian Silvermanf7986142014-04-21 17:42:35 -070018 __attribute__((format(GOOD_PRINTF_FORMAT_TYPE, 3, 0)))
Brian Silvermanf665d692013-02-17 22:11:39 -080019 virtual void DoLog(log_level level, const char *format, va_list ap) {
20 internal::FillInMessage(level, format, ap, &message_);
21
22 used_ = true;
23 }
24
25 LogMessage message_;
26
27 public:
28 const LogMessage &message() { return message_; }
29 bool used() { return used_; }
30 void reset_used() { used_ = false; }
31
32 TestLogImplementation() : used_(false) {}
33
34 bool used_;
35};
36class LoggingTest : public ::testing::Test {
37 protected:
38 AssertionResult WasAnythingLogged() {
39 if (log_implementation->used()) {
40 return AssertionSuccess() << "read message '" <<
41 log_implementation->message().message << "'";
42 }
43 return AssertionFailure();
44 }
45 AssertionResult WasLogged(log_level level, const std::string message) {
46 if (!log_implementation->used()) {
47 return AssertionFailure() << "nothing was logged";
48 }
49 if (log_implementation->message().level != level) {
50 return AssertionFailure() << "a message with level " <<
51 log_str(log_implementation->message().level) <<
52 " was logged instead of " << log_str(level);
53 }
54 internal::Context *context = internal::Context::Get();
55 if (log_implementation->message().source != context->source) {
Brian Silvermanf0bb8372014-04-30 15:58:55 -070056 LOG(FATAL, "got a message from %" PRIu32 ", but we're %" PRIu32 "\n",
Brian Silvermanf665d692013-02-17 22:11:39 -080057 static_cast<uint32_t>(log_implementation->message().source),
58 static_cast<uint32_t>(context->source));
59 }
Brian Silvermanf0bb8372014-04-30 15:58:55 -070060 if (log_implementation->message().name_length != context->name.size() ||
61 memcmp(log_implementation->message().name, context->name.c_str(),
62 context->name.size()) !=
63 0) {
64 LOG(FATAL, "got a message from %.*s, but we're %s\n",
65 static_cast<int>(log_implementation->message().name_length),
Brian Silvermanab6615c2013-03-05 20:29:29 -080066 log_implementation->message().name, context->name.c_str());
Brian Silvermanf665d692013-02-17 22:11:39 -080067 }
68 if (strstr(log_implementation->message().message, message.c_str())
69 == NULL) {
70 return AssertionFailure() << "got a message of '" <<
71 log_implementation->message().message <<
72 "' but expected it to contain '" << message << "'";
73 }
74
75 return AssertionSuccess() << log_implementation->message().message;
76 }
77
78 private:
79 virtual void SetUp() {
80 static bool first = true;
81 if (first) {
82 first = false;
83
84 Init();
85 // We'll end up with several of them stacked up, but it really doesn't
86 // matter.
87 AddImplementation(log_implementation = new TestLogImplementation());
88 }
89
90 log_implementation->reset_used();
91 }
92 virtual void TearDown() {
93 Cleanup();
94 }
95
96 static TestLogImplementation *log_implementation;
97};
98TestLogImplementation *LoggingTest::log_implementation(NULL);
99typedef LoggingTest LoggingDeathTest;
100
101// Tests both basic logging functionality and that the test setup works
102// correctly.
103TEST_F(LoggingTest, Basic) {
104 EXPECT_FALSE(WasAnythingLogged());
105 LOG(INFO, "test log 1\n");
106 EXPECT_TRUE(WasLogged(INFO, "test log 1\n"));
107 LOG(INFO, "test log 1.5\n");
108 // there's a subtle typo on purpose...
109 EXPECT_FALSE(WasLogged(INFO, "test log 15\n"));
110 LOG(ERROR, "test log 2=%d\n", 55);
111 EXPECT_TRUE(WasLogged(ERROR, "test log 2=55\n"));
112 LOG(ERROR, "test log 3\n");
113 EXPECT_FALSE(WasLogged(WARNING, "test log 3\n"));
114 LOG(WARNING, "test log 4\n");
115 EXPECT_TRUE(WasAnythingLogged());
116}
117TEST_F(LoggingTest, Cork) {
118 static const int begin_line = __LINE__;
119 LOG_CORK("first part ");
120 LOG_CORK("second part (=%d) ", 19);
121 EXPECT_FALSE(WasAnythingLogged());
122 LOG_CORK("third part ");
123 static const int end_line = __LINE__;
124 LOG_UNCORK(WARNING, "last part %d\n", 5);
125 std::stringstream expected;
126 expected << "logging_impl_test.cc: ";
127 expected << (begin_line + 1);
128 expected << "-";
129 expected << (end_line + 1);
130 expected << ": ";
Brian Silvermanc0a0d112013-09-19 21:08:49 -0700131 expected << __func__;
Brian Silvermanf665d692013-02-17 22:11:39 -0800132 expected << ": first part second part (=19) third part last part 5\n";
133 EXPECT_TRUE(WasLogged(WARNING, expected.str()));
134}
135
136#ifndef __VXWORKS__
137TEST_F(LoggingDeathTest, Fatal) {
138 ASSERT_EXIT(LOG(FATAL, "this should crash it\n"),
139 ::testing::KilledBySignal(SIGABRT),
140 "this should crash it");
141}
142#endif
143
144TEST_F(LoggingTest, PrintfDirectives) {
145 LOG(INFO, "test log %%1 %%d\n");
146 EXPECT_TRUE(WasLogged(INFO, "test log %1 %d\n"));
147 LOG_DYNAMIC(WARNING, "test log %%2 %%f\n");
148 EXPECT_TRUE(WasLogged(WARNING, "test log %2 %f\n"));
149 LOG_CORK("log 3 part %%1 %%d ");
150 LOG_UNCORK(DEBUG, "log 3 part %%2 %%f\n");
151 EXPECT_TRUE(WasLogged(DEBUG, "log 3 part %1 %d log 3 part %2 %f\n"));
152}
153
154TEST_F(LoggingTest, Timing) {
155 // For writing only.
156 //static const long kTimingCycles = 5000000;
157 static const long kTimingCycles = 5000;
158
159 time::Time start = time::Time::Now();
160 for (long i = 0; i < kTimingCycles; ++i) {
161 LOG(INFO, "a\n");
162 }
163 time::Time end = time::Time::Now();
164 time::Time diff = end - start;
Brian Silverman41abe012014-02-08 18:25:02 -0800165 printf("short message took %" PRId64 " nsec for %ld\n",
Brian Silvermanf665d692013-02-17 22:11:39 -0800166 diff.ToNSec(), kTimingCycles);
167
168 start = time::Time::Now();
169 for (long i = 0; i < kTimingCycles; ++i) {
170 LOG(INFO, "something longer than just \"a\" to log to test timing\n");
171 }
172 end = time::Time::Now();
173 diff = end - start;
Brian Silverman41abe012014-02-08 18:25:02 -0800174 printf("long message took %" PRId64 " nsec for %ld\n",
Brian Silvermanf665d692013-02-17 22:11:39 -0800175 diff.ToNSec(), kTimingCycles);
176}
177
178} // namespace testing
179} // namespace logging
180} // namespace aos