blob: f472bef81a3edfb6e78867239c3c341e6e6cc58d [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"
Brian4a424a22014-04-02 11:52:45 -07008#include <inttypes.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
23 used_ = true;
24 }
25
26 LogMessage message_;
27
28 public:
29 const LogMessage &message() { return message_; }
30 bool used() { return used_; }
31 void reset_used() { used_ = false; }
32
33 TestLogImplementation() : used_(false) {}
34
35 bool used_;
36};
37class LoggingTest : public ::testing::Test {
38 protected:
39 AssertionResult WasAnythingLogged() {
40 if (log_implementation->used()) {
41 return AssertionSuccess() << "read message '" <<
42 log_implementation->message().message << "'";
43 }
44 return AssertionFailure();
45 }
46 AssertionResult WasLogged(log_level level, const std::string message) {
47 if (!log_implementation->used()) {
48 return AssertionFailure() << "nothing was logged";
49 }
50 if (log_implementation->message().level != level) {
51 return AssertionFailure() << "a message with level " <<
52 log_str(log_implementation->message().level) <<
53 " was logged instead of " << log_str(level);
54 }
55 internal::Context *context = internal::Context::Get();
56 if (log_implementation->message().source != context->source) {
Brian Silverman8efe23e2013-07-07 23:31:37 -070057 Die("got a message from %" PRIu32 ", but we're %" PRIu32 "\n",
Brian Silvermanf665d692013-02-17 22:11:39 -080058 static_cast<uint32_t>(log_implementation->message().source),
59 static_cast<uint32_t>(context->source));
60 }
Brian Silvermanab6615c2013-03-05 20:29:29 -080061 if (strcmp(log_implementation->message().name,
62 context->name.c_str()) != 0) {
Brian Silvermanf665d692013-02-17 22:11:39 -080063 Die("got a message from %s, but we're %s\n",
Brian Silvermanab6615c2013-03-05 20:29:29 -080064 log_implementation->message().name, context->name.c_str());
Brian Silvermanf665d692013-02-17 22:11:39 -080065 }
66 if (strstr(log_implementation->message().message, message.c_str())
67 == NULL) {
68 return AssertionFailure() << "got a message of '" <<
69 log_implementation->message().message <<
70 "' but expected it to contain '" << message << "'";
71 }
72
73 return AssertionSuccess() << log_implementation->message().message;
74 }
75
76 private:
77 virtual void SetUp() {
78 static bool first = true;
79 if (first) {
80 first = false;
81
82 Init();
83 // We'll end up with several of them stacked up, but it really doesn't
84 // matter.
85 AddImplementation(log_implementation = new TestLogImplementation());
86 }
87
88 log_implementation->reset_used();
89 }
90 virtual void TearDown() {
91 Cleanup();
92 }
93
94 static TestLogImplementation *log_implementation;
95};
96TestLogImplementation *LoggingTest::log_implementation(NULL);
97typedef LoggingTest LoggingDeathTest;
98
99// Tests both basic logging functionality and that the test setup works
100// correctly.
101TEST_F(LoggingTest, Basic) {
102 EXPECT_FALSE(WasAnythingLogged());
103 LOG(INFO, "test log 1\n");
104 EXPECT_TRUE(WasLogged(INFO, "test log 1\n"));
105 LOG(INFO, "test log 1.5\n");
106 // there's a subtle typo on purpose...
107 EXPECT_FALSE(WasLogged(INFO, "test log 15\n"));
108 LOG(ERROR, "test log 2=%d\n", 55);
109 EXPECT_TRUE(WasLogged(ERROR, "test log 2=55\n"));
110 LOG(ERROR, "test log 3\n");
111 EXPECT_FALSE(WasLogged(WARNING, "test log 3\n"));
112 LOG(WARNING, "test log 4\n");
113 EXPECT_TRUE(WasAnythingLogged());
114}
115TEST_F(LoggingTest, Cork) {
116 static const int begin_line = __LINE__;
117 LOG_CORK("first part ");
118 LOG_CORK("second part (=%d) ", 19);
119 EXPECT_FALSE(WasAnythingLogged());
120 LOG_CORK("third part ");
121 static const int end_line = __LINE__;
122 LOG_UNCORK(WARNING, "last part %d\n", 5);
123 std::stringstream expected;
124 expected << "logging_impl_test.cc: ";
125 expected << (begin_line + 1);
126 expected << "-";
127 expected << (end_line + 1);
128 expected << ": ";
Brian Silvermanc0a0d112013-09-19 21:08:49 -0700129 expected << __func__;
Brian Silvermanf665d692013-02-17 22:11:39 -0800130 expected << ": first part second part (=19) third part last part 5\n";
131 EXPECT_TRUE(WasLogged(WARNING, expected.str()));
132}
133
134#ifndef __VXWORKS__
135TEST_F(LoggingDeathTest, Fatal) {
136 ASSERT_EXIT(LOG(FATAL, "this should crash it\n"),
137 ::testing::KilledBySignal(SIGABRT),
138 "this should crash it");
139}
140#endif
141
142TEST_F(LoggingTest, PrintfDirectives) {
143 LOG(INFO, "test log %%1 %%d\n");
144 EXPECT_TRUE(WasLogged(INFO, "test log %1 %d\n"));
145 LOG_DYNAMIC(WARNING, "test log %%2 %%f\n");
146 EXPECT_TRUE(WasLogged(WARNING, "test log %2 %f\n"));
147 LOG_CORK("log 3 part %%1 %%d ");
148 LOG_UNCORK(DEBUG, "log 3 part %%2 %%f\n");
149 EXPECT_TRUE(WasLogged(DEBUG, "log 3 part %1 %d log 3 part %2 %f\n"));
150}
151
152TEST_F(LoggingTest, Timing) {
153 // For writing only.
154 //static const long kTimingCycles = 5000000;
155 static const long kTimingCycles = 5000;
156
157 time::Time start = time::Time::Now();
158 for (long i = 0; i < kTimingCycles; ++i) {
159 LOG(INFO, "a\n");
160 }
161 time::Time end = time::Time::Now();
162 time::Time diff = end - start;
Brian Silverman41abe012014-02-08 18:25:02 -0800163 printf("short message took %" PRId64 " nsec for %ld\n",
Brian Silvermanf665d692013-02-17 22:11:39 -0800164 diff.ToNSec(), kTimingCycles);
165
166 start = time::Time::Now();
167 for (long i = 0; i < kTimingCycles; ++i) {
168 LOG(INFO, "something longer than just \"a\" to log to test timing\n");
169 }
170 end = time::Time::Now();
171 diff = end - start;
Brian Silverman41abe012014-02-08 18:25:02 -0800172 printf("long message took %" PRId64 " nsec for %ld\n",
Brian Silvermanf665d692013-02-17 22:11:39 -0800173 diff.ToNSec(), kTimingCycles);
174}
175
176} // namespace testing
177} // namespace logging
178} // namespace aos