// // 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 "absl/log/check.h" #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" namespace { 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) { CHECK(true); EXPECT_DEATH(CHECK(false), "Check failed: false"); int i = 2; CHECK(i != 3); // NOLINT } #endif // GTEST_HAS_DEATH_TEST TEST(CHECKTest, TestLogicExpressions) { int i = 5; CHECK(i > 0 && i < 10); CHECK(i < 0 || i > 3); } #if ABSL_INTERNAL_CPLUSPLUS_LANG >= 201703L ABSL_CONST_INIT const auto global_var_check = [](int i) { CHECK(i > 0); // NOLINT return i + 1; }(3); ABSL_CONST_INIT const auto global_var = [](int i) { 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) CHECK(true); if (false) ; // NOLINT else CHECK(true); switch (0) case 0: CHECK(true); // NOLINT #if ABSL_INTERNAL_CPLUSPLUS_LANG >= 201703L constexpr auto var = [](int i) { CHECK(i > 0); // NOLINT return i + 1; }(global_var); (void)var; #endif // ABSL_INTERNAL_CPLUSPLUS_LANG } TEST(CHECKTest, TestBoolConvertible) { struct Tester { } tester; CHECK([&]() { return &tester; }()); } #if GTEST_HAS_DEATH_TEST TEST(CHECKDeathTest, TestChecksWithSideeffects) { int var = 0; CHECK([&var]() { ++var; return true; }()); EXPECT_EQ(var, 1); EXPECT_DEATH(CHECK([&var]() { ++var; return false; }()) << var, "Check failed: .* 2"); } #endif // GTEST_HAS_DEATH_TEST #if GTEST_HAS_DEATH_TEST TEST(CHECKDeachTest, TestOrderOfInvocationsBetweenCheckAndMessage) { int counter = 0; auto GetStr = [&counter]() -> std::string { return counter++ == 0 ? "" : "non-empty"; }; EXPECT_DEATH(CHECK(!GetStr().empty()) << GetStr(), HasSubstr("non-empty")); } TEST(CHECKTest, TestSecondaryFailure) { auto FailingRoutine = []() { CHECK(false) << "Secondary"; return false; }; EXPECT_DEATH(CHECK(FailingRoutine()) << "Primary", AllOf(HasSubstr("Secondary"), Not(HasSubstr("Primary")))); } TEST(CHECKTest, TestSecondaryFailureInMessage) { auto MessageGen = []() { CHECK(false) << "Secondary"; return "Primary"; }; EXPECT_DEATH(CHECK(false) << MessageGen(), AllOf(HasSubstr("Secondary"), Not(HasSubstr("Primary")))); } #endif // GTEST_HAS_DEATH_TEST TEST(CHECKTest, TestBinaryChecksWithPrimitives) { CHECK_EQ(1, 1); CHECK_NE(1, 2); CHECK_GE(1, 1); CHECK_GE(2, 1); CHECK_LE(1, 1); CHECK_LE(1, 2); CHECK_GT(2, 1); 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. CHECK_EQ(CASE_A, CASE_A); CHECK_NE(CASE_A, CASE_B); CHECK_GE(CASE_A, CASE_A); CHECK_GE(CASE_B, CASE_A); CHECK_LE(CASE_A, CASE_A); CHECK_LE(CASE_A, CASE_B); CHECK_GT(CASE_B, CASE_A); CHECK_LT(CASE_A, CASE_B); } TEST(CHECKTest, TestBinaryChecksWithNullptr) { const void* p_null = nullptr; const void* p_not_null = &p_null; CHECK_EQ(p_null, nullptr); CHECK_EQ(nullptr, p_null); CHECK_NE(p_not_null, nullptr); 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(CHECK_EQ(a, b), "Check failed: a == b \\(';' vs. 'b'\\)"); b = 1; EXPECT_DEATH(CHECK_EQ(a, b), "Check failed: a == b \\(';' vs. char value 1\\)"); } { signed char a = ';'; signed char b = 'b'; EXPECT_DEATH(CHECK_EQ(a, b), "Check failed: a == b \\(';' vs. 'b'\\)"); b = -128; EXPECT_DEATH(CHECK_EQ(a, b), "Check failed: a == b \\(';' vs. signed char value -128\\)"); } { unsigned char a = ';'; unsigned char b = 'b'; EXPECT_DEATH(CHECK_EQ(a, b), "Check failed: a == b \\(';' vs. 'b'\\)"); b = 128; EXPECT_DEATH(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(CHECK_NE(a, b), "Check failed: a != b \\(\\(null\\) vs. \\(null\\)\\)"); a = "xx"; EXPECT_DEATH(CHECK_EQ(a, b), "Check failed: a == b \\(xx vs. \\(null\\)\\)"); EXPECT_DEATH(CHECK_EQ(b, a), "Check failed: b == a \\(\\(null\\) vs. xx\\)"); std::nullptr_t n{}; EXPECT_DEATH(CHECK_NE(n, nullptr), "Check failed: n != nullptr \\(\\(null\\) vs. \\(null\\)\\)"); } #endif // GTEST_HAS_DEATH_TEST TEST(CHECKTest, TestSTREQ) { CHECK_STREQ("this", "this"); CHECK_STREQ(nullptr, nullptr); CHECK_STRCASEEQ("this", "tHiS"); CHECK_STRCASEEQ(nullptr, nullptr); CHECK_STRNE("this", "tHiS"); CHECK_STRNE("this", nullptr); CHECK_STRCASENE("this", "that"); CHECK_STRCASENE(nullptr, "that"); CHECK_STREQ((std::string("a") + "b").c_str(), "ab"); 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) CHECK_EQ(1, 1); if (true) CHECK_STREQ("c", "c"); if (false) ; // NOLINT else CHECK_LE(0, 1); if (false) ; // NOLINT else CHECK_STRNE("a", "b"); switch (0) case 0: CHECK_NE(1, 0); switch (0) case 0: CHECK_STRCASEEQ("A", "a"); #if ABSL_INTERNAL_CPLUSPLUS_LANG >= 201703L constexpr auto var = [](int i) { 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) { // CHECK_STRNE("c", "d"); // return i + 1; // }(global_var); #if defined(__GNUC__) int var3 = (({ CHECK_LE(1, 2); }), global_var < 10) ? 1 : 0; (void)var3; int var4 = (({ CHECK_STREQ("a", "a"); }), global_var < 10) ? 1 : 0; (void)var4; #endif // __GNUC__ #endif // ABSL_INTERNAL_CPLUSPLUS_LANG } TEST(CHECKTest, TestDCHECK) { #ifdef NDEBUG DCHECK(1 == 2) << " DCHECK's shouldn't be compiled in normal mode"; #endif DCHECK(1 == 1); // NOLINT(readability/check) DCHECK_EQ(1, 1); DCHECK_NE(1, 2); DCHECK_GE(1, 1); DCHECK_GE(2, 1); DCHECK_LE(1, 1); DCHECK_LE(1, 2); DCHECK_GT(2, 1); DCHECK_LT(1, 2); // Test DCHECK on std::nullptr_t const void* p_null = nullptr; const void* p_not_null = &p_null; DCHECK_EQ(p_null, nullptr); DCHECK_EQ(nullptr, p_null); DCHECK_NE(p_not_null, nullptr); DCHECK_NE(nullptr, p_not_null); } TEST(CHECKTest, TestQCHECK) { // The tests that QCHECK does the same as CHECK QCHECK(1 == 1); // NOLINT(readability/check) QCHECK_EQ(1, 1); QCHECK_NE(1, 2); QCHECK_GE(1, 1); QCHECK_GE(2, 1); QCHECK_LE(1, 1); QCHECK_LE(1, 2); QCHECK_GT(2, 1); QCHECK_LT(1, 2); // Tests using QCHECK*() on anonymous enums. QCHECK_EQ(CASE_A, CASE_A); QCHECK_NE(CASE_A, CASE_B); QCHECK_GE(CASE_A, CASE_A); QCHECK_GE(CASE_B, CASE_A); QCHECK_LE(CASE_A, CASE_A); QCHECK_LE(CASE_A, CASE_B); QCHECK_GT(CASE_B, CASE_A); QCHECK_LT(CASE_A, CASE_B); } TEST(CHECKTest, TestQCHECKPlacementsInCompoundStatements) { // check placement inside if/else clauses if (true) QCHECK(true); if (false) ; // NOLINT else QCHECK(true); if (false) ; // NOLINT else QCHECK(true); switch (0) case 0: QCHECK(true); #if ABSL_INTERNAL_CPLUSPLUS_LANG >= 201703L constexpr auto var = [](int i) { QCHECK(i > 0); // NOLINT return i + 1; }(global_var); (void)var; #if defined(__GNUC__) int var2 = (({ 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) { CHECK_EQ(*this, i); 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) { CHECK_EQ(ComparableType{0}, ComparableType{0}); CHECK_NE(ComparableType{1}, ComparableType{2}); CHECK_LT(ComparableType{1}, ComparableType{2}); CHECK_LE(ComparableType{1}, ComparableType{2}); CHECK_GT(ComparableType{2}, ComparableType{1}); 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( CHECK_EQ(v1, v2), HasSubstr( "Check failed: v1 == v2 (ComparableType{1} vs. ComparableType{2})")); } } // namespace