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
154 #ifdef NDEBUG
TEST(LogStreamerTest,LogDebugFatalStreamer)155 TEST(LogStreamerTest, LogDebugFatalStreamer) {
156 absl::ScopedMockLog test_sink(absl::MockLogDefault::kDisallowUnexpected);
157
158 EXPECT_CALL(
159 test_sink,
160 Send(AllOf(SourceFilename(Eq("path/file.cc")), SourceLine(Eq(1234)),
161 Prefix(IsTrue()), LogSeverity(Eq(absl::LogSeverity::kError)),
162 TimestampInMatchWindow(),
163 ThreadID(Eq(absl::base_internal::GetTID())),
164 TextMessage(Eq("WriteToStream: foo")),
165 ENCODED_MESSAGE(EqualsProto(R"pb(value {
166 str: "WriteToStream: foo"
167 })pb")),
168 Stacktrace(IsEmpty()))));
169
170 test_sink.StartCapturingLogs();
171 WriteToStream("foo",
172 &absl::LogDebugFatalStreamer("path/file.cc", 1234).stream());
173 }
174 #elif GTEST_HAS_DEATH_TEST
TEST(LogStreamerDeathTest,LogDebugFatalStreamer)175 TEST(LogStreamerDeathTest, LogDebugFatalStreamer) {
176 EXPECT_EXIT(
177 {
178 absl::ScopedMockLog test_sink;
179
180 EXPECT_CALL(test_sink, Send)
181 .Times(AnyNumber())
182 .WillRepeatedly(DeathTestUnexpectedLogging());
183
184 EXPECT_CALL(
185 test_sink,
186 Send(AllOf(
187 SourceFilename(Eq("path/file.cc")), SourceLine(Eq(1234)),
188 Prefix(IsTrue()), LogSeverity(Eq(absl::LogSeverity::kFatal)),
189 TimestampInMatchWindow(),
190 ThreadID(Eq(absl::base_internal::GetTID())),
191 TextMessage(Eq("WriteToStream: foo")),
192 ENCODED_MESSAGE(EqualsProto(R"pb(value {
193 str: "WriteToStream: foo"
194 })pb")))))
195 .WillOnce(DeathTestExpectedLogging());
196
197 test_sink.StartCapturingLogs();
198 WriteToStream(
199 "foo", &absl::LogDebugFatalStreamer("path/file.cc", 1234).stream());
200 },
201 DiedOfFatal, DeathTestValidateExpectations());
202 }
203 #endif
204
TEST(LogStreamerTest,LogStreamer)205 TEST(LogStreamerTest, LogStreamer) {
206 absl::ScopedMockLog test_sink(absl::MockLogDefault::kDisallowUnexpected);
207
208 EXPECT_CALL(
209 test_sink,
210 Send(AllOf(SourceFilename(Eq("path/file.cc")), SourceLine(Eq(1234)),
211 Prefix(IsTrue()), LogSeverity(Eq(absl::LogSeverity::kError)),
212 TimestampInMatchWindow(),
213 ThreadID(Eq(absl::base_internal::GetTID())),
214 TextMessage(Eq("WriteToStream: foo")),
215 ENCODED_MESSAGE(EqualsProto(R"pb(value {
216 str: "WriteToStream: foo"
217 })pb")),
218 Stacktrace(IsEmpty()))));
219
220 test_sink.StartCapturingLogs();
221 WriteToStream(
222 "foo", &absl::LogStreamer(absl::LogSeverity::kError, "path/file.cc", 1234)
223 .stream());
224 }
225
226 #if GTEST_HAS_DEATH_TEST
TEST(LogStreamerDeathTest,LogStreamer)227 TEST(LogStreamerDeathTest, LogStreamer) {
228 EXPECT_EXIT(
229 {
230 absl::ScopedMockLog test_sink;
231
232 EXPECT_CALL(test_sink, Send)
233 .Times(AnyNumber())
234 .WillRepeatedly(DeathTestUnexpectedLogging());
235
236 EXPECT_CALL(
237 test_sink,
238 Send(AllOf(
239 SourceFilename(Eq("path/file.cc")), SourceLine(Eq(1234)),
240 Prefix(IsTrue()), LogSeverity(Eq(absl::LogSeverity::kFatal)),
241 TimestampInMatchWindow(),
242 ThreadID(Eq(absl::base_internal::GetTID())),
243 TextMessage(Eq("WriteToStream: foo")),
244 ENCODED_MESSAGE(EqualsProto(R"pb(value {
245 str: "WriteToStream: foo"
246 })pb")))))
247 .WillOnce(DeathTestExpectedLogging());
248
249 test_sink.StartCapturingLogs();
250 WriteToStream("foo", &absl::LogStreamer(absl::LogSeverity::kFatal,
251 "path/file.cc", 1234)
252 .stream());
253 },
254 DiedOfFatal, DeathTestValidateExpectations());
255 }
256 #endif
257
TEST(LogStreamerTest,PassedByReference)258 TEST(LogStreamerTest, PassedByReference) {
259 absl::ScopedMockLog test_sink(absl::MockLogDefault::kDisallowUnexpected);
260
261 EXPECT_CALL(
262 test_sink,
263 Send(AllOf(SourceFilename(Eq("path/file.cc")), SourceLine(Eq(1234)),
264 TextMessage(Eq("WriteToStreamRef: foo")),
265 ENCODED_MESSAGE(EqualsProto(R"pb(value {
266 str: "WriteToStreamRef: foo"
267 })pb")),
268 Stacktrace(IsEmpty()))));
269
270 test_sink.StartCapturingLogs();
271 WriteToStreamRef("foo", absl::LogInfoStreamer("path/file.cc", 1234).stream());
272 }
273
TEST(LogStreamerTest,StoredAsLocal)274 TEST(LogStreamerTest, StoredAsLocal) {
275 absl::ScopedMockLog test_sink(absl::MockLogDefault::kDisallowUnexpected);
276
277 auto streamer = absl::LogInfoStreamer("path/file.cc", 1234);
278 WriteToStream("foo", &streamer.stream());
279 streamer.stream() << " ";
280 WriteToStreamRef("bar", streamer.stream());
281
282 // The call should happen when `streamer` goes out of scope; if it
283 // happened before this `EXPECT_CALL` the call would be unexpected and the
284 // test would fail.
285 EXPECT_CALL(
286 test_sink,
287 Send(AllOf(SourceFilename(Eq("path/file.cc")), SourceLine(Eq(1234)),
288 TextMessage(Eq("WriteToStream: foo WriteToStreamRef: bar")),
289 ENCODED_MESSAGE(EqualsProto(
290 R"pb(value {
291 str: "WriteToStream: foo WriteToStreamRef: bar"
292 })pb")),
293 Stacktrace(IsEmpty()))));
294
295 test_sink.StartCapturingLogs();
296 }
297
298 #if GTEST_HAS_DEATH_TEST
TEST(LogStreamerDeathTest,StoredAsLocal)299 TEST(LogStreamerDeathTest, StoredAsLocal) {
300 EXPECT_EXIT(
301 {
302 // This is fatal when it goes out of scope, but not until then:
303 auto streamer = absl::LogFatalStreamer("path/file.cc", 1234);
304 std::cerr << "I'm still alive" << std::endl;
305 WriteToStream("foo", &streamer.stream());
306 },
307 DiedOfFatal, HasSubstr("I'm still alive"));
308 }
309 #endif
310
TEST(LogStreamerTest,LogsEmptyLine)311 TEST(LogStreamerTest, LogsEmptyLine) {
312 absl::ScopedMockLog test_sink(absl::MockLogDefault::kDisallowUnexpected);
313
314 EXPECT_CALL(test_sink, Send(AllOf(SourceFilename(Eq("path/file.cc")),
315 SourceLine(Eq(1234)), TextMessage(Eq("")),
316 ENCODED_MESSAGE(EqualsProto(R"pb(value {
317 str: ""
318 })pb")),
319 Stacktrace(IsEmpty()))));
320
321 test_sink.StartCapturingLogs();
322 absl::LogInfoStreamer("path/file.cc", 1234);
323 }
324
325 #if GTEST_HAS_DEATH_TEST
TEST(LogStreamerDeathTest,LogsEmptyLine)326 TEST(LogStreamerDeathTest, LogsEmptyLine) {
327 EXPECT_EXIT(
328 {
329 absl::ScopedMockLog test_sink;
330
331 EXPECT_CALL(test_sink, Log)
332 .Times(AnyNumber())
333 .WillRepeatedly(DeathTestUnexpectedLogging());
334
335 EXPECT_CALL(
336 test_sink,
337 Send(AllOf(
338 SourceFilename(Eq("path/file.cc")), TextMessage(Eq("")),
339 ENCODED_MESSAGE(EqualsProto(R"pb(value { str: "" })pb")))))
340 .WillOnce(DeathTestExpectedLogging());
341
342 test_sink.StartCapturingLogs();
343 // This is fatal even though it's never used:
344 auto streamer = absl::LogFatalStreamer("path/file.cc", 1234);
345 },
346 DiedOfFatal, DeathTestValidateExpectations());
347 }
348 #endif
349
TEST(LogStreamerTest,MoveConstruction)350 TEST(LogStreamerTest, MoveConstruction) {
351 absl::ScopedMockLog test_sink(absl::MockLogDefault::kDisallowUnexpected);
352
353 EXPECT_CALL(
354 test_sink,
355 Send(AllOf(SourceFilename(Eq("path/file.cc")), SourceLine(Eq(1234)),
356 LogSeverity(Eq(absl::LogSeverity::kInfo)),
357 TextMessage(Eq("hello 0x10 world 0x10")),
358 ENCODED_MESSAGE(EqualsProto(R"pb(value {
359 str: "hello 0x10 world 0x10"
360 })pb")),
361 Stacktrace(IsEmpty()))));
362
363 test_sink.StartCapturingLogs();
364 auto streamer1 = absl::LogInfoStreamer("path/file.cc", 1234);
365 streamer1.stream() << "hello " << std::hex << 16;
366 absl::LogStreamer streamer2(std::move(streamer1));
367 streamer2.stream() << " world " << 16;
368 }
369
TEST(LogStreamerTest,MoveAssignment)370 TEST(LogStreamerTest, MoveAssignment) {
371 absl::ScopedMockLog test_sink(absl::MockLogDefault::kDisallowUnexpected);
372
373 testing::InSequence seq;
374 EXPECT_CALL(
375 test_sink,
376 Send(AllOf(SourceFilename(Eq("path/file2.cc")), SourceLine(Eq(5678)),
377 LogSeverity(Eq(absl::LogSeverity::kWarning)),
378 TextMessage(Eq("something else")),
379 ENCODED_MESSAGE(EqualsProto(R"pb(value {
380 str: "something else"
381 })pb")),
382 Stacktrace(IsEmpty()))));
383 EXPECT_CALL(
384 test_sink,
385 Send(AllOf(SourceFilename(Eq("path/file.cc")), SourceLine(Eq(1234)),
386 LogSeverity(Eq(absl::LogSeverity::kInfo)),
387 TextMessage(Eq("hello 0x10 world 0x10")),
388 ENCODED_MESSAGE(EqualsProto(R"pb(value {
389 str: "hello 0x10 world 0x10"
390 })pb")),
391 Stacktrace(IsEmpty()))));
392
393 test_sink.StartCapturingLogs();
394 auto streamer1 = absl::LogInfoStreamer("path/file.cc", 1234);
395 streamer1.stream() << "hello " << std::hex << 16;
396 auto streamer2 = absl::LogWarningStreamer("path/file2.cc", 5678);
397 streamer2.stream() << "something else";
398 streamer2 = std::move(streamer1);
399 streamer2.stream() << " world " << 16;
400 }
401
TEST(LogStreamerTest,CorrectDefaultFlags)402 TEST(LogStreamerTest, CorrectDefaultFlags) {
403 absl::ScopedMockLog test_sink(absl::MockLogDefault::kDisallowUnexpected);
404
405 // The `boolalpha` and `showbase` flags should be set by default, to match
406 // `LOG`.
407 EXPECT_CALL(test_sink, Send(AllOf(TextMessage(Eq("false0xdeadbeef")))))
408 .Times(2);
409
410 test_sink.StartCapturingLogs();
411 absl::LogInfoStreamer("path/file.cc", 1234).stream()
412 << false << std::hex << 0xdeadbeef;
413 LOG(INFO) << false << std::hex << 0xdeadbeef;
414 }
415
416 } // namespace
417