1 | //===----- unittests/ErrorTest.cpp - Error.h tests ------------------------===// |
2 | // |
3 | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. |
4 | // See https://llvm.org/LICENSE.txt for license information. |
5 | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception |
6 | // |
7 | //===----------------------------------------------------------------------===// |
8 | |
9 | #include "llvm/Support/Error.h" |
10 | #include "llvm-c/Error.h" |
11 | |
12 | #include "llvm/ADT/Twine.h" |
13 | #include "llvm/Support/Errc.h" |
14 | #include "llvm/Support/ErrorHandling.h" |
15 | #include "llvm/Testing/Support/Error.h" |
16 | #include "gtest/gtest-spi.h" |
17 | #include "gtest/gtest.h" |
18 | #include <memory> |
19 | |
20 | using namespace llvm; |
21 | |
22 | namespace { |
23 | |
24 | // Custom error class with a default base class and some random 'info' attached. |
25 | class CustomError : public ErrorInfo<CustomError> { |
26 | public: |
27 | // Create an error with some info attached. |
28 | CustomError(int Info) : Info(Info) {} |
29 | |
30 | // Get the info attached to this error. |
31 | int getInfo() const { return Info; } |
32 | |
33 | // Log this error to a stream. |
34 | void log(raw_ostream &OS) const override { |
35 | OS << "CustomError {" << getInfo() << "}" ; |
36 | } |
37 | |
38 | std::error_code convertToErrorCode() const override { |
39 | llvm_unreachable("CustomError doesn't support ECError conversion" ); |
40 | } |
41 | |
42 | // Used by ErrorInfo::classID. |
43 | static char ID; |
44 | |
45 | protected: |
46 | // This error is subclassed below, but we can't use inheriting constructors |
47 | // yet, so we can't propagate the constructors through ErrorInfo. Instead |
48 | // we have to have a default constructor and have the subclass initialize all |
49 | // fields. |
50 | CustomError() : Info(0) {} |
51 | |
52 | int Info; |
53 | }; |
54 | |
55 | char CustomError::ID = 0; |
56 | |
57 | // Custom error class with a custom base class and some additional random |
58 | // 'info'. |
59 | class CustomSubError : public ErrorInfo<CustomSubError, CustomError> { |
60 | public: |
61 | // Create a sub-error with some info attached. |
62 | CustomSubError(int Info, int ) : ExtraInfo(ExtraInfo) { |
63 | this->Info = Info; |
64 | } |
65 | |
66 | // Get the extra info attached to this error. |
67 | int () const { return ExtraInfo; } |
68 | |
69 | // Log this error to a stream. |
70 | void log(raw_ostream &OS) const override { |
71 | OS << "CustomSubError { " << getInfo() << ", " << getExtraInfo() << "}" ; |
72 | } |
73 | |
74 | std::error_code convertToErrorCode() const override { |
75 | llvm_unreachable("CustomSubError doesn't support ECError conversion" ); |
76 | } |
77 | |
78 | // Used by ErrorInfo::classID. |
79 | static char ID; |
80 | |
81 | protected: |
82 | int ; |
83 | }; |
84 | |
85 | char CustomSubError::ID = 0; |
86 | |
87 | static Error handleCustomError(const CustomError &CE) { |
88 | return Error::success(); |
89 | } |
90 | |
91 | static void handleCustomErrorVoid(const CustomError &CE) {} |
92 | |
93 | static Error handleCustomErrorUP(std::unique_ptr<CustomError> CE) { |
94 | return Error::success(); |
95 | } |
96 | |
97 | static void handleCustomErrorUPVoid(std::unique_ptr<CustomError> CE) {} |
98 | |
99 | // Test that success values implicitly convert to false, and don't cause crashes |
100 | // once they've been implicitly converted. |
101 | TEST(Error, CheckedSuccess) { |
102 | Error E = Error::success(); |
103 | EXPECT_FALSE(E) << "Unexpected error while testing Error 'Success'" ; |
104 | } |
105 | |
106 | // Test that unchecked success values cause an abort. |
107 | #if LLVM_ENABLE_ABI_BREAKING_CHECKS |
108 | TEST(Error, UncheckedSuccess) { |
109 | EXPECT_DEATH({ Error E = Error::success(); }, |
110 | "Program aborted due to an unhandled Error:" ) |
111 | << "Unchecked Error Succes value did not cause abort()" ; |
112 | } |
113 | #endif |
114 | |
115 | // ErrorAsOutParameter tester. |
116 | void errAsOutParamHelper(Error &Err) { |
117 | ErrorAsOutParameter ErrAsOutParam(&Err); |
118 | // Verify that checked flag is raised - assignment should not crash. |
119 | Err = Error::success(); |
120 | // Raise the checked bit manually - caller should still have to test the |
121 | // error. |
122 | (void)!!Err; |
123 | } |
124 | |
125 | // Test that ErrorAsOutParameter sets the checked flag on construction. |
126 | TEST(Error, ErrorAsOutParameterChecked) { |
127 | Error E = Error::success(); |
128 | errAsOutParamHelper(Err&: E); |
129 | (void)!!E; |
130 | } |
131 | |
132 | // Test that ErrorAsOutParameter clears the checked flag on destruction. |
133 | #if LLVM_ENABLE_ABI_BREAKING_CHECKS |
134 | TEST(Error, ErrorAsOutParameterUnchecked) { |
135 | EXPECT_DEATH({ Error E = Error::success(); errAsOutParamHelper(E); }, |
136 | "Program aborted due to an unhandled Error:" ) |
137 | << "ErrorAsOutParameter did not clear the checked flag on destruction." ; |
138 | } |
139 | #endif |
140 | |
141 | // Check that we abort on unhandled failure cases. (Force conversion to bool |
142 | // to make sure that we don't accidentally treat checked errors as handled). |
143 | // Test runs in debug mode only. |
144 | #if LLVM_ENABLE_ABI_BREAKING_CHECKS |
145 | TEST(Error, UncheckedError) { |
146 | auto DropUnhandledError = []() { |
147 | Error E = make_error<CustomError>(Args: 42); |
148 | (void)!E; |
149 | }; |
150 | EXPECT_DEATH(DropUnhandledError(), |
151 | "Program aborted due to an unhandled Error:" ) |
152 | << "Unhandled Error failure value did not cause abort()" ; |
153 | } |
154 | #endif |
155 | |
156 | // Check 'Error::isA<T>' method handling. |
157 | TEST(Error, IsAHandling) { |
158 | // Check 'isA' handling. |
159 | Error E = make_error<CustomError>(Args: 1); |
160 | Error F = make_error<CustomSubError>(Args: 1, Args: 2); |
161 | Error G = Error::success(); |
162 | |
163 | EXPECT_TRUE(E.isA<CustomError>()); |
164 | EXPECT_FALSE(E.isA<CustomSubError>()); |
165 | EXPECT_TRUE(F.isA<CustomError>()); |
166 | EXPECT_TRUE(F.isA<CustomSubError>()); |
167 | EXPECT_FALSE(G.isA<CustomError>()); |
168 | |
169 | consumeError(Err: std::move(E)); |
170 | consumeError(Err: std::move(F)); |
171 | consumeError(Err: std::move(G)); |
172 | } |
173 | |
174 | // Check that we can handle a custom error. |
175 | TEST(Error, HandleCustomError) { |
176 | int CaughtErrorInfo = 0; |
177 | handleAllErrors(E: make_error<CustomError>(Args: 42), Handlers: [&](const CustomError &CE) { |
178 | CaughtErrorInfo = CE.getInfo(); |
179 | }); |
180 | |
181 | EXPECT_EQ(CaughtErrorInfo, 42) << "Wrong result from CustomError handler" ; |
182 | } |
183 | |
184 | // Check that handler type deduction also works for handlers |
185 | // of the following types: |
186 | // void (const Err&) |
187 | // Error (const Err&) mutable |
188 | // void (const Err&) mutable |
189 | // Error (Err&) |
190 | // void (Err&) |
191 | // Error (Err&) mutable |
192 | // void (Err&) mutable |
193 | // Error (unique_ptr<Err>) |
194 | // void (unique_ptr<Err>) |
195 | // Error (unique_ptr<Err>) mutable |
196 | // void (unique_ptr<Err>) mutable |
197 | TEST(Error, HandlerTypeDeduction) { |
198 | |
199 | handleAllErrors(E: make_error<CustomError>(Args: 42), Handlers: [](const CustomError &CE) {}); |
200 | |
201 | handleAllErrors( |
202 | E: make_error<CustomError>(Args: 42), |
203 | Handlers: [](const CustomError &CE) mutable -> Error { return Error::success(); }); |
204 | |
205 | handleAllErrors(E: make_error<CustomError>(Args: 42), |
206 | Handlers: [](const CustomError &CE) mutable {}); |
207 | |
208 | handleAllErrors(E: make_error<CustomError>(Args: 42), |
209 | Handlers: [](CustomError &CE) -> Error { return Error::success(); }); |
210 | |
211 | handleAllErrors(E: make_error<CustomError>(Args: 42), Handlers: [](CustomError &CE) {}); |
212 | |
213 | handleAllErrors(E: make_error<CustomError>(Args: 42), |
214 | Handlers: [](CustomError &CE) mutable -> Error { return Error::success(); }); |
215 | |
216 | handleAllErrors(E: make_error<CustomError>(Args: 42), Handlers: [](CustomError &CE) mutable {}); |
217 | |
218 | handleAllErrors( |
219 | E: make_error<CustomError>(Args: 42), |
220 | Handlers: [](std::unique_ptr<CustomError> CE) -> Error { return Error::success(); }); |
221 | |
222 | handleAllErrors(E: make_error<CustomError>(Args: 42), |
223 | Handlers: [](std::unique_ptr<CustomError> CE) {}); |
224 | |
225 | handleAllErrors( |
226 | E: make_error<CustomError>(Args: 42), |
227 | Handlers: [](std::unique_ptr<CustomError> CE) mutable -> Error { return Error::success(); }); |
228 | |
229 | handleAllErrors(E: make_error<CustomError>(Args: 42), |
230 | Handlers: [](std::unique_ptr<CustomError> CE) mutable {}); |
231 | |
232 | // Check that named handlers of type 'Error (const Err&)' work. |
233 | handleAllErrors(E: make_error<CustomError>(Args: 42), Handlers&: handleCustomError); |
234 | |
235 | // Check that named handlers of type 'void (const Err&)' work. |
236 | handleAllErrors(E: make_error<CustomError>(Args: 42), Handlers&: handleCustomErrorVoid); |
237 | |
238 | // Check that named handlers of type 'Error (std::unique_ptr<Err>)' work. |
239 | handleAllErrors(E: make_error<CustomError>(Args: 42), Handlers&: handleCustomErrorUP); |
240 | |
241 | // Check that named handlers of type 'Error (std::unique_ptr<Err>)' work. |
242 | handleAllErrors(E: make_error<CustomError>(Args: 42), Handlers&: handleCustomErrorUPVoid); |
243 | } |
244 | |
245 | // Test that we can handle errors with custom base classes. |
246 | TEST(Error, HandleCustomErrorWithCustomBaseClass) { |
247 | int CaughtErrorInfo = 0; |
248 | int = 0; |
249 | handleAllErrors(E: make_error<CustomSubError>(Args: 42, Args: 7), |
250 | Handlers: [&](const CustomSubError &SE) { |
251 | CaughtErrorInfo = SE.getInfo(); |
252 | CaughtErrorExtraInfo = SE.getExtraInfo(); |
253 | }); |
254 | |
255 | EXPECT_EQ(CaughtErrorInfo, 42) << "Wrong result from CustomSubError handler" ; |
256 | EXPECT_EQ(CaughtErrorExtraInfo, 7) |
257 | << "Wrong result from CustomSubError handler" ; |
258 | } |
259 | |
260 | // Check that we trigger only the first handler that applies. |
261 | TEST(Error, FirstHandlerOnly) { |
262 | int DummyInfo = 0; |
263 | int CaughtErrorInfo = 0; |
264 | int = 0; |
265 | |
266 | handleAllErrors(E: make_error<CustomSubError>(Args: 42, Args: 7), |
267 | Handlers: [&](const CustomSubError &SE) { |
268 | CaughtErrorInfo = SE.getInfo(); |
269 | CaughtErrorExtraInfo = SE.getExtraInfo(); |
270 | }, |
271 | Handlers: [&](const CustomError &CE) { DummyInfo = CE.getInfo(); }); |
272 | |
273 | EXPECT_EQ(CaughtErrorInfo, 42) << "Activated the wrong Error handler(s)" ; |
274 | EXPECT_EQ(CaughtErrorExtraInfo, 7) << "Activated the wrong Error handler(s)" ; |
275 | EXPECT_EQ(DummyInfo, 0) << "Activated the wrong Error handler(s)" ; |
276 | } |
277 | |
278 | // Check that general handlers shadow specific ones. |
279 | TEST(Error, HandlerShadowing) { |
280 | int CaughtErrorInfo = 0; |
281 | int DummyInfo = 0; |
282 | int = 0; |
283 | |
284 | handleAllErrors( |
285 | E: make_error<CustomSubError>(Args: 42, Args: 7), |
286 | Handlers: [&](const CustomError &CE) { CaughtErrorInfo = CE.getInfo(); }, |
287 | Handlers: [&](const CustomSubError &SE) { |
288 | DummyInfo = SE.getInfo(); |
289 | DummyExtraInfo = SE.getExtraInfo(); |
290 | }); |
291 | |
292 | EXPECT_EQ(CaughtErrorInfo, 42) |
293 | << "General Error handler did not shadow specific handler" ; |
294 | EXPECT_EQ(DummyInfo, 0) |
295 | << "General Error handler did not shadow specific handler" ; |
296 | EXPECT_EQ(DummyExtraInfo, 0) |
297 | << "General Error handler did not shadow specific handler" ; |
298 | } |
299 | |
300 | // Test joinErrors. |
301 | TEST(Error, CheckJoinErrors) { |
302 | int CustomErrorInfo1 = 0; |
303 | int CustomErrorInfo2 = 0; |
304 | int = 0; |
305 | Error E = |
306 | joinErrors(E1: make_error<CustomError>(Args: 7), E2: make_error<CustomSubError>(Args: 42, Args: 7)); |
307 | |
308 | handleAllErrors(E: std::move(E), |
309 | Handlers: [&](const CustomSubError &SE) { |
310 | CustomErrorInfo2 = SE.getInfo(); |
311 | CustomErrorExtraInfo = SE.getExtraInfo(); |
312 | }, |
313 | Handlers: [&](const CustomError &CE) { |
314 | // Assert that the CustomError instance above is handled |
315 | // before the |
316 | // CustomSubError - joinErrors should preserve error |
317 | // ordering. |
318 | EXPECT_EQ(CustomErrorInfo2, 0) |
319 | << "CustomErrorInfo2 should be 0 here. " |
320 | "joinErrors failed to preserve ordering.\n" ; |
321 | CustomErrorInfo1 = CE.getInfo(); |
322 | }); |
323 | |
324 | EXPECT_EQ(CustomErrorInfo1, 7) << "Failed handling compound Error." ; |
325 | EXPECT_EQ(CustomErrorInfo2, 42) << "Failed handling compound Error." ; |
326 | EXPECT_EQ(CustomErrorExtraInfo, 7) << "Failed handling compound Error." ; |
327 | |
328 | // Test appending a single item to a list. |
329 | { |
330 | int Sum = 0; |
331 | handleAllErrors( |
332 | E: joinErrors( |
333 | E1: joinErrors(E1: make_error<CustomError>(Args: 7), |
334 | E2: make_error<CustomError>(Args: 7)), |
335 | E2: make_error<CustomError>(Args: 7)), |
336 | Handlers: [&](const CustomError &CE) { |
337 | Sum += CE.getInfo(); |
338 | }); |
339 | EXPECT_EQ(Sum, 21) << "Failed to correctly append error to error list." ; |
340 | } |
341 | |
342 | // Test prepending a single item to a list. |
343 | { |
344 | int Sum = 0; |
345 | handleAllErrors( |
346 | E: joinErrors( |
347 | E1: make_error<CustomError>(Args: 7), |
348 | E2: joinErrors(E1: make_error<CustomError>(Args: 7), |
349 | E2: make_error<CustomError>(Args: 7))), |
350 | Handlers: [&](const CustomError &CE) { |
351 | Sum += CE.getInfo(); |
352 | }); |
353 | EXPECT_EQ(Sum, 21) << "Failed to correctly prepend error to error list." ; |
354 | } |
355 | |
356 | // Test concatenating two error lists. |
357 | { |
358 | int Sum = 0; |
359 | handleAllErrors( |
360 | E: joinErrors( |
361 | E1: joinErrors( |
362 | E1: make_error<CustomError>(Args: 7), |
363 | E2: make_error<CustomError>(Args: 7)), |
364 | E2: joinErrors( |
365 | E1: make_error<CustomError>(Args: 7), |
366 | E2: make_error<CustomError>(Args: 7))), |
367 | Handlers: [&](const CustomError &CE) { |
368 | Sum += CE.getInfo(); |
369 | }); |
370 | EXPECT_EQ(Sum, 28) << "Failed to correctly concatenate error lists." ; |
371 | } |
372 | } |
373 | |
374 | // Test that we can consume success values. |
375 | TEST(Error, ConsumeSuccess) { |
376 | Error E = Error::success(); |
377 | consumeError(Err: std::move(E)); |
378 | } |
379 | |
380 | TEST(Error, ConsumeError) { |
381 | Error E = make_error<CustomError>(Args: 7); |
382 | consumeError(Err: std::move(E)); |
383 | } |
384 | |
385 | // Test that handleAllUnhandledErrors crashes if an error is not caught. |
386 | // Test runs in debug mode only. |
387 | #if LLVM_ENABLE_ABI_BREAKING_CHECKS |
388 | TEST(Error, FailureToHandle) { |
389 | auto FailToHandle = []() { |
390 | handleAllErrors(E: make_error<CustomError>(Args: 7), Handlers: [&](const CustomSubError &SE) { |
391 | errs() << "This should never be called" ; |
392 | exit(status: 1); |
393 | }); |
394 | }; |
395 | |
396 | EXPECT_DEATH(FailToHandle(), |
397 | "Failure value returned from cantFail wrapped call\n" |
398 | "CustomError \\{7\\}" ) |
399 | << "Unhandled Error in handleAllErrors call did not cause an " |
400 | "abort()" ; |
401 | } |
402 | #endif |
403 | |
404 | // Test that handleAllUnhandledErrors crashes if an error is returned from a |
405 | // handler. |
406 | // Test runs in debug mode only. |
407 | #if LLVM_ENABLE_ABI_BREAKING_CHECKS |
408 | TEST(Error, FailureFromHandler) { |
409 | auto ReturnErrorFromHandler = []() { |
410 | handleAllErrors(E: make_error<CustomError>(Args: 7), |
411 | Handlers: [&](std::unique_ptr<CustomSubError> SE) { |
412 | return Error(std::move(SE)); |
413 | }); |
414 | }; |
415 | |
416 | EXPECT_DEATH(ReturnErrorFromHandler(), |
417 | "Failure value returned from cantFail wrapped call\n" |
418 | "CustomError \\{7\\}" ) |
419 | << " Error returned from handler in handleAllErrors call did not " |
420 | "cause abort()" ; |
421 | } |
422 | #endif |
423 | |
424 | // Test that we can return values from handleErrors. |
425 | TEST(Error, CatchErrorFromHandler) { |
426 | int ErrorInfo = 0; |
427 | |
428 | Error E = handleErrors( |
429 | E: make_error<CustomError>(Args: 7), |
430 | Hs: [&](std::unique_ptr<CustomError> CE) { return Error(std::move(CE)); }); |
431 | |
432 | handleAllErrors(E: std::move(E), |
433 | Handlers: [&](const CustomError &CE) { ErrorInfo = CE.getInfo(); }); |
434 | |
435 | EXPECT_EQ(ErrorInfo, 7) |
436 | << "Failed to handle Error returned from handleErrors." ; |
437 | } |
438 | |
439 | TEST(Error, StringError) { |
440 | std::string Msg; |
441 | raw_string_ostream S(Msg); |
442 | logAllUnhandledErrors( |
443 | E: make_error<StringError>(Args: "foo" + Twine(42), Args: inconvertibleErrorCode()), OS&: S); |
444 | EXPECT_EQ(S.str(), "foo42\n" ) << "Unexpected StringError log result" ; |
445 | |
446 | auto EC = |
447 | errorToErrorCode(Err: make_error<StringError>(Args: "" , Args: errc::invalid_argument)); |
448 | EXPECT_EQ(EC, errc::invalid_argument) |
449 | << "Failed to convert StringError to error_code." ; |
450 | } |
451 | |
452 | TEST(Error, createStringError) { |
453 | static const char *Bar = "bar" ; |
454 | static const std::error_code EC = errc::invalid_argument; |
455 | std::string Msg; |
456 | raw_string_ostream S(Msg); |
457 | logAllUnhandledErrors(E: createStringError(EC, Fmt: "foo%s%d0x%" PRIx8, Vals: Bar, Vals: 1, Vals: 0xff), |
458 | OS&: S); |
459 | EXPECT_EQ(S.str(), "foobar10xff\n" ) |
460 | << "Unexpected createStringError() log result" ; |
461 | |
462 | S.flush(); |
463 | Msg.clear(); |
464 | logAllUnhandledErrors(E: createStringError(EC, Msg: Bar), OS&: S); |
465 | EXPECT_EQ(S.str(), "bar\n" ) |
466 | << "Unexpected createStringError() (overloaded) log result" ; |
467 | |
468 | S.flush(); |
469 | Msg.clear(); |
470 | auto Res = errorToErrorCode(Err: createStringError(EC, Fmt: "foo%s" , Vals: Bar)); |
471 | EXPECT_EQ(Res, EC) |
472 | << "Failed to convert createStringError() result to error_code." ; |
473 | } |
474 | |
475 | // Test that the ExitOnError utility works as expected. |
476 | TEST(ErrorDeathTest, ExitOnError) { |
477 | ExitOnError ExitOnErr; |
478 | ExitOnErr.setBanner("Error in tool:" ); |
479 | ExitOnErr.setExitCodeMapper([](const Error &E) { |
480 | if (E.isA<CustomSubError>()) |
481 | return 2; |
482 | return 1; |
483 | }); |
484 | |
485 | // Make sure we don't bail on success. |
486 | ExitOnErr(Error::success()); |
487 | EXPECT_EQ(ExitOnErr(Expected<int>(7)), 7) |
488 | << "exitOnError returned an invalid value for Expected" ; |
489 | |
490 | int A = 7; |
491 | int &B = ExitOnErr(Expected<int&>(A)); |
492 | EXPECT_EQ(&A, &B) << "ExitOnError failed to propagate reference" ; |
493 | |
494 | // Exit tests. |
495 | EXPECT_EXIT(ExitOnErr(make_error<CustomError>(7)), |
496 | ::testing::ExitedWithCode(1), "Error in tool:" ) |
497 | << "exitOnError returned an unexpected error result" ; |
498 | |
499 | EXPECT_EXIT(ExitOnErr(Expected<int>(make_error<CustomSubError>(0, 0))), |
500 | ::testing::ExitedWithCode(2), "Error in tool:" ) |
501 | << "exitOnError returned an unexpected error result" ; |
502 | } |
503 | |
504 | // Test that the ExitOnError utility works as expected. |
505 | TEST(Error, CantFailSuccess) { |
506 | cantFail(Err: Error::success()); |
507 | |
508 | int X = cantFail(ValOrErr: Expected<int>(42)); |
509 | EXPECT_EQ(X, 42) << "Expected value modified by cantFail" ; |
510 | |
511 | int Dummy = 42; |
512 | int &Y = cantFail(ValOrErr: Expected<int&>(Dummy)); |
513 | EXPECT_EQ(&Dummy, &Y) << "Reference mangled by cantFail" ; |
514 | } |
515 | |
516 | // Test that cantFail results in a crash if you pass it a failure value. |
517 | #if LLVM_ENABLE_ABI_BREAKING_CHECKS && !defined(NDEBUG) |
518 | TEST(Error, CantFailDeath) { |
519 | EXPECT_DEATH(cantFail(make_error<StringError>("Original error message" , |
520 | inconvertibleErrorCode()), |
521 | "Cantfail call failed" ), |
522 | "Cantfail call failed\n" |
523 | "Original error message" ) |
524 | << "cantFail(Error) did not cause an abort for failure value" ; |
525 | |
526 | EXPECT_DEATH( |
527 | { |
528 | auto IEC = inconvertibleErrorCode(); |
529 | int X = cantFail(Expected<int>(make_error<StringError>("foo" , IEC))); |
530 | (void)X; |
531 | }, |
532 | "Failure value returned from cantFail wrapped call" ) |
533 | << "cantFail(Expected<int>) did not cause an abort for failure value" ; |
534 | } |
535 | #endif |
536 | |
537 | |
538 | // Test Checked Expected<T> in success mode. |
539 | TEST(Error, CheckedExpectedInSuccessMode) { |
540 | Expected<int> A = 7; |
541 | EXPECT_TRUE(!!A) << "Expected with non-error value doesn't convert to 'true'" ; |
542 | // Access is safe in second test, since we checked the error in the first. |
543 | EXPECT_EQ(*A, 7) << "Incorrect Expected non-error value" ; |
544 | } |
545 | |
546 | // Test Expected with reference type. |
547 | TEST(Error, ExpectedWithReferenceType) { |
548 | int A = 7; |
549 | Expected<int&> B = A; |
550 | // 'Check' B. |
551 | (void)!!B; |
552 | int &C = *B; |
553 | EXPECT_EQ(&A, &C) << "Expected failed to propagate reference" ; |
554 | } |
555 | |
556 | // Test Unchecked Expected<T> in success mode. |
557 | // We expect this to blow up the same way Error would. |
558 | // Test runs in debug mode only. |
559 | #if LLVM_ENABLE_ABI_BREAKING_CHECKS |
560 | TEST(Error, UncheckedExpectedInSuccessModeDestruction) { |
561 | EXPECT_DEATH({ Expected<int> A = 7; }, |
562 | "Expected<T> must be checked before access or destruction." ) |
563 | << "Unchecked Expected<T> success value did not cause an abort()." ; |
564 | } |
565 | #endif |
566 | |
567 | // Test Unchecked Expected<T> in success mode. |
568 | // We expect this to blow up the same way Error would. |
569 | // Test runs in debug mode only. |
570 | #if LLVM_ENABLE_ABI_BREAKING_CHECKS |
571 | TEST(Error, UncheckedExpectedInSuccessModeAccess) { |
572 | EXPECT_DEATH( |
573 | { |
574 | const Expected<int> A = 7; |
575 | *A; |
576 | }, |
577 | "Expected<T> must be checked before access or destruction." ) |
578 | << "Unchecked Expected<T> success value did not cause an abort()." ; |
579 | } |
580 | #endif |
581 | |
582 | // Test Unchecked Expected<T> in success mode. |
583 | // We expect this to blow up the same way Error would. |
584 | // Test runs in debug mode only. |
585 | #if LLVM_ENABLE_ABI_BREAKING_CHECKS |
586 | TEST(Error, UncheckedExpectedInSuccessModeAssignment) { |
587 | EXPECT_DEATH( |
588 | { |
589 | Expected<int> A = 7; |
590 | A = 7; |
591 | }, |
592 | "Expected<T> must be checked before access or destruction." ) |
593 | << "Unchecked Expected<T> success value did not cause an abort()." ; |
594 | } |
595 | #endif |
596 | |
597 | // Test Expected<T> in failure mode. |
598 | TEST(Error, ExpectedInFailureMode) { |
599 | Expected<int> A = make_error<CustomError>(Args: 42); |
600 | EXPECT_FALSE(!!A) << "Expected with error value doesn't convert to 'false'" ; |
601 | Error E = A.takeError(); |
602 | EXPECT_TRUE(E.isA<CustomError>()) << "Incorrect Expected error value" ; |
603 | consumeError(Err: std::move(E)); |
604 | } |
605 | |
606 | // Check that an Expected instance with an error value doesn't allow access to |
607 | // operator*. |
608 | // Test runs in debug mode only. |
609 | #if LLVM_ENABLE_ABI_BREAKING_CHECKS |
610 | TEST(Error, AccessExpectedInFailureMode) { |
611 | Expected<int> A = make_error<CustomError>(Args: 42); |
612 | EXPECT_DEATH(*A, "Expected<T> must be checked before access or destruction." ) |
613 | << "Incorrect Expected error value" ; |
614 | consumeError(Err: A.takeError()); |
615 | } |
616 | #endif |
617 | |
618 | // Check that an Expected instance with an error triggers an abort if |
619 | // unhandled. |
620 | // Test runs in debug mode only. |
621 | #if LLVM_ENABLE_ABI_BREAKING_CHECKS |
622 | TEST(Error, UnhandledExpectedInFailureMode) { |
623 | EXPECT_DEATH({ Expected<int> A = make_error<CustomError>(42); }, |
624 | "Expected<T> must be checked before access or destruction." ) |
625 | << "Unchecked Expected<T> failure value did not cause an abort()" ; |
626 | } |
627 | #endif |
628 | |
629 | // Test covariance of Expected. |
630 | TEST(Error, ExpectedCovariance) { |
631 | class B {}; |
632 | class D : public B {}; |
633 | |
634 | Expected<B *> A1(Expected<D *>(nullptr)); |
635 | // Check A1 by converting to bool before assigning to it. |
636 | (void)!!A1; |
637 | A1 = Expected<D *>(nullptr); |
638 | // Check A1 again before destruction. |
639 | (void)!!A1; |
640 | |
641 | Expected<std::unique_ptr<B>> A2(Expected<std::unique_ptr<D>>(nullptr)); |
642 | // Check A2 by converting to bool before assigning to it. |
643 | (void)!!A2; |
644 | A2 = Expected<std::unique_ptr<D>>(nullptr); |
645 | // Check A2 again before destruction. |
646 | (void)!!A2; |
647 | } |
648 | |
649 | // Test that handleExpected just returns success values. |
650 | TEST(Error, HandleExpectedSuccess) { |
651 | auto ValOrErr = |
652 | handleExpected(ValOrErr: Expected<int>(42), |
653 | RecoveryPath: []() { return Expected<int>(43); }); |
654 | EXPECT_TRUE(!!ValOrErr) |
655 | << "handleExpected should have returned a success value here" ; |
656 | EXPECT_EQ(*ValOrErr, 42) |
657 | << "handleExpected should have returned the original success value here" ; |
658 | } |
659 | |
660 | enum FooStrategy { Aggressive, Conservative }; |
661 | |
662 | static Expected<int> foo(FooStrategy S) { |
663 | if (S == Aggressive) |
664 | return make_error<CustomError>(Args: 7); |
665 | return 42; |
666 | } |
667 | |
668 | // Test that handleExpected invokes the error path if errors are not handled. |
669 | TEST(Error, HandleExpectedUnhandledError) { |
670 | // foo(Aggressive) should return a CustomError which should pass through as |
671 | // there is no handler for CustomError. |
672 | auto ValOrErr = |
673 | handleExpected( |
674 | ValOrErr: foo(S: Aggressive), |
675 | RecoveryPath: []() { return foo(S: Conservative); }); |
676 | |
677 | EXPECT_FALSE(!!ValOrErr) |
678 | << "handleExpected should have returned an error here" ; |
679 | auto Err = ValOrErr.takeError(); |
680 | EXPECT_TRUE(Err.isA<CustomError>()) |
681 | << "handleExpected should have returned the CustomError generated by " |
682 | "foo(Aggressive) here" ; |
683 | consumeError(Err: std::move(Err)); |
684 | } |
685 | |
686 | // Test that handleExpected invokes the fallback path if errors are handled. |
687 | TEST(Error, HandleExpectedHandledError) { |
688 | // foo(Aggressive) should return a CustomError which should handle triggering |
689 | // the fallback path. |
690 | auto ValOrErr = |
691 | handleExpected( |
692 | ValOrErr: foo(S: Aggressive), |
693 | RecoveryPath: []() { return foo(S: Conservative); }, |
694 | Handlers: [](const CustomError&) { /* do nothing */ }); |
695 | |
696 | EXPECT_TRUE(!!ValOrErr) |
697 | << "handleExpected should have returned a success value here" ; |
698 | EXPECT_EQ(*ValOrErr, 42) |
699 | << "handleExpected returned the wrong success value" ; |
700 | } |
701 | |
702 | TEST(Error, ErrorCodeConversions) { |
703 | // Round-trip a success value to check that it converts correctly. |
704 | EXPECT_EQ(errorToErrorCode(errorCodeToError(std::error_code())), |
705 | std::error_code()) |
706 | << "std::error_code() should round-trip via Error conversions" ; |
707 | |
708 | // Round-trip an error value to check that it converts correctly. |
709 | EXPECT_EQ(errorToErrorCode(errorCodeToError(errc::invalid_argument)), |
710 | errc::invalid_argument) |
711 | << "std::error_code error value should round-trip via Error " |
712 | "conversions" ; |
713 | |
714 | // Round-trip a success value through ErrorOr/Expected to check that it |
715 | // converts correctly. |
716 | { |
717 | auto Orig = ErrorOr<int>(42); |
718 | auto RoundTripped = |
719 | expectedToErrorOr(E: errorOrToExpected(EO: ErrorOr<int>(42))); |
720 | EXPECT_EQ(*Orig, *RoundTripped) |
721 | << "ErrorOr<T> success value should round-trip via Expected<T> " |
722 | "conversions." ; |
723 | } |
724 | |
725 | // Round-trip a failure value through ErrorOr/Expected to check that it |
726 | // converts correctly. |
727 | { |
728 | auto Orig = ErrorOr<int>(errc::invalid_argument); |
729 | auto RoundTripped = |
730 | expectedToErrorOr( |
731 | E: errorOrToExpected(EO: ErrorOr<int>(errc::invalid_argument))); |
732 | EXPECT_EQ(Orig.getError(), RoundTripped.getError()) |
733 | << "ErrorOr<T> failure value should round-trip via Expected<T> " |
734 | "conversions." ; |
735 | } |
736 | } |
737 | |
738 | // Test that error messages work. |
739 | TEST(Error, ErrorMessage) { |
740 | EXPECT_EQ(toString(Error::success()), "" ); |
741 | |
742 | Error E1 = make_error<CustomError>(Args: 0); |
743 | EXPECT_EQ(toString(std::move(E1)), "CustomError {0}" ); |
744 | |
745 | Error E2 = make_error<CustomError>(Args: 0); |
746 | handleAllErrors(E: std::move(E2), Handlers: [](const CustomError &CE) { |
747 | EXPECT_EQ(CE.message(), "CustomError {0}" ); |
748 | }); |
749 | |
750 | Error E3 = joinErrors(E1: make_error<CustomError>(Args: 0), E2: make_error<CustomError>(Args: 1)); |
751 | EXPECT_EQ(toString(std::move(E3)), "CustomError {0}\n" |
752 | "CustomError {1}" ); |
753 | } |
754 | |
755 | TEST(Error, Stream) { |
756 | { |
757 | Error OK = Error::success(); |
758 | std::string Buf; |
759 | llvm::raw_string_ostream S(Buf); |
760 | S << OK; |
761 | EXPECT_EQ("success" , S.str()); |
762 | consumeError(Err: std::move(OK)); |
763 | } |
764 | { |
765 | Error E1 = make_error<CustomError>(Args: 0); |
766 | std::string Buf; |
767 | llvm::raw_string_ostream S(Buf); |
768 | S << E1; |
769 | EXPECT_EQ("CustomError {0}" , S.str()); |
770 | consumeError(Err: std::move(E1)); |
771 | } |
772 | } |
773 | |
774 | TEST(Error, SucceededMatcher) { |
775 | EXPECT_THAT_ERROR(Error::success(), Succeeded()); |
776 | EXPECT_NONFATAL_FAILURE( |
777 | EXPECT_THAT_ERROR(make_error<CustomError>(0), Succeeded()), |
778 | "Expected: succeeded\n Actual: failed (CustomError {0})" ); |
779 | |
780 | EXPECT_THAT_EXPECTED(Expected<int>(0), Succeeded()); |
781 | EXPECT_NONFATAL_FAILURE( |
782 | EXPECT_THAT_EXPECTED(Expected<int>(make_error<CustomError>(0)), |
783 | Succeeded()), |
784 | "Expected: succeeded\n Actual: failed (CustomError {0})" ); |
785 | int a = 1; |
786 | EXPECT_THAT_EXPECTED(Expected<int &>(a), Succeeded()); |
787 | } |
788 | |
789 | TEST(Error, FailedMatcher) { |
790 | EXPECT_THAT_ERROR(make_error<CustomError>(0), Failed()); |
791 | EXPECT_NONFATAL_FAILURE(EXPECT_THAT_ERROR(Error::success(), Failed()), |
792 | "Expected: failed\n Actual: succeeded" ); |
793 | |
794 | EXPECT_THAT_ERROR(make_error<CustomError>(0), Failed<CustomError>()); |
795 | EXPECT_NONFATAL_FAILURE( |
796 | EXPECT_THAT_ERROR(Error::success(), Failed<CustomError>()), |
797 | "Expected: failed with Error of given type\n Actual: succeeded" ); |
798 | EXPECT_NONFATAL_FAILURE( |
799 | EXPECT_THAT_ERROR(make_error<CustomError>(0), Failed<CustomSubError>()), |
800 | "Error was not of given type" ); |
801 | EXPECT_NONFATAL_FAILURE( |
802 | EXPECT_THAT_ERROR( |
803 | joinErrors(make_error<CustomError>(0), make_error<CustomError>(1)), |
804 | Failed<CustomError>()), |
805 | "multiple errors" ); |
806 | |
807 | EXPECT_THAT_ERROR( |
808 | make_error<CustomError>(0), |
809 | Failed<CustomError>(testing::Property(&CustomError::getInfo, 0))); |
810 | EXPECT_NONFATAL_FAILURE( |
811 | EXPECT_THAT_ERROR( |
812 | make_error<CustomError>(0), |
813 | Failed<CustomError>(testing::Property(&CustomError::getInfo, 1))), |
814 | "Expected: failed with Error of given type and the error is an object " |
815 | "whose given property is equal to 1\n" |
816 | " Actual: failed (CustomError {0})" ); |
817 | EXPECT_THAT_ERROR(make_error<CustomError>(0), Failed<ErrorInfoBase>()); |
818 | |
819 | EXPECT_THAT_EXPECTED(Expected<int>(make_error<CustomError>(0)), Failed()); |
820 | EXPECT_NONFATAL_FAILURE( |
821 | EXPECT_THAT_EXPECTED(Expected<int>(0), Failed()), |
822 | "Expected: failed\n Actual: succeeded with value 0" ); |
823 | EXPECT_THAT_EXPECTED(Expected<int &>(make_error<CustomError>(0)), Failed()); |
824 | } |
825 | |
826 | TEST(Error, HasValueMatcher) { |
827 | EXPECT_THAT_EXPECTED(Expected<int>(0), HasValue(0)); |
828 | EXPECT_NONFATAL_FAILURE( |
829 | EXPECT_THAT_EXPECTED(Expected<int>(make_error<CustomError>(0)), |
830 | HasValue(0)), |
831 | "Expected: succeeded with value (is equal to 0)\n" |
832 | " Actual: failed (CustomError {0})" ); |
833 | EXPECT_NONFATAL_FAILURE( |
834 | EXPECT_THAT_EXPECTED(Expected<int>(1), HasValue(0)), |
835 | "Expected: succeeded with value (is equal to 0)\n" |
836 | " Actual: succeeded with value 1, (isn't equal to 0)" ); |
837 | |
838 | int a = 1; |
839 | EXPECT_THAT_EXPECTED(Expected<int &>(a), HasValue(testing::Eq(1))); |
840 | |
841 | EXPECT_THAT_EXPECTED(Expected<int>(1), HasValue(testing::Gt(0))); |
842 | EXPECT_NONFATAL_FAILURE( |
843 | EXPECT_THAT_EXPECTED(Expected<int>(0), HasValue(testing::Gt(1))), |
844 | "Expected: succeeded with value (is > 1)\n" |
845 | " Actual: succeeded with value 0, (isn't > 1)" ); |
846 | EXPECT_NONFATAL_FAILURE( |
847 | EXPECT_THAT_EXPECTED(Expected<int>(make_error<CustomError>(0)), |
848 | HasValue(testing::Gt(1))), |
849 | "Expected: succeeded with value (is > 1)\n" |
850 | " Actual: failed (CustomError {0})" ); |
851 | } |
852 | |
853 | TEST(Error, FailedWithMessageMatcher) { |
854 | EXPECT_THAT_EXPECTED(Expected<int>(make_error<CustomError>(0)), |
855 | FailedWithMessage("CustomError {0}" )); |
856 | |
857 | EXPECT_NONFATAL_FAILURE( |
858 | EXPECT_THAT_EXPECTED(Expected<int>(make_error<CustomError>(1)), |
859 | FailedWithMessage("CustomError {0}" )), |
860 | "Expected: failed with Error whose message has 1 element that is equal " |
861 | "to \"CustomError {0}\"\n" |
862 | " Actual: failed (CustomError {1})" ); |
863 | |
864 | EXPECT_NONFATAL_FAILURE( |
865 | EXPECT_THAT_EXPECTED(Expected<int>(0), |
866 | FailedWithMessage("CustomError {0}" )), |
867 | "Expected: failed with Error whose message has 1 element that is equal " |
868 | "to \"CustomError {0}\"\n" |
869 | " Actual: succeeded with value 0" ); |
870 | |
871 | EXPECT_NONFATAL_FAILURE( |
872 | EXPECT_THAT_EXPECTED(Expected<int>(make_error<CustomError>(0)), |
873 | FailedWithMessage("CustomError {0}" , "CustomError {0}" )), |
874 | "Expected: failed with Error whose message has 2 elements where\n" |
875 | "element #0 is equal to \"CustomError {0}\",\n" |
876 | "element #1 is equal to \"CustomError {0}\"\n" |
877 | " Actual: failed (CustomError {0}), which has 1 element" ); |
878 | |
879 | EXPECT_NONFATAL_FAILURE( |
880 | EXPECT_THAT_EXPECTED( |
881 | Expected<int>(joinErrors(make_error<CustomError>(0), |
882 | make_error<CustomError>(0))), |
883 | FailedWithMessage("CustomError {0}" )), |
884 | "Expected: failed with Error whose message has 1 element that is equal " |
885 | "to \"CustomError {0}\"\n" |
886 | " Actual: failed (CustomError {0}; CustomError {0}), which has 2 elements" ); |
887 | |
888 | EXPECT_THAT_ERROR( |
889 | joinErrors(make_error<CustomError>(0), make_error<CustomError>(0)), |
890 | FailedWithMessageArray(testing::SizeIs(2))); |
891 | } |
892 | |
893 | TEST(Error, C_API) { |
894 | EXPECT_THAT_ERROR(unwrap(wrap(Error::success())), Succeeded()) |
895 | << "Failed to round-trip Error success value via C API" ; |
896 | EXPECT_THAT_ERROR(unwrap(wrap(make_error<CustomError>(0))), |
897 | Failed<CustomError>()) |
898 | << "Failed to round-trip Error failure value via C API" ; |
899 | |
900 | auto Err = |
901 | wrap(Err: make_error<StringError>(Args: "test message" , Args: inconvertibleErrorCode())); |
902 | EXPECT_EQ(LLVMGetErrorTypeId(Err), LLVMGetStringErrorTypeId()) |
903 | << "Failed to match error type ids via C API" ; |
904 | char *ErrMsg = LLVMGetErrorMessage(Err); |
905 | EXPECT_STREQ(ErrMsg, "test message" ) |
906 | << "Failed to roundtrip StringError error message via C API" ; |
907 | LLVMDisposeErrorMessage(ErrMsg); |
908 | |
909 | bool GotCSE = false; |
910 | bool GotCE = false; |
911 | handleAllErrors( |
912 | E: unwrap(ErrRef: wrap(Err: joinErrors(E1: make_error<CustomSubError>(Args: 42, Args: 7), |
913 | E2: make_error<CustomError>(Args: 42)))), |
914 | Handlers: [&](CustomSubError &CSE) { |
915 | GotCSE = true; |
916 | }, |
917 | Handlers: [&](CustomError &CE) { |
918 | GotCE = true; |
919 | }); |
920 | EXPECT_TRUE(GotCSE) << "Failed to round-trip ErrorList via C API" ; |
921 | EXPECT_TRUE(GotCE) << "Failed to round-trip ErrorList via C API" ; |
922 | } |
923 | |
924 | TEST(Error, FileErrorTest) { |
925 | #if !defined(NDEBUG) && GTEST_HAS_DEATH_TEST |
926 | EXPECT_DEATH( |
927 | { |
928 | Error S = Error::success(); |
929 | consumeError(createFileError("file.bin" , std::move(S))); |
930 | }, |
931 | "" ); |
932 | #endif |
933 | // Not allowed, would fail at compile-time |
934 | //consumeError(createFileError("file.bin", ErrorSuccess())); |
935 | |
936 | Error E1 = make_error<CustomError>(Args: 1); |
937 | Error FE1 = createFileError(F: "file.bin" , E: std::move(E1)); |
938 | EXPECT_EQ(toString(std::move(FE1)), "'file.bin': CustomError {1}" ); |
939 | |
940 | Error E2 = make_error<CustomError>(Args: 2); |
941 | Error FE2 = createFileError(F: "file.bin" , E: std::move(E2)); |
942 | handleAllErrors(E: std::move(FE2), Handlers: [](const FileError &F) { |
943 | EXPECT_EQ(F.message(), "'file.bin': CustomError {2}" ); |
944 | }); |
945 | |
946 | Error E3 = make_error<CustomError>(Args: 3); |
947 | Error FE3 = createFileError(F: "file.bin" , E: std::move(E3)); |
948 | auto E31 = handleErrors(E: std::move(FE3), Hs: [](std::unique_ptr<FileError> F) { |
949 | return F->takeError(); |
950 | }); |
951 | handleAllErrors(E: std::move(E31), Handlers: [](const CustomError &C) { |
952 | EXPECT_EQ(C.message(), "CustomError {3}" ); |
953 | }); |
954 | |
955 | Error FE4 = |
956 | joinErrors(E1: createFileError(F: "file.bin" , E: make_error<CustomError>(Args: 41)), |
957 | E2: createFileError(F: "file2.bin" , E: make_error<CustomError>(Args: 42))); |
958 | EXPECT_EQ(toString(std::move(FE4)), "'file.bin': CustomError {41}\n" |
959 | "'file2.bin': CustomError {42}" ); |
960 | |
961 | Error FE5 = createFileError(F: "" , E: make_error<CustomError>(Args: 5)); |
962 | EXPECT_EQ(toString(std::move(FE5)), "'': CustomError {5}" ); |
963 | |
964 | Error FE6 = createFileError(F: "unused" , E: make_error<CustomError>(Args: 6)); |
965 | handleAllErrors(E: std::move(FE6), Handlers: [](std::unique_ptr<FileError> F) { |
966 | EXPECT_EQ(F->messageWithoutFileInfo(), "CustomError {6}" ); |
967 | }); |
968 | } |
969 | |
970 | TEST(Error, FileErrorErrorCode) { |
971 | for (std::error_code EC : { |
972 | make_error_code(e: std::errc::not_supported), |
973 | make_error_code(e: std::errc::invalid_argument), |
974 | make_error_code(e: std::errc::no_such_file_or_directory), |
975 | }) { |
976 | EXPECT_EQ(EC, errorToErrorCode( |
977 | createFileError("file.bin" , EC))); |
978 | EXPECT_EQ(EC, errorToErrorCode( |
979 | createFileError("file.bin" , /*Line=*/5, EC))); |
980 | EXPECT_EQ(EC, errorToErrorCode( |
981 | createFileError("file.bin" , errorCodeToError(EC)))); |
982 | EXPECT_EQ(EC, errorToErrorCode( |
983 | createFileError("file.bin" , /*Line=*/5, errorCodeToError(EC)))); |
984 | } |
985 | |
986 | // inconvertibleErrorCode() should be wrapped to avoid a fatal error. |
987 | EXPECT_EQ( |
988 | "A file error occurred." , |
989 | errorToErrorCode(createFileError("file.bin" , inconvertibleErrorCode())) |
990 | .message()); |
991 | EXPECT_EQ( |
992 | "A file error occurred." , |
993 | errorToErrorCode(createFileError("file.bin" , /*Line=*/5, inconvertibleErrorCode())) |
994 | .message()); |
995 | } |
996 | |
997 | enum class test_error_code { |
998 | unspecified = 1, |
999 | error_1, |
1000 | error_2, |
1001 | }; |
1002 | |
1003 | } // end anon namespace |
1004 | |
1005 | namespace std { |
1006 | template <> |
1007 | struct is_error_code_enum<test_error_code> : std::true_type {}; |
1008 | } // namespace std |
1009 | |
1010 | namespace { |
1011 | |
1012 | const std::error_category &TErrorCategory(); |
1013 | |
1014 | inline std::error_code make_error_code(test_error_code E) { |
1015 | return std::error_code(static_cast<int>(E), TErrorCategory()); |
1016 | } |
1017 | |
1018 | class TestDebugError : public ErrorInfo<TestDebugError, StringError> { |
1019 | public: |
1020 | using ErrorInfo<TestDebugError, StringError >::ErrorInfo; // inherit constructors |
1021 | TestDebugError(const Twine &S) : ErrorInfo(S, test_error_code::unspecified) {} |
1022 | static char ID; |
1023 | }; |
1024 | |
1025 | class TestErrorCategory : public std::error_category { |
1026 | public: |
1027 | const char *name() const noexcept override { return "error" ; } |
1028 | std::string message(int Condition) const override { |
1029 | switch (static_cast<test_error_code>(Condition)) { |
1030 | case test_error_code::unspecified: |
1031 | return "An unknown error has occurred." ; |
1032 | case test_error_code::error_1: |
1033 | return "Error 1." ; |
1034 | case test_error_code::error_2: |
1035 | return "Error 2." ; |
1036 | } |
1037 | llvm_unreachable("Unrecognized test_error_code" ); |
1038 | } |
1039 | }; |
1040 | |
1041 | const std::error_category &TErrorCategory() { |
1042 | static TestErrorCategory TestErrCategory; |
1043 | return TestErrCategory; |
1044 | } |
1045 | |
1046 | char TestDebugError::ID; |
1047 | |
1048 | TEST(Error, SubtypeStringErrorTest) { |
1049 | auto E1 = make_error<TestDebugError>(Args: test_error_code::error_1); |
1050 | EXPECT_EQ(toString(std::move(E1)), "Error 1." ); |
1051 | |
1052 | auto E2 = make_error<TestDebugError>(Args: test_error_code::error_1, |
1053 | Args: "Detailed information" ); |
1054 | EXPECT_EQ(toString(std::move(E2)), "Error 1. Detailed information" ); |
1055 | |
1056 | auto E3 = make_error<TestDebugError>(Args: test_error_code::error_2); |
1057 | handleAllErrors(E: std::move(E3), Handlers: [](const TestDebugError &F) { |
1058 | EXPECT_EQ(F.message(), "Error 2." ); |
1059 | }); |
1060 | |
1061 | auto E4 = joinErrors(E1: make_error<TestDebugError>(Args: test_error_code::error_1, |
1062 | Args: "Detailed information" ), |
1063 | E2: make_error<TestDebugError>(Args: test_error_code::error_2)); |
1064 | EXPECT_EQ(toString(std::move(E4)), "Error 1. Detailed information\n" |
1065 | "Error 2." ); |
1066 | } |
1067 | |
1068 | static Error createAnyError() { |
1069 | return errorCodeToError(EC: test_error_code::unspecified); |
1070 | } |
1071 | |
1072 | struct MoveOnlyBox { |
1073 | std::optional<int> Box; |
1074 | |
1075 | explicit MoveOnlyBox(int I) : Box(I) {} |
1076 | MoveOnlyBox() = default; |
1077 | MoveOnlyBox(MoveOnlyBox &&) = default; |
1078 | MoveOnlyBox &operator=(MoveOnlyBox &&) = default; |
1079 | |
1080 | MoveOnlyBox(const MoveOnlyBox &) = delete; |
1081 | MoveOnlyBox &operator=(const MoveOnlyBox &) = delete; |
1082 | |
1083 | bool operator==(const MoveOnlyBox &RHS) const { |
1084 | if (bool(Box) != bool(RHS.Box)) |
1085 | return false; |
1086 | return Box ? *Box == *RHS.Box : false; |
1087 | } |
1088 | }; |
1089 | |
1090 | TEST(Error, moveInto) { |
1091 | // Use MoveOnlyBox as the T in Expected<T>. |
1092 | auto make = [](int I) -> Expected<MoveOnlyBox> { return MoveOnlyBox(I); }; |
1093 | auto makeFailure = []() -> Expected<MoveOnlyBox> { return createAnyError(); }; |
1094 | |
1095 | { |
1096 | MoveOnlyBox V; |
1097 | |
1098 | // Failure with no prior value. |
1099 | EXPECT_THAT_ERROR(makeFailure().moveInto(V), Failed()); |
1100 | EXPECT_EQ(std::nullopt, V.Box); |
1101 | |
1102 | // Success with no prior value. |
1103 | EXPECT_THAT_ERROR(make(5).moveInto(V), Succeeded()); |
1104 | EXPECT_EQ(5, V.Box); |
1105 | |
1106 | // Success with an existing value. |
1107 | EXPECT_THAT_ERROR(make(7).moveInto(V), Succeeded()); |
1108 | EXPECT_EQ(7, V.Box); |
1109 | |
1110 | // Failure with an existing value. Might be nice to assign a |
1111 | // default-constructed value in this case, but for now it's being left |
1112 | // alone. |
1113 | EXPECT_THAT_ERROR(makeFailure().moveInto(V), Failed()); |
1114 | EXPECT_EQ(7, V.Box); |
1115 | } |
1116 | |
1117 | // Check that this works with optionals too. |
1118 | { |
1119 | // Same cases as above. |
1120 | std::optional<MoveOnlyBox> MaybeV; |
1121 | EXPECT_THAT_ERROR(makeFailure().moveInto(MaybeV), Failed()); |
1122 | EXPECT_EQ(std::nullopt, MaybeV); |
1123 | |
1124 | EXPECT_THAT_ERROR(make(5).moveInto(MaybeV), Succeeded()); |
1125 | EXPECT_EQ(MoveOnlyBox(5), MaybeV); |
1126 | |
1127 | EXPECT_THAT_ERROR(make(7).moveInto(MaybeV), Succeeded()); |
1128 | EXPECT_EQ(MoveOnlyBox(7), MaybeV); |
1129 | |
1130 | EXPECT_THAT_ERROR(makeFailure().moveInto(MaybeV), Failed()); |
1131 | EXPECT_EQ(MoveOnlyBox(7), MaybeV); |
1132 | } |
1133 | } |
1134 | |
1135 | TEST(Error, FatalBadAllocErrorHandlersInteraction) { |
1136 | auto ErrorHandler = [](void *Data, const char *, bool) {}; |
1137 | install_fatal_error_handler(handler: ErrorHandler, user_data: nullptr); |
1138 | // The following call should not crash; previously, a bug in |
1139 | // install_bad_alloc_error_handler asserted that no fatal-error handler is |
1140 | // installed already. |
1141 | install_bad_alloc_error_handler(handler: ErrorHandler, user_data: nullptr); |
1142 | |
1143 | // Don't interfere with other tests. |
1144 | remove_fatal_error_handler(); |
1145 | remove_bad_alloc_error_handler(); |
1146 | } |
1147 | |
1148 | TEST(Error, BadAllocFatalErrorHandlersInteraction) { |
1149 | auto ErrorHandler = [](void *Data, const char *, bool) {}; |
1150 | install_bad_alloc_error_handler(handler: ErrorHandler, user_data: nullptr); |
1151 | // The following call should not crash; related to |
1152 | // FatalBadAllocErrorHandlersInteraction: Ensure that the error does not occur |
1153 | // in the other direction. |
1154 | install_fatal_error_handler(handler: ErrorHandler, user_data: nullptr); |
1155 | |
1156 | // Don't interfere with other tests. |
1157 | remove_fatal_error_handler(); |
1158 | remove_bad_alloc_error_handler(); |
1159 | } |
1160 | |
1161 | } // namespace |
1162 | |