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