diff options
author | Phoebe Liang <phoebeliang@google.com> | 2022-11-02 15:27:54 -0700 |
---|---|---|
committer | Copybara-Service <copybara-worker@google.com> | 2022-11-02 15:28:46 -0700 |
commit | e6044634dd7caec2d79a13aecc9e765023768757 (patch) | |
tree | 3ffe2c00f4b5e49da4f4e7d9e50c64999f318408 /absl/log/log_format_test.cc | |
parent | 1649c037c556bdaca7241bc0113275506bdb9638 (diff) | |
download | abseil-e6044634dd7caec2d79a13aecc9e765023768757.tar.gz abseil-e6044634dd7caec2d79a13aecc9e765023768757.tar.bz2 abseil-e6044634dd7caec2d79a13aecc9e765023768757.zip |
Support logging of user-defined types that implement `AbslStringify()`
If a user-defined type has `AbslStringify()` defined, it will always be used for logging over `operator<<`.
`HasAbslStringify` now uses the empty class `UnimplementedSink` for its checks instead of `StringifySink` in order to make it work in cases involving other sinks.
PiperOrigin-RevId: 485710377
Change-Id: Ibdd916151c7abc3269c35fbe79b772867f3d25e1
Diffstat (limited to 'absl/log/log_format_test.cc')
-rw-r--r-- | absl/log/log_format_test.cc | 131 |
1 files changed, 131 insertions, 0 deletions
diff --git a/absl/log/log_format_test.cc b/absl/log/log_format_test.cc index c629fce7..397c8d0c 100644 --- a/absl/log/log_format_test.cc +++ b/absl/log/log_format_test.cc @@ -32,6 +32,7 @@ #include "absl/log/scoped_mock_log.h" #include "absl/strings/match.h" #include "absl/strings/str_cat.h" +#include "absl/strings/str_format.h" #include "absl/strings/string_view.h" namespace { @@ -865,6 +866,111 @@ TEST(LogFormatTest, CustomNonCopyable) { LOG(INFO) << value; } +struct Point { + template <typename Sink> + friend void AbslStringify(Sink& sink, const Point& p) { + absl::Format(&sink, "(%d, %d)", p.x, p.y); + } + + int x = 10; + int y = 20; +}; + +TEST(LogFormatTest, AbslStringifyExample) { + absl::ScopedMockLog test_sink(absl::MockLogDefault::kDisallowUnexpected); + + Point p; + + EXPECT_CALL( + test_sink, + Send(AllOf( + TextMessage(Eq("(10, 20)")), TextMessage(Eq(absl::StrCat(p))), + ENCODED_MESSAGE(EqualsProto(R"pb(value { str: "(10, 20)" })pb"))))); + + test_sink.StartCapturingLogs(); + LOG(INFO) << p; +} + +struct PointWithAbslStringifiyAndOstream { + template <typename Sink> + friend void AbslStringify(Sink& sink, + const PointWithAbslStringifiyAndOstream& p) { + absl::Format(&sink, "(%d, %d)", p.x, p.y); + } + + int x = 10; + int y = 20; +}; + +ABSL_ATTRIBUTE_UNUSED std::ostream& operator<<( + std::ostream& os, const PointWithAbslStringifiyAndOstream&) { + return os << "Default to AbslStringify()"; +} + +TEST(LogFormatTest, CustomWithAbslStringifyAndOstream) { + absl::ScopedMockLog test_sink(absl::MockLogDefault::kDisallowUnexpected); + + PointWithAbslStringifiyAndOstream p; + + EXPECT_CALL( + test_sink, + Send(AllOf( + TextMessage(Eq("(10, 20)")), TextMessage(Eq(absl::StrCat(p))), + ENCODED_MESSAGE(EqualsProto(R"pb(value { str: "(10, 20)" })pb"))))); + + test_sink.StartCapturingLogs(); + LOG(INFO) << p; +} + +struct PointStreamsNothing { + template <typename Sink> + friend void AbslStringify(Sink&, const PointStreamsNothing&) {} + + int x = 10; + int y = 20; +}; + +TEST(LogFormatTest, AbslStringifyStreamsNothing) { + absl::ScopedMockLog test_sink(absl::MockLogDefault::kDisallowUnexpected); + + PointStreamsNothing p; + + EXPECT_CALL( + test_sink, + Send(AllOf(TextMessage(Eq("77")), TextMessage(Eq(absl::StrCat(p, 77))), + ENCODED_MESSAGE(EqualsProto(R"pb(value { str: "77" })pb"))))); + + test_sink.StartCapturingLogs(); + LOG(INFO) << p << 77; +} + +struct PointMultipleAppend { + template <typename Sink> + friend void AbslStringify(Sink& sink, const PointMultipleAppend& p) { + sink.Append("("); + sink.Append(absl::StrCat(p.x, ", ", p.y, ")")); + } + + int x = 10; + int y = 20; +}; + +TEST(LogFormatTest, AbslStringifyMultipleAppend) { + absl::ScopedMockLog test_sink(absl::MockLogDefault::kDisallowUnexpected); + + PointMultipleAppend p; + + EXPECT_CALL( + test_sink, + Send(AllOf( + TextMessage(Eq("(10, 20)")), TextMessage(Eq(absl::StrCat(p))), + ENCODED_MESSAGE(EqualsProto(R"pb(value { str: "(" } + value { str: "10, 20)" })pb"))))); + + test_sink.StartCapturingLogs(); + LOG(INFO) << p; +} + TEST(ManipulatorLogFormatTest, BoolAlphaTrue) { absl::ScopedMockLog test_sink(absl::MockLogDefault::kDisallowUnexpected); @@ -1501,6 +1607,31 @@ TEST(ManipulatorLogFormatTest, CustomClassStreamsNothing) { LOG(INFO) << value << 77; } +struct PointPercentV { + template <typename Sink> + friend void AbslStringify(Sink& sink, const PointPercentV& p) { + absl::Format(&sink, "(%v, %v)", p.x, p.y); + } + + int x = 10; + int y = 20; +}; + +TEST(ManipulatorLogFormatTest, IOManipsDoNotAffectAbslStringify) { + absl::ScopedMockLog test_sink(absl::MockLogDefault::kDisallowUnexpected); + + PointPercentV p; + + EXPECT_CALL( + test_sink, + Send(AllOf( + TextMessage(Eq("(10, 20)")), TextMessage(Eq(absl::StrCat(p))), + ENCODED_MESSAGE(EqualsProto(R"pb(value { str: "(10, 20)" })pb"))))); + + test_sink.StartCapturingLogs(); + LOG(INFO) << std::hex << p; +} + // Tests that verify the behavior when more data are streamed into a `LOG` // statement than fit in the buffer. // Structured logging scenario is tested in other unit tests since the output is |