brintos

brintos / llvm-project-archived public Read only

0
0
Text · 14.6 KiB · d80ada9 Raw
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