Line data Source code
1 : // Copyright 2015 the V8 project authors. All rights reserved.
2 : // Use of this source code is governed by a BSD-style license that can be
3 : // found in the LICENSE file.
4 :
5 : #include <cstdint>
6 :
7 : #include "src/base/logging.h"
8 : #include "src/objects.h"
9 : #include "testing/gtest-support.h"
10 :
11 : namespace v8 {
12 : namespace base {
13 : namespace logging_unittest {
14 :
15 : namespace {
16 :
17 : #define CHECK_SUCCEED(NAME, lhs, rhs) \
18 : { \
19 : std::string* error_message = \
20 : Check##NAME##Impl<decltype(lhs), decltype(rhs)>((lhs), (rhs), ""); \
21 : EXPECT_EQ(nullptr, error_message); \
22 : }
23 :
24 : #define CHECK_FAIL(NAME, lhs, rhs) \
25 : { \
26 : std::string* error_message = \
27 : Check##NAME##Impl<decltype(lhs), decltype(rhs)>((lhs), (rhs), ""); \
28 : EXPECT_NE(nullptr, error_message); \
29 : delete error_message; \
30 : }
31 :
32 : } // namespace
33 :
34 13158 : TEST(LoggingTest, CheckEQImpl) {
35 1 : CHECK_SUCCEED(EQ, 0.0, 0.0)
36 1 : CHECK_SUCCEED(EQ, 0.0, -0.0)
37 1 : CHECK_SUCCEED(EQ, -0.0, 0.0)
38 1 : CHECK_SUCCEED(EQ, -0.0, -0.0)
39 1 : }
40 :
41 13158 : TEST(LoggingTest, CompareSignedMismatch) {
42 1 : CHECK_SUCCEED(EQ, static_cast<int32_t>(14), static_cast<uint32_t>(14))
43 3 : CHECK_FAIL(EQ, static_cast<int32_t>(14), static_cast<uint32_t>(15))
44 3 : CHECK_FAIL(EQ, static_cast<int32_t>(-1), static_cast<uint32_t>(-1))
45 1 : CHECK_SUCCEED(LT, static_cast<int32_t>(-1), static_cast<uint32_t>(0))
46 1 : CHECK_SUCCEED(LT, static_cast<int32_t>(-1), static_cast<uint32_t>(-1))
47 1 : CHECK_SUCCEED(LE, static_cast<int32_t>(-1), static_cast<uint32_t>(0))
48 1 : CHECK_SUCCEED(LE, static_cast<int32_t>(55), static_cast<uint32_t>(55))
49 1 : CHECK_SUCCEED(LT, static_cast<int32_t>(55), static_cast<uint32_t>(0x7fffff00))
50 1 : CHECK_SUCCEED(LE, static_cast<int32_t>(55), static_cast<uint32_t>(0x7fffff00))
51 1 : CHECK_SUCCEED(GE, static_cast<uint32_t>(0x7fffff00), static_cast<int32_t>(55))
52 1 : CHECK_SUCCEED(GT, static_cast<uint32_t>(0x7fffff00), static_cast<int32_t>(55))
53 1 : CHECK_SUCCEED(GT, static_cast<uint32_t>(-1), static_cast<int32_t>(-1))
54 1 : CHECK_SUCCEED(GE, static_cast<uint32_t>(0), static_cast<int32_t>(-1))
55 1 : CHECK_SUCCEED(LT, static_cast<int8_t>(-1), static_cast<uint32_t>(0))
56 1 : CHECK_SUCCEED(GT, static_cast<uint64_t>(0x7f01010101010101), 0)
57 1 : CHECK_SUCCEED(LE, static_cast<int64_t>(0xff01010101010101),
58 : static_cast<uint8_t>(13))
59 1 : }
60 :
61 13158 : TEST(LoggingTest, CompareAgainstStaticConstPointer) {
62 : // These used to produce link errors before http://crrev.com/2524093002.
63 3 : CHECK_FAIL(EQ, v8::internal::Smi::kZero, v8::internal::Smi::FromInt(17));
64 1 : CHECK_SUCCEED(GT, 0, v8::internal::Smi::kMinValue);
65 1 : }
66 :
67 : #define CHECK_BOTH(name, lhs, rhs) \
68 : CHECK_##name(lhs, rhs); \
69 : DCHECK_##name(lhs, rhs)
70 :
71 : namespace {
72 10 : std::string FailureMessage(const char* msg, const char* debug_msg) {
73 10 : std::string regexp(msg);
74 : #ifdef DEBUG
75 : regexp.append(" (").append(debug_msg).append(")");
76 : #endif
77 : size_t last_pos = 0;
78 : do {
79 20 : size_t pos = regexp.find_first_of("(){}+*", last_pos);
80 20 : if (pos == std::string::npos) break;
81 10 : regexp.insert(pos, "\\");
82 10 : last_pos = pos + 2;
83 : } while (true);
84 10 : return regexp;
85 : }
86 : } // namespace
87 :
88 13158 : TEST(LoggingTest, CompareWithDifferentSignedness) {
89 1 : int32_t i32 = 10;
90 : uint32_t u32 = 20;
91 : int64_t i64 = 30;
92 1 : uint64_t u64 = 40;
93 :
94 : // All these checks should compile (!) and succeed.
95 1 : CHECK_BOTH(EQ, i32 + 10, u32);
96 1 : CHECK_BOTH(LT, i32, u64);
97 : CHECK_BOTH(LE, u32, i64);
98 : CHECK_BOTH(IMPLIES, i32, i64);
99 : CHECK_BOTH(IMPLIES, u32, i64);
100 : CHECK_BOTH(IMPLIES, !u32, !i64);
101 :
102 : // Check that the values are output correctly on error.
103 4 : ASSERT_DEATH_IF_SUPPORTED(
104 : ([&] { CHECK_GT(i32, u64); })(),
105 : FailureMessage("Check failed: i32 > u64", "10 vs. 40"));
106 : }
107 :
108 13158 : TEST(LoggingTest, CompareWithReferenceType) {
109 1 : int32_t i32 = 10;
110 : uint32_t u32 = 20;
111 : int64_t i64 = 30;
112 1 : uint64_t u64 = 40;
113 :
114 : // All these checks should compile (!) and succeed.
115 1 : CHECK_BOTH(EQ, i32 + 10, *&u32);
116 1 : CHECK_BOTH(LT, *&i32, u64);
117 : CHECK_BOTH(IMPLIES, *&i32, i64);
118 1 : CHECK_BOTH(IMPLIES, *&i32, u64);
119 :
120 : // Check that the values are output correctly on error.
121 4 : ASSERT_DEATH_IF_SUPPORTED(
122 : ([&] { CHECK_GT(*&i32, u64); })(),
123 : FailureMessage("Check failed: *&i32 > u64", "10 vs. 40"));
124 : }
125 :
126 : enum TestEnum1 { ONE, TWO };
127 : enum TestEnum2 : uint16_t { FOO = 14, BAR = 5 };
128 : enum class TestEnum3 { A, B };
129 : enum class TestEnum4 : uint8_t { FIRST, SECOND };
130 :
131 13158 : TEST(LoggingTest, CompareEnumTypes) {
132 : // All these checks should compile (!) and succeed.
133 : CHECK_BOTH(EQ, ONE, ONE);
134 : CHECK_BOTH(LT, ONE, TWO);
135 : CHECK_BOTH(EQ, BAR, 5);
136 : CHECK_BOTH(LT, BAR, FOO);
137 : CHECK_BOTH(EQ, TestEnum3::A, TestEnum3::A);
138 : CHECK_BOTH(LT, TestEnum3::A, TestEnum3::B);
139 : CHECK_BOTH(EQ, TestEnum4::FIRST, TestEnum4::FIRST);
140 : CHECK_BOTH(LT, TestEnum4::FIRST, TestEnum4::SECOND);
141 1 : }
142 :
143 : class TestClass1 {
144 : public:
145 1 : bool operator==(const TestClass1&) const { return true; }
146 0 : bool operator!=(const TestClass1&) const { return false; }
147 : };
148 : class TestClass2 {
149 : public:
150 1 : explicit TestClass2(int val) : val_(val) {}
151 1 : bool operator<(const TestClass2& other) const { return val_ < other.val_; }
152 0 : int val() const { return val_; }
153 :
154 : private:
155 : int val_;
156 : };
157 0 : std::ostream& operator<<(std::ostream& str, const TestClass2& val) {
158 0 : return str << "TestClass2(" << val.val() << ")";
159 : }
160 :
161 13158 : TEST(LoggingTest, CompareClassTypes) {
162 : // All these checks should compile (!) and succeed.
163 1 : CHECK_BOTH(EQ, TestClass1{}, TestClass1{});
164 1 : CHECK_BOTH(LT, TestClass2{2}, TestClass2{7});
165 :
166 : // Check that the values are output correctly on error.
167 4 : ASSERT_DEATH_IF_SUPPORTED(
168 : ([&] { CHECK_NE(TestClass1{}, TestClass1{}); })(),
169 : FailureMessage("Check failed: TestClass1{} != TestClass1{}",
170 : "<unprintable> vs. <unprintable>"));
171 5 : ASSERT_DEATH_IF_SUPPORTED(
172 : ([&] { CHECK_LT(TestClass2{4}, TestClass2{3}); })(),
173 : FailureMessage("Check failed: TestClass2{4} < TestClass2{3}",
174 : "TestClass2(4) vs. TestClass2(3)"));
175 : }
176 :
177 13158 : TEST(LoggingDeathTest, OutputEnumValues) {
178 4 : ASSERT_DEATH_IF_SUPPORTED(
179 : ([&] { CHECK_EQ(ONE, TWO); })(),
180 : FailureMessage("Check failed: ONE == TWO", "0 vs. 1"));
181 5 : ASSERT_DEATH_IF_SUPPORTED(
182 : ([&] { CHECK_NE(BAR, 2 + 3); })(),
183 : FailureMessage("Check failed: BAR != 2 + 3", "5 vs. 5"));
184 5 : ASSERT_DEATH_IF_SUPPORTED(
185 : ([&] { CHECK_EQ(TestEnum3::A, TestEnum3::B); })(),
186 : FailureMessage("Check failed: TestEnum3::A == TestEnum3::B", "0 vs. 1"));
187 5 : ASSERT_DEATH_IF_SUPPORTED(
188 : ([&] { CHECK_GE(TestEnum4::FIRST, TestEnum4::SECOND); })(),
189 : FailureMessage("Check failed: TestEnum4::FIRST >= TestEnum4::SECOND",
190 : "0 vs. 1"));
191 : }
192 :
193 : enum TestEnum5 { TEST_A, TEST_B };
194 : enum class TestEnum6 { TEST_C, TEST_D };
195 0 : std::ostream& operator<<(std::ostream& str, TestEnum5 val) {
196 0 : return str << (val == TEST_A ? "A" : "B");
197 : }
198 0 : void operator<<(std::ostream& str, TestEnum6 val) {
199 0 : str << (val == TestEnum6::TEST_C ? "C" : "D");
200 0 : }
201 :
202 13158 : TEST(LoggingDeathTest, OutputEnumWithOutputOperator) {
203 4 : ASSERT_DEATH_IF_SUPPORTED(
204 : ([&] { CHECK_EQ(TEST_A, TEST_B); })(),
205 : FailureMessage("Check failed: TEST_A == TEST_B", "A vs. B"));
206 5 : ASSERT_DEATH_IF_SUPPORTED(
207 : ([&] { CHECK_GE(TestEnum6::TEST_C, TestEnum6::TEST_D); })(),
208 : FailureMessage("Check failed: TestEnum6::TEST_C >= TestEnum6::TEST_D",
209 : "C vs. D"));
210 : }
211 :
212 13158 : TEST(LoggingDeathTest, FatalKills) {
213 4 : ASSERT_DEATH_IF_SUPPORTED(FATAL("Dread pirate"), "Dread pirate");
214 : }
215 :
216 13158 : TEST(LoggingDeathTest, DcheckIsOnlyFatalInDebug) {
217 : #ifdef DEBUG
218 : ASSERT_DEATH_IF_SUPPORTED(DCHECK(false && "Dread pirate"), "Dread pirate");
219 : #else
220 : // DCHECK should be non-fatal if DEBUG is undefined.
221 : DCHECK(false && "I'm a benign teapot");
222 : #endif
223 1 : }
224 :
225 : namespace {
226 0 : void DcheckOverrideFunction(const char*, int, const char*) {}
227 : } // namespace
228 :
229 13158 : TEST(LoggingDeathTest, V8_DcheckCanBeOverridden) {
230 : // Default DCHECK state should be fatal.
231 4 : ASSERT_DEATH_IF_SUPPORTED(V8_Dcheck(__FILE__, __LINE__, "Dread pirate"),
232 : "Dread pirate");
233 :
234 4 : ASSERT_DEATH_IF_SUPPORTED(
235 : {
236 : v8::base::SetDcheckFunction(&DcheckOverrideFunction);
237 : // This should be non-fatal.
238 : V8_Dcheck(__FILE__, __LINE__, "I'm a benign teapot.");
239 :
240 : // Restore default behavior, and assert on lethality.
241 : v8::base::SetDcheckFunction(nullptr);
242 : V8_Dcheck(__FILE__, __LINE__, "Dread pirate");
243 : },
244 : "Dread pirate");
245 : }
246 :
247 : } // namespace logging_unittest
248 : } // namespace base
249 7893 : } // namespace v8
|