// // 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. #ifndef ABSL_LOG_CHECK_TEST_IMPL_H_ #define ABSL_LOG_CHECK_TEST_IMPL_H_ // Verify that both sets of macros behave identically by parameterizing the // entire test file. #ifndef ABSL_TEST_CHECK #error ABSL_TEST_CHECK must be defined for these tests to work. #endif #include #include #include "gmock/gmock.h" #include "gtest/gtest.h" #include "absl/base/attributes.h" #include "absl/base/config.h" #include "absl/log/internal/test_helpers.h" #include "absl/status/status.h" #include "absl/strings/string_view.h" #include "absl/strings/substitute.h" // NOLINTBEGIN(misc-definitions-in-headers) namespace absl_log_internal { using ::testing::AllOf; using ::testing::HasSubstr; using ::testing::Not; auto* test_env ABSL_ATTRIBUTE_UNUSED = ::testing::AddGlobalTestEnvironment( new absl::log_internal::LogTestEnvironment); #if GTEST_HAS_DEATH_TEST TEST(CHECKDeathTest, TestBasicValues) { ABSL_TEST_CHECK(true); EXPECT_DEATH(ABSL_TEST_CHECK(false), "Check failed: false"); int i = 2; ABSL_TEST_CHECK(i != 3); // NOLINT } #endif // GTEST_HAS_DEATH_TEST TEST(CHECKTest, TestLogicExpressions) { int i = 5; ABSL_TEST_CHECK(i > 0 && i < 10); ABSL_TEST_CHECK(i < 0 || i > 3); } #if ABSL_INTERNAL_CPLUSPLUS_LANG >= 201703L ABSL_CONST_INIT const auto global_var_check = [](int i) { ABSL_TEST_CHECK(i > 0); // NOLINT return i + 1; }(3); ABSL_CONST_INIT const auto global_var = [](int i) { ABSL_TEST_CHECK_GE(i, 0); // NOLINT return i + 1; }(global_var_check); #endif // ABSL_INTERNAL_CPLUSPLUS_LANG TEST(CHECKTest, TestPlacementsInCompoundStatements) { // check placement inside if/else clauses if (true) ABSL_TEST_CHECK(true); if (false) ; // NOLINT else ABSL_TEST_CHECK(true); switch (0) case 0: ABSL_TEST_CHECK(true); // NOLINT #if ABSL_INTERNAL_CPLUSPLUS_LANG >= 201703L constexpr auto var = [](int i) { ABSL_TEST_CHECK(i > 0); // NOLINT return i + 1; }(global_var); (void)var; #endif // ABSL_INTERNAL_CPLUSPLUS_LANG } TEST(CHECKTest, TestBoolConvertible) { struct Tester { } tester; ABSL_TEST_CHECK([&]() { return &tester; }()); } #if GTEST_HAS_DEATH_TEST TEST(CHECKDeathTest, TestChecksWithSideEffects) { int var = 0; ABSL_TEST_CHECK([&var]() { ++var; return true; }()); EXPECT_EQ(var, 1); EXPECT_DEATH(ABSL_TEST_CHECK([&var]() { ++var; return false; }()) << var, "Check failed: .* 2"); } #endif // GTEST_HAS_DEATH_TEST template constexpr int sum() { return a + b; } #define MACRO_ONE 1 #define TEMPLATE_SUM(a, b) sum() #define CONCAT(a, b) a b #define IDENTITY(x) x TEST(CHECKTest, TestPassingMacroExpansion) { ABSL_TEST_CHECK(IDENTITY(true)); ABSL_TEST_CHECK_EQ(TEMPLATE_SUM(MACRO_ONE, 2), 3); ABSL_TEST_CHECK_STREQ(CONCAT("x", "y"), "xy"); } #if GTEST_HAS_DEATH_TEST TEST(CHECKTest, TestMacroExpansionInMessage) { auto MessageGen = []() { ABSL_TEST_CHECK(IDENTITY(false)); }; EXPECT_DEATH(MessageGen(), HasSubstr("IDENTITY(false)")); } TEST(CHECKTest, TestNestedMacroExpansionInMessage) { EXPECT_DEATH(ABSL_TEST_CHECK(IDENTITY(false)), HasSubstr("IDENTITY(false)")); } TEST(CHECKTest, TestMacroExpansionCompare) { EXPECT_DEATH(ABSL_TEST_CHECK_EQ(IDENTITY(false), IDENTITY(true)), HasSubstr("IDENTITY(false) == IDENTITY(true)")); EXPECT_DEATH(ABSL_TEST_CHECK_GT(IDENTITY(1), IDENTITY(2)), HasSubstr("IDENTITY(1) > IDENTITY(2)")); } TEST(CHECKTest, TestMacroExpansionStrCompare) { EXPECT_DEATH(ABSL_TEST_CHECK_STREQ(IDENTITY("x"), IDENTITY("y")), HasSubstr("IDENTITY(\"x\") == IDENTITY(\"y\")")); EXPECT_DEATH(ABSL_TEST_CHECK_STRCASENE(IDENTITY("a"), IDENTITY("A")), HasSubstr("IDENTITY(\"a\") != IDENTITY(\"A\")")); } TEST(CHECKTest, TestMacroExpansionStatus) { EXPECT_DEATH( ABSL_TEST_CHECK_OK(IDENTITY(absl::FailedPreconditionError("message"))), HasSubstr("IDENTITY(absl::FailedPreconditionError(\"message\"))")); } TEST(CHECKTest, TestMacroExpansionComma) { EXPECT_DEATH(ABSL_TEST_CHECK(TEMPLATE_SUM(MACRO_ONE, 2) == 4), HasSubstr("TEMPLATE_SUM(MACRO_ONE, 2) == 4")); } TEST(CHECKTest, TestMacroExpansionCommaCompare) { EXPECT_DEATH( ABSL_TEST_CHECK_EQ(TEMPLATE_SUM(2, MACRO_ONE), TEMPLATE_SUM(3, 2)), HasSubstr("TEMPLATE_SUM(2, MACRO_ONE) == TEMPLATE_SUM(3, 2)")); EXPECT_DEATH( ABSL_TEST_CHECK_GT(TEMPLATE_SUM(2, MACRO_ONE), TEMPLATE_SUM(3, 2)), HasSubstr("TEMPLATE_SUM(2, MACRO_ONE) > TEMPLATE_SUM(3, 2)")); } TEST(CHECKTest, TestMacroExpansionCommaStrCompare) { EXPECT_DEATH(ABSL_TEST_CHECK_STREQ(CONCAT("x", "y"), "z"), HasSubstr("CONCAT(\"x\", \"y\") == \"z\"")); EXPECT_DEATH(ABSL_TEST_CHECK_STRNE(CONCAT("x", "y"), "xy"), HasSubstr("CONCAT(\"x\", \"y\") != \"xy\"")); } #endif // GTEST_HAS_DEATH_TEST #undef TEMPLATE_SUM #undef CONCAT #undef MACRO #undef ONE #if GTEST_HAS_DEATH_TEST TEST(CHECKDeachTest, TestOrderOfInvocationsBetweenCheckAndMessage) { int counter = 0; auto GetStr = [&counter]() -> std::string { return counter++ == 0 ? "" : "non-empty"; }; EXPECT_DEATH(ABSL_TEST_CHECK(!GetStr().empty()) << GetStr(), HasSubstr("non-empty")); } TEST(CHECKTest, TestSecondaryFailure) { auto FailingRoutine = []() { ABSL_TEST_CHECK(false) << "Secondary"; return false; }; EXPECT_DEATH(ABSL_TEST_CHECK(FailingRoutine()) << "Primary", AllOf(HasSubstr("Secondary"), Not(HasSubstr("Primary")))); } TEST(CHECKTest, TestSecondaryFailureInMessage) { auto MessageGen = []() { ABSL_TEST_CHECK(false) << "Secondary"; return "Primary"; }; EXPECT_DEATH(ABSL_TEST_CHECK(false) << MessageGen(), AllOf(HasSubstr("Secondary"), Not(HasSubstr("Primary")))); } #endif // GTEST_HAS_DEATH_TEST TEST(CHECKTest, TestBinaryChecksWithPrimitives) { ABSL_TEST_CHECK_EQ(1, 1); ABSL_TEST_CHECK_NE(1, 2); ABSL_TEST_CHECK_GE(1, 1); ABSL_TEST_CHECK_GE(2, 1); ABSL_TEST_CHECK_LE(1, 1); ABSL_TEST_CHECK_LE(1, 2); ABSL_TEST_CHECK_GT(2, 1); ABSL_TEST_CHECK_LT(1, 2); } // For testing using CHECK*() on anonymous enums. enum { CASE_A, CASE_B }; TEST(CHECKTest, TestBinaryChecksWithEnumValues) { // Tests using CHECK*() on anonymous enums. ABSL_TEST_CHECK_EQ(CASE_A, CASE_A); ABSL_TEST_CHECK_NE(CASE_A, CASE_B); ABSL_TEST_CHECK_GE(CASE_A, CASE_A); ABSL_TEST_CHECK_GE(CASE_B, CASE_A); ABSL_TEST_CHECK_LE(CASE_A, CASE_A); ABSL_TEST_CHECK_LE(CASE_A, CASE_B); ABSL_TEST_CHECK_GT(CASE_B, CASE_A); ABSL_TEST_CHECK_LT(CASE_A, CASE_B); } TEST(CHECKTest, TestBinaryChecksWithNullptr) { const void* p_null = nullptr; const void* p_not_null = &p_null; ABSL_TEST_CHECK_EQ(p_null, nullptr); ABSL_TEST_CHECK_EQ(nullptr, p_null); ABSL_TEST_CHECK_NE(p_not_null, nullptr); ABSL_TEST_CHECK_NE(nullptr, p_not_null); } #if GTEST_HAS_DEATH_TEST // Test logging of various char-typed values by failing CHECK*(). TEST(CHECKDeathTest, TestComparingCharsValues) { { char a = ';'; char b = 'b'; EXPECT_DEATH(ABSL_TEST_CHECK_EQ(a, b), "Check failed: a == b \\(';' vs. 'b'\\)"); b = 1; EXPECT_DEATH(ABSL_TEST_CHECK_EQ(a, b), "Check failed: a == b \\(';' vs. char value 1\\)"); } { signed char a = ';'; signed char b = 'b'; EXPECT_DEATH(ABSL_TEST_CHECK_EQ(a, b), "Check failed: a == b \\(';' vs. 'b'\\)"); b = -128; EXPECT_DEATH(ABSL_TEST_CHECK_EQ(a, b), "Check failed: a == b \\(';' vs. signed char value -128\\)"); } { unsigned char a = ';'; unsigned char b = 'b'; EXPECT_DEATH(ABSL_TEST_CHECK_EQ(a, b), "Check failed: a == b \\(';' vs. 'b'\\)"); b = 128; EXPECT_DEATH(ABSL_TEST_CHECK_EQ(a, b), "Check failed: a == b \\(';' vs. unsigned char value 128\\)"); } } TEST(CHECKDeathTest, TestNullValuesAreReportedCleanly) { const char* a = nullptr; const char* b = nullptr; EXPECT_DEATH(ABSL_TEST_CHECK_NE(a, b), "Check failed: a != b \\(\\(null\\) vs. \\(null\\)\\)"); a = "xx"; EXPECT_DEATH(ABSL_TEST_CHECK_EQ(a, b), "Check failed: a == b \\(xx vs. \\(null\\)\\)"); EXPECT_DEATH(ABSL_TEST_CHECK_EQ(b, a), "Check failed: b == a \\(\\(null\\) vs. xx\\)"); std::nullptr_t n{}; EXPECT_DEATH(ABSL_TEST_CHECK_NE(n, nullptr), "Check failed: n != nullptr \\(\\(null\\) vs. \\(null\\)\\)"); } #endif // GTEST_HAS_DEATH_TEST TEST(CHECKTest, TestSTREQ) { ABSL_TEST_CHECK_STREQ("this", "this"); ABSL_TEST_CHECK_STREQ(nullptr, nullptr); ABSL_TEST_CHECK_STRCASEEQ("this", "tHiS"); ABSL_TEST_CHECK_STRCASEEQ(nullptr, nullptr); ABSL_TEST_CHECK_STRNE("this", "tHiS"); ABSL_TEST_CHECK_STRNE("this", nullptr); ABSL_TEST_CHECK_STRCASENE("this", "that"); ABSL_TEST_CHECK_STRCASENE(nullptr, "that"); ABSL_TEST_CHECK_STREQ((std::string("a") + "b").c_str(), "ab"); ABSL_TEST_CHECK_STREQ(std::string("test").c_str(), (std::string("te") + std::string("st")).c_str()); } TEST(CHECKTest, TestComparisonPlacementsInCompoundStatements) { // check placement inside if/else clauses if (true) ABSL_TEST_CHECK_EQ(1, 1); if (true) ABSL_TEST_CHECK_STREQ("c", "c"); if (false) ; // NOLINT else ABSL_TEST_CHECK_LE(0, 1); if (false) ; // NOLINT else ABSL_TEST_CHECK_STRNE("a", "b"); switch (0) case 0: ABSL_TEST_CHECK_NE(1, 0); switch (0) case 0: ABSL_TEST_CHECK_STRCASEEQ("A", "a"); #if ABSL_INTERNAL_CPLUSPLUS_LANG >= 201703L constexpr auto var = [](int i) { ABSL_TEST_CHECK_GT(i, 0); return i + 1; }(global_var); (void)var; // CHECK_STR... checks are not supported in constexpr routines. // constexpr auto var2 = [](int i) { // ABSL_TEST_CHECK_STRNE("c", "d"); // return i + 1; // }(global_var); #if defined(__GNUC__) int var3 = (({ ABSL_TEST_CHECK_LE(1, 2); }), global_var < 10) ? 1 : 0; (void)var3; int var4 = (({ ABSL_TEST_CHECK_STREQ("a", "a"); }), global_var < 10) ? 1 : 0; (void)var4; #endif // __GNUC__ #endif // ABSL_INTERNAL_CPLUSPLUS_LANG } TEST(CHECKTest, TestDCHECK) { #ifdef NDEBUG ABSL_TEST_DCHECK(1 == 2) << " DCHECK's shouldn't be compiled in normal mode"; #endif ABSL_TEST_DCHECK(1 == 1); // NOLINT(readability/check) ABSL_TEST_DCHECK_EQ(1, 1); ABSL_TEST_DCHECK_NE(1, 2); ABSL_TEST_DCHECK_GE(1, 1); ABSL_TEST_DCHECK_GE(2, 1); ABSL_TEST_DCHECK_LE(1, 1); ABSL_TEST_DCHECK_LE(1, 2); ABSL_TEST_DCHECK_GT(2, 1); ABSL_TEST_DCHECK_LT(1, 2); // Test DCHECK on std::nullptr_t const void* p_null = nullptr; const void* p_not_null = &p_null; ABSL_TEST_DCHECK_EQ(p_null, nullptr); ABSL_TEST_DCHECK_EQ(nullptr, p_null); ABSL_TEST_DCHECK_NE(p_not_null, nullptr); ABSL_TEST_DCHECK_NE(nullptr, p_not_null); } TEST(CHECKTest, TestQCHECK) { // The tests that QCHECK does the same as CHECK ABSL_TEST_QCHECK(1 == 1); // NOLINT(readability/check) ABSL_TEST_QCHECK_EQ(1, 1); ABSL_TEST_QCHECK_NE(1, 2); ABSL_TEST_QCHECK_GE(1, 1); ABSL_TEST_QCHECK_GE(2, 1); ABSL_TEST_QCHECK_LE(1, 1); ABSL_TEST_QCHECK_LE(1, 2); ABSL_TEST_QCHECK_GT(2, 1); ABSL_TEST_QCHECK_LT(1, 2); // Tests using QCHECK*() on anonymous enums. ABSL_TEST_QCHECK_EQ(CASE_A, CASE_A); ABSL_TEST_QCHECK_NE(CASE_A, CASE_B); ABSL_TEST_QCHECK_GE(CASE_A, CASE_A); ABSL_TEST_QCHECK_GE(CASE_B, CASE_A); ABSL_TEST_QCHECK_LE(CASE_A, CASE_A); ABSL_TEST_QCHECK_LE(CASE_A, CASE_B); ABSL_TEST_QCHECK_GT(CASE_B, CASE_A); ABSL_TEST_QCHECK_LT(CASE_A, CASE_B); } TEST(CHECKTest, TestQCHECKPlacementsInCompoundStatements) { // check placement inside if/else clauses if (true) ABSL_TEST_QCHECK(true); if (false) ; // NOLINT else ABSL_TEST_QCHECK(true); if (false) ; // NOLINT else ABSL_TEST_QCHECK(true); switch (0) case 0: ABSL_TEST_QCHECK(true); #if ABSL_INTERNAL_CPLUSPLUS_LANG >= 201703L constexpr auto var = [](int i) { ABSL_TEST_QCHECK(i > 0); // NOLINT return i + 1; }(global_var); (void)var; #if defined(__GNUC__) int var2 = (({ ABSL_TEST_CHECK_LE(1, 2); }), global_var < 10) ? 1 : 0; (void)var2; #endif // __GNUC__ #endif // ABSL_INTERNAL_CPLUSPLUS_LANG } class ComparableType { public: explicit ComparableType(int v) : v_(v) {} void MethodWithCheck(int i) { ABSL_TEST_CHECK_EQ(*this, i); ABSL_TEST_CHECK_EQ(i, *this); } int Get() const { return v_; } private: friend bool operator==(const ComparableType& lhs, const ComparableType& rhs) { return lhs.v_ == rhs.v_; } friend bool operator!=(const ComparableType& lhs, const ComparableType& rhs) { return lhs.v_ != rhs.v_; } friend bool operator<(const ComparableType& lhs, const ComparableType& rhs) { return lhs.v_ < rhs.v_; } friend bool operator<=(const ComparableType& lhs, const ComparableType& rhs) { return lhs.v_ <= rhs.v_; } friend bool operator>(const ComparableType& lhs, const ComparableType& rhs) { return lhs.v_ > rhs.v_; } friend bool operator>=(const ComparableType& lhs, const ComparableType& rhs) { return lhs.v_ >= rhs.v_; } friend bool operator==(const ComparableType& lhs, int rhs) { return lhs.v_ == rhs; } friend bool operator==(int lhs, const ComparableType& rhs) { return lhs == rhs.v_; } friend std::ostream& operator<<(std::ostream& out, const ComparableType& v) { return out << "ComparableType{" << v.Get() << "}"; } int v_; }; TEST(CHECKTest, TestUserDefinedCompOp) { ABSL_TEST_CHECK_EQ(ComparableType{0}, ComparableType{0}); ABSL_TEST_CHECK_NE(ComparableType{1}, ComparableType{2}); ABSL_TEST_CHECK_LT(ComparableType{1}, ComparableType{2}); ABSL_TEST_CHECK_LE(ComparableType{1}, ComparableType{2}); ABSL_TEST_CHECK_GT(ComparableType{2}, ComparableType{1}); ABSL_TEST_CHECK_GE(ComparableType{2}, ComparableType{2}); } TEST(CHECKTest, TestCheckInMethod) { ComparableType v{1}; v.MethodWithCheck(1); } TEST(CHECKDeathTest, TestUserDefinedStreaming) { ComparableType v1{1}; ComparableType v2{2}; EXPECT_DEATH( ABSL_TEST_CHECK_EQ(v1, v2), HasSubstr( "Check failed: v1 == v2 (ComparableType{1} vs. ComparableType{2})")); } // A type that can be printed using AbslStringify. struct StringifiableType { int x = 0; explicit StringifiableType(int x) : x(x) {} friend bool operator==(const StringifiableType& lhs, const StringifiableType& rhs) { return lhs.x == rhs.x; } friend bool operator!=(const StringifiableType& lhs, const StringifiableType& rhs) { return lhs.x != rhs.x; } friend bool operator<(const StringifiableType& lhs, const StringifiableType& rhs) { return lhs.x < rhs.x; } friend bool operator>(const StringifiableType& lhs, const StringifiableType& rhs) { return lhs.x > rhs.x; } friend bool operator<=(const StringifiableType& lhs, const StringifiableType& rhs) { return lhs.x <= rhs.x; } friend bool operator>=(const StringifiableType& lhs, const StringifiableType& rhs) { return lhs.x >= rhs.x; } template friend void AbslStringify(Sink& sink, const StringifiableType& obj) { absl::Format(&sink, "StringifiableType{%d}", obj.x); } // Make sure no unintended copy happens. StringifiableType(const StringifiableType&) = delete; }; TEST(CHECKTest, TestUserDefinedAbslStringify) { const StringifiableType v1(1); const StringifiableType v2(2); ABSL_TEST_CHECK_EQ(v1, v1); ABSL_TEST_CHECK_NE(v1, v2); ABSL_TEST_CHECK_LT(v1, v2); ABSL_TEST_CHECK_LE(v1, v2); ABSL_TEST_CHECK_GT(v2, v1); ABSL_TEST_CHECK_GE(v2, v1); } TEST(CHECKDeathTest, TestUserDefinedAbslStringify) { const StringifiableType v1(1); const StringifiableType v2(2); // Returns a matcher for the expected check failure message when comparing two // values. auto expected_output = [](int lhs, absl::string_view condition, int rhs) { return HasSubstr( absl::Substitute("Check failed: v$0 $1 v$2 (StringifiableType{$0} vs. " "StringifiableType{$2})", lhs, condition, rhs)); }; // Test comparisons where the check fails. EXPECT_DEATH(ABSL_TEST_CHECK_EQ(v1, v2), expected_output(1, "==", 2)); EXPECT_DEATH(ABSL_TEST_CHECK_NE(v1, v1), expected_output(1, "!=", 1)); EXPECT_DEATH(ABSL_TEST_CHECK_LT(v2, v1), expected_output(2, "<", 1)); EXPECT_DEATH(ABSL_TEST_CHECK_LE(v2, v1), expected_output(2, "<=", 1)); EXPECT_DEATH(ABSL_TEST_CHECK_GT(v1, v2), expected_output(1, ">", 2)); EXPECT_DEATH(ABSL_TEST_CHECK_GE(v1, v2), expected_output(1, ">=", 2)); } // A type that can be printed using both AbslStringify and operator<<. struct StringifiableStreamableType { int x = 0; explicit StringifiableStreamableType(int x) : x(x) {} friend bool operator==(const StringifiableStreamableType& lhs, const StringifiableStreamableType& rhs) { return lhs.x == rhs.x; } friend bool operator!=(const StringifiableStreamableType& lhs, const StringifiableStreamableType& rhs) { return lhs.x != rhs.x; } template friend void AbslStringify(Sink& sink, const StringifiableStreamableType& obj) { absl::Format(&sink, "Strigified{%d}", obj.x); } friend std::ostream& operator<<(std::ostream& out, const StringifiableStreamableType& obj) { return out << "Streamed{" << obj.x << "}"; } // Avoid unintentional copy. StringifiableStreamableType(const StringifiableStreamableType&) = delete; }; TEST(CHECKDeathTest, TestStreamingPreferredOverAbslStringify) { StringifiableStreamableType v1(1); StringifiableStreamableType v2(2); EXPECT_DEATH( ABSL_TEST_CHECK_EQ(v1, v2), HasSubstr("Check failed: v1 == v2 (Streamed{1} vs. Streamed{2})")); } // A type whose pointer can be passed to AbslStringify. struct PointerIsStringifiable {}; template void AbslStringify(Sink& sink, const PointerIsStringifiable* var) { sink.Append("PointerIsStringifiable"); } // Verifies that a pointer is printed as a number despite having AbslStringify // defined. Users may implement AbslStringify that dereferences the pointer, and // doing so as part of DCHECK would not be good. TEST(CHECKDeathTest, TestPointerPrintedAsNumberDespiteAbslStringify) { const auto* p = reinterpret_cast(0x1234); #ifdef _MSC_VER EXPECT_DEATH( ABSL_TEST_CHECK_EQ(p, nullptr), HasSubstr("Check failed: p == nullptr (0000000000001234 vs. (null))")); #else // _MSC_VER EXPECT_DEATH(ABSL_TEST_CHECK_EQ(p, nullptr), HasSubstr("Check failed: p == nullptr (0x1234 vs. (null))")); #endif // _MSC_VER } // An uncopyable object with operator<<. struct Uncopyable { int x; explicit Uncopyable(int x) : x(x) {} Uncopyable(const Uncopyable&) = delete; friend bool operator==(const Uncopyable& lhs, const Uncopyable& rhs) { return lhs.x == rhs.x; } friend bool operator!=(const Uncopyable& lhs, const Uncopyable& rhs) { return lhs.x != rhs.x; } friend std::ostream& operator<<(std::ostream& os, const Uncopyable& obj) { return os << "Uncopyable{" << obj.x << "}"; } }; // Test that an uncopyable object can be used. // Will catch us if implementation has an unintended copy. TEST(CHECKDeathTest, TestUncopyable) { const Uncopyable v1(1); const Uncopyable v2(2); EXPECT_DEATH( ABSL_TEST_CHECK_EQ(v1, v2), HasSubstr("Check failed: v1 == v2 (Uncopyable{1} vs. Uncopyable{2})")); } } // namespace absl_log_internal // NOLINTEND(misc-definitions-in-headers) #endif // ABSL_LOG_CHECK_TEST_IMPL_H_