| // |
| // Copyright 2022 The Abseil Authors. |
| // |
| // Licensed under the Apache License, Version 2.0 (the "License"); |
| // you may not use this file except in compliance with the License. |
| // You may obtain a copy of the License at |
| // |
| // https://www.apache.org/licenses/LICENSE-2.0 |
| // |
| // Unless required by applicable law or agreed to in writing, software |
| // distributed under the License is distributed on an "AS IS" BASIS, |
| // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| // See the License for the specific language governing permissions and |
| // limitations under the License. |
| |
| #include <math.h> |
| |
| #include <iomanip> |
| #include <ios> |
| #include <limits> |
| #include <ostream> |
| #include <sstream> |
| #include <string> |
| #include <type_traits> |
| |
| #ifdef __ANDROID__ |
| #include <android/api-level.h> |
| #endif |
| #include "gmock/gmock.h" |
| #include "gtest/gtest.h" |
| #include "absl/log/check.h" |
| #include "absl/log/internal/test_matchers.h" |
| #include "absl/log/log.h" |
| #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" |
| #include "absl/types/optional.h" |
| |
| namespace { |
| using ::absl::log_internal::AsString; |
| using ::absl::log_internal::MatchesOstream; |
| using ::absl::log_internal::RawEncodedMessage; |
| using ::absl::log_internal::TextMessage; |
| using ::absl::log_internal::TextPrefix; |
| using ::testing::AllOf; |
| using ::testing::AnyOf; |
| using ::testing::Each; |
| using ::testing::EndsWith; |
| using ::testing::Eq; |
| using ::testing::Ge; |
| using ::testing::IsEmpty; |
| using ::testing::Le; |
| using ::testing::SizeIs; |
| using ::testing::Types; |
| |
| // Some aspects of formatting streamed data (e.g. pointer handling) are |
| // implementation-defined. Others are buggy in supported implementations. |
| // These tests validate that the formatting matches that performed by a |
| // `std::ostream` and also that the result is one of a list of expected formats. |
| |
| std::ostringstream ComparisonStream() { |
| std::ostringstream str; |
| str.setf(std::ios_base::showbase | std::ios_base::boolalpha | |
| std::ios_base::internal); |
| return str; |
| } |
| |
| TEST(LogFormatTest, NoMessage) { |
| absl::ScopedMockLog test_sink(absl::MockLogDefault::kDisallowUnexpected); |
| |
| const int log_line = __LINE__ + 1; |
| auto do_log = [] { LOG(INFO); }; |
| |
| EXPECT_CALL(test_sink, |
| Send(AllOf(TextMessage(MatchesOstream(ComparisonStream())), |
| TextPrefix(AsString(EndsWith(absl::StrCat( |
| " log_format_test.cc:", log_line, "] ")))), |
| TextMessage(IsEmpty()), |
| ENCODED_MESSAGE(HasValues(IsEmpty()))))); |
| |
| test_sink.StartCapturingLogs(); |
| do_log(); |
| } |
| |
| template <typename T> |
| class CharLogFormatTest : public testing::Test {}; |
| using CharTypes = Types<char, signed char, unsigned char>; |
| TYPED_TEST_SUITE(CharLogFormatTest, CharTypes); |
| |
| TYPED_TEST(CharLogFormatTest, Printable) { |
| absl::ScopedMockLog test_sink(absl::MockLogDefault::kDisallowUnexpected); |
| |
| const TypeParam value = 'x'; |
| auto comparison_stream = ComparisonStream(); |
| comparison_stream << value; |
| |
| EXPECT_CALL(test_sink, |
| Send(AllOf(TextMessage(MatchesOstream(comparison_stream)), |
| TextMessage(Eq("x")), |
| ENCODED_MESSAGE(HasValues( |
| ElementsAre(EqualsProto(R"pb(str: "x")pb"))))))); |
| |
| test_sink.StartCapturingLogs(); |
| LOG(INFO) << value; |
| } |
| |
| TYPED_TEST(CharLogFormatTest, Unprintable) { |
| absl::ScopedMockLog test_sink(absl::MockLogDefault::kDisallowUnexpected); |
| |
| constexpr auto value = static_cast<TypeParam>(0xeeu); |
| auto comparison_stream = ComparisonStream(); |
| comparison_stream << value; |
| |
| EXPECT_CALL(test_sink, |
| Send(AllOf(TextMessage(MatchesOstream(comparison_stream)), |
| TextMessage(Eq("\xee")), |
| ENCODED_MESSAGE(HasValues(ElementsAre( |
| EqualsProto(R"pb(str: "\xee")pb"))))))); |
| |
| test_sink.StartCapturingLogs(); |
| LOG(INFO) << value; |
| } |
| |
| template <typename T> |
| class UnsignedIntLogFormatTest : public testing::Test {}; |
| using UnsignedIntTypes = Types<unsigned short, unsigned int, // NOLINT |
| unsigned long, unsigned long long>; // NOLINT |
| TYPED_TEST_SUITE(UnsignedIntLogFormatTest, UnsignedIntTypes); |
| |
| TYPED_TEST(UnsignedIntLogFormatTest, Positive) { |
| absl::ScopedMockLog test_sink(absl::MockLogDefault::kDisallowUnexpected); |
| |
| const TypeParam value = 224; |
| auto comparison_stream = ComparisonStream(); |
| comparison_stream << value; |
| |
| EXPECT_CALL(test_sink, |
| Send(AllOf(TextMessage(MatchesOstream(comparison_stream)), |
| TextMessage(Eq("224")), |
| ENCODED_MESSAGE(HasValues( |
| ElementsAre(EqualsProto(R"pb(str: "224")pb"))))))); |
| |
| test_sink.StartCapturingLogs(); |
| LOG(INFO) << value; |
| } |
| |
| TYPED_TEST(UnsignedIntLogFormatTest, BitfieldPositive) { |
| absl::ScopedMockLog test_sink(absl::MockLogDefault::kDisallowUnexpected); |
| |
| const struct { |
| TypeParam bits : 6; |
| } value{42}; |
| auto comparison_stream = ComparisonStream(); |
| comparison_stream << value.bits; |
| |
| EXPECT_CALL(test_sink, |
| Send(AllOf(TextMessage(MatchesOstream(comparison_stream)), |
| TextMessage(Eq("42")), |
| ENCODED_MESSAGE(HasValues( |
| ElementsAre(EqualsProto(R"pb(str: "42")pb"))))))); |
| |
| test_sink.StartCapturingLogs(); |
| LOG(INFO) << value.bits; |
| } |
| |
| template <typename T> |
| class SignedIntLogFormatTest : public testing::Test {}; |
| using SignedIntTypes = |
| Types<signed short, signed int, signed long, signed long long>; // NOLINT |
| TYPED_TEST_SUITE(SignedIntLogFormatTest, SignedIntTypes); |
| |
| TYPED_TEST(SignedIntLogFormatTest, Positive) { |
| absl::ScopedMockLog test_sink(absl::MockLogDefault::kDisallowUnexpected); |
| |
| const TypeParam value = 224; |
| auto comparison_stream = ComparisonStream(); |
| comparison_stream << value; |
| |
| EXPECT_CALL(test_sink, |
| Send(AllOf(TextMessage(MatchesOstream(comparison_stream)), |
| TextMessage(Eq("224")), |
| ENCODED_MESSAGE(HasValues( |
| ElementsAre(EqualsProto(R"pb(str: "224")pb"))))))); |
| |
| test_sink.StartCapturingLogs(); |
| LOG(INFO) << value; |
| } |
| |
| TYPED_TEST(SignedIntLogFormatTest, Negative) { |
| absl::ScopedMockLog test_sink(absl::MockLogDefault::kDisallowUnexpected); |
| |
| const TypeParam value = -112; |
| auto comparison_stream = ComparisonStream(); |
| comparison_stream << value; |
| |
| EXPECT_CALL(test_sink, |
| Send(AllOf(TextMessage(MatchesOstream(comparison_stream)), |
| TextMessage(Eq("-112")), |
| ENCODED_MESSAGE(HasValues(ElementsAre( |
| EqualsProto(R"pb(str: "-112")pb"))))))); |
| |
| test_sink.StartCapturingLogs(); |
| LOG(INFO) << value; |
| } |
| |
| TYPED_TEST(SignedIntLogFormatTest, BitfieldPositive) { |
| absl::ScopedMockLog test_sink(absl::MockLogDefault::kDisallowUnexpected); |
| |
| const struct { |
| TypeParam bits : 6; |
| } value{21}; |
| auto comparison_stream = ComparisonStream(); |
| comparison_stream << value.bits; |
| |
| EXPECT_CALL(test_sink, |
| Send(AllOf(TextMessage(MatchesOstream(comparison_stream)), |
| TextMessage(Eq("21")), |
| ENCODED_MESSAGE(HasValues( |
| ElementsAre(EqualsProto(R"pb(str: "21")pb"))))))); |
| |
| test_sink.StartCapturingLogs(); |
| LOG(INFO) << value.bits; |
| } |
| |
| TYPED_TEST(SignedIntLogFormatTest, BitfieldNegative) { |
| absl::ScopedMockLog test_sink(absl::MockLogDefault::kDisallowUnexpected); |
| |
| const struct { |
| TypeParam bits : 6; |
| } value{-21}; |
| auto comparison_stream = ComparisonStream(); |
| comparison_stream << value.bits; |
| |
| EXPECT_CALL(test_sink, |
| Send(AllOf(TextMessage(MatchesOstream(comparison_stream)), |
| TextMessage(Eq("-21")), |
| ENCODED_MESSAGE(HasValues( |
| ElementsAre(EqualsProto(R"pb(str: "-21")pb"))))))); |
| |
| test_sink.StartCapturingLogs(); |
| LOG(INFO) << value.bits; |
| } |
| |
| // Ignore these test cases on GCC due to "is too small to hold all values ..." |
| // warning. |
| #if !defined(__GNUC__) || defined(__clang__) |
| // The implementation may choose a signed or unsigned integer type to represent |
| // this enum, so it may be tested by either `UnsignedEnumLogFormatTest` or |
| // `SignedEnumLogFormatTest`. |
| enum MyUnsignedEnum { |
| MyUnsignedEnum_ZERO = 0, |
| MyUnsignedEnum_FORTY_TWO = 42, |
| MyUnsignedEnum_TWO_HUNDRED_TWENTY_FOUR = 224, |
| }; |
| enum MyUnsignedIntEnum : unsigned int { |
| MyUnsignedIntEnum_ZERO = 0, |
| MyUnsignedIntEnum_FORTY_TWO = 42, |
| MyUnsignedIntEnum_TWO_HUNDRED_TWENTY_FOUR = 224, |
| }; |
| |
| template <typename T> |
| class UnsignedEnumLogFormatTest : public testing::Test {}; |
| using UnsignedEnumTypes = std::conditional< |
| std::is_signed<std::underlying_type<MyUnsignedEnum>::type>::value, |
| Types<MyUnsignedIntEnum>, Types<MyUnsignedEnum, MyUnsignedIntEnum>>::type; |
| TYPED_TEST_SUITE(UnsignedEnumLogFormatTest, UnsignedEnumTypes); |
| |
| TYPED_TEST(UnsignedEnumLogFormatTest, Positive) { |
| absl::ScopedMockLog test_sink(absl::MockLogDefault::kDisallowUnexpected); |
| |
| const TypeParam value = static_cast<TypeParam>(224); |
| auto comparison_stream = ComparisonStream(); |
| comparison_stream << value; |
| |
| EXPECT_CALL(test_sink, |
| Send(AllOf(TextMessage(MatchesOstream(comparison_stream)), |
| TextMessage(Eq("224")), |
| ENCODED_MESSAGE(HasValues( |
| ElementsAre(EqualsProto(R"pb(str: "224")pb"))))))); |
| |
| test_sink.StartCapturingLogs(); |
| LOG(INFO) << value; |
| } |
| |
| TYPED_TEST(UnsignedEnumLogFormatTest, BitfieldPositive) { |
| absl::ScopedMockLog test_sink(absl::MockLogDefault::kDisallowUnexpected); |
| |
| const struct { |
| TypeParam bits : 6; |
| } value{static_cast<TypeParam>(42)}; |
| auto comparison_stream = ComparisonStream(); |
| comparison_stream << value.bits; |
| |
| EXPECT_CALL(test_sink, |
| Send(AllOf(TextMessage(MatchesOstream(comparison_stream)), |
| TextMessage(Eq("42")), |
| ENCODED_MESSAGE(HasValues( |
| ElementsAre(EqualsProto(R"pb(str: "42")pb"))))))); |
| |
| test_sink.StartCapturingLogs(); |
| LOG(INFO) << value.bits; |
| } |
| |
| enum MySignedEnum { |
| MySignedEnum_NEGATIVE_ONE_HUNDRED_TWELVE = -112, |
| MySignedEnum_NEGATIVE_TWENTY_ONE = -21, |
| MySignedEnum_ZERO = 0, |
| MySignedEnum_TWENTY_ONE = 21, |
| MySignedEnum_TWO_HUNDRED_TWENTY_FOUR = 224, |
| }; |
| enum MySignedIntEnum : signed int { |
| MySignedIntEnum_NEGATIVE_ONE_HUNDRED_TWELVE = -112, |
| MySignedIntEnum_NEGATIVE_TWENTY_ONE = -21, |
| MySignedIntEnum_ZERO = 0, |
| MySignedIntEnum_TWENTY_ONE = 21, |
| MySignedIntEnum_TWO_HUNDRED_TWENTY_FOUR = 224, |
| }; |
| |
| template <typename T> |
| class SignedEnumLogFormatTest : public testing::Test {}; |
| using SignedEnumTypes = std::conditional< |
| std::is_signed<std::underlying_type<MyUnsignedEnum>::type>::value, |
| Types<MyUnsignedEnum, MySignedEnum, MySignedIntEnum>, |
| Types<MySignedEnum, MySignedIntEnum>>::type; |
| TYPED_TEST_SUITE(SignedEnumLogFormatTest, SignedEnumTypes); |
| |
| TYPED_TEST(SignedEnumLogFormatTest, Positive) { |
| absl::ScopedMockLog test_sink(absl::MockLogDefault::kDisallowUnexpected); |
| |
| const TypeParam value = static_cast<TypeParam>(224); |
| auto comparison_stream = ComparisonStream(); |
| comparison_stream << value; |
| |
| EXPECT_CALL(test_sink, |
| Send(AllOf(TextMessage(MatchesOstream(comparison_stream)), |
| TextMessage(Eq("224")), |
| ENCODED_MESSAGE(HasValues( |
| ElementsAre(EqualsProto(R"pb(str: "224")pb"))))))); |
| |
| test_sink.StartCapturingLogs(); |
| LOG(INFO) << value; |
| } |
| |
| TYPED_TEST(SignedEnumLogFormatTest, Negative) { |
| absl::ScopedMockLog test_sink(absl::MockLogDefault::kDisallowUnexpected); |
| |
| const TypeParam value = static_cast<TypeParam>(-112); |
| auto comparison_stream = ComparisonStream(); |
| comparison_stream << value; |
| |
| EXPECT_CALL(test_sink, |
| Send(AllOf(TextMessage(MatchesOstream(comparison_stream)), |
| TextMessage(Eq("-112")), |
| ENCODED_MESSAGE(HasValues(ElementsAre( |
| EqualsProto(R"pb(str: "-112")pb"))))))); |
| |
| test_sink.StartCapturingLogs(); |
| LOG(INFO) << value; |
| } |
| |
| TYPED_TEST(SignedEnumLogFormatTest, BitfieldPositive) { |
| absl::ScopedMockLog test_sink(absl::MockLogDefault::kDisallowUnexpected); |
| |
| const struct { |
| TypeParam bits : 6; |
| } value{static_cast<TypeParam>(21)}; |
| auto comparison_stream = ComparisonStream(); |
| comparison_stream << value.bits; |
| |
| EXPECT_CALL(test_sink, |
| Send(AllOf(TextMessage(MatchesOstream(comparison_stream)), |
| TextMessage(Eq("21")), |
| ENCODED_MESSAGE(HasValues( |
| ElementsAre(EqualsProto(R"pb(str: "21")pb"))))))); |
| |
| test_sink.StartCapturingLogs(); |
| LOG(INFO) << value.bits; |
| } |
| |
| TYPED_TEST(SignedEnumLogFormatTest, BitfieldNegative) { |
| absl::ScopedMockLog test_sink(absl::MockLogDefault::kDisallowUnexpected); |
| |
| const struct { |
| TypeParam bits : 6; |
| } value{static_cast<TypeParam>(-21)}; |
| auto comparison_stream = ComparisonStream(); |
| comparison_stream << value.bits; |
| |
| EXPECT_CALL(test_sink, |
| Send(AllOf(TextMessage(MatchesOstream(comparison_stream)), |
| TextMessage(Eq("-21")), |
| ENCODED_MESSAGE(HasValues( |
| ElementsAre(EqualsProto(R"pb(str: "-21")pb"))))))); |
| |
| test_sink.StartCapturingLogs(); |
| LOG(INFO) << value.bits; |
| } |
| #endif |
| |
| TEST(FloatLogFormatTest, Positive) { |
| absl::ScopedMockLog test_sink(absl::MockLogDefault::kDisallowUnexpected); |
| |
| const float value = 6.02e23f; |
| auto comparison_stream = ComparisonStream(); |
| comparison_stream << value; |
| |
| EXPECT_CALL(test_sink, |
| Send(AllOf(TextMessage(MatchesOstream(comparison_stream)), |
| TextMessage(Eq("6.02e+23")), |
| ENCODED_MESSAGE(HasValues(ElementsAre( |
| EqualsProto(R"pb(str: "6.02e+23")pb"))))))); |
| |
| test_sink.StartCapturingLogs(); |
| LOG(INFO) << value; |
| } |
| |
| TEST(FloatLogFormatTest, Negative) { |
| absl::ScopedMockLog test_sink(absl::MockLogDefault::kDisallowUnexpected); |
| |
| const float value = -6.02e23f; |
| auto comparison_stream = ComparisonStream(); |
| comparison_stream << value; |
| |
| EXPECT_CALL(test_sink, |
| Send(AllOf(TextMessage(MatchesOstream(comparison_stream)), |
| TextMessage(Eq("-6.02e+23")), |
| ENCODED_MESSAGE(HasValues(ElementsAre( |
| EqualsProto(R"pb(str: "-6.02e+23")pb"))))))); |
| |
| test_sink.StartCapturingLogs(); |
| LOG(INFO) << value; |
| } |
| |
| TEST(FloatLogFormatTest, NegativeExponent) { |
| absl::ScopedMockLog test_sink(absl::MockLogDefault::kDisallowUnexpected); |
| |
| const float value = 6.02e-23f; |
| auto comparison_stream = ComparisonStream(); |
| comparison_stream << value; |
| |
| EXPECT_CALL(test_sink, |
| Send(AllOf(TextMessage(MatchesOstream(comparison_stream)), |
| TextMessage(Eq("6.02e-23")), |
| ENCODED_MESSAGE(HasValues(ElementsAre( |
| EqualsProto(R"pb(str: "6.02e-23")pb"))))))); |
| |
| test_sink.StartCapturingLogs(); |
| LOG(INFO) << value; |
| } |
| |
| TEST(DoubleLogFormatTest, Positive) { |
| absl::ScopedMockLog test_sink(absl::MockLogDefault::kDisallowUnexpected); |
| |
| const double value = 6.02e23; |
| auto comparison_stream = ComparisonStream(); |
| comparison_stream << value; |
| |
| EXPECT_CALL(test_sink, |
| Send(AllOf(TextMessage(MatchesOstream(comparison_stream)), |
| TextMessage(Eq("6.02e+23")), |
| ENCODED_MESSAGE(HasValues(ElementsAre( |
| EqualsProto(R"pb(str: "6.02e+23")pb"))))))); |
| |
| test_sink.StartCapturingLogs(); |
| LOG(INFO) << value; |
| } |
| |
| TEST(DoubleLogFormatTest, Negative) { |
| absl::ScopedMockLog test_sink(absl::MockLogDefault::kDisallowUnexpected); |
| |
| const double value = -6.02e23; |
| auto comparison_stream = ComparisonStream(); |
| comparison_stream << value; |
| |
| EXPECT_CALL(test_sink, |
| Send(AllOf(TextMessage(MatchesOstream(comparison_stream)), |
| TextMessage(Eq("-6.02e+23")), |
| ENCODED_MESSAGE(HasValues(ElementsAre( |
| EqualsProto(R"pb(str: "-6.02e+23")pb"))))))); |
| |
| test_sink.StartCapturingLogs(); |
| LOG(INFO) << value; |
| } |
| |
| TEST(DoubleLogFormatTest, NegativeExponent) { |
| absl::ScopedMockLog test_sink(absl::MockLogDefault::kDisallowUnexpected); |
| |
| const double value = 6.02e-23; |
| auto comparison_stream = ComparisonStream(); |
| comparison_stream << value; |
| |
| EXPECT_CALL(test_sink, |
| Send(AllOf(TextMessage(MatchesOstream(comparison_stream)), |
| TextMessage(Eq("6.02e-23")), |
| ENCODED_MESSAGE(HasValues(ElementsAre( |
| EqualsProto(R"pb(str: "6.02e-23")pb"))))))); |
| |
| test_sink.StartCapturingLogs(); |
| LOG(INFO) << value; |
| } |
| |
| template <typename T> |
| class FloatingPointLogFormatTest : public testing::Test {}; |
| using FloatingPointTypes = Types<float, double>; |
| TYPED_TEST_SUITE(FloatingPointLogFormatTest, FloatingPointTypes); |
| |
| TYPED_TEST(FloatingPointLogFormatTest, Zero) { |
| absl::ScopedMockLog test_sink(absl::MockLogDefault::kDisallowUnexpected); |
| |
| const TypeParam value = 0.0; |
| auto comparison_stream = ComparisonStream(); |
| comparison_stream << value; |
| |
| EXPECT_CALL(test_sink, |
| Send(AllOf(TextMessage(MatchesOstream(comparison_stream)), |
| TextMessage(Eq("0")), |
| ENCODED_MESSAGE(HasValues( |
| ElementsAre(EqualsProto(R"pb(str: "0")pb"))))))); |
| |
| test_sink.StartCapturingLogs(); |
| LOG(INFO) << value; |
| } |
| |
| TYPED_TEST(FloatingPointLogFormatTest, Integer) { |
| absl::ScopedMockLog test_sink(absl::MockLogDefault::kDisallowUnexpected); |
| |
| const TypeParam value = 1.0; |
| auto comparison_stream = ComparisonStream(); |
| comparison_stream << value; |
| |
| EXPECT_CALL(test_sink, |
| Send(AllOf(TextMessage(MatchesOstream(comparison_stream)), |
| TextMessage(Eq("1")), |
| ENCODED_MESSAGE(HasValues( |
| ElementsAre(EqualsProto(R"pb(str: "1")pb"))))))); |
| |
| test_sink.StartCapturingLogs(); |
| LOG(INFO) << value; |
| } |
| |
| TYPED_TEST(FloatingPointLogFormatTest, Infinity) { |
| absl::ScopedMockLog test_sink(absl::MockLogDefault::kDisallowUnexpected); |
| |
| const TypeParam value = std::numeric_limits<TypeParam>::infinity(); |
| auto comparison_stream = ComparisonStream(); |
| comparison_stream << value; |
| |
| EXPECT_CALL(test_sink, |
| Send(AllOf(TextMessage(MatchesOstream(comparison_stream)), |
| TextMessage(AnyOf(Eq("inf"), Eq("Inf"))), |
| ENCODED_MESSAGE(HasValues( |
| ElementsAre(EqualsProto(R"pb(str: "inf")pb"))))))); |
| |
| test_sink.StartCapturingLogs(); |
| LOG(INFO) << value; |
| } |
| |
| TYPED_TEST(FloatingPointLogFormatTest, NegativeInfinity) { |
| absl::ScopedMockLog test_sink(absl::MockLogDefault::kDisallowUnexpected); |
| |
| const TypeParam value = -std::numeric_limits<TypeParam>::infinity(); |
| auto comparison_stream = ComparisonStream(); |
| comparison_stream << value; |
| |
| EXPECT_CALL(test_sink, |
| Send(AllOf(TextMessage(MatchesOstream(comparison_stream)), |
| TextMessage(AnyOf(Eq("-inf"), Eq("-Inf"))), |
| ENCODED_MESSAGE(HasValues(ElementsAre( |
| EqualsProto(R"pb(str: "-inf")pb"))))))); |
| |
| test_sink.StartCapturingLogs(); |
| LOG(INFO) << value; |
| } |
| |
| TYPED_TEST(FloatingPointLogFormatTest, NaN) { |
| absl::ScopedMockLog test_sink(absl::MockLogDefault::kDisallowUnexpected); |
| |
| const TypeParam value = std::numeric_limits<TypeParam>::quiet_NaN(); |
| auto comparison_stream = ComparisonStream(); |
| comparison_stream << value; |
| |
| EXPECT_CALL(test_sink, |
| Send(AllOf(TextMessage(MatchesOstream(comparison_stream)), |
| TextMessage(AnyOf(Eq("nan"), Eq("NaN"))), |
| ENCODED_MESSAGE(HasValues( |
| ElementsAre(EqualsProto(R"pb(str: "nan")pb"))))))); |
| test_sink.StartCapturingLogs(); |
| LOG(INFO) << value; |
| } |
| |
| TYPED_TEST(FloatingPointLogFormatTest, NegativeNaN) { |
| absl::ScopedMockLog test_sink(absl::MockLogDefault::kDisallowUnexpected); |
| |
| const TypeParam value = |
| std::copysign(std::numeric_limits<TypeParam>::quiet_NaN(), -1.0); |
| auto comparison_stream = ComparisonStream(); |
| comparison_stream << value; |
| |
| // On RISC-V, don't expect that formatting -NaN produces the same string as |
| // streaming it. #ifdefing out just the relevant line breaks the MSVC build, |
| // so duplicate the entire EXPECT_CALL. |
| #ifdef __riscv |
| EXPECT_CALL( |
| test_sink, |
| Send(AllOf( |
| TextMessage(AnyOf(Eq("-nan"), Eq("nan"), Eq("NaN"), Eq("-nan(ind)"))), |
| ENCODED_MESSAGE(HasValues( |
| ElementsAre(AnyOf(EqualsProto(R"pb(str: "-nan")pb"), |
| EqualsProto(R"pb(str: "nan")pb"), |
| EqualsProto(R"pb(str: "-nan(ind)")pb")))))))); |
| #else |
| EXPECT_CALL( |
| test_sink, |
| Send(AllOf( |
| TextMessage(MatchesOstream(comparison_stream)), |
| TextMessage(AnyOf(Eq("-nan"), Eq("nan"), Eq("NaN"), Eq("-nan(ind)"))), |
| ENCODED_MESSAGE(HasValues( |
| ElementsAre(AnyOf(EqualsProto(R"pb(str: "-nan")pb"), |
| EqualsProto(R"pb(str: "nan")pb"), |
| EqualsProto(R"pb(str: "-nan(ind)")pb")))))))); |
| #endif |
| test_sink.StartCapturingLogs(); |
| LOG(INFO) << value; |
| } |
| |
| template <typename T> |
| class VoidPtrLogFormatTest : public testing::Test {}; |
| using VoidPtrTypes = Types<void *, const void *>; |
| TYPED_TEST_SUITE(VoidPtrLogFormatTest, VoidPtrTypes); |
| |
| TYPED_TEST(VoidPtrLogFormatTest, Null) { |
| absl::ScopedMockLog test_sink(absl::MockLogDefault::kDisallowUnexpected); |
| |
| const TypeParam value = nullptr; |
| auto comparison_stream = ComparisonStream(); |
| comparison_stream << value; |
| |
| EXPECT_CALL( |
| test_sink, |
| Send(AllOf(TextMessage(MatchesOstream(comparison_stream)), |
| TextMessage(AnyOf(Eq("(nil)"), Eq("0"), Eq("0x0"), |
| Eq("00000000"), Eq("0000000000000000")))))); |
| |
| test_sink.StartCapturingLogs(); |
| LOG(INFO) << value; |
| } |
| |
| TYPED_TEST(VoidPtrLogFormatTest, NonNull) { |
| absl::ScopedMockLog test_sink(absl::MockLogDefault::kDisallowUnexpected); |
| |
| const TypeParam value = reinterpret_cast<TypeParam>(0xdeadbeefULL); |
| auto comparison_stream = ComparisonStream(); |
| comparison_stream << value; |
| |
| EXPECT_CALL( |
| test_sink, |
| Send(AllOf(TextMessage(MatchesOstream(comparison_stream)), |
| TextMessage(AnyOf(Eq("0xdeadbeef"), Eq("DEADBEEF"), |
| Eq("00000000DEADBEEF"))), |
| ENCODED_MESSAGE(HasValues(ElementsAre( |
| AnyOf(EqualsProto(R"pb(str: "0xdeadbeef")pb"), |
| EqualsProto(R"pb(str: "00000000DEADBEEF")pb")))))))); |
| |
| test_sink.StartCapturingLogs(); |
| LOG(INFO) << value; |
| } |
| |
| template <typename T> |
| class VolatilePtrLogFormatTest : public testing::Test {}; |
| using VolatilePtrTypes = |
| Types<volatile void*, const volatile void*, volatile char*, |
| const volatile char*, volatile signed char*, |
| const volatile signed char*, volatile unsigned char*, |
| const volatile unsigned char*>; |
| TYPED_TEST_SUITE(VolatilePtrLogFormatTest, VolatilePtrTypes); |
| |
| TYPED_TEST(VolatilePtrLogFormatTest, Null) { |
| absl::ScopedMockLog test_sink(absl::MockLogDefault::kDisallowUnexpected); |
| |
| const TypeParam value = nullptr; |
| auto comparison_stream = ComparisonStream(); |
| comparison_stream << value; |
| |
| EXPECT_CALL(test_sink, |
| Send(AllOf(TextMessage(MatchesOstream(comparison_stream)), |
| TextMessage(Eq("false")), |
| ENCODED_MESSAGE(HasValues(ElementsAre( |
| EqualsProto(R"pb(str: "false")pb"))))))); |
| |
| test_sink.StartCapturingLogs(); |
| LOG(INFO) << value; |
| } |
| |
| TYPED_TEST(VolatilePtrLogFormatTest, NonNull) { |
| absl::ScopedMockLog test_sink(absl::MockLogDefault::kDisallowUnexpected); |
| |
| const TypeParam value = reinterpret_cast<TypeParam>(0xdeadbeefLL); |
| auto comparison_stream = ComparisonStream(); |
| comparison_stream << value; |
| |
| EXPECT_CALL(test_sink, |
| Send(AllOf(TextMessage(MatchesOstream(comparison_stream)), |
| TextMessage(Eq("true")), |
| ENCODED_MESSAGE(HasValues(ElementsAre( |
| EqualsProto(R"pb(str: "true")pb"))))))); |
| |
| test_sink.StartCapturingLogs(); |
| LOG(INFO) << value; |
| } |
| |
| template <typename T> |
| class CharPtrLogFormatTest : public testing::Test {}; |
| using CharPtrTypes = Types<char, const char, signed char, const signed char, |
| unsigned char, const unsigned char>; |
| TYPED_TEST_SUITE(CharPtrLogFormatTest, CharPtrTypes); |
| |
| TYPED_TEST(CharPtrLogFormatTest, Null) { |
| absl::ScopedMockLog test_sink(absl::MockLogDefault::kDisallowUnexpected); |
| |
| // Streaming `([cv] char *)nullptr` into a `std::ostream` is UB, and some C++ |
| // standard library implementations choose to crash. We take measures to log |
| // something useful instead of crashing, even when that differs from the |
| // standard library in use (and thus the behavior of `std::ostream`). |
| TypeParam* const value = nullptr; |
| |
| EXPECT_CALL( |
| test_sink, |
| Send(AllOf( |
| // `MatchesOstream` deliberately omitted since we deliberately differ. |
| TextMessage(Eq("(null)")), |
| ENCODED_MESSAGE( |
| HasValues(ElementsAre(EqualsProto(R"pb(str: "(null)")pb"))))))); |
| |
| test_sink.StartCapturingLogs(); |
| LOG(INFO) << value; |
| } |
| |
| TYPED_TEST(CharPtrLogFormatTest, NonNull) { |
| absl::ScopedMockLog test_sink(absl::MockLogDefault::kDisallowUnexpected); |
| |
| TypeParam data[] = {'v', 'a', 'l', 'u', 'e', '\0'}; |
| TypeParam* const value = data; |
| auto comparison_stream = ComparisonStream(); |
| comparison_stream << value; |
| |
| EXPECT_CALL(test_sink, |
| Send(AllOf(TextMessage(MatchesOstream(comparison_stream)), |
| TextMessage(Eq("value")), |
| ENCODED_MESSAGE(HasValues(ElementsAre( |
| EqualsProto(R"pb(str: "value")pb"))))))); |
| |
| test_sink.StartCapturingLogs(); |
| LOG(INFO) << value; |
| } |
| |
| TEST(BoolLogFormatTest, True) { |
| absl::ScopedMockLog test_sink(absl::MockLogDefault::kDisallowUnexpected); |
| |
| const bool value = true; |
| auto comparison_stream = ComparisonStream(); |
| comparison_stream << value; |
| |
| EXPECT_CALL(test_sink, |
| Send(AllOf(TextMessage(MatchesOstream(comparison_stream)), |
| TextMessage(Eq("true")), |
| ENCODED_MESSAGE(HasValues(ElementsAre( |
| EqualsProto(R"pb(str: "true")pb"))))))); |
| |
| test_sink.StartCapturingLogs(); |
| LOG(INFO) << value; |
| } |
| |
| TEST(BoolLogFormatTest, False) { |
| absl::ScopedMockLog test_sink(absl::MockLogDefault::kDisallowUnexpected); |
| |
| const bool value = false; |
| auto comparison_stream = ComparisonStream(); |
| comparison_stream << value; |
| |
| EXPECT_CALL(test_sink, |
| Send(AllOf(TextMessage(MatchesOstream(comparison_stream)), |
| TextMessage(Eq("false")), |
| ENCODED_MESSAGE(HasValues(ElementsAre( |
| EqualsProto(R"pb(str: "false")pb"))))))); |
| |
| test_sink.StartCapturingLogs(); |
| LOG(INFO) << value; |
| } |
| |
| TEST(LogFormatTest, StringLiteral) { |
| absl::ScopedMockLog test_sink(absl::MockLogDefault::kDisallowUnexpected); |
| |
| auto comparison_stream = ComparisonStream(); |
| comparison_stream << "value"; |
| |
| EXPECT_CALL(test_sink, |
| Send(AllOf(TextMessage(MatchesOstream(comparison_stream)), |
| TextMessage(Eq("value")), |
| ENCODED_MESSAGE(HasValues(ElementsAre( |
| EqualsProto(R"pb(literal: "value")pb"))))))); |
| |
| test_sink.StartCapturingLogs(); |
| LOG(INFO) << "value"; |
| } |
| |
| TEST(LogFormatTest, CharArray) { |
| absl::ScopedMockLog test_sink(absl::MockLogDefault::kDisallowUnexpected); |
| |
| char value[] = "value"; |
| auto comparison_stream = ComparisonStream(); |
| comparison_stream << value; |
| |
| EXPECT_CALL(test_sink, |
| Send(AllOf(TextMessage(MatchesOstream(comparison_stream)), |
| TextMessage(Eq("value")), |
| ENCODED_MESSAGE(HasValues(ElementsAre( |
| EqualsProto(R"pb(str: "value")pb"))))))); |
| |
| test_sink.StartCapturingLogs(); |
| LOG(INFO) << value; |
| } |
| |
| class CustomClass {}; |
| std::ostream& operator<<(std::ostream& os, const CustomClass&) { |
| return os << "CustomClass{}"; |
| } |
| |
| TEST(LogFormatTest, Custom) { |
| absl::ScopedMockLog test_sink(absl::MockLogDefault::kDisallowUnexpected); |
| |
| CustomClass value; |
| auto comparison_stream = ComparisonStream(); |
| comparison_stream << value; |
| |
| EXPECT_CALL(test_sink, |
| Send(AllOf(TextMessage(MatchesOstream(comparison_stream)), |
| TextMessage(Eq("CustomClass{}")), |
| ENCODED_MESSAGE(HasValues(ElementsAre( |
| EqualsProto(R"pb(str: "CustomClass{}")pb"))))))); |
| test_sink.StartCapturingLogs(); |
| LOG(INFO) << value; |
| } |
| |
| class CustomClassNonCopyable { |
| public: |
| CustomClassNonCopyable() = default; |
| CustomClassNonCopyable(const CustomClassNonCopyable&) = delete; |
| CustomClassNonCopyable& operator=(const CustomClassNonCopyable&) = delete; |
| }; |
| std::ostream& operator<<(std::ostream& os, const CustomClassNonCopyable&) { |
| return os << "CustomClassNonCopyable{}"; |
| } |
| |
| TEST(LogFormatTest, CustomNonCopyable) { |
| absl::ScopedMockLog test_sink(absl::MockLogDefault::kDisallowUnexpected); |
| |
| CustomClassNonCopyable value; |
| auto comparison_stream = ComparisonStream(); |
| comparison_stream << value; |
| |
| EXPECT_CALL(test_sink, |
| Send(AllOf(TextMessage(MatchesOstream(comparison_stream)), |
| TextMessage(Eq("CustomClassNonCopyable{}")), |
| ENCODED_MESSAGE(HasValues(ElementsAre(EqualsProto( |
| R"pb(str: "CustomClassNonCopyable{}")pb"))))))); |
| |
| test_sink.StartCapturingLogs(); |
| 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(HasValues( |
| ElementsAre(EqualsProto(R"pb(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(HasValues( |
| ElementsAre(EqualsProto(R"pb(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(HasValues(ElementsAre( |
| EqualsProto(R"pb(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(HasValues( |
| ElementsAre(EqualsProto(R"pb(str: "(")pb"), |
| EqualsProto(R"pb(str: "10, 20)")pb"))))))); |
| |
| test_sink.StartCapturingLogs(); |
| LOG(INFO) << p; |
| } |
| |
| TEST(ManipulatorLogFormatTest, BoolAlphaTrue) { |
| absl::ScopedMockLog test_sink(absl::MockLogDefault::kDisallowUnexpected); |
| |
| const bool value = true; |
| auto comparison_stream = ComparisonStream(); |
| comparison_stream << std::noboolalpha << value << " " // |
| << std::boolalpha << value << " " // |
| << std::noboolalpha << value; |
| |
| EXPECT_CALL(test_sink, |
| Send(AllOf(TextMessage(MatchesOstream(comparison_stream)), |
| TextMessage(Eq("1 true 1")), |
| ENCODED_MESSAGE(HasValues( |
| ElementsAre(EqualsProto(R"pb(str: "1")pb"), |
| EqualsProto(R"pb(literal: " ")pb"), |
| EqualsProto(R"pb(str: "true")pb"), |
| EqualsProto(R"pb(literal: " ")pb"), |
| EqualsProto(R"pb(str: "1")pb"))))))); |
| |
| test_sink.StartCapturingLogs(); |
| LOG(INFO) << std::noboolalpha << value << " " // |
| << std::boolalpha << value << " " // |
| << std::noboolalpha << value; |
| } |
| |
| TEST(ManipulatorLogFormatTest, BoolAlphaFalse) { |
| absl::ScopedMockLog test_sink(absl::MockLogDefault::kDisallowUnexpected); |
| |
| const bool value = false; |
| auto comparison_stream = ComparisonStream(); |
| comparison_stream << std::noboolalpha << value << " " // |
| << std::boolalpha << value << " " // |
| << std::noboolalpha << value; |
| |
| EXPECT_CALL(test_sink, |
| Send(AllOf(TextMessage(MatchesOstream(comparison_stream)), |
| TextMessage(Eq("0 false 0")), |
| ENCODED_MESSAGE(HasValues( |
| ElementsAre(EqualsProto(R"pb(str: "0")pb"), |
| EqualsProto(R"pb(literal: " ")pb"), |
| EqualsProto(R"pb(str: "false")pb"), |
| EqualsProto(R"pb(literal: " ")pb"), |
| EqualsProto(R"pb(str: "0")pb"))))))); |
| |
| test_sink.StartCapturingLogs(); |
| LOG(INFO) << std::noboolalpha << value << " " // |
| << std::boolalpha << value << " " // |
| << std::noboolalpha << value; |
| } |
| |
| TEST(ManipulatorLogFormatTest, ShowPoint) { |
| absl::ScopedMockLog test_sink(absl::MockLogDefault::kDisallowUnexpected); |
| |
| const double value = 77.0; |
| auto comparison_stream = ComparisonStream(); |
| comparison_stream << std::noshowpoint << value << " " // |
| << std::showpoint << value << " " // |
| << std::noshowpoint << value; |
| |
| EXPECT_CALL(test_sink, |
| Send(AllOf(TextMessage(MatchesOstream(comparison_stream)), |
| TextMessage(Eq("77 77.0000 77")), |
| ENCODED_MESSAGE(HasValues( |
| ElementsAre(EqualsProto(R"pb(str: "77")pb"), |
| EqualsProto(R"pb(literal: " ")pb"), |
| EqualsProto(R"pb(str: "77.0000")pb"), |
| EqualsProto(R"pb(literal: " ")pb"), |
| EqualsProto(R"pb(str: "77")pb"))))))); |
| |
| test_sink.StartCapturingLogs(); |
| LOG(INFO) << std::noshowpoint << value << " " // |
| << std::showpoint << value << " " // |
| << std::noshowpoint << value; |
| } |
| |
| TEST(ManipulatorLogFormatTest, ShowPos) { |
| absl::ScopedMockLog test_sink(absl::MockLogDefault::kDisallowUnexpected); |
| |
| const int value = 77; |
| auto comparison_stream = ComparisonStream(); |
| comparison_stream << std::noshowpos << value << " " // |
| << std::showpos << value << " " // |
| << std::noshowpos << value; |
| |
| EXPECT_CALL(test_sink, |
| Send(AllOf(TextMessage(MatchesOstream(comparison_stream)), |
| TextMessage(Eq("77 +77 77")), |
| ENCODED_MESSAGE(HasValues( |
| ElementsAre(EqualsProto(R"pb(str: "77")pb"), |
| EqualsProto(R"pb(literal: " ")pb"), |
| EqualsProto(R"pb(str: "+77")pb"), |
| EqualsProto(R"pb(literal: " ")pb"), |
| EqualsProto(R"pb(str: "77")pb"))))))); |
| |
| test_sink.StartCapturingLogs(); |
| LOG(INFO) << std::noshowpos << value << " " // |
| << std::showpos << value << " " // |
| << std::noshowpos << value; |
| } |
| |
| TEST(ManipulatorLogFormatTest, UppercaseFloat) { |
| absl::ScopedMockLog test_sink(absl::MockLogDefault::kDisallowUnexpected); |
| |
| const double value = 7.7e7; |
| auto comparison_stream = ComparisonStream(); |
| comparison_stream << std::nouppercase << value << " " // |
| << std::uppercase << value << " " // |
| << std::nouppercase << value; |
| |
| EXPECT_CALL(test_sink, |
| Send(AllOf(TextMessage(MatchesOstream(comparison_stream)), |
| TextMessage(Eq("7.7e+07 7.7E+07 7.7e+07")), |
| ENCODED_MESSAGE(HasValues(ElementsAre( |
| EqualsProto(R"pb(str: "7.7e+07")pb"), |
| EqualsProto(R"pb(literal: " ")pb"), |
| EqualsProto(R"pb(str: "7.7E+07")pb"), |
| EqualsProto(R"pb(literal: " ")pb"), |
| EqualsProto(R"pb(str: "7.7e+07")pb"))))))); |
| |
| test_sink.StartCapturingLogs(); |
| LOG(INFO) << std::nouppercase << value << " " // |
| << std::uppercase << value << " " // |
| << std::nouppercase << value; |
| } |
| |
| TEST(ManipulatorLogFormatTest, Hex) { |
| absl::ScopedMockLog test_sink(absl::MockLogDefault::kDisallowUnexpected); |
| |
| const int value = 0x77; |
| auto comparison_stream = ComparisonStream(); |
| comparison_stream << std::hex << value; |
| |
| EXPECT_CALL(test_sink, |
| Send(AllOf(TextMessage(MatchesOstream(comparison_stream)), |
| TextMessage(Eq("0x77")), |
| ENCODED_MESSAGE(HasValues(ElementsAre( |
| EqualsProto(R"pb(str: "0x77")pb"))))))); |
| test_sink.StartCapturingLogs(); |
| LOG(INFO) << std::hex << value; |
| } |
| |
| TEST(ManipulatorLogFormatTest, Oct) { |
| absl::ScopedMockLog test_sink(absl::MockLogDefault::kDisallowUnexpected); |
| |
| const int value = 077; |
| auto comparison_stream = ComparisonStream(); |
| comparison_stream << std::oct << value; |
| |
| EXPECT_CALL(test_sink, |
| Send(AllOf(TextMessage(MatchesOstream(comparison_stream)), |
| TextMessage(Eq("077")), |
| ENCODED_MESSAGE(HasValues( |
| ElementsAre(EqualsProto(R"pb(str: "077")pb"))))))); |
| |
| test_sink.StartCapturingLogs(); |
| LOG(INFO) << std::oct << value; |
| } |
| |
| TEST(ManipulatorLogFormatTest, Dec) { |
| absl::ScopedMockLog test_sink(absl::MockLogDefault::kDisallowUnexpected); |
| |
| const int value = 77; |
| auto comparison_stream = ComparisonStream(); |
| comparison_stream << std::hex << std::dec << value; |
| |
| EXPECT_CALL(test_sink, |
| Send(AllOf(TextMessage(MatchesOstream(comparison_stream)), |
| TextMessage(Eq("77")), |
| ENCODED_MESSAGE(HasValues( |
| ElementsAre(EqualsProto(R"pb(str: "77")pb"))))))); |
| |
| test_sink.StartCapturingLogs(); |
| LOG(INFO) << std::hex << std::dec << value; |
| } |
| |
| TEST(ManipulatorLogFormatTest, ShowbaseHex) { |
| absl::ScopedMockLog test_sink(absl::MockLogDefault::kDisallowUnexpected); |
| |
| const int value = 0x77; |
| auto comparison_stream = ComparisonStream(); |
| comparison_stream << std::hex // |
| << std::noshowbase << value << " " // |
| << std::showbase << value << " " // |
| << std::noshowbase << value; |
| |
| EXPECT_CALL(test_sink, |
| Send(AllOf(TextMessage(MatchesOstream(comparison_stream)), |
| TextMessage(Eq("77 0x77 77")), |
| ENCODED_MESSAGE(HasValues( |
| ElementsAre(EqualsProto(R"pb(str: "77")pb"), |
| EqualsProto(R"pb(literal: " ")pb"), |
| EqualsProto(R"pb(str: "0x77")pb"), |
| EqualsProto(R"pb(literal: " ")pb"), |
| EqualsProto(R"pb(str: "77")pb"))))))); |
| |
| test_sink.StartCapturingLogs(); |
| LOG(INFO) << std::hex // |
| << std::noshowbase << value << " " // |
| << std::showbase << value << " " // |
| << std::noshowbase << value; |
| } |
| |
| TEST(ManipulatorLogFormatTest, ShowbaseOct) { |
| absl::ScopedMockLog test_sink(absl::MockLogDefault::kDisallowUnexpected); |
| |
| const int value = 077; |
| auto comparison_stream = ComparisonStream(); |
| comparison_stream << std::oct // |
| << std::noshowbase << value << " " // |
| << std::showbase << value << " " // |
| << std::noshowbase << value; |
| |
| EXPECT_CALL(test_sink, |
| Send(AllOf(TextMessage(MatchesOstream(comparison_stream)), |
| TextMessage(Eq("77 077 77")), |
| ENCODED_MESSAGE(HasValues( |
| ElementsAre(EqualsProto(R"pb(str: "77")pb"), |
| EqualsProto(R"pb(literal: " ")pb"), |
| EqualsProto(R"pb(str: "077")pb"), |
| EqualsProto(R"pb(literal: " ")pb"), |
| EqualsProto(R"pb(str: "77")pb"))))))); |
| |
| test_sink.StartCapturingLogs(); |
| LOG(INFO) << std::oct // |
| << std::noshowbase << value << " " // |
| << std::showbase << value << " " // |
| << std::noshowbase << value; |
| } |
| |
| TEST(ManipulatorLogFormatTest, UppercaseHex) { |
| absl::ScopedMockLog test_sink(absl::MockLogDefault::kDisallowUnexpected); |
| |
| const int value = 0xbeef; |
| auto comparison_stream = ComparisonStream(); |
| comparison_stream // |
| << std::hex // |
| << std::nouppercase << value << " " // |
| << std::uppercase << value << " " // |
| << std::nouppercase << value; |
| |
| EXPECT_CALL(test_sink, |
| Send(AllOf(TextMessage(MatchesOstream(comparison_stream)), |
| TextMessage(Eq("0xbeef 0XBEEF 0xbeef")), |
| ENCODED_MESSAGE(HasValues(ElementsAre( |
| EqualsProto(R"pb(str: "0xbeef")pb"), |
| EqualsProto(R"pb(literal: " ")pb"), |
| EqualsProto(R"pb(str: "0XBEEF")pb"), |
| EqualsProto(R"pb(literal: " ")pb"), |
| EqualsProto(R"pb(str: "0xbeef")pb"))))))); |
| |
| test_sink.StartCapturingLogs(); |
| LOG(INFO) << std::hex // |
| << std::nouppercase << value << " " // |
| << std::uppercase << value << " " // |
| << std::nouppercase << value; |
| } |
| |
| TEST(ManipulatorLogFormatTest, FixedFloat) { |
| absl::ScopedMockLog test_sink(absl::MockLogDefault::kDisallowUnexpected); |
| |
| const double value = 7.7e7; |
| auto comparison_stream = ComparisonStream(); |
| comparison_stream << std::fixed << value; |
| |
| EXPECT_CALL(test_sink, |
| Send(AllOf(TextMessage(MatchesOstream(comparison_stream)), |
| TextMessage(Eq("77000000.000000")), |
| ENCODED_MESSAGE(HasValues(ElementsAre( |
| EqualsProto(R"pb(str: "77000000.000000")pb"))))))); |
| |
| test_sink.StartCapturingLogs(); |
| LOG(INFO) << std::fixed << value; |
| } |
| |
| TEST(ManipulatorLogFormatTest, ScientificFloat) { |
| absl::ScopedMockLog test_sink(absl::MockLogDefault::kDisallowUnexpected); |
| |
| const double value = 7.7e7; |
| auto comparison_stream = ComparisonStream(); |
| comparison_stream << std::scientific << value; |
| |
| EXPECT_CALL(test_sink, |
| Send(AllOf(TextMessage(MatchesOstream(comparison_stream)), |
| TextMessage(Eq("7.700000e+07")), |
| ENCODED_MESSAGE(HasValues(ElementsAre( |
| EqualsProto(R"pb(str: "7.700000e+07")pb"))))))); |
| |
| test_sink.StartCapturingLogs(); |
| LOG(INFO) << std::scientific << value; |
| } |
| |
| #if defined(__BIONIC__) && (!defined(__ANDROID_API__) || __ANDROID_API__ < 22) |
| // Bionic doesn't support `%a` until API 22, so this prints 'a' even if the |
| // C++ standard library implements it correctly (by forwarding to printf). |
| #elif defined(__GLIBCXX__) && __cplusplus < 201402L |
| // libstdc++ shipped C++11 support without `std::hexfloat`. |
| #else |
| TEST(ManipulatorLogFormatTest, FixedAndScientificFloat) { |
| absl::ScopedMockLog test_sink(absl::MockLogDefault::kDisallowUnexpected); |
| |
| const double value = 7.7e7; |
| auto comparison_stream = ComparisonStream(); |
| comparison_stream << std::setiosflags(std::ios_base::scientific | |
| std::ios_base::fixed) |
| << value; |
| |
| EXPECT_CALL( |
| test_sink, |
| Send(AllOf(TextMessage(MatchesOstream(comparison_stream)), |
| TextMessage(AnyOf(Eq("0x1.25bb50p+26"), Eq("0x1.25bb5p+26"), |
| Eq("0x1.25bb500000000p+26"))), |
| ENCODED_MESSAGE(HasValues(ElementsAre(AnyOf( |
| EqualsProto(R"pb(str: "0x1.25bb5p+26")pb"), |
| EqualsProto(R"pb(str: "0x1.25bb500000000p+26")pb")))))))); |
| |
| test_sink.StartCapturingLogs(); |
| |
| // This combination should mean the same thing as `std::hexfloat`. |
| LOG(INFO) << std::setiosflags(std::ios_base::scientific | |
| std::ios_base::fixed) |
| << value; |
| } |
| #endif |
| |
| #if defined(__BIONIC__) && (!defined(__ANDROID_API__) || __ANDROID_API__ < 22) |
| // Bionic doesn't support `%a` until API 22, so this prints 'a' even if the C++ |
| // standard library supports `std::hexfloat` (by forwarding to printf). |
| #elif defined(__GLIBCXX__) && __cplusplus < 201402L |
| // libstdc++ shipped C++11 support without `std::hexfloat`. |
| #else |
| TEST(ManipulatorLogFormatTest, HexfloatFloat) { |
| absl::ScopedMockLog test_sink(absl::MockLogDefault::kDisallowUnexpected); |
| |
| const double value = 7.7e7; |
| auto comparison_stream = ComparisonStream(); |
| comparison_stream << std::hexfloat << value; |
| |
| EXPECT_CALL( |
| test_sink, |
| Send(AllOf(TextMessage(MatchesOstream(comparison_stream)), |
| TextMessage(AnyOf(Eq("0x1.25bb50p+26"), Eq("0x1.25bb5p+26"), |
| Eq("0x1.25bb500000000p+26"))), |
| ENCODED_MESSAGE(HasValues(ElementsAre(AnyOf( |
| EqualsProto(R"pb(str: "0x1.25bb5p+26")pb"), |
| EqualsProto(R"pb(str: "0x1.25bb500000000p+26")pb")))))))); |
| |
| test_sink.StartCapturingLogs(); |
| LOG(INFO) << std::hexfloat << value; |
| } |
| #endif |
| |
| TEST(ManipulatorLogFormatTest, DefaultFloatFloat) { |
| absl::ScopedMockLog test_sink(absl::MockLogDefault::kDisallowUnexpected); |
| |
| const double value = 7.7e7; |
| auto comparison_stream = ComparisonStream(); |
| comparison_stream << std::hexfloat << std::defaultfloat << value; |
| |
| EXPECT_CALL(test_sink, |
| Send(AllOf(TextMessage(MatchesOstream(comparison_stream)), |
| TextMessage(Eq("7.7e+07")), |
| ENCODED_MESSAGE(HasValues(ElementsAre( |
| EqualsProto(R"pb(str: "7.7e+07")pb"))))))); |
| |
| test_sink.StartCapturingLogs(); |
| LOG(INFO) << std::hexfloat << std::defaultfloat << value; |
| } |
| |
| TEST(ManipulatorLogFormatTest, Ends) { |
| absl::ScopedMockLog test_sink(absl::MockLogDefault::kDisallowUnexpected); |
| |
| auto comparison_stream = ComparisonStream(); |
| comparison_stream << std::ends; |
| |
| EXPECT_CALL(test_sink, |
| Send(AllOf(TextMessage(MatchesOstream(comparison_stream)), |
| TextMessage(Eq(absl::string_view("\0", 1))), |
| ENCODED_MESSAGE(HasValues( |
| ElementsAre(EqualsProto(R"pb(str: "\0")pb"))))))); |
| |
| test_sink.StartCapturingLogs(); |
| LOG(INFO) << std::ends; |
| } |
| |
| TEST(ManipulatorLogFormatTest, Endl) { |
| absl::ScopedMockLog test_sink(absl::MockLogDefault::kDisallowUnexpected); |
| |
| auto comparison_stream = ComparisonStream(); |
| comparison_stream << std::endl; |
| |
| EXPECT_CALL( |
| test_sink, |
| Send(AllOf( |
| TextMessage(MatchesOstream(comparison_stream)), |
| TextMessage(Eq("\n")), |
| ENCODED_MESSAGE(HasValues(ElementsAre(EqualsProto(R"pb(str: |
| "\n")pb"))))))); |
| |
| test_sink.StartCapturingLogs(); |
| LOG(INFO) << std::endl; |
| } |
| |
| TEST(ManipulatorLogFormatTest, SetIosFlags) { |
| absl::ScopedMockLog test_sink(absl::MockLogDefault::kDisallowUnexpected); |
| |
| const int value = 0x77; |
| auto comparison_stream = ComparisonStream(); |
| comparison_stream << std::resetiosflags(std::ios_base::basefield) |
| << std::setiosflags(std::ios_base::hex) << value << " " // |
| << std::resetiosflags(std::ios_base::basefield) |
| << std::setiosflags(std::ios_base::dec) << value; |
| |
| EXPECT_CALL( |
| test_sink, |
| Send(AllOf( |
| TextMessage(MatchesOstream(comparison_stream)), |
| TextMessage(Eq("0x77 119")), |
| // `std::setiosflags` and `std::resetiosflags` aren't manipulators. |
| // We're unable to distinguish their return type(s) from arbitrary |
| // user-defined types and thus don't suppress the empty str value. |
| ENCODED_MESSAGE( |
| HasValues(ElementsAre(EqualsProto(R"pb(str: "0x77")pb"), |
| EqualsProto(R"pb(literal: " ")pb"), |
| EqualsProto(R"pb(str: "119")pb"))))))); |
| |
| test_sink.StartCapturingLogs(); |
| LOG(INFO) << std::resetiosflags(std::ios_base::basefield) |
| << std::setiosflags(std::ios_base::hex) << value << " " // |
| << std::resetiosflags(std::ios_base::basefield) |
| << std::setiosflags(std::ios_base::dec) << value; |
| } |
| |
| TEST(ManipulatorLogFormatTest, SetBase) { |
| absl::ScopedMockLog test_sink(absl::MockLogDefault::kDisallowUnexpected); |
| |
| const int value = 0x77; |
| auto comparison_stream = ComparisonStream(); |
| comparison_stream << std::setbase(16) << value << " " // |
| << std::setbase(0) << value; |
| |
| EXPECT_CALL( |
| test_sink, |
| Send(AllOf(TextMessage(MatchesOstream(comparison_stream)), |
| TextMessage(Eq("0x77 119")), |
| // `std::setbase` isn't a manipulator. We're unable to |
| // distinguish its return type from arbitrary user-defined |
| // types and thus don't suppress the empty str value. |
| ENCODED_MESSAGE(HasValues( |
| ElementsAre(EqualsProto(R"pb(str: "0x77")pb"), |
| EqualsProto(R"pb(literal: " ")pb"), |
| EqualsProto(R"pb(str: "119")pb"))))))); |
| |
| test_sink.StartCapturingLogs(); |
| LOG(INFO) << std::setbase(16) << value << " " // |
| << std::setbase(0) << value; |
| } |
| |
| TEST(ManipulatorLogFormatTest, SetPrecision) { |
| absl::ScopedMockLog test_sink(absl::MockLogDefault::kDisallowUnexpected); |
| |
| const double value = 6.022140857e23; |
| auto comparison_stream = ComparisonStream(); |
| comparison_stream << std::setprecision(4) << value; |
| |
| EXPECT_CALL( |
| test_sink, |
| Send(AllOf(TextMessage(MatchesOstream(comparison_stream)), |
| TextMessage(Eq("6.022e+23")), |
| // `std::setprecision` isn't a manipulator. We're unable to |
| // distinguish its return type from arbitrary user-defined |
| // types and thus don't suppress the empty str value. |
| ENCODED_MESSAGE(HasValues( |
| ElementsAre(EqualsProto(R"pb(str: "6.022e+23")pb"))))))); |
| |
| test_sink.StartCapturingLogs(); |
| LOG(INFO) << std::setprecision(4) << value; |
| } |
| |
| TEST(ManipulatorLogFormatTest, SetPrecisionOverflow) { |
| absl::ScopedMockLog test_sink(absl::MockLogDefault::kDisallowUnexpected); |
| |
| const double value = 6.022140857e23; |
| auto comparison_stream = ComparisonStream(); |
| comparison_stream << std::setprecision(200) << value; |
| |
| EXPECT_CALL(test_sink, |
| Send(AllOf(TextMessage(MatchesOstream(comparison_stream)), |
| TextMessage(Eq("602214085700000015187968")), |
| ENCODED_MESSAGE(HasValues(ElementsAre(EqualsProto( |
| R"pb(str: "602214085700000015187968")pb"))))))); |
| |
| test_sink.StartCapturingLogs(); |
| LOG(INFO) << std::setprecision(200) << value; |
| } |
| |
| TEST(ManipulatorLogFormatTest, SetW) { |
| absl::ScopedMockLog test_sink(absl::MockLogDefault::kDisallowUnexpected); |
| |
| const int value = 77; |
| auto comparison_stream = ComparisonStream(); |
| comparison_stream << std::setw(8) << value; |
| |
| EXPECT_CALL( |
| test_sink, |
| Send(AllOf(TextMessage(MatchesOstream(comparison_stream)), |
| TextMessage(Eq(" 77")), |
| // `std::setw` isn't a manipulator. We're unable to |
| // distinguish its return type from arbitrary user-defined |
| // types and thus don't suppress the empty str value. |
| ENCODED_MESSAGE(HasValues( |
| ElementsAre(EqualsProto(R"pb(str: " 77")pb"))))))); |
| |
| test_sink.StartCapturingLogs(); |
| LOG(INFO) << std::setw(8) << value; |
| } |
| |
| TEST(ManipulatorLogFormatTest, Left) { |
| absl::ScopedMockLog test_sink(absl::MockLogDefault::kDisallowUnexpected); |
| |
| const int value = -77; |
| auto comparison_stream = ComparisonStream(); |
| comparison_stream << std::left << std::setw(8) << value; |
| |
| EXPECT_CALL(test_sink, |
| Send(AllOf(TextMessage(MatchesOstream(comparison_stream)), |
| TextMessage(Eq("-77 ")), |
| ENCODED_MESSAGE(HasValues(ElementsAre( |
| EqualsProto(R"pb(str: "-77 ")pb"))))))); |
| |
| test_sink.StartCapturingLogs(); |
| LOG(INFO) << std::left << std::setw(8) << value; |
| } |
| |
| TEST(ManipulatorLogFormatTest, Right) { |
| absl::ScopedMockLog test_sink(absl::MockLogDefault::kDisallowUnexpected); |
| |
| const int value = -77; |
| auto comparison_stream = ComparisonStream(); |
| comparison_stream << std::right << std::setw(8) << value; |
| |
| EXPECT_CALL(test_sink, |
| Send(AllOf(TextMessage(MatchesOstream(comparison_stream)), |
| TextMessage(Eq(" -77")), |
| ENCODED_MESSAGE(HasValues(ElementsAre( |
| EqualsProto(R"pb(str: " -77")pb"))))))); |
| |
| test_sink.StartCapturingLogs(); |
| LOG(INFO) << std::right << std::setw(8) << value; |
| } |
| |
| TEST(ManipulatorLogFormatTest, Internal) { |
| absl::ScopedMockLog test_sink(absl::MockLogDefault::kDisallowUnexpected); |
| |
| const int value = -77; |
| auto comparison_stream = ComparisonStream(); |
| comparison_stream << std::internal << std::setw(8) << value; |
| |
| EXPECT_CALL(test_sink, |
| Send(AllOf(TextMessage(MatchesOstream(comparison_stream)), |
| TextMessage(Eq("- 77")), |
| ENCODED_MESSAGE(HasValues(ElementsAre( |
| EqualsProto(R"pb(str: "- 77")pb"))))))); |
| |
| test_sink.StartCapturingLogs(); |
| LOG(INFO) << std::internal << std::setw(8) << value; |
| } |
| |
| TEST(ManipulatorLogFormatTest, SetFill) { |
| absl::ScopedMockLog test_sink(absl::MockLogDefault::kDisallowUnexpected); |
| |
| const int value = 77; |
| auto comparison_stream = ComparisonStream(); |
| comparison_stream << std::setfill('0') << std::setw(8) << value; |
| |
| EXPECT_CALL(test_sink, |
| Send(AllOf(TextMessage(MatchesOstream(comparison_stream)), |
| TextMessage(Eq("00000077")), |
| // `std::setfill` isn't a manipulator. We're |
| // unable to distinguish its return |
| // type from arbitrary user-defined types and |
| // thus don't suppress the empty str value. |
| ENCODED_MESSAGE(HasValues(ElementsAre( |
| EqualsProto(R"pb(str: "00000077")pb"))))))); |
| |
| test_sink.StartCapturingLogs(); |
| LOG(INFO) << std::setfill('0') << std::setw(8) << value; |
| } |
| |
| class FromCustomClass {}; |
| std::ostream& operator<<(std::ostream& os, const FromCustomClass&) { |
| return os << "FromCustomClass{}" << std::hex; |
| } |
| |
| TEST(ManipulatorLogFormatTest, FromCustom) { |
| absl::ScopedMockLog test_sink(absl::MockLogDefault::kDisallowUnexpected); |
| |
| FromCustomClass value; |
| auto comparison_stream = ComparisonStream(); |
| comparison_stream << value << " " << 0x77; |
| |
| EXPECT_CALL(test_sink, |
| Send(AllOf(TextMessage(MatchesOstream(comparison_stream)), |
| TextMessage(Eq("FromCustomClass{} 0x77")), |
| ENCODED_MESSAGE(HasValues(ElementsAre( |
| EqualsProto(R"pb(str: "FromCustomClass{}")pb"), |
| EqualsProto(R"pb(literal: " ")pb"), |
| EqualsProto(R"pb(str: "0x77")pb"))))))); |
| |
| test_sink.StartCapturingLogs(); |
| LOG(INFO) << value << " " << 0x77; |
| } |
| |
| class StreamsNothing {}; |
| std::ostream& operator<<(std::ostream& os, const StreamsNothing&) { return os; } |
| |
| TEST(ManipulatorLogFormatTest, CustomClassStreamsNothing) { |
| absl::ScopedMockLog test_sink(absl::MockLogDefault::kDisallowUnexpected); |
| |
| StreamsNothing value; |
| auto comparison_stream = ComparisonStream(); |
| comparison_stream << value << 77; |
| |
| EXPECT_CALL(test_sink, |
| Send(AllOf(TextMessage(MatchesOstream(comparison_stream)), |
| TextMessage(Eq("77")), |
| ENCODED_MESSAGE(HasValues( |
| ElementsAre(EqualsProto(R"pb(str: "77")pb"))))))); |
| |
| test_sink.StartCapturingLogs(); |
| 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(HasValues( |
| ElementsAre(EqualsProto(R"pb(str: "(10, 20)")pb"))))))); |
| |
| test_sink.StartCapturingLogs(); |
| LOG(INFO) << std::hex << p; |
| } |
| |
| TEST(StructuredLoggingOverflowTest, TruncatesStrings) { |
| absl::ScopedMockLog test_sink(absl::MockLogDefault::kDisallowUnexpected); |
| |
| // This message is too long and should be truncated to some unspecified size |
| // no greater than the buffer size but not too much less either. It should be |
| // truncated rather than discarded. |
| EXPECT_CALL( |
| test_sink, |
| Send(AllOf( |
| TextMessage(AllOf( |
| SizeIs(AllOf(Ge(absl::log_internal::kLogMessageBufferSize - 256), |
| Le(absl::log_internal::kLogMessageBufferSize))), |
| Each(Eq('x')))), |
| ENCODED_MESSAGE(HasOneStrThat(AllOf( |
| SizeIs(AllOf(Ge(absl::log_internal::kLogMessageBufferSize - 256), |
| Le(absl::log_internal::kLogMessageBufferSize))), |
| Each(Eq('x')))))))); |
| |
| test_sink.StartCapturingLogs(); |
| LOG(INFO) << std::string(2 * absl::log_internal::kLogMessageBufferSize, 'x'); |
| } |
| |
| struct StringLike { |
| absl::string_view data; |
| }; |
| std::ostream& operator<<(std::ostream& os, StringLike str) { |
| return os << str.data; |
| } |
| |
| TEST(StructuredLoggingOverflowTest, TruncatesInsertionOperators) { |
| absl::ScopedMockLog test_sink(absl::MockLogDefault::kDisallowUnexpected); |
| |
| // This message is too long and should be truncated to some unspecified size |
| // no greater than the buffer size but not too much less either. It should be |
| // truncated rather than discarded. |
| EXPECT_CALL( |
| test_sink, |
| Send(AllOf( |
| TextMessage(AllOf( |
| SizeIs(AllOf(Ge(absl::log_internal::kLogMessageBufferSize - 256), |
| Le(absl::log_internal::kLogMessageBufferSize))), |
| Each(Eq('x')))), |
| ENCODED_MESSAGE(HasOneStrThat(AllOf( |
| SizeIs(AllOf(Ge(absl::log_internal::kLogMessageBufferSize - 256), |
| Le(absl::log_internal::kLogMessageBufferSize))), |
| Each(Eq('x')))))))); |
| |
| test_sink.StartCapturingLogs(); |
| LOG(INFO) << StringLike{ |
| std::string(2 * absl::log_internal::kLogMessageBufferSize, 'x')}; |
| } |
| |
| // Returns the size of the largest string that will fit in a `LOG` message |
| // buffer with no prefix. |
| size_t MaxLogFieldLengthNoPrefix() { |
| class StringLengthExtractorSink : public absl::LogSink { |
| public: |
| void Send(const absl::LogEntry& entry) override { |
| CHECK(!size_.has_value()); |
| CHECK_EQ(entry.text_message().find_first_not_of('x'), |
| absl::string_view::npos); |
| size_.emplace(entry.text_message().size()); |
| } |
| size_t size() const { |
| CHECK(size_.has_value()); |
| return *size_; |
| } |
| |
| private: |
| absl::optional<size_t> size_; |
| } extractor_sink; |
| LOG(INFO).NoPrefix().ToSinkOnly(&extractor_sink) |
| << std::string(2 * absl::log_internal::kLogMessageBufferSize, 'x'); |
| return extractor_sink.size(); |
| } |
| |
| TEST(StructuredLoggingOverflowTest, TruncatesStringsCleanly) { |
| const size_t longest_fit = MaxLogFieldLengthNoPrefix(); |
| // To log a second value field, we need four bytes: two tag/type bytes and two |
| // sizes. To put any data in the field we need a fifth byte. |
| { |
| absl::ScopedMockLog test_sink(absl::MockLogDefault::kDisallowUnexpected); |
| EXPECT_CALL(test_sink, |
| Send(AllOf(ENCODED_MESSAGE(HasOneStrThat( |
| AllOf(SizeIs(longest_fit), Each(Eq('x'))))), |
| RawEncodedMessage(AsString(EndsWith("x")))))); |
| test_sink.StartCapturingLogs(); |
| // x fits exactly, no part of y fits. |
| LOG(INFO).NoPrefix() << std::string(longest_fit, 'x') << "y"; |
| } |
| { |
| absl::ScopedMockLog test_sink(absl::MockLogDefault::kDisallowUnexpected); |
| EXPECT_CALL(test_sink, |
| Send(AllOf(ENCODED_MESSAGE(HasOneStrThat( |
| AllOf(SizeIs(longest_fit - 1), Each(Eq('x'))))), |
| RawEncodedMessage(AsString(EndsWith("x")))))); |
| test_sink.StartCapturingLogs(); |
| // x fits, one byte from y's header fits but shouldn't be visible. |
| LOG(INFO).NoPrefix() << std::string(longest_fit - 1, 'x') << "y"; |
| } |
| { |
| absl::ScopedMockLog test_sink(absl::MockLogDefault::kDisallowUnexpected); |
| EXPECT_CALL(test_sink, |
| Send(AllOf(ENCODED_MESSAGE(HasOneStrThat( |
| AllOf(SizeIs(longest_fit - 2), Each(Eq('x'))))), |
| RawEncodedMessage(AsString(EndsWith("x")))))); |
| test_sink.StartCapturingLogs(); |
| // x fits, two bytes from y's header fit but shouldn't be visible. |
| LOG(INFO).NoPrefix() << std::string(longest_fit - 2, 'x') << "y"; |
| } |
| { |
| absl::ScopedMockLog test_sink(absl::MockLogDefault::kDisallowUnexpected); |
| EXPECT_CALL(test_sink, |
| Send(AllOf(ENCODED_MESSAGE(HasOneStrThat( |
| AllOf(SizeIs(longest_fit - 3), Each(Eq('x'))))), |
| RawEncodedMessage(AsString(EndsWith("x")))))); |
| test_sink.StartCapturingLogs(); |
| // x fits, three bytes from y's header fit but shouldn't be visible. |
| LOG(INFO).NoPrefix() << std::string(longest_fit - 3, 'x') << "y"; |
| } |
| { |
| absl::ScopedMockLog test_sink(absl::MockLogDefault::kDisallowUnexpected); |
| EXPECT_CALL(test_sink, |
| Send(AllOf(ENCODED_MESSAGE(HasOneStrAndOneLiteralThat( |
| AllOf(SizeIs(longest_fit - 4), Each(Eq('x'))), |
| IsEmpty())), |
| RawEncodedMessage(Not(AsString(EndsWith("x"))))))); |
| test_sink.StartCapturingLogs(); |
| // x fits, all four bytes from y's header fit but no data bytes do, so we |
| // encode an empty string. |
| LOG(INFO).NoPrefix() << std::string(longest_fit - 4, 'x') << "y"; |
| } |
| { |
| absl::ScopedMockLog test_sink(absl::MockLogDefault::kDisallowUnexpected); |
| EXPECT_CALL( |
| test_sink, |
| Send(AllOf(ENCODED_MESSAGE(HasOneStrAndOneLiteralThat( |
| AllOf(SizeIs(longest_fit - 5), Each(Eq('x'))), Eq("y"))), |
| RawEncodedMessage(AsString(EndsWith("y")))))); |
| test_sink.StartCapturingLogs(); |
| // x fits, y fits exactly. |
| LOG(INFO).NoPrefix() << std::string(longest_fit - 5, 'x') << "y"; |
| } |
| } |
| |
| TEST(StructuredLoggingOverflowTest, TruncatesInsertionOperatorsCleanly) { |
| const size_t longest_fit = MaxLogFieldLengthNoPrefix(); |
| // To log a second value field, we need four bytes: two tag/type bytes and two |
| // sizes. To put any data in the field we need a fifth byte. |
| { |
| absl::ScopedMockLog test_sink(absl::MockLogDefault::kDisallowUnexpected); |
| EXPECT_CALL(test_sink, |
| Send(AllOf(ENCODED_MESSAGE(HasOneStrThat( |
| AllOf(SizeIs(longest_fit), Each(Eq('x'))))), |
| RawEncodedMessage(AsString(EndsWith("x")))))); |
| test_sink.StartCapturingLogs(); |
| // x fits exactly, no part of y fits. |
| LOG(INFO).NoPrefix() << std::string(longest_fit, 'x') << StringLike{"y"}; |
| } |
| { |
| absl::ScopedMockLog test_sink(absl::MockLogDefault::kDisallowUnexpected); |
| EXPECT_CALL(test_sink, |
| Send(AllOf(ENCODED_MESSAGE(HasOneStrThat( |
| AllOf(SizeIs(longest_fit - 1), Each(Eq('x'))))), |
| RawEncodedMessage(AsString(EndsWith("x")))))); |
| test_sink.StartCapturingLogs(); |
| // x fits, one byte from y's header fits but shouldn't be visible. |
| LOG(INFO).NoPrefix() << std::string(longest_fit - 1, 'x') |
| << StringLike{"y"}; |
| } |
| { |
| absl::ScopedMockLog test_sink(absl::MockLogDefault::kDisallowUnexpected); |
| EXPECT_CALL(test_sink, |
| Send(AllOf(ENCODED_MESSAGE(HasOneStrThat( |
| AllOf(SizeIs(longest_fit - 2), Each(Eq('x'))))), |
| RawEncodedMessage(AsString(EndsWith("x")))))); |
| test_sink.StartCapturingLogs(); |
| // x fits, two bytes from y's header fit but shouldn't be visible. |
| LOG(INFO).NoPrefix() << std::string(longest_fit - 2, 'x') |
| << StringLike{"y"}; |
| } |
| { |
| absl::ScopedMockLog test_sink(absl::MockLogDefault::kDisallowUnexpected); |
| EXPECT_CALL(test_sink, |
| Send(AllOf(ENCODED_MESSAGE(HasOneStrThat( |
| AllOf(SizeIs(longest_fit - 3), Each(Eq('x'))))), |
| RawEncodedMessage(AsString(EndsWith("x")))))); |
| test_sink.StartCapturingLogs(); |
| // x fits, three bytes from y's header fit but shouldn't be visible. |
| LOG(INFO).NoPrefix() << std::string(longest_fit - 3, 'x') |
| << StringLike{"y"}; |
| } |
| { |
| absl::ScopedMockLog test_sink(absl::MockLogDefault::kDisallowUnexpected); |
| EXPECT_CALL(test_sink, |
| Send(AllOf(ENCODED_MESSAGE(HasOneStrThat( |
| AllOf(SizeIs(longest_fit - 4), Each(Eq('x'))))), |
| RawEncodedMessage(AsString(EndsWith("x")))))); |
| test_sink.StartCapturingLogs(); |
| // x fits, all four bytes from y's header fit but no data bytes do. We |
| // don't encode an empty string here because every I/O manipulator hits this |
| // codepath and those shouldn't leave empty strings behind. |
| LOG(INFO).NoPrefix() << std::string(longest_fit - 4, 'x') |
| << StringLike{"y"}; |
| } |
| { |
| absl::ScopedMockLog test_sink(absl::MockLogDefault::kDisallowUnexpected); |
| EXPECT_CALL( |
| test_sink, |
| Send(AllOf(ENCODED_MESSAGE(HasTwoStrsThat( |
| AllOf(SizeIs(longest_fit - 5), Each(Eq('x'))), Eq("y"))), |
| RawEncodedMessage(AsString(EndsWith("y")))))); |
| test_sink.StartCapturingLogs(); |
| // x fits, y fits exactly. |
| LOG(INFO).NoPrefix() << std::string(longest_fit - 5, 'x') |
| << StringLike{"y"}; |
| } |
| } |
| |
| } // namespace |