blob: 8331c370fc65d53a9d66937e9619da3224f4273a [file] [log] [blame]
Brian Silvermanf665d692013-02-17 22:11:39 -08001#include <string>
2
Brian Silvermanfe457de2014-05-26 22:04:08 -07003#include <inttypes.h>
4
Brian Silvermanf665d692013-02-17 22:11:39 -08005#include "gtest/gtest.h"
6
7#include "aos/common/logging/logging_impl.h"
8#include "aos/common/time.h"
Brian Silvermanf665d692013-02-17 22:11:39 -08009
10using ::testing::AssertionResult;
11using ::testing::AssertionSuccess;
12using ::testing::AssertionFailure;
13
14namespace aos {
15namespace logging {
16namespace testing {
17
18class TestLogImplementation : public LogImplementation {
Brian Silvermanf7986142014-04-21 17:42:35 -070019 __attribute__((format(GOOD_PRINTF_FORMAT_TYPE, 3, 0)))
Brian Silvermanf665d692013-02-17 22:11:39 -080020 virtual void DoLog(log_level level, const char *format, va_list ap) {
21 internal::FillInMessage(level, format, ap, &message_);
22
Brian Silvermanfe457de2014-05-26 22:04:08 -070023 if (level == FATAL) {
24 internal::PrintMessage(stderr, message_);
25 abort();
26 }
27
Brian Silvermanf665d692013-02-17 22:11:39 -080028 used_ = true;
29 }
30
31 LogMessage message_;
32
33 public:
34 const LogMessage &message() { return message_; }
35 bool used() { return used_; }
36 void reset_used() { used_ = false; }
37
38 TestLogImplementation() : used_(false) {}
39
40 bool used_;
41};
42class LoggingTest : public ::testing::Test {
43 protected:
44 AssertionResult WasAnythingLogged() {
45 if (log_implementation->used()) {
46 return AssertionSuccess() << "read message '" <<
47 log_implementation->message().message << "'";
48 }
49 return AssertionFailure();
50 }
51 AssertionResult WasLogged(log_level level, const std::string message) {
52 if (!log_implementation->used()) {
53 return AssertionFailure() << "nothing was logged";
54 }
55 if (log_implementation->message().level != level) {
56 return AssertionFailure() << "a message with level " <<
57 log_str(log_implementation->message().level) <<
58 " was logged instead of " << log_str(level);
59 }
60 internal::Context *context = internal::Context::Get();
61 if (log_implementation->message().source != context->source) {
Brian Silvermanf0bb8372014-04-30 15:58:55 -070062 LOG(FATAL, "got a message from %" PRIu32 ", but we're %" PRIu32 "\n",
Brian Silvermanf665d692013-02-17 22:11:39 -080063 static_cast<uint32_t>(log_implementation->message().source),
64 static_cast<uint32_t>(context->source));
65 }
Brian Silvermanf0bb8372014-04-30 15:58:55 -070066 if (log_implementation->message().name_length != context->name.size() ||
67 memcmp(log_implementation->message().name, context->name.c_str(),
68 context->name.size()) !=
69 0) {
70 LOG(FATAL, "got a message from %.*s, but we're %s\n",
71 static_cast<int>(log_implementation->message().name_length),
Brian Silvermanab6615c2013-03-05 20:29:29 -080072 log_implementation->message().name, context->name.c_str());
Brian Silvermanf665d692013-02-17 22:11:39 -080073 }
74 if (strstr(log_implementation->message().message, message.c_str())
75 == NULL) {
76 return AssertionFailure() << "got a message of '" <<
77 log_implementation->message().message <<
78 "' but expected it to contain '" << message << "'";
79 }
80
81 return AssertionSuccess() << log_implementation->message().message;
82 }
83
84 private:
85 virtual void SetUp() {
86 static bool first = true;
87 if (first) {
88 first = false;
89
90 Init();
Brian Silvermanf665d692013-02-17 22:11:39 -080091 AddImplementation(log_implementation = new TestLogImplementation());
92 }
93
94 log_implementation->reset_used();
95 }
96 virtual void TearDown() {
97 Cleanup();
98 }
99
100 static TestLogImplementation *log_implementation;
101};
102TestLogImplementation *LoggingTest::log_implementation(NULL);
103typedef LoggingTest LoggingDeathTest;
104
105// Tests both basic logging functionality and that the test setup works
106// correctly.
107TEST_F(LoggingTest, Basic) {
108 EXPECT_FALSE(WasAnythingLogged());
109 LOG(INFO, "test log 1\n");
110 EXPECT_TRUE(WasLogged(INFO, "test log 1\n"));
111 LOG(INFO, "test log 1.5\n");
112 // there's a subtle typo on purpose...
113 EXPECT_FALSE(WasLogged(INFO, "test log 15\n"));
114 LOG(ERROR, "test log 2=%d\n", 55);
115 EXPECT_TRUE(WasLogged(ERROR, "test log 2=55\n"));
116 LOG(ERROR, "test log 3\n");
117 EXPECT_FALSE(WasLogged(WARNING, "test log 3\n"));
118 LOG(WARNING, "test log 4\n");
119 EXPECT_TRUE(WasAnythingLogged());
120}
121TEST_F(LoggingTest, Cork) {
122 static const int begin_line = __LINE__;
123 LOG_CORK("first part ");
124 LOG_CORK("second part (=%d) ", 19);
125 EXPECT_FALSE(WasAnythingLogged());
126 LOG_CORK("third part ");
127 static const int end_line = __LINE__;
128 LOG_UNCORK(WARNING, "last part %d\n", 5);
129 std::stringstream expected;
130 expected << "logging_impl_test.cc: ";
131 expected << (begin_line + 1);
132 expected << "-";
133 expected << (end_line + 1);
134 expected << ": ";
Brian Silvermanc0a0d112013-09-19 21:08:49 -0700135 expected << __func__;
Brian Silvermanf665d692013-02-17 22:11:39 -0800136 expected << ": first part second part (=19) third part last part 5\n";
137 EXPECT_TRUE(WasLogged(WARNING, expected.str()));
138}
139
Brian Silvermanf665d692013-02-17 22:11:39 -0800140TEST_F(LoggingDeathTest, Fatal) {
141 ASSERT_EXIT(LOG(FATAL, "this should crash it\n"),
142 ::testing::KilledBySignal(SIGABRT),
143 "this should crash it");
144}
Brian Silvermanfe457de2014-05-26 22:04:08 -0700145
146TEST_F(LoggingDeathTest, PCHECK) {
147 EXPECT_DEATH(PCHECK(fprintf(stdin, "nope")),
148 ".*fprintf\\(stdin, \"nope\"\\).*failed.*");
149}
150
151TEST_F(LoggingTest, PCHECK) {
152 EXPECT_EQ(7, PCHECK(printf("abc123\n")));
153}
Brian Silvermanf665d692013-02-17 22:11:39 -0800154
155TEST_F(LoggingTest, PrintfDirectives) {
156 LOG(INFO, "test log %%1 %%d\n");
157 EXPECT_TRUE(WasLogged(INFO, "test log %1 %d\n"));
158 LOG_DYNAMIC(WARNING, "test log %%2 %%f\n");
159 EXPECT_TRUE(WasLogged(WARNING, "test log %2 %f\n"));
160 LOG_CORK("log 3 part %%1 %%d ");
161 LOG_UNCORK(DEBUG, "log 3 part %%2 %%f\n");
162 EXPECT_TRUE(WasLogged(DEBUG, "log 3 part %1 %d log 3 part %2 %f\n"));
163}
164
165TEST_F(LoggingTest, Timing) {
166 // For writing only.
167 //static const long kTimingCycles = 5000000;
168 static const long kTimingCycles = 5000;
169
170 time::Time start = time::Time::Now();
171 for (long i = 0; i < kTimingCycles; ++i) {
172 LOG(INFO, "a\n");
173 }
174 time::Time end = time::Time::Now();
175 time::Time diff = end - start;
Brian Silverman41abe012014-02-08 18:25:02 -0800176 printf("short message took %" PRId64 " nsec for %ld\n",
Brian Silvermanf665d692013-02-17 22:11:39 -0800177 diff.ToNSec(), kTimingCycles);
178
179 start = time::Time::Now();
180 for (long i = 0; i < kTimingCycles; ++i) {
181 LOG(INFO, "something longer than just \"a\" to log to test timing\n");
182 }
183 end = time::Time::Now();
184 diff = end - start;
Brian Silverman41abe012014-02-08 18:25:02 -0800185 printf("long message took %" PRId64 " nsec for %ld\n",
Brian Silvermanf665d692013-02-17 22:11:39 -0800186 diff.ToNSec(), kTimingCycles);
187}
188
189} // namespace testing
190} // namespace logging
191} // namespace aos