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