466 lines · cpp
1//===- ErrorTest.cpp ------------------------------------------------------===//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-exception6//7//===----------------------------------------------------------------------===//8//9// This file is a part of the ORC runtime.10//11// Note:12// This unit test was adapted from13// llvm/unittests/Support/ErrorTest.cpp14//15//===----------------------------------------------------------------------===//16 17#include "orc-rt/Error.h"18#include "gtest/gtest.h"19 20using namespace orc_rt;21 22namespace {23 24class CustomError : public RTTIExtends<CustomError, ErrorInfoBase> {25public:26 CustomError(int Info) : Info(Info) {}27 std::string toString() const override {28 return "CustomError (" + std::to_string(Info) + ")";29 }30 int getInfo() const { return Info; }31 32protected:33 int Info;34};35 36class CustomSubError : public RTTIExtends<CustomSubError, CustomError> {37public:38 CustomSubError(int Info, std::string ExtraInfo)39 : RTTIExtends<CustomSubError, CustomError>(Info),40 ExtraInfo(std::move(ExtraInfo)) {}41 42 std::string toString() const override {43 return "CustomSubError (" + std::to_string(Info) + ", " + ExtraInfo + ")";44 }45 const std::string &getExtraInfo() const { return ExtraInfo; }46 47protected:48 std::string ExtraInfo;49};50 51static Error handleCustomError(const CustomError &CE) {52 return Error::success();53}54 55static void handleCustomErrorVoid(const CustomError &CE) {}56 57static Error handleCustomErrorUP(std::unique_ptr<CustomError> CE) {58 return Error::success();59}60 61static void handleCustomErrorUPVoid(std::unique_ptr<CustomError> CE) {}62 63} // end anonymous namespace64 65// Test that a checked success value doesn't cause any issues.66TEST(ErrorTest, CheckedSuccess) {67 Error E = Error::success();68 EXPECT_FALSE(E) << "Unexpected error while testing Error 'Success'";69}70 71// Check that a consumed success value doesn't cause any issues.72TEST(ErrorTest, ConsumeSuccess) { consumeError(Error::success()); }73 74TEST(ErrorTest, ConsumeError) {75 Error E = make_error<CustomError>(42);76 if (E) {77 consumeError(std::move(E));78 } else79 ADD_FAILURE() << "Error failure value should convert to true";80}81 82// Test that unchecked success values cause an abort.83TEST(ErrorTest, UncheckedSuccess) {84 EXPECT_DEATH(85 { Error E = Error::success(); },86 "Error must be checked prior to destruction")87 << "Unchecked Error Succes value did not cause abort()";88}89 90// Test that a checked but unhandled error causes an abort.91TEST(ErrorTest, CheckedButUnhandledError) {92 auto DropUnhandledError = []() {93 Error E = make_error<CustomError>(42);94 (void)!E;95 };96 EXPECT_DEATH(DropUnhandledError(),97 "Error must be checked prior to destruction")98 << "Unhandled Error failure value did not cause an abort()";99}100 101// Check that we can handle a custom error.102TEST(ErrorTest, HandleCustomError) {103 int CaughtErrorInfo = 0;104 handleAllErrors(make_error<CustomError>(42), [&](const CustomError &CE) {105 CaughtErrorInfo = CE.getInfo();106 });107 108 EXPECT_EQ(CaughtErrorInfo, 42) << "Wrong result from CustomError handler";109}110 111// Check that handler type deduction also works for handlers112// of the following types:113// void (const Err&)114// Error (const Err&) mutable115// void (const Err&) mutable116// Error (Err&)117// void (Err&)118// Error (Err&) mutable119// void (Err&) mutable120// Error (unique_ptr<Err>)121// void (unique_ptr<Err>)122// Error (unique_ptr<Err>) mutable123// void (unique_ptr<Err>) mutable124TEST(ErrorTest, HandlerTypeDeduction) {125 126 handleAllErrors(make_error<CustomError>(42), [](const CustomError &CE) {});127 128 handleAllErrors(129 make_error<CustomError>(42),130 [](const CustomError &CE) mutable -> Error { return Error::success(); });131 132 handleAllErrors(make_error<CustomError>(42),133 [](const CustomError &CE) mutable {});134 135 handleAllErrors(make_error<CustomError>(42),136 [](CustomError &CE) -> Error { return Error::success(); });137 138 handleAllErrors(make_error<CustomError>(42), [](CustomError &CE) {});139 140 handleAllErrors(141 make_error<CustomError>(42),142 [](CustomError &CE) mutable -> Error { return Error::success(); });143 144 handleAllErrors(make_error<CustomError>(42), [](CustomError &CE) mutable {});145 146 handleAllErrors(make_error<CustomError>(42),147 [](std::unique_ptr<CustomError> CE) -> Error {148 return Error::success();149 });150 151 handleAllErrors(make_error<CustomError>(42),152 [](std::unique_ptr<CustomError> CE) {});153 154 handleAllErrors(make_error<CustomError>(42),155 [](std::unique_ptr<CustomError> CE) mutable -> Error {156 return Error::success();157 });158 159 handleAllErrors(make_error<CustomError>(42),160 [](std::unique_ptr<CustomError> CE) mutable {});161 162 // Check that named handlers of type 'Error (const Err&)' work.163 handleAllErrors(make_error<CustomError>(42), handleCustomError);164 165 // Check that named handlers of type 'void (const Err&)' work.166 handleAllErrors(make_error<CustomError>(42), handleCustomErrorVoid);167 168 // Check that named handlers of type 'Error (std::unique_ptr<Err>)' work.169 handleAllErrors(make_error<CustomError>(42), handleCustomErrorUP);170 171 // Check that named handlers of type 'Error (std::unique_ptr<Err>)' work.172 handleAllErrors(make_error<CustomError>(42), handleCustomErrorUPVoid);173}174 175// Test that we can handle errors with custom base classes.176TEST(ErrorTest, HandleCustomErrorWithCustomBaseClass) {177 int CaughtErrorInfo = 0;178 std::string CaughtErrorExtraInfo;179 handleAllErrors(make_error<CustomSubError>(42, "foo"),180 [&](const CustomSubError &SE) {181 CaughtErrorInfo = SE.getInfo();182 CaughtErrorExtraInfo = SE.getExtraInfo();183 });184 185 EXPECT_EQ(CaughtErrorInfo, 42) << "Wrong result from CustomSubError handler";186 EXPECT_EQ(CaughtErrorExtraInfo, "foo")187 << "Wrong result from CustomSubError handler";188}189 190// Check that we trigger only the first handler that applies.191TEST(ErrorTest, FirstHandlerOnly) {192 int DummyInfo = 0;193 int CaughtErrorInfo = 0;194 std::string CaughtErrorExtraInfo;195 196 handleAllErrors(197 make_error<CustomSubError>(42, "foo"),198 [&](const CustomSubError &SE) {199 CaughtErrorInfo = SE.getInfo();200 CaughtErrorExtraInfo = SE.getExtraInfo();201 },202 [&](const CustomError &CE) { DummyInfo = CE.getInfo(); });203 204 EXPECT_EQ(CaughtErrorInfo, 42) << "Activated the wrong Error handler(s)";205 EXPECT_EQ(CaughtErrorExtraInfo, "foo")206 << "Activated the wrong Error handler(s)";207 EXPECT_EQ(DummyInfo, 0) << "Activated the wrong Error handler(s)";208}209 210// Check that general handlers shadow specific ones.211TEST(ErrorTest, HandlerShadowing) {212 int CaughtErrorInfo = 0;213 int DummyInfo = 0;214 std::string DummyExtraInfo;215 216 handleAllErrors(217 make_error<CustomSubError>(42, "foo"),218 [&](const CustomError &CE) { CaughtErrorInfo = CE.getInfo(); },219 [&](const CustomSubError &SE) {220 DummyInfo = SE.getInfo();221 DummyExtraInfo = SE.getExtraInfo();222 });223 224 EXPECT_EQ(CaughtErrorInfo, 42)225 << "General Error handler did not shadow specific handler";226 EXPECT_EQ(DummyInfo, 0)227 << "General Error handler did not shadow specific handler";228 EXPECT_EQ(DummyExtraInfo, "")229 << "General Error handler did not shadow specific handler";230}231 232// ErrorAsOutParameter tester.233static void errAsOutParamHelper(Error &Err) {234 ErrorAsOutParameter ErrAsOutParam(&Err);235 // Verify that checked flag is raised - assignment should not crash.236 Err = Error::success();237 // Raise the checked bit manually - caller should still have to test the238 // error.239 (void)!!Err;240}241 242// Test that ErrorAsOutParameter sets the checked flag on construction.243TEST(ErrorTest, ErrorAsOutParameterChecked) {244 Error E = Error::success();245 errAsOutParamHelper(E);246 (void)!!E;247}248 249// Test that ErrorAsOutParameter clears the checked flag on destruction.250TEST(ErrorTest, ErrorAsOutParameterUnchecked) {251 EXPECT_DEATH(252 {253 Error E = Error::success();254 errAsOutParamHelper(E);255 },256 "Error must be checked prior to destruction")257 << "ErrorAsOutParameter did not clear the checked flag on destruction.";258}259 260// Test that we can construct an ErrorAsOutParameter from an Error&.261TEST(ErrorTest, ErrorAsOutParameterRefConstructor) {262 Error E = Error::success();263 {264 ErrorAsOutParameter _(E); // construct with Error&.265 }266 (void)!!E;267}268 269// Check 'Error::isA<T>' method handling.270TEST(ErrorTest, IsAHandling) {271 // Check 'isA' handling.272 Error E = make_error<CustomError>(42);273 Error F = make_error<CustomSubError>(42, "foo");274 Error G = Error::success();275 276 EXPECT_TRUE(E.isA<CustomError>());277 EXPECT_FALSE(E.isA<CustomSubError>());278 EXPECT_TRUE(F.isA<CustomError>());279 EXPECT_TRUE(F.isA<CustomSubError>());280 EXPECT_FALSE(G.isA<CustomError>());281 282 consumeError(std::move(E));283 consumeError(std::move(F));284 consumeError(std::move(G));285}286 287TEST(ErrorTest, StringError) {288 auto E = make_error<StringError>("foo");289 if (E.isA<StringError>())290 EXPECT_EQ(toString(std::move(E)), "foo") << "Unexpected StringError value";291 else292 ADD_FAILURE() << "Expected StringError value";293}294 295// Test Checked Expected<T> in success mode.296TEST(ErrorTest, CheckedExpectedInSuccessMode) {297 Expected<int> A = 7;298 EXPECT_TRUE(!!A) << "Expected with non-error value doesn't convert to 'true'";299 // Access is safe in second test, since we checked the error in the first.300 EXPECT_EQ(*A, 7) << "Incorrect Expected non-error value";301}302 303// Test Expected with reference type.304TEST(ErrorTest, ExpectedWithReferenceType) {305 int A = 7;306 Expected<int &> B = A;307 // 'Check' B.308 (void)!!B;309 int &C = *B;310 EXPECT_EQ(&A, &C) << "Expected failed to propagate reference";311}312 313// Test Unchecked Expected<T> in success mode.314// We expect this to blow up the same way Error would.315// Test runs in debug mode only.316TEST(ErrorTest, UncheckedExpectedInSuccessModeDestruction) {317 EXPECT_DEATH(318 { Expected<int> A = 7; },319 "Expected<T> must be checked before access or destruction.")320 << "Unchecekd Expected<T> success value did not cause an abort().";321}322 323// Test Unchecked Expected<T> in success mode.324// We expect this to blow up the same way Error would.325// Test runs in debug mode only.326TEST(ErrorTest, UncheckedExpectedInSuccessModeAccess) {327 EXPECT_DEATH(328 {329 Expected<int> A = 7;330 *A;331 },332 "Expected<T> must be checked before access or destruction.")333 << "Unchecekd Expected<T> success value did not cause an abort().";334}335 336// Test Unchecked Expected<T> in success mode.337// We expect this to blow up the same way Error would.338// Test runs in debug mode only.339TEST(ErrorTest, UncheckedExpectedInSuccessModeAssignment) {340 EXPECT_DEATH(341 {342 Expected<int> A = 7;343 A = 7;344 },345 "Expected<T> must be checked before access or destruction.")346 << "Unchecekd Expected<T> success value did not cause an abort().";347}348 349// Test Expected<T> in failure mode.350TEST(ErrorTest, ExpectedInFailureMode) {351 Expected<int> A = make_error<CustomError>(42);352 EXPECT_FALSE(!!A) << "Expected with error value doesn't convert to 'false'";353 Error E = A.takeError();354 EXPECT_TRUE(E.isA<CustomError>()) << "Incorrect Expected error value";355 consumeError(std::move(E));356}357 358// Check that an Expected instance with an error value doesn't allow access to359// operator*.360// Test runs in debug mode only.361TEST(ErrorTest, AccessExpectedInFailureMode) {362 Expected<int> A = make_error<CustomError>(42);363 EXPECT_DEATH(*A, "Expected<T> must be checked before access or destruction.")364 << "Incorrect Expected error value";365 consumeError(A.takeError());366}367 368// Check that an Expected instance with an error triggers an abort if369// unhandled.370// Test runs in debug mode only.371TEST(ErrorTest, UnhandledExpectedInFailureMode) {372 EXPECT_DEATH(373 { Expected<int> A = make_error<CustomError>(42); },374 "Expected<T> must be checked before access or destruction.")375 << "Unchecked Expected<T> failure value did not cause an abort()";376}377 378// Test covariance of Expected.379TEST(ErrorTest, ExpectedCovariance) {380 class B {};381 class D : public B {};382 383 Expected<B *> A1(Expected<D *>(nullptr));384 // Check A1 by converting to bool before assigning to it.385 (void)!!A1;386 A1 = Expected<D *>(nullptr);387 // Check A1 again before destruction.388 (void)!!A1;389 390 Expected<std::unique_ptr<B>> A2(Expected<std::unique_ptr<D>>(nullptr));391 // Check A2 by converting to bool before assigning to it.392 (void)!!A2;393 A2 = Expected<std::unique_ptr<D>>(nullptr);394 // Check A2 again before destruction.395 (void)!!A2;396}397 398// Test that Expected<Error> works as expected.399TEST(ErrorTest, ExpectedError) {400 {401 // Test success-success case.402 Expected<Error> E(Error::success(), ForceExpectedSuccessValue());403 EXPECT_TRUE(!!E);404 cantFail(E.takeError());405 auto Err = std::move(*E);406 EXPECT_FALSE(!!Err);407 }408 409 {410 // Test "failure" success case.411 Expected<Error> E(make_error<StringError>("foo"),412 ForceExpectedSuccessValue());413 EXPECT_TRUE(!!E);414 cantFail(E.takeError());415 auto Err = std::move(*E);416 EXPECT_TRUE(!!Err);417 EXPECT_EQ(toString(std::move(Err)), "foo");418 }419}420 421// Test that Expected<Expected<T>> works as expected.422TEST(ErrorTest, ExpectedExpected) {423 {424 // Test success-success case.425 Expected<Expected<int>> E(Expected<int>(42), ForceExpectedSuccessValue());426 EXPECT_TRUE(!!E);427 cantFail(E.takeError());428 auto EI = std::move(*E);429 EXPECT_TRUE(!!EI);430 cantFail(EI.takeError());431 EXPECT_EQ(*EI, 42);432 }433 434 {435 // Test "failure" success case.436 Expected<Expected<int>> E(Expected<int>(make_error<StringError>("foo")),437 ForceExpectedSuccessValue());438 EXPECT_TRUE(!!E);439 cantFail(E.takeError());440 auto EI = std::move(*E);441 EXPECT_FALSE(!!EI);442 EXPECT_EQ(toString(EI.takeError()), "foo");443 }444}445 446// Test that the ExitOnError utility works as expected.447TEST(ErrorTest, CantFailSuccess) {448 cantFail(Error::success());449 450 int X = cantFail(Expected<int>(42));451 EXPECT_EQ(X, 42) << "Expected value modified by cantFail";452 453 int Dummy = 42;454 int &Y = cantFail(Expected<int &>(Dummy));455 EXPECT_EQ(&Dummy, &Y) << "Reference mangled by cantFail";456}457 458// Test that cantFail results in a crash if you pass it a failure value.459TEST(ErrorTest, CantFailDeath) {460 EXPECT_DEATH(cantFail(make_error<StringError>("foo")), "")461 << "cantFail(Error) did not cause an abort for failure value";462 463 EXPECT_DEATH(cantFail(Expected<int>(make_error<StringError>("foo"))), "")464 << "cantFail(Expected<int>) did not cause an abort for failure value";465}466