blob: 64318108e71eb35ddf99d0c9e4fa760ed696e6bb [file] [log] [blame]
//
// 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 <ostream>
#include <string>
#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 <int a, int b>
constexpr int sum() {
return a + b;
}
#define MACRO_ONE 1
#define TEMPLATE_SUM(a, b) sum<a, b>()
#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 <typename Sink>
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 <typename Sink>
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 <typename Sink>
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<const PointerIsStringifiable*>(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_