1 //
2 // Copyright 2022 The Abseil Authors.
3 //
4 // Licensed under the Apache License, Version 2.0 (the "License");
5 // you may not use this file except in compliance with the License.
6 // You may obtain a copy of the License at
7 //
8 // https://www.apache.org/licenses/LICENSE-2.0
9 //
10 // Unless required by applicable law or agreed to in writing, software
11 // distributed under the License is distributed on an "AS IS" BASIS,
12 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 // See the License for the specific language governing permissions and
14 // limitations under the License.
15
16 #include "absl/log/log_streamer.h"
17
18 #include <ios>
19 #include <iostream>
20 #include <utility>
21
22 #include "gmock/gmock.h"
23 #include "gtest/gtest.h"
24 #include "absl/base/attributes.h"
25 #include "absl/base/internal/sysinfo.h"
26 #include "absl/base/log_severity.h"
27 #include "absl/log/internal/test_actions.h"
28 #include "absl/log/internal/test_helpers.h"
29 #include "absl/log/internal/test_matchers.h"
30 #include "absl/log/log.h"
31 #include "absl/log/scoped_mock_log.h"
32 #include "absl/strings/string_view.h"
33
34 namespace {
35 using ::absl::log_internal::DeathTestExpectedLogging;
36 using ::absl::log_internal::DeathTestUnexpectedLogging;
37 using ::absl::log_internal::DeathTestValidateExpectations;
38 #if GTEST_HAS_DEATH_TEST
39 using ::absl::log_internal::DiedOfFatal;
40 #endif
41 using ::absl::log_internal::LogSeverity;
42 using ::absl::log_internal::Prefix;
43 using ::absl::log_internal::SourceFilename;
44 using ::absl::log_internal::SourceLine;
45 using ::absl::log_internal::Stacktrace;
46 using ::absl::log_internal::TextMessage;
47 using ::absl::log_internal::ThreadID;
48 using ::absl::log_internal::TimestampInMatchWindow;
49 using ::testing::AnyNumber;
50 using ::testing::Eq;
51 using ::testing::HasSubstr;
52 using ::testing::IsEmpty;
53 using ::testing::IsTrue;
54
55 auto* test_env ABSL_ATTRIBUTE_UNUSED = ::testing::AddGlobalTestEnvironment(
56 new absl::log_internal::LogTestEnvironment);
57
WriteToStream(absl::string_view data,std::ostream * os)58 void WriteToStream(absl::string_view data, std::ostream* os) {
59 *os << "WriteToStream: " << data;
60 }
WriteToStreamRef(absl::string_view data,std::ostream & os)61 void WriteToStreamRef(absl::string_view data, std::ostream& os) {
62 os << "WriteToStreamRef: " << data;
63 }
64
TEST(LogStreamerTest,LogInfoStreamer)65 TEST(LogStreamerTest, LogInfoStreamer) {
66 absl::ScopedMockLog test_sink(absl::MockLogDefault::kDisallowUnexpected);
67
68 EXPECT_CALL(
69 test_sink,
70 Send(AllOf(SourceFilename(Eq("path/file.cc")), SourceLine(Eq(1234)),
71 Prefix(IsTrue()), LogSeverity(Eq(absl::LogSeverity::kInfo)),
72 TimestampInMatchWindow(),
73 ThreadID(Eq(absl::base_internal::GetTID())),
74 TextMessage(Eq("WriteToStream: foo")),
75 ENCODED_MESSAGE(EqualsProto(R"pb(value {
76 str: "WriteToStream: foo"
77 })pb")),
78 Stacktrace(IsEmpty()))));
79
80 test_sink.StartCapturingLogs();
81 WriteToStream("foo", &absl::LogInfoStreamer("path/file.cc", 1234).stream());
82 }
83
TEST(LogStreamerTest,LogWarningStreamer)84 TEST(LogStreamerTest, LogWarningStreamer) {
85 absl::ScopedMockLog test_sink(absl::MockLogDefault::kDisallowUnexpected);
86
87 EXPECT_CALL(
88 test_sink,
89 Send(AllOf(SourceFilename(Eq("path/file.cc")), SourceLine(Eq(1234)),
90 Prefix(IsTrue()), LogSeverity(Eq(absl::LogSeverity::kWarning)),
91 TimestampInMatchWindow(),
92 ThreadID(Eq(absl::base_internal::GetTID())),
93 TextMessage(Eq("WriteToStream: foo")),
94 ENCODED_MESSAGE(EqualsProto(R"pb(value {
95 str: "WriteToStream: foo"
96 })pb")),
97 Stacktrace(IsEmpty()))));
98
99 test_sink.StartCapturingLogs();
100 WriteToStream("foo",
101 &absl::LogWarningStreamer("path/file.cc", 1234).stream());
102 }
103
TEST(LogStreamerTest,LogErrorStreamer)104 TEST(LogStreamerTest, LogErrorStreamer) {
105 absl::ScopedMockLog test_sink(absl::MockLogDefault::kDisallowUnexpected);
106
107 EXPECT_CALL(
108 test_sink,
109 Send(AllOf(SourceFilename(Eq("path/file.cc")), SourceLine(Eq(1234)),
110 Prefix(IsTrue()), LogSeverity(Eq(absl::LogSeverity::kError)),
111 TimestampInMatchWindow(),
112 ThreadID(Eq(absl::base_internal::GetTID())),
113 TextMessage(Eq("WriteToStream: foo")),
114 ENCODED_MESSAGE(EqualsProto(R"pb(value {
115 str: "WriteToStream: foo"
116 })pb")),
117 Stacktrace(IsEmpty()))));
118
119 test_sink.StartCapturingLogs();
120 WriteToStream("foo", &absl::LogErrorStreamer("path/file.cc", 1234).stream());
121 }
122
123 #if GTEST_HAS_DEATH_TEST
TEST(LogStreamerDeathTest,LogFatalStreamer)124 TEST(LogStreamerDeathTest, LogFatalStreamer) {
125 EXPECT_EXIT(
126 {
127 absl::ScopedMockLog test_sink;
128
129 EXPECT_CALL(test_sink, Send)
130 .Times(AnyNumber())
131 .WillRepeatedly(DeathTestUnexpectedLogging());
132
133 EXPECT_CALL(
134 test_sink,
135 Send(AllOf(
136 SourceFilename(Eq("path/file.cc")), SourceLine(Eq(1234)),
137 Prefix(IsTrue()), LogSeverity(Eq(absl::LogSeverity::kFatal)),
138 TimestampInMatchWindow(),
139 ThreadID(Eq(absl::base_internal::GetTID())),
140 TextMessage(Eq("WriteToStream: foo")),
141 ENCODED_MESSAGE(EqualsProto(R"pb(value {
142 str: "WriteToStream: foo"
143 })pb")))))
144 .WillOnce(DeathTestExpectedLogging());
145
146 test_sink.StartCapturingLogs();
147 WriteToStream("foo",
148 &absl::LogFatalStreamer("path/file.cc", 1234).stream());
149 },
150 DiedOfFatal, DeathTestValidateExpectations());
151 }
152 #endif
153
TEST(LogStreamerTest,LogStreamer)154 TEST(LogStreamerTest, LogStreamer) {
155 absl::ScopedMockLog test_sink(absl::MockLogDefault::kDisallowUnexpected);
156
157 EXPECT_CALL(
158 test_sink,
159 Send(AllOf(SourceFilename(Eq("path/file.cc")), SourceLine(Eq(1234)),
160 Prefix(IsTrue()), LogSeverity(Eq(absl::LogSeverity::kError)),
161 TimestampInMatchWindow(),
162 ThreadID(Eq(absl::base_internal::GetTID())),
163 TextMessage(Eq("WriteToStream: foo")),
164 ENCODED_MESSAGE(EqualsProto(R"pb(value {
165 str: "WriteToStream: foo"
166 })pb")),
167 Stacktrace(IsEmpty()))));
168
169 test_sink.StartCapturingLogs();
170 WriteToStream(
171 "foo", &absl::LogStreamer(absl::LogSeverity::kError, "path/file.cc", 1234)
172 .stream());
173 }
174
175 #if GTEST_HAS_DEATH_TEST
TEST(LogStreamerDeathTest,LogStreamer)176 TEST(LogStreamerDeathTest, LogStreamer) {
177 EXPECT_EXIT(
178 {
179 absl::ScopedMockLog test_sink;
180
181 EXPECT_CALL(test_sink, Send)
182 .Times(AnyNumber())
183 .WillRepeatedly(DeathTestUnexpectedLogging());
184
185 EXPECT_CALL(
186 test_sink,
187 Send(AllOf(
188 SourceFilename(Eq("path/file.cc")), SourceLine(Eq(1234)),
189 Prefix(IsTrue()), LogSeverity(Eq(absl::LogSeverity::kFatal)),
190 TimestampInMatchWindow(),
191 ThreadID(Eq(absl::base_internal::GetTID())),
192 TextMessage(Eq("WriteToStream: foo")),
193 ENCODED_MESSAGE(EqualsProto(R"pb(value {
194 str: "WriteToStream: foo"
195 })pb")))))
196 .WillOnce(DeathTestExpectedLogging());
197
198 test_sink.StartCapturingLogs();
199 WriteToStream("foo", &absl::LogStreamer(absl::LogSeverity::kFatal,
200 "path/file.cc", 1234)
201 .stream());
202 },
203 DiedOfFatal, DeathTestValidateExpectations());
204 }
205 #endif
206
TEST(LogStreamerTest,PassedByReference)207 TEST(LogStreamerTest, PassedByReference) {
208 absl::ScopedMockLog test_sink(absl::MockLogDefault::kDisallowUnexpected);
209
210 EXPECT_CALL(
211 test_sink,
212 Send(AllOf(SourceFilename(Eq("path/file.cc")), SourceLine(Eq(1234)),
213 TextMessage(Eq("WriteToStreamRef: foo")),
214 ENCODED_MESSAGE(EqualsProto(R"pb(value {
215 str: "WriteToStreamRef: foo"
216 })pb")),
217 Stacktrace(IsEmpty()))));
218
219 test_sink.StartCapturingLogs();
220 WriteToStreamRef("foo", absl::LogInfoStreamer("path/file.cc", 1234).stream());
221 }
222
TEST(LogStreamerTest,StoredAsLocal)223 TEST(LogStreamerTest, StoredAsLocal) {
224 absl::ScopedMockLog test_sink(absl::MockLogDefault::kDisallowUnexpected);
225
226 auto streamer = absl::LogInfoStreamer("path/file.cc", 1234);
227 WriteToStream("foo", &streamer.stream());
228 streamer.stream() << " ";
229 WriteToStreamRef("bar", streamer.stream());
230
231 // The call should happen when `streamer` goes out of scope; if it
232 // happened before this `EXPECT_CALL` the call would be unexpected and the
233 // test would fail.
234 EXPECT_CALL(
235 test_sink,
236 Send(AllOf(SourceFilename(Eq("path/file.cc")), SourceLine(Eq(1234)),
237 TextMessage(Eq("WriteToStream: foo WriteToStreamRef: bar")),
238 ENCODED_MESSAGE(EqualsProto(
239 R"pb(value {
240 str: "WriteToStream: foo WriteToStreamRef: bar"
241 })pb")),
242 Stacktrace(IsEmpty()))));
243
244 test_sink.StartCapturingLogs();
245 }
246
247 #if GTEST_HAS_DEATH_TEST
TEST(LogStreamerDeathTest,StoredAsLocal)248 TEST(LogStreamerDeathTest, StoredAsLocal) {
249 EXPECT_EXIT(
250 {
251 // This is fatal when it goes out of scope, but not until then:
252 auto streamer = absl::LogFatalStreamer("path/file.cc", 1234);
253 std::cerr << "I'm still alive" << std::endl;
254 WriteToStream("foo", &streamer.stream());
255 },
256 DiedOfFatal, HasSubstr("I'm still alive"));
257 }
258 #endif
259
TEST(LogStreamerTest,LogsEmptyLine)260 TEST(LogStreamerTest, LogsEmptyLine) {
261 absl::ScopedMockLog test_sink(absl::MockLogDefault::kDisallowUnexpected);
262
263 EXPECT_CALL(test_sink, Send(AllOf(SourceFilename(Eq("path/file.cc")),
264 SourceLine(Eq(1234)), TextMessage(Eq("")),
265 ENCODED_MESSAGE(EqualsProto(R"pb(value {
266 str: ""
267 })pb")),
268 Stacktrace(IsEmpty()))));
269
270 test_sink.StartCapturingLogs();
271 absl::LogInfoStreamer("path/file.cc", 1234);
272 }
273
274 #if GTEST_HAS_DEATH_TEST
TEST(LogStreamerDeathTest,LogsEmptyLine)275 TEST(LogStreamerDeathTest, LogsEmptyLine) {
276 EXPECT_EXIT(
277 {
278 absl::ScopedMockLog test_sink;
279
280 EXPECT_CALL(test_sink, Log)
281 .Times(AnyNumber())
282 .WillRepeatedly(DeathTestUnexpectedLogging());
283
284 EXPECT_CALL(
285 test_sink,
286 Send(AllOf(
287 SourceFilename(Eq("path/file.cc")), TextMessage(Eq("")),
288 ENCODED_MESSAGE(EqualsProto(R"pb(value { str: "" })pb")))))
289 .WillOnce(DeathTestExpectedLogging());
290
291 test_sink.StartCapturingLogs();
292 // This is fatal even though it's never used:
293 auto streamer = absl::LogFatalStreamer("path/file.cc", 1234);
294 },
295 DiedOfFatal, DeathTestValidateExpectations());
296 }
297 #endif
298
TEST(LogStreamerTest,MoveConstruction)299 TEST(LogStreamerTest, MoveConstruction) {
300 absl::ScopedMockLog test_sink(absl::MockLogDefault::kDisallowUnexpected);
301
302 EXPECT_CALL(
303 test_sink,
304 Send(AllOf(SourceFilename(Eq("path/file.cc")), SourceLine(Eq(1234)),
305 LogSeverity(Eq(absl::LogSeverity::kInfo)),
306 TextMessage(Eq("hello 0x10 world 0x10")),
307 ENCODED_MESSAGE(EqualsProto(R"pb(value {
308 str: "hello 0x10 world 0x10"
309 })pb")),
310 Stacktrace(IsEmpty()))));
311
312 test_sink.StartCapturingLogs();
313 auto streamer1 = absl::LogInfoStreamer("path/file.cc", 1234);
314 streamer1.stream() << "hello " << std::hex << 16;
315 absl::LogStreamer streamer2(std::move(streamer1));
316 streamer2.stream() << " world " << 16;
317 }
318
TEST(LogStreamerTest,MoveAssignment)319 TEST(LogStreamerTest, MoveAssignment) {
320 absl::ScopedMockLog test_sink(absl::MockLogDefault::kDisallowUnexpected);
321
322 testing::InSequence seq;
323 EXPECT_CALL(
324 test_sink,
325 Send(AllOf(SourceFilename(Eq("path/file2.cc")), SourceLine(Eq(5678)),
326 LogSeverity(Eq(absl::LogSeverity::kWarning)),
327 TextMessage(Eq("something else")),
328 ENCODED_MESSAGE(EqualsProto(R"pb(value {
329 str: "something else"
330 })pb")),
331 Stacktrace(IsEmpty()))));
332 EXPECT_CALL(
333 test_sink,
334 Send(AllOf(SourceFilename(Eq("path/file.cc")), SourceLine(Eq(1234)),
335 LogSeverity(Eq(absl::LogSeverity::kInfo)),
336 TextMessage(Eq("hello 0x10 world 0x10")),
337 ENCODED_MESSAGE(EqualsProto(R"pb(value {
338 str: "hello 0x10 world 0x10"
339 })pb")),
340 Stacktrace(IsEmpty()))));
341
342 test_sink.StartCapturingLogs();
343 auto streamer1 = absl::LogInfoStreamer("path/file.cc", 1234);
344 streamer1.stream() << "hello " << std::hex << 16;
345 auto streamer2 = absl::LogWarningStreamer("path/file2.cc", 5678);
346 streamer2.stream() << "something else";
347 streamer2 = std::move(streamer1);
348 streamer2.stream() << " world " << 16;
349 }
350
TEST(LogStreamerTest,CorrectDefaultFlags)351 TEST(LogStreamerTest, CorrectDefaultFlags) {
352 absl::ScopedMockLog test_sink(absl::MockLogDefault::kDisallowUnexpected);
353
354 // The `boolalpha` and `showbase` flags should be set by default, to match
355 // `LOG`.
356 EXPECT_CALL(test_sink, Send(AllOf(TextMessage(Eq("false0xdeadbeef")))))
357 .Times(2);
358
359 test_sink.StartCapturingLogs();
360 absl::LogInfoStreamer("path/file.cc", 1234).stream()
361 << false << std::hex << 0xdeadbeef;
362 LOG(INFO) << false << std::hex << 0xdeadbeef;
363 }
364
365 } // namespace
366