mirror of
https://github.com/abseil/abseil-cpp.git
synced 2026-06-04 12:07:05 +08:00
Prior to this change logging absl::SourceLocation sometimes worked when //absl/strings/internal/stringify_sink.h was in the transitive includes, usually through str_cat.h. This change adds native support to logging, to avoid dependency issues. PiperOrigin-RevId: 922782911 Change-Id: I599390a062c6f8828985d6475a6dbd324d3e52c9
2279 lines
80 KiB
C++
2279 lines
80 KiB
C++
//
|
||
// 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 <cstring>
|
||
#include <iomanip>
|
||
#include <ios>
|
||
#include <limits>
|
||
#include <optional>
|
||
#include <ostream>
|
||
#include <sstream>
|
||
#include <string>
|
||
#include <string_view>
|
||
#include <type_traits>
|
||
|
||
#ifdef __ANDROID__
|
||
#include <android/api-level.h>
|
||
#endif
|
||
|
||
#include "gmock/gmock.h"
|
||
#include "gtest/gtest.h"
|
||
#include "absl/base/config.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/source_location.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::_;
|
||
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);
|
||
EXPECT_CALL(test_sink, Send).Times(0);
|
||
|
||
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);
|
||
EXPECT_CALL(test_sink, Send).Times(0);
|
||
|
||
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(ValueWithStr(Eq("x"))))))));
|
||
|
||
test_sink.StartCapturingLogs();
|
||
LOG(INFO) << value;
|
||
}
|
||
|
||
TYPED_TEST(CharLogFormatTest, Unprintable) {
|
||
absl::ScopedMockLog test_sink(absl::MockLogDefault::kDisallowUnexpected);
|
||
EXPECT_CALL(test_sink, Send).Times(0);
|
||
|
||
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(ValueWithStr(Eq("\xee"))))))));
|
||
|
||
test_sink.StartCapturingLogs();
|
||
LOG(INFO) << value;
|
||
}
|
||
|
||
TEST(WideCharLogFormatTest, Printable) {
|
||
absl::ScopedMockLog test_sink(absl::MockLogDefault::kDisallowUnexpected);
|
||
EXPECT_CALL(test_sink, Send).Times(0);
|
||
|
||
EXPECT_CALL(test_sink, Send(AllOf(TextMessage(Eq("€")),
|
||
ENCODED_MESSAGE(HasValues(
|
||
ElementsAre(ValueWithStr(Eq("€"))))))));
|
||
|
||
test_sink.StartCapturingLogs();
|
||
const wchar_t value = L'\u20AC';
|
||
LOG(INFO) << value;
|
||
}
|
||
|
||
TEST(WideCharLogFormatTest, Unprintable) {
|
||
absl::ScopedMockLog test_sink(absl::MockLogDefault::kDisallowUnexpected);
|
||
EXPECT_CALL(test_sink, Send).Times(0);
|
||
|
||
// Using NEL (Next Line) Unicode character (U+0085).
|
||
// It is encoded as "\xC2\x85" in UTF-8.
|
||
constexpr wchar_t wide_value = L'\u0085';
|
||
constexpr char value[] = "\xC2\x85";
|
||
EXPECT_CALL(test_sink, Send(AllOf(TextMessage(Eq(value)),
|
||
ENCODED_MESSAGE(HasValues(ElementsAre(
|
||
ValueWithStr(Eq(value))))))));
|
||
|
||
test_sink.StartCapturingLogs();
|
||
LOG(INFO) << wide_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);
|
||
EXPECT_CALL(test_sink, Send).Times(0);
|
||
|
||
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(ValueWithStr(Eq("224"))))))));
|
||
|
||
test_sink.StartCapturingLogs();
|
||
LOG(INFO) << value;
|
||
}
|
||
|
||
TYPED_TEST(UnsignedIntLogFormatTest, BitfieldPositive) {
|
||
absl::ScopedMockLog test_sink(absl::MockLogDefault::kDisallowUnexpected);
|
||
EXPECT_CALL(test_sink, Send).Times(0);
|
||
|
||
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(ValueWithStr(Eq("42"))))))));
|
||
|
||
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);
|
||
EXPECT_CALL(test_sink, Send).Times(0);
|
||
|
||
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(ValueWithStr(Eq("224"))))))));
|
||
|
||
test_sink.StartCapturingLogs();
|
||
LOG(INFO) << value;
|
||
}
|
||
|
||
TYPED_TEST(SignedIntLogFormatTest, Negative) {
|
||
absl::ScopedMockLog test_sink(absl::MockLogDefault::kDisallowUnexpected);
|
||
EXPECT_CALL(test_sink, Send).Times(0);
|
||
|
||
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(ValueWithStr(Eq("-112"))))))));
|
||
|
||
test_sink.StartCapturingLogs();
|
||
LOG(INFO) << value;
|
||
}
|
||
|
||
TYPED_TEST(SignedIntLogFormatTest, BitfieldPositive) {
|
||
absl::ScopedMockLog test_sink(absl::MockLogDefault::kDisallowUnexpected);
|
||
EXPECT_CALL(test_sink, Send).Times(0);
|
||
|
||
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(ValueWithStr(Eq("21"))))))));
|
||
|
||
test_sink.StartCapturingLogs();
|
||
LOG(INFO) << value.bits;
|
||
}
|
||
|
||
TYPED_TEST(SignedIntLogFormatTest, BitfieldNegative) {
|
||
absl::ScopedMockLog test_sink(absl::MockLogDefault::kDisallowUnexpected);
|
||
EXPECT_CALL(test_sink, Send).Times(0);
|
||
|
||
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(ValueWithStr(Eq("-21"))))))));
|
||
|
||
test_sink.StartCapturingLogs();
|
||
LOG(INFO) << value.bits;
|
||
}
|
||
|
||
TEST(SourceLocationTest, Format) {
|
||
absl::ScopedMockLog test_sink(absl::MockLogDefault::kDisallowUnexpected);
|
||
EXPECT_CALL(test_sink, Send).Times(0);
|
||
|
||
absl::SourceLocation loc = absl::SourceLocation::current();
|
||
std::string expected = absl::StrCat(__FILE__, ":", __LINE__ - 1);
|
||
|
||
EXPECT_CALL(test_sink, Send(AllOf(TextMessage(Eq(expected)),
|
||
ENCODED_MESSAGE(HasValues(ElementsAre(
|
||
ValueWithStr(Eq(expected))))))));
|
||
|
||
test_sink.StartCapturingLogs();
|
||
LOG(INFO) << loc;
|
||
}
|
||
|
||
// 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);
|
||
EXPECT_CALL(test_sink, Send).Times(0);
|
||
|
||
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(ValueWithStr(Eq("224"))))))));
|
||
|
||
test_sink.StartCapturingLogs();
|
||
LOG(INFO) << value;
|
||
}
|
||
|
||
TYPED_TEST(UnsignedEnumLogFormatTest, BitfieldPositive) {
|
||
absl::ScopedMockLog test_sink(absl::MockLogDefault::kDisallowUnexpected);
|
||
EXPECT_CALL(test_sink, Send).Times(0);
|
||
|
||
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(ValueWithStr(Eq("42"))))))));
|
||
|
||
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);
|
||
EXPECT_CALL(test_sink, Send).Times(0);
|
||
|
||
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(ValueWithStr(Eq("224"))))))));
|
||
|
||
test_sink.StartCapturingLogs();
|
||
LOG(INFO) << value;
|
||
}
|
||
|
||
TYPED_TEST(SignedEnumLogFormatTest, Negative) {
|
||
absl::ScopedMockLog test_sink(absl::MockLogDefault::kDisallowUnexpected);
|
||
EXPECT_CALL(test_sink, Send).Times(0);
|
||
|
||
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(ValueWithStr(Eq("-112"))))))));
|
||
|
||
test_sink.StartCapturingLogs();
|
||
LOG(INFO) << value;
|
||
}
|
||
|
||
TYPED_TEST(SignedEnumLogFormatTest, BitfieldPositive) {
|
||
absl::ScopedMockLog test_sink(absl::MockLogDefault::kDisallowUnexpected);
|
||
EXPECT_CALL(test_sink, Send).Times(0);
|
||
|
||
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(ValueWithStr(Eq("21"))))))));
|
||
|
||
test_sink.StartCapturingLogs();
|
||
LOG(INFO) << value.bits;
|
||
}
|
||
|
||
TYPED_TEST(SignedEnumLogFormatTest, BitfieldNegative) {
|
||
absl::ScopedMockLog test_sink(absl::MockLogDefault::kDisallowUnexpected);
|
||
EXPECT_CALL(test_sink, Send).Times(0);
|
||
|
||
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(ValueWithStr(Eq("-21"))))))));
|
||
|
||
test_sink.StartCapturingLogs();
|
||
LOG(INFO) << value.bits;
|
||
}
|
||
#endif
|
||
|
||
TEST(FloatLogFormatTest, Positive) {
|
||
absl::ScopedMockLog test_sink(absl::MockLogDefault::kDisallowUnexpected);
|
||
EXPECT_CALL(test_sink, Send).Times(0);
|
||
|
||
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(ValueWithStr(Eq("6.02e+23"))))))));
|
||
|
||
test_sink.StartCapturingLogs();
|
||
LOG(INFO) << value;
|
||
}
|
||
|
||
TEST(FloatLogFormatTest, Negative) {
|
||
absl::ScopedMockLog test_sink(absl::MockLogDefault::kDisallowUnexpected);
|
||
EXPECT_CALL(test_sink, Send).Times(0);
|
||
|
||
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(ValueWithStr(Eq("-6.02e+23"))))))));
|
||
|
||
test_sink.StartCapturingLogs();
|
||
LOG(INFO) << value;
|
||
}
|
||
|
||
TEST(FloatLogFormatTest, NegativeExponent) {
|
||
absl::ScopedMockLog test_sink(absl::MockLogDefault::kDisallowUnexpected);
|
||
EXPECT_CALL(test_sink, Send).Times(0);
|
||
|
||
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(ValueWithStr(Eq("6.02e-23"))))))));
|
||
|
||
test_sink.StartCapturingLogs();
|
||
LOG(INFO) << value;
|
||
}
|
||
|
||
TEST(DoubleLogFormatTest, Positive) {
|
||
absl::ScopedMockLog test_sink(absl::MockLogDefault::kDisallowUnexpected);
|
||
EXPECT_CALL(test_sink, Send).Times(0);
|
||
|
||
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(ValueWithStr(Eq("6.02e+23"))))))));
|
||
|
||
test_sink.StartCapturingLogs();
|
||
LOG(INFO) << value;
|
||
}
|
||
|
||
TEST(DoubleLogFormatTest, Negative) {
|
||
absl::ScopedMockLog test_sink(absl::MockLogDefault::kDisallowUnexpected);
|
||
EXPECT_CALL(test_sink, Send).Times(0);
|
||
|
||
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(ValueWithStr(Eq("-6.02e+23"))))))));
|
||
|
||
test_sink.StartCapturingLogs();
|
||
LOG(INFO) << value;
|
||
}
|
||
|
||
TEST(DoubleLogFormatTest, NegativeExponent) {
|
||
absl::ScopedMockLog test_sink(absl::MockLogDefault::kDisallowUnexpected);
|
||
EXPECT_CALL(test_sink, Send).Times(0);
|
||
|
||
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(ValueWithStr(Eq("6.02e-23"))))))));
|
||
|
||
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);
|
||
EXPECT_CALL(test_sink, Send).Times(0);
|
||
|
||
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(ValueWithStr(Eq("0"))))))));
|
||
|
||
test_sink.StartCapturingLogs();
|
||
LOG(INFO) << value;
|
||
}
|
||
|
||
TYPED_TEST(FloatingPointLogFormatTest, Integer) {
|
||
absl::ScopedMockLog test_sink(absl::MockLogDefault::kDisallowUnexpected);
|
||
EXPECT_CALL(test_sink, Send).Times(0);
|
||
|
||
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(ValueWithStr(Eq("1"))))))));
|
||
|
||
test_sink.StartCapturingLogs();
|
||
LOG(INFO) << value;
|
||
}
|
||
|
||
TYPED_TEST(FloatingPointLogFormatTest, Infinity) {
|
||
absl::ScopedMockLog test_sink(absl::MockLogDefault::kDisallowUnexpected);
|
||
EXPECT_CALL(test_sink, Send).Times(0);
|
||
|
||
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(ValueWithStr(Eq("inf"))))))));
|
||
|
||
test_sink.StartCapturingLogs();
|
||
LOG(INFO) << value;
|
||
}
|
||
|
||
TYPED_TEST(FloatingPointLogFormatTest, NegativeInfinity) {
|
||
absl::ScopedMockLog test_sink(absl::MockLogDefault::kDisallowUnexpected);
|
||
EXPECT_CALL(test_sink, Send).Times(0);
|
||
|
||
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(ValueWithStr(Eq("-inf"))))))));
|
||
|
||
test_sink.StartCapturingLogs();
|
||
LOG(INFO) << value;
|
||
}
|
||
|
||
TYPED_TEST(FloatingPointLogFormatTest, NaN) {
|
||
absl::ScopedMockLog test_sink(absl::MockLogDefault::kDisallowUnexpected);
|
||
EXPECT_CALL(test_sink, Send).Times(0);
|
||
|
||
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(ValueWithStr(Eq("nan"))))))));
|
||
test_sink.StartCapturingLogs();
|
||
LOG(INFO) << value;
|
||
}
|
||
|
||
TYPED_TEST(FloatingPointLogFormatTest, NegativeNaN) {
|
||
absl::ScopedMockLog test_sink(absl::MockLogDefault::kDisallowUnexpected);
|
||
EXPECT_CALL(test_sink, Send).Times(0);
|
||
|
||
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(
|
||
ValueWithStr(Eq("-nan")), ValueWithStr(Eq("nan")),
|
||
ValueWithStr(Eq("-nan(ind)")))))))));
|
||
#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(
|
||
ValueWithStr(Eq("-nan")), ValueWithStr(Eq("nan")),
|
||
ValueWithStr(Eq("-nan(ind)")))))))));
|
||
#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);
|
||
EXPECT_CALL(test_sink, Send).Times(0);
|
||
|
||
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);
|
||
EXPECT_CALL(test_sink, Send).Times(0);
|
||
|
||
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(ValueWithStr(Eq("0xdeadbeef")),
|
||
ValueWithStr(Eq("00000000DEADBEEF")))))))));
|
||
|
||
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*, volatile wchar_t*, const volatile wchar_t*>;
|
||
TYPED_TEST_SUITE(VolatilePtrLogFormatTest, VolatilePtrTypes);
|
||
|
||
TYPED_TEST(VolatilePtrLogFormatTest, Null) {
|
||
absl::ScopedMockLog test_sink(absl::MockLogDefault::kDisallowUnexpected);
|
||
EXPECT_CALL(test_sink, Send).Times(0);
|
||
|
||
const TypeParam value = nullptr;
|
||
auto comparison_stream = ComparisonStream();
|
||
comparison_stream << value;
|
||
|
||
// https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2021/p1147r1.html
|
||
#if ABSL_INTERNAL_CPLUSPLUS_LANG >= 202302L
|
||
EXPECT_CALL(
|
||
test_sink,
|
||
Send(AllOf(TextMessage(MatchesOstream(comparison_stream)),
|
||
TextMessage(AnyOf(Eq("(nil)"), Eq("0"), Eq("0x0"),
|
||
Eq("00000000"), Eq("0000000000000000"))))));
|
||
#else
|
||
EXPECT_CALL(
|
||
test_sink,
|
||
Send(AllOf(
|
||
TextMessage(MatchesOstream(comparison_stream)),
|
||
TextMessage(Eq("false")),
|
||
ENCODED_MESSAGE(HasValues(ElementsAre(ValueWithStr(Eq("false"))))))));
|
||
#endif
|
||
|
||
test_sink.StartCapturingLogs();
|
||
LOG(INFO) << value;
|
||
}
|
||
|
||
TYPED_TEST(VolatilePtrLogFormatTest, NonNull) {
|
||
absl::ScopedMockLog test_sink(absl::MockLogDefault::kDisallowUnexpected);
|
||
EXPECT_CALL(test_sink, Send).Times(0);
|
||
|
||
const TypeParam value = reinterpret_cast<TypeParam>(0xdeadbeefLL);
|
||
auto comparison_stream = ComparisonStream();
|
||
comparison_stream << value;
|
||
|
||
// https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2021/p1147r1.html
|
||
#if ABSL_INTERNAL_CPLUSPLUS_LANG >= 202302L
|
||
EXPECT_CALL(test_sink,
|
||
Send(AllOf(TextMessage(MatchesOstream(comparison_stream)),
|
||
TextMessage(AnyOf(Eq("0xdeadbeef"), Eq("DEADBEEF"),
|
||
Eq("00000000DEADBEEF"))),
|
||
ENCODED_MESSAGE(HasValues(ElementsAre(
|
||
AnyOf(ValueWithStr(Eq("0xdeadbeef")),
|
||
ValueWithStr(Eq("00000000DEADBEEF")))))))));
|
||
#else
|
||
EXPECT_CALL(
|
||
test_sink,
|
||
Send(AllOf(
|
||
TextMessage(MatchesOstream(comparison_stream)),
|
||
TextMessage(Eq("true")),
|
||
ENCODED_MESSAGE(HasValues(ElementsAre(ValueWithStr(Eq("true"))))))));
|
||
#endif
|
||
|
||
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);
|
||
EXPECT_CALL(test_sink, Send).Times(0);
|
||
|
||
// 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(
|
||
ValueWithStr(Eq("(null)"))))))));
|
||
|
||
test_sink.StartCapturingLogs();
|
||
LOG(INFO) << value;
|
||
}
|
||
|
||
TYPED_TEST(CharPtrLogFormatTest, NonNull) {
|
||
absl::ScopedMockLog test_sink(absl::MockLogDefault::kDisallowUnexpected);
|
||
EXPECT_CALL(test_sink, Send).Times(0);
|
||
|
||
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(ValueWithStr(Eq("value"))))))));
|
||
|
||
test_sink.StartCapturingLogs();
|
||
LOG(INFO) << value;
|
||
}
|
||
|
||
template <typename T>
|
||
class WideCharPtrLogFormatTest : public testing::Test {};
|
||
using WideCharPtrTypes = Types<wchar_t, const wchar_t>;
|
||
TYPED_TEST_SUITE(WideCharPtrLogFormatTest, WideCharPtrTypes);
|
||
|
||
TYPED_TEST(WideCharPtrLogFormatTest, Null) {
|
||
absl::ScopedMockLog test_sink(absl::MockLogDefault::kDisallowUnexpected);
|
||
EXPECT_CALL(test_sink, Send).Times(0);
|
||
|
||
TypeParam* const value = nullptr;
|
||
|
||
EXPECT_CALL(test_sink, Send(AllOf(TextMessage(Eq("(null)")),
|
||
ENCODED_MESSAGE(HasValues(ElementsAre(
|
||
ValueWithStr(Eq("(null)"))))))));
|
||
|
||
test_sink.StartCapturingLogs();
|
||
LOG(INFO) << value;
|
||
}
|
||
|
||
TYPED_TEST(WideCharPtrLogFormatTest, NonNull) {
|
||
absl::ScopedMockLog test_sink(absl::MockLogDefault::kDisallowUnexpected);
|
||
EXPECT_CALL(test_sink, Send).Times(0);
|
||
|
||
TypeParam data[] = {'v', 'a', 'l', 'u', 'e', '\0'};
|
||
TypeParam* const value = data;
|
||
|
||
EXPECT_CALL(test_sink, Send(AllOf(TextMessage(Eq("value")),
|
||
ENCODED_MESSAGE(HasValues(ElementsAre(
|
||
ValueWithStr(Eq("value"))))))));
|
||
|
||
test_sink.StartCapturingLogs();
|
||
LOG(INFO) << value;
|
||
}
|
||
|
||
TEST(BoolLogFormatTest, True) {
|
||
absl::ScopedMockLog test_sink(absl::MockLogDefault::kDisallowUnexpected);
|
||
EXPECT_CALL(test_sink, Send).Times(0);
|
||
|
||
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(ValueWithStr(Eq("true"))))))));
|
||
|
||
test_sink.StartCapturingLogs();
|
||
LOG(INFO) << value;
|
||
}
|
||
|
||
TEST(BoolLogFormatTest, False) {
|
||
absl::ScopedMockLog test_sink(absl::MockLogDefault::kDisallowUnexpected);
|
||
EXPECT_CALL(test_sink, Send).Times(0);
|
||
|
||
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(ValueWithStr(Eq("false"))))))));
|
||
|
||
test_sink.StartCapturingLogs();
|
||
LOG(INFO) << value;
|
||
}
|
||
|
||
TEST(LogFormatTest, StringLiteral) {
|
||
absl::ScopedMockLog test_sink(absl::MockLogDefault::kDisallowUnexpected);
|
||
EXPECT_CALL(test_sink, Send).Times(0);
|
||
|
||
auto comparison_stream = ComparisonStream();
|
||
comparison_stream << "value";
|
||
|
||
EXPECT_CALL(test_sink,
|
||
Send(AllOf(TextMessage(MatchesOstream(comparison_stream)),
|
||
TextMessage(Eq("value")),
|
||
ENCODED_MESSAGE(HasValues(
|
||
ElementsAre(ValueWithLiteral(Eq("value"))))))));
|
||
|
||
test_sink.StartCapturingLogs();
|
||
LOG(INFO) << "value";
|
||
}
|
||
|
||
TEST(LogFormatTest, WideStringLiteral) {
|
||
absl::ScopedMockLog test_sink(absl::MockLogDefault::kDisallowUnexpected);
|
||
EXPECT_CALL(test_sink, Send).Times(0);
|
||
|
||
EXPECT_CALL(test_sink, Send(AllOf(TextMessage(Eq("value")),
|
||
ENCODED_MESSAGE(HasValues(ElementsAre(
|
||
ValueWithLiteral(Eq("value"))))))));
|
||
|
||
test_sink.StartCapturingLogs();
|
||
LOG(INFO) << L"value";
|
||
}
|
||
|
||
TEST(LogFormatTest, CharArray) {
|
||
absl::ScopedMockLog test_sink(absl::MockLogDefault::kDisallowUnexpected);
|
||
EXPECT_CALL(test_sink, Send).Times(0);
|
||
|
||
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(ValueWithStr(Eq("value"))))))));
|
||
|
||
test_sink.StartCapturingLogs();
|
||
LOG(INFO) << value;
|
||
}
|
||
|
||
TEST(LogFormatTest, WideCharArray) {
|
||
absl::ScopedMockLog test_sink(absl::MockLogDefault::kDisallowUnexpected);
|
||
EXPECT_CALL(test_sink, Send).Times(0);
|
||
|
||
wchar_t value[] = L"value";
|
||
|
||
EXPECT_CALL(test_sink, Send(AllOf(TextMessage(Eq("value")),
|
||
ENCODED_MESSAGE(HasValues(ElementsAre(
|
||
ValueWithStr(Eq("value"))))))));
|
||
|
||
test_sink.StartCapturingLogs();
|
||
LOG(INFO) << value;
|
||
}
|
||
|
||
// Comprehensive test string for validating wchar_t to UTF-8 conversion.
|
||
// See details in absl/strings/internal/utf8_test.cc.
|
||
//
|
||
// clang-format off
|
||
#define ABSL_LOG_INTERNAL_WIDE_LITERAL L"Holá €1 你好 שָׁלוֹם 👍🏻🇺🇸👩❤️💋👨 中"
|
||
#define ABSL_LOG_INTERNAL_UTF8_LITERAL u8"Holá €1 你好 שָׁלוֹם 👍🏻🇺🇸👩❤️💋👨 中"
|
||
// clang-format on
|
||
|
||
absl::string_view GetUtf8TestString() {
|
||
// `u8""` forces UTF-8 encoding; MSVC will default to e.g. CP1252 (and warn)
|
||
// without it. However, the resulting character type differs between pre-C++20
|
||
// (`char`) and C++20 (`char8_t`). So we reinterpret_cast to `char*` and wrap
|
||
// it in a `string_view`.
|
||
static const absl::string_view kUtf8TestString(
|
||
reinterpret_cast<const char*>(ABSL_LOG_INTERNAL_UTF8_LITERAL),
|
||
sizeof(ABSL_LOG_INTERNAL_UTF8_LITERAL) - 1);
|
||
return kUtf8TestString;
|
||
}
|
||
|
||
template <typename T>
|
||
class WideStringLogFormatTest : public testing::Test {};
|
||
using StringTypes =
|
||
Types<std::wstring, const std::wstring, wchar_t[], const wchar_t*>;
|
||
TYPED_TEST_SUITE(WideStringLogFormatTest, StringTypes);
|
||
|
||
TYPED_TEST(WideStringLogFormatTest, NonLiterals) {
|
||
absl::ScopedMockLog test_sink(absl::MockLogDefault::kDisallowUnexpected);
|
||
EXPECT_CALL(test_sink, Send).Times(0);
|
||
|
||
TypeParam value = ABSL_LOG_INTERNAL_WIDE_LITERAL;
|
||
absl::string_view utf8_value = GetUtf8TestString();
|
||
|
||
EXPECT_CALL(test_sink, Send(AllOf(TextMessage(Eq(utf8_value)),
|
||
ENCODED_MESSAGE(HasValues(ElementsAre(
|
||
ValueWithStr(Eq(utf8_value))))))));
|
||
|
||
test_sink.StartCapturingLogs();
|
||
LOG(INFO) << value;
|
||
}
|
||
|
||
TEST(WideStringLogFormatTest, StringView) {
|
||
absl::ScopedMockLog test_sink(absl::MockLogDefault::kDisallowUnexpected);
|
||
EXPECT_CALL(test_sink, Send).Times(0);
|
||
|
||
std::wstring_view value = ABSL_LOG_INTERNAL_WIDE_LITERAL;
|
||
absl::string_view utf8_value = GetUtf8TestString();
|
||
|
||
EXPECT_CALL(test_sink, Send(AllOf(TextMessage(Eq(utf8_value)),
|
||
ENCODED_MESSAGE(HasValues(ElementsAre(
|
||
ValueWithStr(Eq(utf8_value))))))));
|
||
|
||
test_sink.StartCapturingLogs();
|
||
LOG(INFO) << value;
|
||
}
|
||
|
||
TEST(WideStringLogFormatTest, Literal) {
|
||
absl::ScopedMockLog test_sink(absl::MockLogDefault::kDisallowUnexpected);
|
||
EXPECT_CALL(test_sink, Send).Times(0);
|
||
|
||
absl::string_view utf8_value = GetUtf8TestString();
|
||
|
||
EXPECT_CALL(test_sink, Send(AllOf(TextMessage(Eq(utf8_value)),
|
||
ENCODED_MESSAGE(HasValues(ElementsAre(
|
||
ValueWithLiteral(Eq(utf8_value))))))));
|
||
|
||
test_sink.StartCapturingLogs();
|
||
LOG(INFO) << ABSL_LOG_INTERNAL_WIDE_LITERAL;
|
||
}
|
||
|
||
#undef ABSL_LOG_INTERNAL_WIDE_LITERAL
|
||
#undef ABSL_LOG_INTERNAL_UTF8_LITERAL
|
||
|
||
TYPED_TEST(WideStringLogFormatTest, IsolatedLowSurrogatesAreReplaced) {
|
||
absl::ScopedMockLog test_sink(absl::MockLogDefault::kDisallowUnexpected);
|
||
EXPECT_CALL(test_sink, Send).Times(0);
|
||
|
||
TypeParam value = L"AAA \xDC00 BBB";
|
||
// NOLINTNEXTLINE(readability/utf8)
|
||
absl::string_view utf8_value = "AAA <20> BBB";
|
||
|
||
EXPECT_CALL(test_sink, Send(AllOf(TextMessage(Eq(utf8_value)),
|
||
ENCODED_MESSAGE(HasValues(ElementsAre(
|
||
ValueWithStr(Eq(utf8_value))))))));
|
||
|
||
test_sink.StartCapturingLogs();
|
||
LOG(INFO) << value;
|
||
}
|
||
|
||
TYPED_TEST(WideStringLogFormatTest,
|
||
DISABLED_IsolatedHighSurrogatesAreReplaced) {
|
||
absl::ScopedMockLog test_sink(absl::MockLogDefault::kDisallowUnexpected);
|
||
EXPECT_CALL(test_sink, Send).Times(0);
|
||
|
||
TypeParam value = L"AAA \xD800 BBB";
|
||
// NOLINTNEXTLINE(readability/utf8)
|
||
absl::string_view utf8_value = "AAA <20> BBB";
|
||
// Currently, this is "AAA \xF0\x90 BBB".
|
||
|
||
EXPECT_CALL(test_sink, Send(AllOf(TextMessage(Eq(utf8_value)),
|
||
ENCODED_MESSAGE(HasValues(ElementsAre(
|
||
ValueWithStr(Eq(utf8_value))))))));
|
||
|
||
test_sink.StartCapturingLogs();
|
||
LOG(INFO) << value;
|
||
}
|
||
|
||
TYPED_TEST(WideStringLogFormatTest,
|
||
DISABLED_ConsecutiveHighSurrogatesAreReplaced) {
|
||
absl::ScopedMockLog test_sink(absl::MockLogDefault::kDisallowUnexpected);
|
||
EXPECT_CALL(test_sink, Send).Times(0);
|
||
|
||
TypeParam value = L"AAA \xD800\xD800 BBB";
|
||
// NOLINTNEXTLINE(readability/utf8)
|
||
absl::string_view utf8_value = "AAA <20><> BBB";
|
||
// Currently, this is "AAA \xF0\x90\xF0\x90 BBB".
|
||
|
||
EXPECT_CALL(test_sink, Send(AllOf(TextMessage(Eq(utf8_value)),
|
||
ENCODED_MESSAGE(HasValues(ElementsAre(
|
||
ValueWithStr(Eq(utf8_value))))))));
|
||
|
||
test_sink.StartCapturingLogs();
|
||
LOG(INFO) << value;
|
||
}
|
||
|
||
TYPED_TEST(WideStringLogFormatTest,
|
||
DISABLED_HighHighLowSurrogateSequencesAreReplaced) {
|
||
absl::ScopedMockLog test_sink(absl::MockLogDefault::kDisallowUnexpected);
|
||
EXPECT_CALL(test_sink, Send).Times(0);
|
||
|
||
TypeParam value = L"AAA \xD800\xD800\xDC00 BBB";
|
||
// NOLINTNEXTLINE(readability/utf8)
|
||
absl::string_view utf8_value = "AAA <20>𐀀 BBB";
|
||
// Currently, this is "AAA \xF0\x90𐀀 BBB".
|
||
|
||
EXPECT_CALL(test_sink, Send(AllOf(TextMessage(Eq(utf8_value)),
|
||
ENCODED_MESSAGE(HasValues(ElementsAre(
|
||
ValueWithStr(Eq(utf8_value))))))));
|
||
|
||
test_sink.StartCapturingLogs();
|
||
LOG(INFO) << value;
|
||
}
|
||
|
||
TYPED_TEST(WideStringLogFormatTest,
|
||
DISABLED_TrailingHighSurrogatesAreReplaced) {
|
||
absl::ScopedMockLog test_sink(absl::MockLogDefault::kDisallowUnexpected);
|
||
EXPECT_CALL(test_sink, Send).Times(0);
|
||
|
||
TypeParam value = L"AAA \xD800";
|
||
// NOLINTNEXTLINE(readability/utf8)
|
||
absl::string_view utf8_value = "AAA <20>";
|
||
// Currently, this is "AAA \xF0\x90".
|
||
|
||
EXPECT_CALL(test_sink, Send(AllOf(TextMessage(Eq(utf8_value)),
|
||
ENCODED_MESSAGE(HasValues(ElementsAre(
|
||
ValueWithStr(Eq(utf8_value))))))));
|
||
|
||
test_sink.StartCapturingLogs();
|
||
LOG(INFO) << value;
|
||
}
|
||
|
||
TYPED_TEST(WideStringLogFormatTest, EmptyWideString) {
|
||
absl::ScopedMockLog test_sink(absl::MockLogDefault::kDisallowUnexpected);
|
||
EXPECT_CALL(test_sink, Send).Times(0);
|
||
|
||
TypeParam value = L"";
|
||
|
||
EXPECT_CALL(test_sink, Send(AllOf(TextMessage(Eq("")),
|
||
ENCODED_MESSAGE(HasValues(
|
||
ElementsAre(ValueWithStr(Eq(""))))))));
|
||
|
||
test_sink.StartCapturingLogs();
|
||
LOG(INFO) << value;
|
||
}
|
||
|
||
TEST(WideStringLogFormatTest, MixedNarrowAndWideStrings) {
|
||
absl::ScopedMockLog test_sink(absl::MockLogDefault::kDisallowUnexpected);
|
||
|
||
EXPECT_CALL(test_sink, Log(_, _, "1234"));
|
||
|
||
test_sink.StartCapturingLogs();
|
||
LOG(INFO) << "1" << L"2" << "3" << L"4";
|
||
}
|
||
|
||
class CustomClass {};
|
||
std::ostream& operator<<(std::ostream& os, const CustomClass&) {
|
||
return os << "CustomClass{}";
|
||
}
|
||
|
||
TEST(LogFormatTest, Custom) {
|
||
absl::ScopedMockLog test_sink(absl::MockLogDefault::kDisallowUnexpected);
|
||
EXPECT_CALL(test_sink, Send).Times(0);
|
||
|
||
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(
|
||
ValueWithStr(Eq("CustomClass{}"))))))));
|
||
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);
|
||
EXPECT_CALL(test_sink, Send).Times(0);
|
||
|
||
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(
|
||
ValueWithStr(Eq("CustomClassNonCopyable{}"))))))));
|
||
|
||
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);
|
||
EXPECT_CALL(test_sink, Send).Times(0);
|
||
|
||
Point p;
|
||
|
||
EXPECT_CALL(
|
||
test_sink,
|
||
Send(AllOf(TextMessage(Eq("(10, 20)")), TextMessage(Eq(absl::StrCat(p))),
|
||
ENCODED_MESSAGE(
|
||
HasValues(ElementsAre(ValueWithStr(Eq("(10, 20)"))))))));
|
||
|
||
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);
|
||
EXPECT_CALL(test_sink, Send).Times(0);
|
||
|
||
PointWithAbslStringifiyAndOstream p;
|
||
|
||
EXPECT_CALL(
|
||
test_sink,
|
||
Send(AllOf(TextMessage(Eq("(10, 20)")), TextMessage(Eq(absl::StrCat(p))),
|
||
ENCODED_MESSAGE(
|
||
HasValues(ElementsAre(ValueWithStr(Eq("(10, 20)"))))))));
|
||
|
||
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);
|
||
EXPECT_CALL(test_sink, Send).Times(0);
|
||
|
||
PointStreamsNothing p;
|
||
|
||
EXPECT_CALL(
|
||
test_sink,
|
||
Send(AllOf(
|
||
TextMessage(Eq("77")), TextMessage(Eq(absl::StrCat(p, 77))),
|
||
ENCODED_MESSAGE(HasValues(ElementsAre(ValueWithStr(Eq("77"))))))));
|
||
|
||
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);
|
||
EXPECT_CALL(test_sink, Send).Times(0);
|
||
|
||
PointMultipleAppend p;
|
||
|
||
EXPECT_CALL(
|
||
test_sink,
|
||
Send(AllOf(TextMessage(Eq("(10, 20)")), TextMessage(Eq(absl::StrCat(p))),
|
||
ENCODED_MESSAGE(HasValues(ElementsAre(
|
||
ValueWithStr(Eq("(")), ValueWithStr(Eq("10, 20)"))))))));
|
||
|
||
test_sink.StartCapturingLogs();
|
||
LOG(INFO) << p;
|
||
}
|
||
|
||
TEST(ManipulatorLogFormatTest, BoolAlphaTrue) {
|
||
absl::ScopedMockLog test_sink(absl::MockLogDefault::kDisallowUnexpected);
|
||
EXPECT_CALL(test_sink, Send).Times(0);
|
||
|
||
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(
|
||
ValueWithStr(Eq("1")), ValueWithLiteral(Eq(" ")),
|
||
ValueWithStr(Eq("true")), ValueWithLiteral(Eq(" ")),
|
||
ValueWithStr(Eq("1"))))))));
|
||
|
||
test_sink.StartCapturingLogs();
|
||
LOG(INFO) << std::noboolalpha << value << " " //
|
||
<< std::boolalpha << value << " " //
|
||
<< std::noboolalpha << value;
|
||
}
|
||
|
||
TEST(ManipulatorLogFormatTest, BoolAlphaFalse) {
|
||
absl::ScopedMockLog test_sink(absl::MockLogDefault::kDisallowUnexpected);
|
||
EXPECT_CALL(test_sink, Send).Times(0);
|
||
|
||
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(
|
||
ValueWithStr(Eq("0")), ValueWithLiteral(Eq(" ")),
|
||
ValueWithStr(Eq("false")), ValueWithLiteral(Eq(" ")),
|
||
ValueWithStr(Eq("0"))))))));
|
||
|
||
test_sink.StartCapturingLogs();
|
||
LOG(INFO) << std::noboolalpha << value << " " //
|
||
<< std::boolalpha << value << " " //
|
||
<< std::noboolalpha << value;
|
||
}
|
||
|
||
TEST(ManipulatorLogFormatTest, ShowPoint) {
|
||
absl::ScopedMockLog test_sink(absl::MockLogDefault::kDisallowUnexpected);
|
||
EXPECT_CALL(test_sink, Send).Times(0);
|
||
|
||
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(
|
||
ValueWithStr(Eq("77")), ValueWithLiteral(Eq(" ")),
|
||
ValueWithStr(Eq("77.0000")), ValueWithLiteral(Eq(" ")),
|
||
ValueWithStr(Eq("77"))))))));
|
||
|
||
test_sink.StartCapturingLogs();
|
||
LOG(INFO) << std::noshowpoint << value << " " //
|
||
<< std::showpoint << value << " " //
|
||
<< std::noshowpoint << value;
|
||
}
|
||
|
||
TEST(ManipulatorLogFormatTest, ShowPos) {
|
||
absl::ScopedMockLog test_sink(absl::MockLogDefault::kDisallowUnexpected);
|
||
EXPECT_CALL(test_sink, Send).Times(0);
|
||
|
||
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(
|
||
ValueWithStr(Eq("77")), ValueWithLiteral(Eq(" ")),
|
||
ValueWithStr(Eq("+77")), ValueWithLiteral(Eq(" ")),
|
||
ValueWithStr(Eq("77"))))))));
|
||
|
||
test_sink.StartCapturingLogs();
|
||
LOG(INFO) << std::noshowpos << value << " " //
|
||
<< std::showpos << value << " " //
|
||
<< std::noshowpos << value;
|
||
}
|
||
|
||
TEST(ManipulatorLogFormatTest, UppercaseFloat) {
|
||
absl::ScopedMockLog test_sink(absl::MockLogDefault::kDisallowUnexpected);
|
||
EXPECT_CALL(test_sink, Send).Times(0);
|
||
|
||
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(
|
||
ValueWithStr(Eq("7.7e+07")), ValueWithLiteral(Eq(" ")),
|
||
ValueWithStr(Eq("7.7E+07")), ValueWithLiteral(Eq(" ")),
|
||
ValueWithStr(Eq("7.7e+07"))))))));
|
||
|
||
test_sink.StartCapturingLogs();
|
||
LOG(INFO) << std::nouppercase << value << " " //
|
||
<< std::uppercase << value << " " //
|
||
<< std::nouppercase << value;
|
||
}
|
||
|
||
TEST(ManipulatorLogFormatTest, Hex) {
|
||
absl::ScopedMockLog test_sink(absl::MockLogDefault::kDisallowUnexpected);
|
||
EXPECT_CALL(test_sink, Send).Times(0);
|
||
|
||
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(ValueWithStr(Eq("0x77"))))))));
|
||
test_sink.StartCapturingLogs();
|
||
LOG(INFO) << std::hex << value;
|
||
}
|
||
|
||
TEST(ManipulatorLogFormatTest, Oct) {
|
||
absl::ScopedMockLog test_sink(absl::MockLogDefault::kDisallowUnexpected);
|
||
EXPECT_CALL(test_sink, Send).Times(0);
|
||
|
||
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(ValueWithStr(Eq("077"))))))));
|
||
|
||
test_sink.StartCapturingLogs();
|
||
LOG(INFO) << std::oct << value;
|
||
}
|
||
|
||
TEST(ManipulatorLogFormatTest, Dec) {
|
||
absl::ScopedMockLog test_sink(absl::MockLogDefault::kDisallowUnexpected);
|
||
EXPECT_CALL(test_sink, Send).Times(0);
|
||
|
||
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(ValueWithStr(Eq("77"))))))));
|
||
|
||
test_sink.StartCapturingLogs();
|
||
LOG(INFO) << std::hex << std::dec << value;
|
||
}
|
||
|
||
TEST(ManipulatorLogFormatTest, ShowbaseHex) {
|
||
absl::ScopedMockLog test_sink(absl::MockLogDefault::kDisallowUnexpected);
|
||
EXPECT_CALL(test_sink, Send).Times(0);
|
||
|
||
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(
|
||
ValueWithStr(Eq("77")), ValueWithLiteral(Eq(" ")),
|
||
ValueWithStr(Eq("0x77")), ValueWithLiteral(Eq(" ")),
|
||
ValueWithStr(Eq("77"))))))));
|
||
|
||
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);
|
||
EXPECT_CALL(test_sink, Send).Times(0);
|
||
|
||
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(
|
||
ValueWithStr(Eq("77")), ValueWithLiteral(Eq(" ")),
|
||
ValueWithStr(Eq("077")), ValueWithLiteral(Eq(" ")),
|
||
ValueWithStr(Eq("77"))))))));
|
||
|
||
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);
|
||
EXPECT_CALL(test_sink, Send).Times(0);
|
||
|
||
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(
|
||
ValueWithStr(Eq("0xbeef")), ValueWithLiteral(Eq(" ")),
|
||
ValueWithStr(Eq("0XBEEF")), ValueWithLiteral(Eq(" ")),
|
||
ValueWithStr(Eq("0xbeef"))))))));
|
||
|
||
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);
|
||
EXPECT_CALL(test_sink, Send).Times(0);
|
||
|
||
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(
|
||
ValueWithStr(Eq("77000000.000000"))))))));
|
||
|
||
test_sink.StartCapturingLogs();
|
||
LOG(INFO) << std::fixed << value;
|
||
}
|
||
|
||
TEST(ManipulatorLogFormatTest, ScientificFloat) {
|
||
absl::ScopedMockLog test_sink(absl::MockLogDefault::kDisallowUnexpected);
|
||
EXPECT_CALL(test_sink, Send).Times(0);
|
||
|
||
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(ValueWithStr(Eq("7.700000e+07"))))))));
|
||
|
||
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);
|
||
EXPECT_CALL(test_sink, Send).Times(0);
|
||
|
||
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(ValueWithStr(Eq("0x1.25bb5p+26")),
|
||
ValueWithStr(Eq("0x1.25bb500000000p+26")))))))));
|
||
|
||
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);
|
||
EXPECT_CALL(test_sink, Send).Times(0);
|
||
|
||
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(ValueWithStr(Eq("0x1.25bb5p+26")),
|
||
ValueWithStr(Eq("0x1.25bb500000000p+26")))))))));
|
||
|
||
test_sink.StartCapturingLogs();
|
||
LOG(INFO) << std::hexfloat << value;
|
||
}
|
||
#endif
|
||
|
||
TEST(ManipulatorLogFormatTest, DefaultFloatFloat) {
|
||
absl::ScopedMockLog test_sink(absl::MockLogDefault::kDisallowUnexpected);
|
||
EXPECT_CALL(test_sink, Send).Times(0);
|
||
|
||
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(ValueWithStr(Eq("7.7e+07"))))))));
|
||
|
||
test_sink.StartCapturingLogs();
|
||
LOG(INFO) << std::hexfloat << std::defaultfloat << value;
|
||
}
|
||
|
||
TEST(ManipulatorLogFormatTest, Ends) {
|
||
absl::ScopedMockLog test_sink(absl::MockLogDefault::kDisallowUnexpected);
|
||
EXPECT_CALL(test_sink, Send).Times(0);
|
||
|
||
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(
|
||
ValueWithStr(Eq(absl::string_view("\0", 1)))))))));
|
||
|
||
test_sink.StartCapturingLogs();
|
||
LOG(INFO) << std::ends;
|
||
}
|
||
|
||
TEST(ManipulatorLogFormatTest, Endl) {
|
||
absl::ScopedMockLog test_sink(absl::MockLogDefault::kDisallowUnexpected);
|
||
EXPECT_CALL(test_sink, Send).Times(0);
|
||
|
||
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(ValueWithStr(Eq("\n"))))))));
|
||
|
||
test_sink.StartCapturingLogs();
|
||
LOG(INFO) << std::endl;
|
||
}
|
||
|
||
TEST(ManipulatorLogFormatTest, SetIosFlags) {
|
||
absl::ScopedMockLog test_sink(absl::MockLogDefault::kDisallowUnexpected);
|
||
EXPECT_CALL(test_sink, Send).Times(0);
|
||
|
||
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(ValueWithStr(Eq("0x77")),
|
||
ValueWithLiteral(Eq(" ")),
|
||
ValueWithStr(Eq("119"))))))));
|
||
|
||
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);
|
||
EXPECT_CALL(test_sink, Send).Times(0);
|
||
|
||
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(
|
||
ValueWithStr(Eq("0x77")), ValueWithLiteral(Eq(" ")),
|
||
ValueWithStr(Eq("119"))))))));
|
||
|
||
test_sink.StartCapturingLogs();
|
||
LOG(INFO) << std::setbase(16) << value << " " //
|
||
<< std::setbase(0) << value;
|
||
}
|
||
|
||
TEST(ManipulatorLogFormatTest, SetPrecision) {
|
||
absl::ScopedMockLog test_sink(absl::MockLogDefault::kDisallowUnexpected);
|
||
EXPECT_CALL(test_sink, Send).Times(0);
|
||
|
||
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(ValueWithStr(Eq("6.022e+23"))))))));
|
||
|
||
test_sink.StartCapturingLogs();
|
||
LOG(INFO) << std::setprecision(4) << value;
|
||
}
|
||
|
||
TEST(ManipulatorLogFormatTest, SetPrecisionOverflow) {
|
||
absl::ScopedMockLog test_sink(absl::MockLogDefault::kDisallowUnexpected);
|
||
EXPECT_CALL(test_sink, Send).Times(0);
|
||
|
||
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(
|
||
ValueWithStr(Eq("602214085700000015187968"))))))));
|
||
|
||
test_sink.StartCapturingLogs();
|
||
LOG(INFO) << std::setprecision(200) << value;
|
||
}
|
||
|
||
TEST(ManipulatorLogFormatTest, SetW) {
|
||
absl::ScopedMockLog test_sink(absl::MockLogDefault::kDisallowUnexpected);
|
||
EXPECT_CALL(test_sink, Send).Times(0);
|
||
|
||
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(ValueWithStr(Eq(" 77"))))))));
|
||
|
||
test_sink.StartCapturingLogs();
|
||
LOG(INFO) << std::setw(8) << value;
|
||
}
|
||
|
||
TEST(ManipulatorLogFormatTest, Left) {
|
||
absl::ScopedMockLog test_sink(absl::MockLogDefault::kDisallowUnexpected);
|
||
EXPECT_CALL(test_sink, Send).Times(0);
|
||
|
||
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(ValueWithStr(Eq("-77 "))))))));
|
||
|
||
test_sink.StartCapturingLogs();
|
||
LOG(INFO) << std::left << std::setw(8) << value;
|
||
}
|
||
|
||
TEST(ManipulatorLogFormatTest, Right) {
|
||
absl::ScopedMockLog test_sink(absl::MockLogDefault::kDisallowUnexpected);
|
||
EXPECT_CALL(test_sink, Send).Times(0);
|
||
|
||
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(ValueWithStr(Eq(" -77"))))))));
|
||
|
||
test_sink.StartCapturingLogs();
|
||
LOG(INFO) << std::right << std::setw(8) << value;
|
||
}
|
||
|
||
TEST(ManipulatorLogFormatTest, Internal) {
|
||
absl::ScopedMockLog test_sink(absl::MockLogDefault::kDisallowUnexpected);
|
||
EXPECT_CALL(test_sink, Send).Times(0);
|
||
|
||
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(ValueWithStr(Eq("- 77"))))))));
|
||
|
||
test_sink.StartCapturingLogs();
|
||
LOG(INFO) << std::internal << std::setw(8) << value;
|
||
}
|
||
|
||
TEST(ManipulatorLogFormatTest, SetFill) {
|
||
absl::ScopedMockLog test_sink(absl::MockLogDefault::kDisallowUnexpected);
|
||
EXPECT_CALL(test_sink, Send).Times(0);
|
||
|
||
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(ValueWithStr(Eq("00000077"))))))));
|
||
|
||
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);
|
||
EXPECT_CALL(test_sink, Send).Times(0);
|
||
|
||
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(
|
||
ValueWithStr(Eq("FromCustomClass{}")),
|
||
ValueWithLiteral(Eq(" ")), ValueWithStr(Eq("0x77"))))))));
|
||
|
||
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);
|
||
EXPECT_CALL(test_sink, Send).Times(0);
|
||
|
||
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(ValueWithStr(Eq("77"))))))));
|
||
|
||
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);
|
||
EXPECT_CALL(test_sink, Send).Times(0);
|
||
|
||
PointPercentV p;
|
||
|
||
EXPECT_CALL(
|
||
test_sink,
|
||
Send(AllOf(TextMessage(Eq("(10, 20)")), TextMessage(Eq(absl::StrCat(p))),
|
||
ENCODED_MESSAGE(
|
||
HasValues(ElementsAre(ValueWithStr(Eq("(10, 20)"))))))));
|
||
|
||
test_sink.StartCapturingLogs();
|
||
LOG(INFO) << std::hex << p;
|
||
}
|
||
|
||
TEST(StructuredLoggingOverflowTest, TruncatesStrings) {
|
||
absl::ScopedMockLog test_sink(absl::MockLogDefault::kDisallowUnexpected);
|
||
EXPECT_CALL(test_sink, Send).Times(0);
|
||
|
||
// 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');
|
||
}
|
||
|
||
TEST(StructuredLoggingOverflowTest, TruncatesWideStrings) {
|
||
absl::ScopedMockLog test_sink(absl::MockLogDefault::kDisallowUnexpected);
|
||
EXPECT_CALL(test_sink, Send).Times(0);
|
||
|
||
// 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::wstring(2 * absl::log_internal::kLogMessageBufferSize,
|
||
L'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);
|
||
EXPECT_CALL(test_sink, Send).Times(0);
|
||
|
||
// 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:
|
||
std::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).Times(0);
|
||
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).Times(0);
|
||
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).Times(0);
|
||
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).Times(0);
|
||
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).Times(0);
|
||
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).Times(0);
|
||
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).Times(0);
|
||
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).Times(0);
|
||
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).Times(0);
|
||
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).Times(0);
|
||
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).Times(0);
|
||
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).Times(0);
|
||
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
|