blob: 16a02850cb6c73a6514948c401651e17cc673253 [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"
7#include "aos/common/die.h"
8#include "aos/common/inttypes.h"
9
10using ::testing::AssertionResult;
11using ::testing::AssertionSuccess;
12using ::testing::AssertionFailure;
13
14namespace aos {
15namespace logging {
16namespace testing {
17
18class TestLogImplementation : public LogImplementation {
19 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 Silverman8efe23e2013-07-07 23:31:37 -070056 Die("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 Silvermanab6615c2013-03-05 20:29:29 -080060 if (strcmp(log_implementation->message().name,
61 context->name.c_str()) != 0) {
Brian Silvermanf665d692013-02-17 22:11:39 -080062 Die("got a message from %s, but we're %s\n",
Brian Silvermanab6615c2013-03-05 20:29:29 -080063 log_implementation->message().name, context->name.c_str());
Brian Silvermanf665d692013-02-17 22:11:39 -080064 }
65 if (strstr(log_implementation->message().message, message.c_str())
66 == NULL) {
67 return AssertionFailure() << "got a message of '" <<
68 log_implementation->message().message <<
69 "' but expected it to contain '" << message << "'";
70 }
71
72 return AssertionSuccess() << log_implementation->message().message;
73 }
74
75 private:
76 virtual void SetUp() {
77 static bool first = true;
78 if (first) {
79 first = false;
80
81 Init();
82 // We'll end up with several of them stacked up, but it really doesn't
83 // matter.
84 AddImplementation(log_implementation = new TestLogImplementation());
85 }
86
87 log_implementation->reset_used();
88 }
89 virtual void TearDown() {
90 Cleanup();
91 }
92
93 static TestLogImplementation *log_implementation;
94};
95TestLogImplementation *LoggingTest::log_implementation(NULL);
96typedef LoggingTest LoggingDeathTest;
97
98// Tests both basic logging functionality and that the test setup works
99// correctly.
100TEST_F(LoggingTest, Basic) {
101 EXPECT_FALSE(WasAnythingLogged());
102 LOG(INFO, "test log 1\n");
103 EXPECT_TRUE(WasLogged(INFO, "test log 1\n"));
104 LOG(INFO, "test log 1.5\n");
105 // there's a subtle typo on purpose...
106 EXPECT_FALSE(WasLogged(INFO, "test log 15\n"));
107 LOG(ERROR, "test log 2=%d\n", 55);
108 EXPECT_TRUE(WasLogged(ERROR, "test log 2=55\n"));
109 LOG(ERROR, "test log 3\n");
110 EXPECT_FALSE(WasLogged(WARNING, "test log 3\n"));
111 LOG(WARNING, "test log 4\n");
112 EXPECT_TRUE(WasAnythingLogged());
113}
114TEST_F(LoggingTest, Cork) {
115 static const int begin_line = __LINE__;
116 LOG_CORK("first part ");
117 LOG_CORK("second part (=%d) ", 19);
118 EXPECT_FALSE(WasAnythingLogged());
119 LOG_CORK("third part ");
120 static const int end_line = __LINE__;
121 LOG_UNCORK(WARNING, "last part %d\n", 5);
122 std::stringstream expected;
123 expected << "logging_impl_test.cc: ";
124 expected << (begin_line + 1);
125 expected << "-";
126 expected << (end_line + 1);
127 expected << ": ";
128 expected << __PRETTY_FUNCTION__;
129 expected << ": first part second part (=19) third part last part 5\n";
130 EXPECT_TRUE(WasLogged(WARNING, expected.str()));
131}
132
133#ifndef __VXWORKS__
134TEST_F(LoggingDeathTest, Fatal) {
135 ASSERT_EXIT(LOG(FATAL, "this should crash it\n"),
136 ::testing::KilledBySignal(SIGABRT),
137 "this should crash it");
138}
139#endif
140
141TEST_F(LoggingTest, PrintfDirectives) {
142 LOG(INFO, "test log %%1 %%d\n");
143 EXPECT_TRUE(WasLogged(INFO, "test log %1 %d\n"));
144 LOG_DYNAMIC(WARNING, "test log %%2 %%f\n");
145 EXPECT_TRUE(WasLogged(WARNING, "test log %2 %f\n"));
146 LOG_CORK("log 3 part %%1 %%d ");
147 LOG_UNCORK(DEBUG, "log 3 part %%2 %%f\n");
148 EXPECT_TRUE(WasLogged(DEBUG, "log 3 part %1 %d log 3 part %2 %f\n"));
149}
150
151TEST_F(LoggingTest, Timing) {
152 // For writing only.
153 //static const long kTimingCycles = 5000000;
154 static const long kTimingCycles = 5000;
155
156 time::Time start = time::Time::Now();
157 for (long i = 0; i < kTimingCycles; ++i) {
158 LOG(INFO, "a\n");
159 }
160 time::Time end = time::Time::Now();
161 time::Time diff = end - start;
162 printf("short message took %lld nsec for %ld\n",
163 diff.ToNSec(), kTimingCycles);
164
165 start = time::Time::Now();
166 for (long i = 0; i < kTimingCycles; ++i) {
167 LOG(INFO, "something longer than just \"a\" to log to test timing\n");
168 }
169 end = time::Time::Now();
170 diff = end - start;
171 printf("long message took %lld nsec for %ld\n",
172 diff.ToNSec(), kTimingCycles);
173}
174
175} // namespace testing
176} // namespace logging
177} // namespace aos