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 "src/objects/smi.h"
10 : #include "testing/gtest-support.h"
11 :
12 : namespace v8 {
13 : namespace base {
14 : namespace logging_unittest {
15 :
16 : namespace {
17 :
18 : #define CHECK_SUCCEED(NAME, lhs, rhs) \
19 : { \
20 : std::string* error_message = \
21 : Check##NAME##Impl<decltype(lhs), decltype(rhs)>((lhs), (rhs), ""); \
22 : EXPECT_EQ(nullptr, error_message); \
23 : }
24 :
25 : #define CHECK_FAIL(NAME, lhs, rhs) \
26 : { \
27 : std::string* error_message = \
28 : Check##NAME##Impl<decltype(lhs), decltype(rhs)>((lhs), (rhs), ""); \
29 : EXPECT_NE(nullptr, error_message); \
30 : delete error_message; \
31 : }
32 :
33 : } // namespace
34 :
35 15373 : TEST(LoggingTest, CheckEQImpl) {
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 : CHECK_SUCCEED(EQ, -0.0, -0.0);
40 1 : }
41 :
42 15373 : TEST(LoggingTest, CompareSignedMismatch) {
43 1 : CHECK_SUCCEED(EQ, static_cast<int32_t>(14), static_cast<uint32_t>(14));
44 3 : CHECK_FAIL(EQ, static_cast<int32_t>(14), static_cast<uint32_t>(15));
45 3 : CHECK_FAIL(EQ, static_cast<int32_t>(-1), static_cast<uint32_t>(-1));
46 1 : CHECK_SUCCEED(LT, static_cast<int32_t>(-1), static_cast<uint32_t>(0));
47 1 : CHECK_SUCCEED(LT, static_cast<int32_t>(-1), static_cast<uint32_t>(-1));
48 1 : CHECK_SUCCEED(LE, static_cast<int32_t>(-1), static_cast<uint32_t>(0));
49 1 : CHECK_SUCCEED(LE, static_cast<int32_t>(55), static_cast<uint32_t>(55));
50 1 : CHECK_SUCCEED(LT, static_cast<int32_t>(55),
51 : static_cast<uint32_t>(0x7FFFFF00));
52 1 : CHECK_SUCCEED(LE, static_cast<int32_t>(55),
53 : static_cast<uint32_t>(0x7FFFFF00));
54 1 : CHECK_SUCCEED(GE, static_cast<uint32_t>(0x7FFFFF00),
55 : static_cast<int32_t>(55));
56 1 : CHECK_SUCCEED(GT, static_cast<uint32_t>(0x7FFFFF00),
57 : static_cast<int32_t>(55));
58 1 : CHECK_SUCCEED(GT, static_cast<uint32_t>(-1), static_cast<int32_t>(-1));
59 1 : CHECK_SUCCEED(GE, static_cast<uint32_t>(0), static_cast<int32_t>(-1));
60 1 : CHECK_SUCCEED(LT, static_cast<int8_t>(-1), static_cast<uint32_t>(0));
61 1 : CHECK_SUCCEED(GT, static_cast<uint64_t>(0x7F01010101010101), 0);
62 1 : CHECK_SUCCEED(LE, static_cast<int64_t>(0xFF01010101010101),
63 : static_cast<uint8_t>(13));
64 1 : }
65 :
66 15373 : TEST(LoggingTest, CompareAgainstStaticConstPointer) {
67 : // These used to produce link errors before http://crrev.com/2524093002.
68 3 : CHECK_FAIL(EQ, v8::internal::Smi::zero(), v8::internal::Smi::FromInt(17));
69 1 : CHECK_SUCCEED(GT, 0, v8::internal::Smi::kMinValue);
70 1 : }
71 :
72 : #define CHECK_BOTH(name, lhs, rhs) \
73 : CHECK_##name(lhs, rhs); \
74 : DCHECK_##name(lhs, rhs)
75 :
76 : namespace {
77 10 : std::string FailureMessage(const char* msg, const char* debug_msg) {
78 10 : std::string regexp(msg);
79 : #ifdef DEBUG
80 : regexp.append(" (").append(debug_msg).append(")");
81 : #endif
82 : size_t last_pos = 0;
83 : do {
84 : size_t pos = regexp.find_first_of("(){}+*", last_pos);
85 20 : if (pos == std::string::npos) break;
86 10 : regexp.insert(pos, "\\");
87 10 : last_pos = pos + 2;
88 : } while (true);
89 10 : return regexp;
90 : }
91 : } // namespace
92 :
93 15373 : TEST(LoggingTest, CompareWithDifferentSignedness) {
94 1 : int32_t i32 = 10;
95 : uint32_t u32 = 20;
96 : int64_t i64 = 30;
97 1 : uint64_t u64 = 40;
98 :
99 : // All these checks should compile (!) and succeed.
100 : CHECK_BOTH(EQ, i32 + 10, u32);
101 : CHECK_BOTH(LT, i32, u64);
102 : CHECK_BOTH(LE, u32, i64);
103 : CHECK_BOTH(IMPLIES, i32, i64);
104 : CHECK_BOTH(IMPLIES, u32, i64);
105 : CHECK_BOTH(IMPLIES, !u32, !i64);
106 :
107 : // Check that the values are output correctly on error.
108 3 : ASSERT_DEATH_IF_SUPPORTED(
109 : ([&] { CHECK_GT(i32, u64); })(),
110 : FailureMessage("Check failed: i32 > u64", "10 vs. 40"));
111 : }
112 :
113 15373 : TEST(LoggingTest, CompareWithReferenceType) {
114 1 : int32_t i32 = 10;
115 : uint32_t u32 = 20;
116 : int64_t i64 = 30;
117 1 : uint64_t u64 = 40;
118 :
119 : // All these checks should compile (!) and succeed.
120 : CHECK_BOTH(EQ, i32 + 10, *&u32);
121 : CHECK_BOTH(LT, *&i32, u64);
122 : CHECK_BOTH(IMPLIES, *&i32, i64);
123 : CHECK_BOTH(IMPLIES, *&i32, u64);
124 :
125 : // Check that the values are output correctly on error.
126 3 : ASSERT_DEATH_IF_SUPPORTED(
127 : ([&] { CHECK_GT(*&i32, u64); })(),
128 : FailureMessage("Check failed: *&i32 > u64", "10 vs. 40"));
129 : }
130 :
131 : enum TestEnum1 { ONE, TWO };
132 : enum TestEnum2 : uint16_t { FOO = 14, BAR = 5 };
133 : enum class TestEnum3 { A, B };
134 : enum class TestEnum4 : uint8_t { FIRST, SECOND };
135 :
136 15373 : TEST(LoggingTest, CompareEnumTypes) {
137 : // All these checks should compile (!) and succeed.
138 : CHECK_BOTH(EQ, ONE, ONE);
139 : CHECK_BOTH(LT, ONE, TWO);
140 : CHECK_BOTH(EQ, BAR, 5);
141 : CHECK_BOTH(LT, BAR, FOO);
142 : CHECK_BOTH(EQ, TestEnum3::A, TestEnum3::A);
143 : CHECK_BOTH(LT, TestEnum3::A, TestEnum3::B);
144 : CHECK_BOTH(EQ, TestEnum4::FIRST, TestEnum4::FIRST);
145 : CHECK_BOTH(LT, TestEnum4::FIRST, TestEnum4::SECOND);
146 1 : }
147 :
148 : class TestClass1 {
149 : public:
150 : bool operator==(const TestClass1&) const { return true; }
151 : bool operator!=(const TestClass1&) const { return false; }
152 : };
153 : class TestClass2 {
154 : public:
155 : explicit TestClass2(int val) : val_(val) {}
156 : bool operator<(const TestClass2& other) const { return val_ < other.val_; }
157 0 : int val() const { return val_; }
158 :
159 : private:
160 : int val_;
161 : };
162 0 : std::ostream& operator<<(std::ostream& str, const TestClass2& val) {
163 0 : return str << "TestClass2(" << val.val() << ")";
164 : }
165 :
166 15373 : TEST(LoggingTest, CompareClassTypes) {
167 : // All these checks should compile (!) and succeed.
168 : CHECK_BOTH(EQ, TestClass1{}, TestClass1{});
169 : CHECK_BOTH(LT, TestClass2{2}, TestClass2{7});
170 :
171 : // Check that the values are output correctly on error.
172 3 : ASSERT_DEATH_IF_SUPPORTED(
173 : ([&] { CHECK_NE(TestClass1{}, TestClass1{}); })(),
174 : FailureMessage("Check failed: TestClass1{} != TestClass1{}",
175 : "<unprintable> vs. <unprintable>"));
176 4 : ASSERT_DEATH_IF_SUPPORTED(
177 : ([&] { CHECK_LT(TestClass2{4}, TestClass2{3}); })(),
178 : FailureMessage("Check failed: TestClass2{4} < TestClass2{3}",
179 : "TestClass2(4) vs. TestClass2(3)"));
180 : }
181 :
182 15373 : TEST(LoggingDeathTest, OutputEnumValues) {
183 3 : ASSERT_DEATH_IF_SUPPORTED(
184 : ([&] { CHECK_EQ(ONE, TWO); })(),
185 : FailureMessage("Check failed: ONE == TWO", "0 vs. 1"));
186 4 : ASSERT_DEATH_IF_SUPPORTED(
187 : ([&] { CHECK_NE(BAR, 2 + 3); })(),
188 : FailureMessage("Check failed: BAR != 2 + 3", "5 vs. 5"));
189 4 : ASSERT_DEATH_IF_SUPPORTED(
190 : ([&] { CHECK_EQ(TestEnum3::A, TestEnum3::B); })(),
191 : FailureMessage("Check failed: TestEnum3::A == TestEnum3::B", "0 vs. 1"));
192 4 : ASSERT_DEATH_IF_SUPPORTED(
193 : ([&] { CHECK_GE(TestEnum4::FIRST, TestEnum4::SECOND); })(),
194 : FailureMessage("Check failed: TestEnum4::FIRST >= TestEnum4::SECOND",
195 : "0 vs. 1"));
196 : }
197 :
198 : enum TestEnum5 { TEST_A, TEST_B };
199 : enum class TestEnum6 { TEST_C, TEST_D };
200 0 : std::ostream& operator<<(std::ostream& str, TestEnum5 val) {
201 0 : return str << (val == TEST_A ? "A" : "B");
202 : }
203 0 : void operator<<(std::ostream& str, TestEnum6 val) {
204 0 : str << (val == TestEnum6::TEST_C ? "C" : "D");
205 0 : }
206 :
207 15373 : TEST(LoggingDeathTest, OutputEnumWithOutputOperator) {
208 3 : ASSERT_DEATH_IF_SUPPORTED(
209 : ([&] { CHECK_EQ(TEST_A, TEST_B); })(),
210 : FailureMessage("Check failed: TEST_A == TEST_B", "A vs. B"));
211 4 : ASSERT_DEATH_IF_SUPPORTED(
212 : ([&] { CHECK_GE(TestEnum6::TEST_C, TestEnum6::TEST_D); })(),
213 : FailureMessage("Check failed: TestEnum6::TEST_C >= TestEnum6::TEST_D",
214 : "C vs. D"));
215 : }
216 :
217 15373 : TEST(LoggingDeathTest, FatalKills) {
218 2 : ASSERT_DEATH_IF_SUPPORTED(FATAL("Dread pirate"), "Dread pirate");
219 : }
220 :
221 15373 : TEST(LoggingDeathTest, DcheckIsOnlyFatalInDebug) {
222 : #ifdef DEBUG
223 : ASSERT_DEATH_IF_SUPPORTED(DCHECK(false && "Dread pirate"), "Dread pirate");
224 : #else
225 : // DCHECK should be non-fatal if DEBUG is undefined.
226 : DCHECK(false && "I'm a benign teapot");
227 : #endif
228 1 : }
229 :
230 : namespace {
231 0 : void DcheckOverrideFunction(const char*, int, const char*) {}
232 : } // namespace
233 :
234 15373 : TEST(LoggingDeathTest, V8_DcheckCanBeOverridden) {
235 : // Default DCHECK state should be fatal.
236 2 : ASSERT_DEATH_IF_SUPPORTED(V8_Dcheck(__FILE__, __LINE__, "Dread pirate"),
237 : "Dread pirate");
238 :
239 3 : ASSERT_DEATH_IF_SUPPORTED(
240 : {
241 : v8::base::SetDcheckFunction(&DcheckOverrideFunction);
242 : // This should be non-fatal.
243 : V8_Dcheck(__FILE__, __LINE__, "I'm a benign teapot.");
244 :
245 : // Restore default behavior, and assert on lethality.
246 : v8::base::SetDcheckFunction(nullptr);
247 : V8_Dcheck(__FILE__, __LINE__, "Dread pirate");
248 : },
249 : "Dread pirate");
250 : }
251 :
252 : #if defined(DEBUG)
253 : namespace {
254 : int g_log_sink_call_count = 0;
255 : void DcheckCountFunction(const char* file, int line, const char* message) {
256 : ++g_log_sink_call_count;
257 : }
258 :
259 : void DcheckEmptyFunction1() {
260 : // Provide a body so that Release builds do not cause the compiler to
261 : // optimize DcheckEmptyFunction1 and DcheckEmptyFunction2 as a single
262 : // function, which breaks the Dcheck tests below.
263 : // Note that this function is never actually called.
264 : g_log_sink_call_count += 42;
265 : }
266 : void DcheckEmptyFunction2() {}
267 :
268 : } // namespace
269 :
270 : TEST(LoggingTest, LogFunctionPointers) {
271 : v8::base::SetDcheckFunction(&DcheckCountFunction);
272 : g_log_sink_call_count = 0;
273 : void (*fp1)() = DcheckEmptyFunction1;
274 : void (*fp2)() = DcheckEmptyFunction2;
275 : void (*fp3)() = DcheckEmptyFunction1;
276 : DCHECK_EQ(fp1, DcheckEmptyFunction1);
277 : DCHECK_EQ(fp1, fp3);
278 : EXPECT_EQ(0, g_log_sink_call_count);
279 : DCHECK_EQ(fp1, fp2);
280 : EXPECT_EQ(1, g_log_sink_call_count);
281 : std::string* error_message =
282 : CheckEQImpl<decltype(fp1), decltype(fp2)>(fp1, fp2, "");
283 : EXPECT_NE(*error_message, "(1 vs 1)");
284 : delete error_message;
285 : }
286 : #endif // defined(DEBUG)
287 :
288 : } // namespace logging_unittest
289 : } // namespace base
290 9222 : } // namespace v8
|