|  | //===----- unittests/ErrorTest.cpp - Error.h tests ------------------------===// | 
|  | // | 
|  | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. | 
|  | // See https://llvm.org/LICENSE.txt for license information. | 
|  | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception | 
|  | // | 
|  | //===----------------------------------------------------------------------===// | 
|  |  | 
|  | #include "llvm/Support/Error.h" | 
|  | #include "llvm-c/Error.h" | 
|  |  | 
|  | #include "llvm/ADT/Twine.h" | 
|  | #include "llvm/Support/Errc.h" | 
|  | #include "llvm/Support/ErrorHandling.h" | 
|  | #include "llvm/Testing/Support/Error.h" | 
|  | #include "gmock/gmock.h" | 
|  | #include "gtest/gtest-spi.h" | 
|  | #include "gtest/gtest.h" | 
|  | #include <memory> | 
|  |  | 
|  | using namespace llvm; | 
|  |  | 
|  | namespace { | 
|  |  | 
|  | // Custom error class with a default base class and some random 'info' attached. | 
|  | class CustomError : public ErrorInfo<CustomError> { | 
|  | public: | 
|  | // Create an error with some info attached. | 
|  | CustomError(int Info) : Info(Info) {} | 
|  |  | 
|  | // Get the info attached to this error. | 
|  | int getInfo() const { return Info; } | 
|  |  | 
|  | // Log this error to a stream. | 
|  | void log(raw_ostream &OS) const override { | 
|  | OS << "CustomError {" << getInfo() << "}"; | 
|  | } | 
|  |  | 
|  | std::error_code convertToErrorCode() const override { | 
|  | llvm_unreachable("CustomError doesn't support ECError conversion"); | 
|  | } | 
|  |  | 
|  | // Used by ErrorInfo::classID. | 
|  | static char ID; | 
|  |  | 
|  | protected: | 
|  | // This error is subclassed below, but we can't use inheriting constructors | 
|  | // yet, so we can't propagate the constructors through ErrorInfo. Instead | 
|  | // we have to have a default constructor and have the subclass initialize all | 
|  | // fields. | 
|  | CustomError() : Info(0) {} | 
|  |  | 
|  | int Info; | 
|  | }; | 
|  |  | 
|  | char CustomError::ID = 0; | 
|  |  | 
|  | // Custom error class with a custom base class and some additional random | 
|  | // 'info'. | 
|  | class CustomSubError : public ErrorInfo<CustomSubError, CustomError> { | 
|  | public: | 
|  | // Create a sub-error with some info attached. | 
|  | CustomSubError(int Info, int ExtraInfo) : ExtraInfo(ExtraInfo) { | 
|  | this->Info = Info; | 
|  | } | 
|  |  | 
|  | // Get the extra info attached to this error. | 
|  | int getExtraInfo() const { return ExtraInfo; } | 
|  |  | 
|  | // Log this error to a stream. | 
|  | void log(raw_ostream &OS) const override { | 
|  | OS << "CustomSubError { " << getInfo() << ", " << getExtraInfo() << "}"; | 
|  | } | 
|  |  | 
|  | std::error_code convertToErrorCode() const override { | 
|  | llvm_unreachable("CustomSubError doesn't support ECError conversion"); | 
|  | } | 
|  |  | 
|  | // Used by ErrorInfo::classID. | 
|  | static char ID; | 
|  |  | 
|  | protected: | 
|  | int ExtraInfo; | 
|  | }; | 
|  |  | 
|  | char CustomSubError::ID = 0; | 
|  |  | 
|  | static Error handleCustomError(const CustomError &CE) { | 
|  | return Error::success(); | 
|  | } | 
|  |  | 
|  | static void handleCustomErrorVoid(const CustomError &CE) {} | 
|  |  | 
|  | static Error handleCustomErrorUP(std::unique_ptr<CustomError> CE) { | 
|  | return Error::success(); | 
|  | } | 
|  |  | 
|  | static void handleCustomErrorUPVoid(std::unique_ptr<CustomError> CE) {} | 
|  |  | 
|  | // Test that success values implicitly convert to false, and don't cause crashes | 
|  | // once they've been implicitly converted. | 
|  | TEST(Error, CheckedSuccess) { | 
|  | Error E = Error::success(); | 
|  | EXPECT_FALSE(E) << "Unexpected error while testing Error 'Success'"; | 
|  | } | 
|  |  | 
|  | // Test that unchecked success values cause an abort. | 
|  | #if LLVM_ENABLE_ABI_BREAKING_CHECKS | 
|  | TEST(Error, UncheckedSuccess) { | 
|  | EXPECT_DEATH({ Error E = Error::success(); }, | 
|  | "Program aborted due to an unhandled Error:") | 
|  | << "Unchecked Error Succes value did not cause abort()"; | 
|  | } | 
|  | #endif | 
|  |  | 
|  | // ErrorAsOutParameter tester. | 
|  | void errAsOutParamHelper(Error &Err) { | 
|  | ErrorAsOutParameter ErrAsOutParam(&Err); | 
|  | // Verify that checked flag is raised - assignment should not crash. | 
|  | Err = Error::success(); | 
|  | // Raise the checked bit manually - caller should still have to test the | 
|  | // error. | 
|  | (void)!!Err; | 
|  | } | 
|  |  | 
|  | // Test that ErrorAsOutParameter sets the checked flag on construction. | 
|  | TEST(Error, ErrorAsOutParameterChecked) { | 
|  | Error E = Error::success(); | 
|  | errAsOutParamHelper(E); | 
|  | (void)!!E; | 
|  | } | 
|  |  | 
|  | // Test that ErrorAsOutParameter clears the checked flag on destruction. | 
|  | #if LLVM_ENABLE_ABI_BREAKING_CHECKS | 
|  | TEST(Error, ErrorAsOutParameterUnchecked) { | 
|  | EXPECT_DEATH({ Error E = Error::success(); errAsOutParamHelper(E); }, | 
|  | "Program aborted due to an unhandled Error:") | 
|  | << "ErrorAsOutParameter did not clear the checked flag on destruction."; | 
|  | } | 
|  | #endif | 
|  |  | 
|  | // Check that we abort on unhandled failure cases. (Force conversion to bool | 
|  | // to make sure that we don't accidentally treat checked errors as handled). | 
|  | // Test runs in debug mode only. | 
|  | #if LLVM_ENABLE_ABI_BREAKING_CHECKS | 
|  | TEST(Error, UncheckedError) { | 
|  | auto DropUnhandledError = []() { | 
|  | Error E = make_error<CustomError>(42); | 
|  | (void)!E; | 
|  | }; | 
|  | EXPECT_DEATH(DropUnhandledError(), | 
|  | "Program aborted due to an unhandled Error:") | 
|  | << "Unhandled Error failure value did not cause abort()"; | 
|  | } | 
|  | #endif | 
|  |  | 
|  | // Check 'Error::isA<T>' method handling. | 
|  | TEST(Error, IsAHandling) { | 
|  | // Check 'isA' handling. | 
|  | Error E = make_error<CustomError>(1); | 
|  | Error F = make_error<CustomSubError>(1, 2); | 
|  | Error G = Error::success(); | 
|  |  | 
|  | EXPECT_TRUE(E.isA<CustomError>()); | 
|  | EXPECT_FALSE(E.isA<CustomSubError>()); | 
|  | EXPECT_TRUE(F.isA<CustomError>()); | 
|  | EXPECT_TRUE(F.isA<CustomSubError>()); | 
|  | EXPECT_FALSE(G.isA<CustomError>()); | 
|  |  | 
|  | consumeError(std::move(E)); | 
|  | consumeError(std::move(F)); | 
|  | consumeError(std::move(G)); | 
|  | } | 
|  |  | 
|  | // Check that we can handle a custom error. | 
|  | TEST(Error, HandleCustomError) { | 
|  | int CaughtErrorInfo = 0; | 
|  | handleAllErrors(make_error<CustomError>(42), [&](const CustomError &CE) { | 
|  | CaughtErrorInfo = CE.getInfo(); | 
|  | }); | 
|  |  | 
|  | EXPECT_EQ(CaughtErrorInfo, 42) << "Wrong result from CustomError handler"; | 
|  | } | 
|  |  | 
|  | // Check that handler type deduction also works for handlers | 
|  | // of the following types: | 
|  | // void (const Err&) | 
|  | // Error (const Err&) mutable | 
|  | // void (const Err&) mutable | 
|  | // Error (Err&) | 
|  | // void (Err&) | 
|  | // Error (Err&) mutable | 
|  | // void (Err&) mutable | 
|  | // Error (unique_ptr<Err>) | 
|  | // void (unique_ptr<Err>) | 
|  | // Error (unique_ptr<Err>) mutable | 
|  | // void (unique_ptr<Err>) mutable | 
|  | TEST(Error, HandlerTypeDeduction) { | 
|  |  | 
|  | handleAllErrors(make_error<CustomError>(42), [](const CustomError &CE) {}); | 
|  |  | 
|  | handleAllErrors( | 
|  | make_error<CustomError>(42), | 
|  | [](const CustomError &CE) mutable  -> Error { return Error::success(); }); | 
|  |  | 
|  | handleAllErrors(make_error<CustomError>(42), | 
|  | [](const CustomError &CE) mutable {}); | 
|  |  | 
|  | handleAllErrors(make_error<CustomError>(42), | 
|  | [](CustomError &CE) -> Error { return Error::success(); }); | 
|  |  | 
|  | handleAllErrors(make_error<CustomError>(42), [](CustomError &CE) {}); | 
|  |  | 
|  | handleAllErrors(make_error<CustomError>(42), | 
|  | [](CustomError &CE) mutable -> Error { return Error::success(); }); | 
|  |  | 
|  | handleAllErrors(make_error<CustomError>(42), [](CustomError &CE) mutable {}); | 
|  |  | 
|  | handleAllErrors( | 
|  | make_error<CustomError>(42), | 
|  | [](std::unique_ptr<CustomError> CE) -> Error { return Error::success(); }); | 
|  |  | 
|  | handleAllErrors(make_error<CustomError>(42), | 
|  | [](std::unique_ptr<CustomError> CE) {}); | 
|  |  | 
|  | handleAllErrors( | 
|  | make_error<CustomError>(42), | 
|  | [](std::unique_ptr<CustomError> CE) mutable -> Error { return Error::success(); }); | 
|  |  | 
|  | handleAllErrors(make_error<CustomError>(42), | 
|  | [](std::unique_ptr<CustomError> CE) mutable {}); | 
|  |  | 
|  | // Check that named handlers of type 'Error (const Err&)' work. | 
|  | handleAllErrors(make_error<CustomError>(42), handleCustomError); | 
|  |  | 
|  | // Check that named handlers of type 'void (const Err&)' work. | 
|  | handleAllErrors(make_error<CustomError>(42), handleCustomErrorVoid); | 
|  |  | 
|  | // Check that named handlers of type 'Error (std::unique_ptr<Err>)' work. | 
|  | handleAllErrors(make_error<CustomError>(42), handleCustomErrorUP); | 
|  |  | 
|  | // Check that named handlers of type 'Error (std::unique_ptr<Err>)' work. | 
|  | handleAllErrors(make_error<CustomError>(42), handleCustomErrorUPVoid); | 
|  | } | 
|  |  | 
|  | // Test that we can handle errors with custom base classes. | 
|  | TEST(Error, HandleCustomErrorWithCustomBaseClass) { | 
|  | int CaughtErrorInfo = 0; | 
|  | int CaughtErrorExtraInfo = 0; | 
|  | handleAllErrors(make_error<CustomSubError>(42, 7), | 
|  | [&](const CustomSubError &SE) { | 
|  | CaughtErrorInfo = SE.getInfo(); | 
|  | CaughtErrorExtraInfo = SE.getExtraInfo(); | 
|  | }); | 
|  |  | 
|  | EXPECT_EQ(CaughtErrorInfo, 42) << "Wrong result from CustomSubError handler"; | 
|  | EXPECT_EQ(CaughtErrorExtraInfo, 7) | 
|  | << "Wrong result from CustomSubError handler"; | 
|  | } | 
|  |  | 
|  | // Check that we trigger only the first handler that applies. | 
|  | TEST(Error, FirstHandlerOnly) { | 
|  | int DummyInfo = 0; | 
|  | int CaughtErrorInfo = 0; | 
|  | int CaughtErrorExtraInfo = 0; | 
|  |  | 
|  | handleAllErrors(make_error<CustomSubError>(42, 7), | 
|  | [&](const CustomSubError &SE) { | 
|  | CaughtErrorInfo = SE.getInfo(); | 
|  | CaughtErrorExtraInfo = SE.getExtraInfo(); | 
|  | }, | 
|  | [&](const CustomError &CE) { DummyInfo = CE.getInfo(); }); | 
|  |  | 
|  | EXPECT_EQ(CaughtErrorInfo, 42) << "Activated the wrong Error handler(s)"; | 
|  | EXPECT_EQ(CaughtErrorExtraInfo, 7) << "Activated the wrong Error handler(s)"; | 
|  | EXPECT_EQ(DummyInfo, 0) << "Activated the wrong Error handler(s)"; | 
|  | } | 
|  |  | 
|  | // Check that general handlers shadow specific ones. | 
|  | TEST(Error, HandlerShadowing) { | 
|  | int CaughtErrorInfo = 0; | 
|  | int DummyInfo = 0; | 
|  | int DummyExtraInfo = 0; | 
|  |  | 
|  | handleAllErrors( | 
|  | make_error<CustomSubError>(42, 7), | 
|  | [&](const CustomError &CE) { CaughtErrorInfo = CE.getInfo(); }, | 
|  | [&](const CustomSubError &SE) { | 
|  | DummyInfo = SE.getInfo(); | 
|  | DummyExtraInfo = SE.getExtraInfo(); | 
|  | }); | 
|  |  | 
|  | EXPECT_EQ(CaughtErrorInfo, 42) | 
|  | << "General Error handler did not shadow specific handler"; | 
|  | EXPECT_EQ(DummyInfo, 0) | 
|  | << "General Error handler did not shadow specific handler"; | 
|  | EXPECT_EQ(DummyExtraInfo, 0) | 
|  | << "General Error handler did not shadow specific handler"; | 
|  | } | 
|  |  | 
|  | // Test joinErrors. | 
|  | TEST(Error, CheckJoinErrors) { | 
|  | int CustomErrorInfo1 = 0; | 
|  | int CustomErrorInfo2 = 0; | 
|  | int CustomErrorExtraInfo = 0; | 
|  | Error E = | 
|  | joinErrors(make_error<CustomError>(7), make_error<CustomSubError>(42, 7)); | 
|  |  | 
|  | handleAllErrors(std::move(E), | 
|  | [&](const CustomSubError &SE) { | 
|  | CustomErrorInfo2 = SE.getInfo(); | 
|  | CustomErrorExtraInfo = SE.getExtraInfo(); | 
|  | }, | 
|  | [&](const CustomError &CE) { | 
|  | // Assert that the CustomError instance above is handled | 
|  | // before the | 
|  | // CustomSubError - joinErrors should preserve error | 
|  | // ordering. | 
|  | EXPECT_EQ(CustomErrorInfo2, 0) | 
|  | << "CustomErrorInfo2 should be 0 here. " | 
|  | "joinErrors failed to preserve ordering.\n"; | 
|  | CustomErrorInfo1 = CE.getInfo(); | 
|  | }); | 
|  |  | 
|  | EXPECT_EQ(CustomErrorInfo1, 7) << "Failed handling compound Error."; | 
|  | EXPECT_EQ(CustomErrorInfo2, 42) << "Failed handling compound Error."; | 
|  | EXPECT_EQ(CustomErrorExtraInfo, 7) << "Failed handling compound Error."; | 
|  |  | 
|  | // Test appending a single item to a list. | 
|  | { | 
|  | int Sum = 0; | 
|  | handleAllErrors( | 
|  | joinErrors( | 
|  | joinErrors(make_error<CustomError>(7), | 
|  | make_error<CustomError>(7)), | 
|  | make_error<CustomError>(7)), | 
|  | [&](const CustomError &CE) { | 
|  | Sum += CE.getInfo(); | 
|  | }); | 
|  | EXPECT_EQ(Sum, 21) << "Failed to correctly append error to error list."; | 
|  | } | 
|  |  | 
|  | // Test prepending a single item to a list. | 
|  | { | 
|  | int Sum = 0; | 
|  | handleAllErrors( | 
|  | joinErrors( | 
|  | make_error<CustomError>(7), | 
|  | joinErrors(make_error<CustomError>(7), | 
|  | make_error<CustomError>(7))), | 
|  | [&](const CustomError &CE) { | 
|  | Sum += CE.getInfo(); | 
|  | }); | 
|  | EXPECT_EQ(Sum, 21) << "Failed to correctly prepend error to error list."; | 
|  | } | 
|  |  | 
|  | // Test concatenating two error lists. | 
|  | { | 
|  | int Sum = 0; | 
|  | handleAllErrors( | 
|  | joinErrors( | 
|  | joinErrors( | 
|  | make_error<CustomError>(7), | 
|  | make_error<CustomError>(7)), | 
|  | joinErrors( | 
|  | make_error<CustomError>(7), | 
|  | make_error<CustomError>(7))), | 
|  | [&](const CustomError &CE) { | 
|  | Sum += CE.getInfo(); | 
|  | }); | 
|  | EXPECT_EQ(Sum, 28) << "Failed to correctly concatenate error lists."; | 
|  | } | 
|  | } | 
|  |  | 
|  | // Test that we can consume success values. | 
|  | TEST(Error, ConsumeSuccess) { | 
|  | Error E = Error::success(); | 
|  | consumeError(std::move(E)); | 
|  | } | 
|  |  | 
|  | TEST(Error, ConsumeError) { | 
|  | Error E = make_error<CustomError>(7); | 
|  | consumeError(std::move(E)); | 
|  | } | 
|  |  | 
|  | // Test that handleAllUnhandledErrors crashes if an error is not caught. | 
|  | // Test runs in debug mode only. | 
|  | #if LLVM_ENABLE_ABI_BREAKING_CHECKS | 
|  | TEST(Error, FailureToHandle) { | 
|  | auto FailToHandle = []() { | 
|  | handleAllErrors(make_error<CustomError>(7), [&](const CustomSubError &SE) { | 
|  | errs() << "This should never be called"; | 
|  | exit(1); | 
|  | }); | 
|  | }; | 
|  |  | 
|  | EXPECT_DEATH(FailToHandle(), | 
|  | "Failure value returned from cantFail wrapped call\n" | 
|  | "CustomError \\{7\\}") | 
|  | << "Unhandled Error in handleAllErrors call did not cause an " | 
|  | "abort()"; | 
|  | } | 
|  | #endif | 
|  |  | 
|  | // Test that handleAllUnhandledErrors crashes if an error is returned from a | 
|  | // handler. | 
|  | // Test runs in debug mode only. | 
|  | #if LLVM_ENABLE_ABI_BREAKING_CHECKS | 
|  | TEST(Error, FailureFromHandler) { | 
|  | auto ReturnErrorFromHandler = []() { | 
|  | handleAllErrors(make_error<CustomError>(7), | 
|  | [&](std::unique_ptr<CustomSubError> SE) { | 
|  | return Error(std::move(SE)); | 
|  | }); | 
|  | }; | 
|  |  | 
|  | EXPECT_DEATH(ReturnErrorFromHandler(), | 
|  | "Failure value returned from cantFail wrapped call\n" | 
|  | "CustomError \\{7\\}") | 
|  | << " Error returned from handler in handleAllErrors call did not " | 
|  | "cause abort()"; | 
|  | } | 
|  | #endif | 
|  |  | 
|  | // Test that we can return values from handleErrors. | 
|  | TEST(Error, CatchErrorFromHandler) { | 
|  | int ErrorInfo = 0; | 
|  |  | 
|  | Error E = handleErrors( | 
|  | make_error<CustomError>(7), | 
|  | [&](std::unique_ptr<CustomError> CE) { return Error(std::move(CE)); }); | 
|  |  | 
|  | handleAllErrors(std::move(E), | 
|  | [&](const CustomError &CE) { ErrorInfo = CE.getInfo(); }); | 
|  |  | 
|  | EXPECT_EQ(ErrorInfo, 7) | 
|  | << "Failed to handle Error returned from handleErrors."; | 
|  | } | 
|  |  | 
|  | TEST(Error, StringError) { | 
|  | std::string Msg; | 
|  | raw_string_ostream S(Msg); | 
|  | logAllUnhandledErrors( | 
|  | make_error<StringError>("foo" + Twine(42), inconvertibleErrorCode()), S); | 
|  | EXPECT_EQ(Msg, "foo42\n") << "Unexpected StringError log result"; | 
|  |  | 
|  | auto EC = | 
|  | errorToErrorCode(make_error<StringError>("", errc::invalid_argument)); | 
|  | EXPECT_EQ(EC, errc::invalid_argument) | 
|  | << "Failed to convert StringError to error_code."; | 
|  | } | 
|  |  | 
|  | TEST(Error, createStringError) { | 
|  | static const char *Bar = "bar"; | 
|  | static const std::error_code EC = errc::invalid_argument; | 
|  | std::string Msg; | 
|  | raw_string_ostream S(Msg); | 
|  | logAllUnhandledErrors(createStringError(EC, "foo%s%d0x%" PRIx8, Bar, 1, 0xff), | 
|  | S); | 
|  | EXPECT_EQ(Msg, "foobar10xff\n") | 
|  | << "Unexpected createStringError() log result"; | 
|  |  | 
|  | Msg.clear(); | 
|  | logAllUnhandledErrors(createStringError(EC, Bar), S); | 
|  | EXPECT_EQ(Msg, "bar\n") | 
|  | << "Unexpected createStringError() (overloaded) log result"; | 
|  |  | 
|  | Msg.clear(); | 
|  | auto Res = errorToErrorCode(createStringError(EC, "foo%s", Bar)); | 
|  | EXPECT_EQ(Res, EC) | 
|  | << "Failed to convert createStringError() result to error_code."; | 
|  | } | 
|  |  | 
|  | // Test that the ExitOnError utility works as expected. | 
|  | TEST(ErrorDeathTest, ExitOnError) { | 
|  | ExitOnError ExitOnErr; | 
|  | ExitOnErr.setBanner("Error in tool:"); | 
|  | ExitOnErr.setExitCodeMapper([](const Error &E) { | 
|  | if (E.isA<CustomSubError>()) | 
|  | return 2; | 
|  | return 1; | 
|  | }); | 
|  |  | 
|  | // Make sure we don't bail on success. | 
|  | ExitOnErr(Error::success()); | 
|  | EXPECT_EQ(ExitOnErr(Expected<int>(7)), 7) | 
|  | << "exitOnError returned an invalid value for Expected"; | 
|  |  | 
|  | int A = 7; | 
|  | int &B = ExitOnErr(Expected<int&>(A)); | 
|  | EXPECT_EQ(&A, &B) << "ExitOnError failed to propagate reference"; | 
|  |  | 
|  | // Exit tests. | 
|  | EXPECT_EXIT(ExitOnErr(make_error<CustomError>(7)), | 
|  | ::testing::ExitedWithCode(1), "Error in tool:") | 
|  | << "exitOnError returned an unexpected error result"; | 
|  |  | 
|  | EXPECT_EXIT(ExitOnErr(Expected<int>(make_error<CustomSubError>(0, 0))), | 
|  | ::testing::ExitedWithCode(2), "Error in tool:") | 
|  | << "exitOnError returned an unexpected error result"; | 
|  | } | 
|  |  | 
|  | // Test that the ExitOnError utility works as expected. | 
|  | TEST(Error, CantFailSuccess) { | 
|  | cantFail(Error::success()); | 
|  |  | 
|  | int X = cantFail(Expected<int>(42)); | 
|  | EXPECT_EQ(X, 42) << "Expected value modified by cantFail"; | 
|  |  | 
|  | int Dummy = 42; | 
|  | int &Y = cantFail(Expected<int&>(Dummy)); | 
|  | EXPECT_EQ(&Dummy, &Y) << "Reference mangled by cantFail"; | 
|  | } | 
|  |  | 
|  | // Test that cantFail results in a crash if you pass it a failure value. | 
|  | #if LLVM_ENABLE_ABI_BREAKING_CHECKS && !defined(NDEBUG) | 
|  | TEST(Error, CantFailDeath) { | 
|  | EXPECT_DEATH(cantFail(make_error<StringError>("Original error message", | 
|  | inconvertibleErrorCode()), | 
|  | "Cantfail call failed"), | 
|  | "Cantfail call failed\n" | 
|  | "Original error message") | 
|  | << "cantFail(Error) did not cause an abort for failure value"; | 
|  |  | 
|  | EXPECT_DEATH( | 
|  | { | 
|  | auto IEC = inconvertibleErrorCode(); | 
|  | int X = cantFail(Expected<int>(make_error<StringError>("foo", IEC))); | 
|  | (void)X; | 
|  | }, | 
|  | "Failure value returned from cantFail wrapped call") | 
|  | << "cantFail(Expected<int>) did not cause an abort for failure value"; | 
|  | } | 
|  | #endif | 
|  |  | 
|  |  | 
|  | // Test Checked Expected<T> in success mode. | 
|  | TEST(Error, CheckedExpectedInSuccessMode) { | 
|  | Expected<int> A = 7; | 
|  | EXPECT_TRUE(!!A) << "Expected with non-error value doesn't convert to 'true'"; | 
|  | // Access is safe in second test, since we checked the error in the first. | 
|  | EXPECT_EQ(*A, 7) << "Incorrect Expected non-error value"; | 
|  | } | 
|  |  | 
|  | // Test Expected with reference type. | 
|  | TEST(Error, ExpectedWithReferenceType) { | 
|  | int A = 7; | 
|  | Expected<int&> B = A; | 
|  | // 'Check' B. | 
|  | (void)!!B; | 
|  | int &C = *B; | 
|  | EXPECT_EQ(&A, &C) << "Expected failed to propagate reference"; | 
|  | } | 
|  |  | 
|  | // Test Unchecked Expected<T> in success mode. | 
|  | // We expect this to blow up the same way Error would. | 
|  | // Test runs in debug mode only. | 
|  | #if LLVM_ENABLE_ABI_BREAKING_CHECKS | 
|  | TEST(Error, UncheckedExpectedInSuccessModeDestruction) { | 
|  | EXPECT_DEATH({ Expected<int> A = 7; }, | 
|  | "Expected<T> must be checked before access or destruction.") | 
|  | << "Unchecked Expected<T> success value did not cause an abort()."; | 
|  | } | 
|  | #endif | 
|  |  | 
|  | // Test Unchecked Expected<T> in success mode. | 
|  | // We expect this to blow up the same way Error would. | 
|  | // Test runs in debug mode only. | 
|  | #if LLVM_ENABLE_ABI_BREAKING_CHECKS | 
|  | TEST(Error, UncheckedExpectedInSuccessModeAccess) { | 
|  | EXPECT_DEATH( | 
|  | { | 
|  | const Expected<int> A = 7; | 
|  | *A; | 
|  | }, | 
|  | "Expected<T> must be checked before access or destruction.") | 
|  | << "Unchecked Expected<T> success value did not cause an abort()."; | 
|  | } | 
|  | #endif | 
|  |  | 
|  | // Test Unchecked Expected<T> in success mode. | 
|  | // We expect this to blow up the same way Error would. | 
|  | // Test runs in debug mode only. | 
|  | #if LLVM_ENABLE_ABI_BREAKING_CHECKS | 
|  | TEST(Error, UncheckedExpectedInSuccessModeAssignment) { | 
|  | EXPECT_DEATH( | 
|  | { | 
|  | Expected<int> A = 7; | 
|  | A = 7; | 
|  | }, | 
|  | "Expected<T> must be checked before access or destruction.") | 
|  | << "Unchecked Expected<T> success value did not cause an abort()."; | 
|  | } | 
|  | #endif | 
|  |  | 
|  | // Test Expected<T> in failure mode. | 
|  | TEST(Error, ExpectedInFailureMode) { | 
|  | Expected<int> A = make_error<CustomError>(42); | 
|  | EXPECT_FALSE(!!A) << "Expected with error value doesn't convert to 'false'"; | 
|  | Error E = A.takeError(); | 
|  | EXPECT_TRUE(E.isA<CustomError>()) << "Incorrect Expected error value"; | 
|  | consumeError(std::move(E)); | 
|  | } | 
|  |  | 
|  | // Check that an Expected instance with an error value doesn't allow access to | 
|  | // operator*. | 
|  | // Test runs in debug mode only. | 
|  | #if LLVM_ENABLE_ABI_BREAKING_CHECKS | 
|  | TEST(Error, AccessExpectedInFailureMode) { | 
|  | Expected<int> A = make_error<CustomError>(42); | 
|  | EXPECT_DEATH(*A, "Expected<T> must be checked before access or destruction.") | 
|  | << "Incorrect Expected error value"; | 
|  | consumeError(A.takeError()); | 
|  | } | 
|  | #endif | 
|  |  | 
|  | // Check that an Expected instance with an error triggers an abort if | 
|  | // unhandled. | 
|  | // Test runs in debug mode only. | 
|  | #if LLVM_ENABLE_ABI_BREAKING_CHECKS | 
|  | TEST(Error, UnhandledExpectedInFailureMode) { | 
|  | EXPECT_DEATH({ Expected<int> A = make_error<CustomError>(42); }, | 
|  | "Expected<T> must be checked before access or destruction.") | 
|  | << "Unchecked Expected<T> failure value did not cause an abort()"; | 
|  | } | 
|  | #endif | 
|  |  | 
|  | // Test covariance of Expected. | 
|  | TEST(Error, ExpectedCovariance) { | 
|  | class B {}; | 
|  | class D : public B {}; | 
|  |  | 
|  | Expected<B *> A1(Expected<D *>(nullptr)); | 
|  | // Check A1 by converting to bool before assigning to it. | 
|  | (void)!!A1; | 
|  | A1 = Expected<D *>(nullptr); | 
|  | // Check A1 again before destruction. | 
|  | (void)!!A1; | 
|  |  | 
|  | Expected<std::unique_ptr<B>> A2(Expected<std::unique_ptr<D>>(nullptr)); | 
|  | // Check A2 by converting to bool before assigning to it. | 
|  | (void)!!A2; | 
|  | A2 = Expected<std::unique_ptr<D>>(nullptr); | 
|  | // Check A2 again before destruction. | 
|  | (void)!!A2; | 
|  | } | 
|  |  | 
|  | // Test that handleExpected just returns success values. | 
|  | TEST(Error, HandleExpectedSuccess) { | 
|  | auto ValOrErr = | 
|  | handleExpected(Expected<int>(42), | 
|  | []() { return Expected<int>(43); }); | 
|  | EXPECT_TRUE(!!ValOrErr) | 
|  | << "handleExpected should have returned a success value here"; | 
|  | EXPECT_EQ(*ValOrErr, 42) | 
|  | << "handleExpected should have returned the original success value here"; | 
|  | } | 
|  |  | 
|  | enum FooStrategy { Aggressive, Conservative }; | 
|  |  | 
|  | static Expected<int> foo(FooStrategy S) { | 
|  | if (S == Aggressive) | 
|  | return make_error<CustomError>(7); | 
|  | return 42; | 
|  | } | 
|  |  | 
|  | // Test that handleExpected invokes the error path if errors are not handled. | 
|  | TEST(Error, HandleExpectedUnhandledError) { | 
|  | // foo(Aggressive) should return a CustomError which should pass through as | 
|  | // there is no handler for CustomError. | 
|  | auto ValOrErr = | 
|  | handleExpected( | 
|  | foo(Aggressive), | 
|  | []() { return foo(Conservative); }); | 
|  |  | 
|  | EXPECT_FALSE(!!ValOrErr) | 
|  | << "handleExpected should have returned an error here"; | 
|  | auto Err = ValOrErr.takeError(); | 
|  | EXPECT_TRUE(Err.isA<CustomError>()) | 
|  | << "handleExpected should have returned the CustomError generated by " | 
|  | "foo(Aggressive) here"; | 
|  | consumeError(std::move(Err)); | 
|  | } | 
|  |  | 
|  | // Test that handleExpected invokes the fallback path if errors are handled. | 
|  | TEST(Error, HandleExpectedHandledError) { | 
|  | // foo(Aggressive) should return a CustomError which should handle triggering | 
|  | // the fallback path. | 
|  | auto ValOrErr = | 
|  | handleExpected( | 
|  | foo(Aggressive), | 
|  | []() { return foo(Conservative); }, | 
|  | [](const CustomError&) { /* do nothing */ }); | 
|  |  | 
|  | EXPECT_TRUE(!!ValOrErr) | 
|  | << "handleExpected should have returned a success value here"; | 
|  | EXPECT_EQ(*ValOrErr, 42) | 
|  | << "handleExpected returned the wrong success value"; | 
|  | } | 
|  |  | 
|  | TEST(Error, ErrorCodeConversions) { | 
|  | // Round-trip a success value to check that it converts correctly. | 
|  | EXPECT_EQ(errorToErrorCode(errorCodeToError(std::error_code())), | 
|  | std::error_code()) | 
|  | << "std::error_code() should round-trip via Error conversions"; | 
|  |  | 
|  | // Round-trip an error value to check that it converts correctly. | 
|  | EXPECT_EQ(errorToErrorCode(errorCodeToError(errc::invalid_argument)), | 
|  | errc::invalid_argument) | 
|  | << "std::error_code error value should round-trip via Error " | 
|  | "conversions"; | 
|  |  | 
|  | // Round-trip a success value through ErrorOr/Expected to check that it | 
|  | // converts correctly. | 
|  | { | 
|  | auto Orig = ErrorOr<int>(42); | 
|  | auto RoundTripped = | 
|  | expectedToErrorOr(errorOrToExpected(ErrorOr<int>(42))); | 
|  | EXPECT_EQ(*Orig, *RoundTripped) | 
|  | << "ErrorOr<T> success value should round-trip via Expected<T> " | 
|  | "conversions."; | 
|  | } | 
|  |  | 
|  | // Round-trip a failure value through ErrorOr/Expected to check that it | 
|  | // converts correctly. | 
|  | { | 
|  | auto Orig = ErrorOr<int>(errc::invalid_argument); | 
|  | auto RoundTripped = | 
|  | expectedToErrorOr( | 
|  | errorOrToExpected(ErrorOr<int>(errc::invalid_argument))); | 
|  | EXPECT_EQ(Orig.getError(), RoundTripped.getError()) | 
|  | << "ErrorOr<T> failure value should round-trip via Expected<T> " | 
|  | "conversions."; | 
|  | } | 
|  | } | 
|  |  | 
|  | // Test that error messages work. | 
|  | TEST(Error, ErrorMessage) { | 
|  | EXPECT_EQ(toString(Error::success()), ""); | 
|  |  | 
|  | Error E0 = Error::success(); | 
|  | EXPECT_EQ(toStringWithoutConsuming(E0), ""); | 
|  | EXPECT_EQ(toString(std::move(E0)), ""); | 
|  |  | 
|  | Error E1 = make_error<CustomError>(0); | 
|  | EXPECT_EQ(toStringWithoutConsuming(E1), "CustomError {0}"); | 
|  | EXPECT_EQ(toString(std::move(E1)), "CustomError {0}"); | 
|  |  | 
|  | Error E2 = make_error<CustomError>(0); | 
|  | visitErrors(E2, [](const ErrorInfoBase &EI) { | 
|  | EXPECT_EQ(EI.message(), "CustomError {0}"); | 
|  | }); | 
|  | handleAllErrors(std::move(E2), [](const CustomError &CE) { | 
|  | EXPECT_EQ(CE.message(), "CustomError {0}"); | 
|  | }); | 
|  |  | 
|  | Error E3 = joinErrors(make_error<CustomError>(0), make_error<CustomError>(1)); | 
|  | EXPECT_EQ(toStringWithoutConsuming(E3), "CustomError {0}\n" | 
|  | "CustomError {1}"); | 
|  | EXPECT_EQ(toString(std::move(E3)), "CustomError {0}\n" | 
|  | "CustomError {1}"); | 
|  | } | 
|  |  | 
|  | TEST(Error, Stream) { | 
|  | { | 
|  | Error OK = Error::success(); | 
|  | std::string Buf; | 
|  | llvm::raw_string_ostream S(Buf); | 
|  | S << OK; | 
|  | EXPECT_EQ("success", Buf); | 
|  | consumeError(std::move(OK)); | 
|  | } | 
|  | { | 
|  | Error E1 = make_error<CustomError>(0); | 
|  | std::string Buf; | 
|  | llvm::raw_string_ostream S(Buf); | 
|  | S << E1; | 
|  | EXPECT_EQ("CustomError {0}", Buf); | 
|  | consumeError(std::move(E1)); | 
|  | } | 
|  | } | 
|  |  | 
|  | TEST(Error, SucceededMatcher) { | 
|  | EXPECT_THAT_ERROR(Error::success(), Succeeded()); | 
|  | EXPECT_NONFATAL_FAILURE( | 
|  | EXPECT_THAT_ERROR(make_error<CustomError>(0), Succeeded()), | 
|  | "Expected: succeeded\n  Actual: failed  (CustomError {0})"); | 
|  |  | 
|  | EXPECT_THAT_EXPECTED(Expected<int>(0), Succeeded()); | 
|  | EXPECT_NONFATAL_FAILURE( | 
|  | EXPECT_THAT_EXPECTED(Expected<int>(make_error<CustomError>(0)), | 
|  | Succeeded()), | 
|  | "Expected: succeeded\n  Actual: failed  (CustomError {0})"); | 
|  | int a = 1; | 
|  | EXPECT_THAT_EXPECTED(Expected<int &>(a), Succeeded()); | 
|  | } | 
|  |  | 
|  | TEST(Error, FailedMatcher) { | 
|  | EXPECT_THAT_ERROR(make_error<CustomError>(0), Failed()); | 
|  | EXPECT_NONFATAL_FAILURE(EXPECT_THAT_ERROR(Error::success(), Failed()), | 
|  | "Expected: failed\n  Actual: succeeded"); | 
|  |  | 
|  | EXPECT_THAT_ERROR(make_error<CustomError>(0), Failed<CustomError>()); | 
|  | EXPECT_NONFATAL_FAILURE( | 
|  | EXPECT_THAT_ERROR(Error::success(), Failed<CustomError>()), | 
|  | "Expected: failed with Error of given type\n  Actual: succeeded"); | 
|  | EXPECT_NONFATAL_FAILURE( | 
|  | EXPECT_THAT_ERROR(make_error<CustomError>(0), Failed<CustomSubError>()), | 
|  | "Error was not of given type"); | 
|  | EXPECT_NONFATAL_FAILURE( | 
|  | EXPECT_THAT_ERROR( | 
|  | joinErrors(make_error<CustomError>(0), make_error<CustomError>(1)), | 
|  | Failed<CustomError>()), | 
|  | "multiple errors"); | 
|  |  | 
|  | EXPECT_THAT_ERROR( | 
|  | make_error<CustomError>(0), | 
|  | Failed<CustomError>(testing::Property(&CustomError::getInfo, 0))); | 
|  | EXPECT_NONFATAL_FAILURE( | 
|  | EXPECT_THAT_ERROR( | 
|  | make_error<CustomError>(0), | 
|  | Failed<CustomError>(testing::Property(&CustomError::getInfo, 1))), | 
|  | "Expected: failed with Error of given type and the error is an object " | 
|  | "whose given property is equal to 1\n" | 
|  | "  Actual: failed  (CustomError {0})"); | 
|  | EXPECT_THAT_ERROR(make_error<CustomError>(0), Failed<ErrorInfoBase>()); | 
|  |  | 
|  | EXPECT_THAT_EXPECTED(Expected<int>(make_error<CustomError>(0)), Failed()); | 
|  | EXPECT_NONFATAL_FAILURE( | 
|  | EXPECT_THAT_EXPECTED(Expected<int>(0), Failed()), | 
|  | "Expected: failed\n  Actual: succeeded with value 0"); | 
|  | EXPECT_THAT_EXPECTED(Expected<int &>(make_error<CustomError>(0)), Failed()); | 
|  | } | 
|  |  | 
|  | TEST(Error, HasValueMatcher) { | 
|  | EXPECT_THAT_EXPECTED(Expected<int>(0), HasValue(0)); | 
|  | EXPECT_NONFATAL_FAILURE( | 
|  | EXPECT_THAT_EXPECTED(Expected<int>(make_error<CustomError>(0)), | 
|  | HasValue(0)), | 
|  | "Expected: succeeded with value (is equal to 0)\n" | 
|  | "  Actual: failed  (CustomError {0})"); | 
|  | EXPECT_NONFATAL_FAILURE( | 
|  | EXPECT_THAT_EXPECTED(Expected<int>(1), HasValue(0)), | 
|  | "Expected: succeeded with value (is equal to 0)\n" | 
|  | "  Actual: succeeded with value 1, (isn't equal to 0)"); | 
|  |  | 
|  | int a = 1; | 
|  | EXPECT_THAT_EXPECTED(Expected<int &>(a), HasValue(testing::Eq(1))); | 
|  |  | 
|  | EXPECT_THAT_EXPECTED(Expected<int>(1), HasValue(testing::Gt(0))); | 
|  | EXPECT_NONFATAL_FAILURE( | 
|  | EXPECT_THAT_EXPECTED(Expected<int>(0), HasValue(testing::Gt(1))), | 
|  | "Expected: succeeded with value (is > 1)\n" | 
|  | "  Actual: succeeded with value 0, (isn't > 1)"); | 
|  | EXPECT_NONFATAL_FAILURE( | 
|  | EXPECT_THAT_EXPECTED(Expected<int>(make_error<CustomError>(0)), | 
|  | HasValue(testing::Gt(1))), | 
|  | "Expected: succeeded with value (is > 1)\n" | 
|  | "  Actual: failed  (CustomError {0})"); | 
|  | } | 
|  |  | 
|  | TEST(Error, FailedWithMessageMatcher) { | 
|  | EXPECT_THAT_EXPECTED(Expected<int>(make_error<CustomError>(0)), | 
|  | FailedWithMessage("CustomError {0}")); | 
|  |  | 
|  | EXPECT_NONFATAL_FAILURE( | 
|  | EXPECT_THAT_EXPECTED(Expected<int>(make_error<CustomError>(1)), | 
|  | FailedWithMessage("CustomError {0}")), | 
|  | "Expected: failed with Error whose message has 1 element that is equal " | 
|  | "to \"CustomError {0}\"\n" | 
|  | "  Actual: failed  (CustomError {1})"); | 
|  |  | 
|  | EXPECT_NONFATAL_FAILURE( | 
|  | EXPECT_THAT_EXPECTED(Expected<int>(0), | 
|  | FailedWithMessage("CustomError {0}")), | 
|  | "Expected: failed with Error whose message has 1 element that is equal " | 
|  | "to \"CustomError {0}\"\n" | 
|  | "  Actual: succeeded with value 0"); | 
|  |  | 
|  | EXPECT_NONFATAL_FAILURE( | 
|  | EXPECT_THAT_EXPECTED(Expected<int>(make_error<CustomError>(0)), | 
|  | FailedWithMessage("CustomError {0}", "CustomError {0}")), | 
|  | "Expected: failed with Error whose message has 2 elements where\n" | 
|  | "element #0 is equal to \"CustomError {0}\",\n" | 
|  | "element #1 is equal to \"CustomError {0}\"\n" | 
|  | "  Actual: failed  (CustomError {0}), which has 1 element"); | 
|  |  | 
|  | EXPECT_NONFATAL_FAILURE( | 
|  | EXPECT_THAT_EXPECTED( | 
|  | Expected<int>(joinErrors(make_error<CustomError>(0), | 
|  | make_error<CustomError>(0))), | 
|  | FailedWithMessage("CustomError {0}")), | 
|  | "Expected: failed with Error whose message has 1 element that is equal " | 
|  | "to \"CustomError {0}\"\n" | 
|  | "  Actual: failed  (CustomError {0}; CustomError {0}), which has 2 elements"); | 
|  |  | 
|  | EXPECT_THAT_ERROR( | 
|  | joinErrors(make_error<CustomError>(0), make_error<CustomError>(0)), | 
|  | FailedWithMessageArray(testing::SizeIs(2))); | 
|  | } | 
|  |  | 
|  | TEST(Error, C_API) { | 
|  | EXPECT_THAT_ERROR(unwrap(wrap(Error::success())), Succeeded()) | 
|  | << "Failed to round-trip Error success value via C API"; | 
|  | EXPECT_THAT_ERROR(unwrap(wrap(make_error<CustomError>(0))), | 
|  | Failed<CustomError>()) | 
|  | << "Failed to round-trip Error failure value via C API"; | 
|  |  | 
|  | auto Err = | 
|  | wrap(make_error<StringError>("test message", inconvertibleErrorCode())); | 
|  | EXPECT_EQ(LLVMGetErrorTypeId(Err), LLVMGetStringErrorTypeId()) | 
|  | << "Failed to match error type ids via C API"; | 
|  | char *ErrMsg = LLVMGetErrorMessage(Err); | 
|  | EXPECT_STREQ(ErrMsg, "test message") | 
|  | << "Failed to roundtrip StringError error message via C API"; | 
|  | LLVMDisposeErrorMessage(ErrMsg); | 
|  |  | 
|  | bool GotCSE = false; | 
|  | bool GotCE = false; | 
|  | handleAllErrors( | 
|  | unwrap(wrap(joinErrors(make_error<CustomSubError>(42, 7), | 
|  | make_error<CustomError>(42)))), | 
|  | [&](CustomSubError &CSE) { | 
|  | GotCSE = true; | 
|  | }, | 
|  | [&](CustomError &CE) { | 
|  | GotCE = true; | 
|  | }); | 
|  | EXPECT_TRUE(GotCSE) << "Failed to round-trip ErrorList via C API"; | 
|  | EXPECT_TRUE(GotCE) << "Failed to round-trip ErrorList via C API"; | 
|  |  | 
|  | LLVMCantFail(wrap(Error::success())); | 
|  | } | 
|  |  | 
|  | TEST(Error, FileErrorTest) { | 
|  | #if !defined(NDEBUG) && GTEST_HAS_DEATH_TEST | 
|  | EXPECT_DEATH( | 
|  | { | 
|  | Error S = Error::success(); | 
|  | consumeError(createFileError("file.bin", std::move(S))); | 
|  | }, | 
|  | ""); | 
|  | #endif | 
|  | // Not allowed, would fail at compile-time | 
|  | //consumeError(createFileError("file.bin", ErrorSuccess())); | 
|  |  | 
|  | Error E1 = make_error<CustomError>(1); | 
|  | Error FE1 = createFileError("file.bin", std::move(E1)); | 
|  | EXPECT_EQ(toString(std::move(FE1)), "'file.bin': CustomError {1}"); | 
|  |  | 
|  | Error E2 = make_error<CustomError>(2); | 
|  | Error FE2 = createFileError("file.bin", std::move(E2)); | 
|  | handleAllErrors(std::move(FE2), [](const FileError &F) { | 
|  | EXPECT_EQ(F.message(), "'file.bin': CustomError {2}"); | 
|  | }); | 
|  |  | 
|  | Error E3 = make_error<CustomError>(3); | 
|  | Error FE3 = createFileError("file.bin", std::move(E3)); | 
|  | auto E31 = handleErrors(std::move(FE3), [](std::unique_ptr<FileError> F) { | 
|  | return F->takeError(); | 
|  | }); | 
|  | handleAllErrors(std::move(E31), [](const CustomError &C) { | 
|  | EXPECT_EQ(C.message(), "CustomError {3}"); | 
|  | }); | 
|  |  | 
|  | Error FE4 = | 
|  | joinErrors(createFileError("file.bin", make_error<CustomError>(41)), | 
|  | createFileError("file2.bin", make_error<CustomError>(42))); | 
|  | EXPECT_EQ(toString(std::move(FE4)), "'file.bin': CustomError {41}\n" | 
|  | "'file2.bin': CustomError {42}"); | 
|  |  | 
|  | Error FE5 = createFileError("", make_error<CustomError>(5)); | 
|  | EXPECT_EQ(toString(std::move(FE5)), "'': CustomError {5}"); | 
|  |  | 
|  | Error FE6 = createFileError("unused", make_error<CustomError>(6)); | 
|  | handleAllErrors(std::move(FE6), [](std::unique_ptr<FileError> F) { | 
|  | EXPECT_EQ(F->messageWithoutFileInfo(), "CustomError {6}"); | 
|  | }); | 
|  |  | 
|  | Error FE7 = | 
|  | createFileError("file.bin", make_error_code(std::errc::invalid_argument), | 
|  | "invalid argument"); | 
|  | EXPECT_EQ(toString(std::move(FE7)), "'file.bin': invalid argument"); | 
|  |  | 
|  | StringRef Argument = "arg"; | 
|  | Error FE8 = | 
|  | createFileError("file.bin", make_error_code(std::errc::invalid_argument), | 
|  | "invalid argument '%s'", Argument.str().c_str()); | 
|  | EXPECT_EQ(toString(std::move(FE8)), "'file.bin': invalid argument 'arg'"); | 
|  | } | 
|  |  | 
|  | TEST(Error, FileErrorErrorCode) { | 
|  | for (std::error_code EC : { | 
|  | make_error_code(std::errc::not_supported), | 
|  | make_error_code(std::errc::invalid_argument), | 
|  | make_error_code(std::errc::no_such_file_or_directory), | 
|  | }) { | 
|  | EXPECT_EQ(EC, errorToErrorCode( | 
|  | createFileError("file.bin", EC))); | 
|  | EXPECT_EQ(EC, errorToErrorCode( | 
|  | createFileError("file.bin", /*Line=*/5, EC))); | 
|  | EXPECT_EQ(EC, errorToErrorCode( | 
|  | createFileError("file.bin", errorCodeToError(EC)))); | 
|  | EXPECT_EQ(EC, errorToErrorCode( | 
|  | createFileError("file.bin", /*Line=*/5, errorCodeToError(EC)))); | 
|  | } | 
|  |  | 
|  | // inconvertibleErrorCode() should be wrapped to avoid a fatal error. | 
|  | EXPECT_EQ( | 
|  | "A file error occurred.", | 
|  | errorToErrorCode(createFileError("file.bin", inconvertibleErrorCode())) | 
|  | .message()); | 
|  | EXPECT_EQ( | 
|  | "A file error occurred.", | 
|  | errorToErrorCode(createFileError("file.bin", /*Line=*/5, inconvertibleErrorCode())) | 
|  | .message()); | 
|  | } | 
|  |  | 
|  | enum class test_error_code { | 
|  | unspecified = 1, | 
|  | error_1, | 
|  | error_2, | 
|  | }; | 
|  |  | 
|  | } // end anon namespace | 
|  |  | 
|  | namespace std { | 
|  | template <> | 
|  | struct is_error_code_enum<test_error_code> : std::true_type {}; | 
|  | } // namespace std | 
|  |  | 
|  | namespace { | 
|  |  | 
|  | const std::error_category &TErrorCategory(); | 
|  |  | 
|  | inline std::error_code make_error_code(test_error_code E) { | 
|  | return std::error_code(static_cast<int>(E), TErrorCategory()); | 
|  | } | 
|  |  | 
|  | class TestDebugError : public ErrorInfo<TestDebugError, StringError> { | 
|  | public: | 
|  | using ErrorInfo<TestDebugError, StringError >::ErrorInfo; // inherit constructors | 
|  | TestDebugError(const Twine &S) : ErrorInfo(S, test_error_code::unspecified) {} | 
|  | static char ID; | 
|  | }; | 
|  |  | 
|  | class TestErrorCategory : public std::error_category { | 
|  | public: | 
|  | const char *name() const noexcept override { return "error"; } | 
|  | std::string message(int Condition) const override { | 
|  | switch (static_cast<test_error_code>(Condition)) { | 
|  | case test_error_code::unspecified: | 
|  | return "An unknown error has occurred."; | 
|  | case test_error_code::error_1: | 
|  | return "Error 1."; | 
|  | case test_error_code::error_2: | 
|  | return "Error 2."; | 
|  | } | 
|  | llvm_unreachable("Unrecognized test_error_code"); | 
|  | } | 
|  | }; | 
|  |  | 
|  | const std::error_category &TErrorCategory() { | 
|  | static TestErrorCategory TestErrCategory; | 
|  | return TestErrCategory; | 
|  | } | 
|  |  | 
|  | char TestDebugError::ID; | 
|  |  | 
|  | TEST(Error, SubtypeStringErrorTest) { | 
|  | auto E1 = make_error<TestDebugError>(test_error_code::error_1); | 
|  | EXPECT_EQ(toString(std::move(E1)), "Error 1."); | 
|  |  | 
|  | auto E2 = make_error<TestDebugError>(test_error_code::error_1, | 
|  | "Detailed information"); | 
|  | EXPECT_EQ(toString(std::move(E2)), "Error 1. Detailed information"); | 
|  |  | 
|  | auto E3 = make_error<TestDebugError>(test_error_code::error_2); | 
|  | handleAllErrors(std::move(E3), [](const TestDebugError &F) { | 
|  | EXPECT_EQ(F.message(), "Error 2."); | 
|  | }); | 
|  |  | 
|  | auto E4 = joinErrors(make_error<TestDebugError>(test_error_code::error_1, | 
|  | "Detailed information"), | 
|  | make_error<TestDebugError>(test_error_code::error_2)); | 
|  | EXPECT_EQ(toString(std::move(E4)), "Error 1. Detailed information\n" | 
|  | "Error 2."); | 
|  | } | 
|  |  | 
|  | static Error createAnyError() { | 
|  | return errorCodeToError(test_error_code::unspecified); | 
|  | } | 
|  |  | 
|  | struct MoveOnlyBox { | 
|  | std::optional<int> Box; | 
|  |  | 
|  | explicit MoveOnlyBox(int I) : Box(I) {} | 
|  | MoveOnlyBox() = default; | 
|  | MoveOnlyBox(MoveOnlyBox &&) = default; | 
|  | MoveOnlyBox &operator=(MoveOnlyBox &&) = default; | 
|  |  | 
|  | MoveOnlyBox(const MoveOnlyBox &) = delete; | 
|  | MoveOnlyBox &operator=(const MoveOnlyBox &) = delete; | 
|  |  | 
|  | bool operator==(const MoveOnlyBox &RHS) const { | 
|  | if (bool(Box) != bool(RHS.Box)) | 
|  | return false; | 
|  | return Box ? *Box == *RHS.Box : false; | 
|  | } | 
|  | }; | 
|  |  | 
|  | TEST(Error, moveInto) { | 
|  | // Use MoveOnlyBox as the T in Expected<T>. | 
|  | auto make = [](int I) -> Expected<MoveOnlyBox> { return MoveOnlyBox(I); }; | 
|  | auto makeFailure = []() -> Expected<MoveOnlyBox> { return createAnyError(); }; | 
|  |  | 
|  | { | 
|  | MoveOnlyBox V; | 
|  |  | 
|  | // Failure with no prior value. | 
|  | EXPECT_THAT_ERROR(makeFailure().moveInto(V), Failed()); | 
|  | EXPECT_EQ(std::nullopt, V.Box); | 
|  |  | 
|  | // Success with no prior value. | 
|  | EXPECT_THAT_ERROR(make(5).moveInto(V), Succeeded()); | 
|  | EXPECT_EQ(5, V.Box); | 
|  |  | 
|  | // Success with an existing value. | 
|  | EXPECT_THAT_ERROR(make(7).moveInto(V), Succeeded()); | 
|  | EXPECT_EQ(7, V.Box); | 
|  |  | 
|  | // Failure with an existing value. Might be nice to assign a | 
|  | // default-constructed value in this case, but for now it's being left | 
|  | // alone. | 
|  | EXPECT_THAT_ERROR(makeFailure().moveInto(V), Failed()); | 
|  | EXPECT_EQ(7, V.Box); | 
|  | } | 
|  |  | 
|  | // Check that this works with optionals too. | 
|  | { | 
|  | // Same cases as above. | 
|  | std::optional<MoveOnlyBox> MaybeV; | 
|  | EXPECT_THAT_ERROR(makeFailure().moveInto(MaybeV), Failed()); | 
|  | EXPECT_EQ(std::nullopt, MaybeV); | 
|  |  | 
|  | EXPECT_THAT_ERROR(make(5).moveInto(MaybeV), Succeeded()); | 
|  | EXPECT_EQ(MoveOnlyBox(5), MaybeV); | 
|  |  | 
|  | EXPECT_THAT_ERROR(make(7).moveInto(MaybeV), Succeeded()); | 
|  | EXPECT_EQ(MoveOnlyBox(7), MaybeV); | 
|  |  | 
|  | EXPECT_THAT_ERROR(makeFailure().moveInto(MaybeV), Failed()); | 
|  | EXPECT_EQ(MoveOnlyBox(7), MaybeV); | 
|  | } | 
|  | } | 
|  |  | 
|  | TEST(Error, FatalBadAllocErrorHandlersInteraction) { | 
|  | auto ErrorHandler = [](void *Data, const char *, bool) {}; | 
|  | install_fatal_error_handler(ErrorHandler, nullptr); | 
|  | // The following call should not crash; previously, a bug in | 
|  | // install_bad_alloc_error_handler asserted that no fatal-error handler is | 
|  | // installed already. | 
|  | install_bad_alloc_error_handler(ErrorHandler, nullptr); | 
|  |  | 
|  | // Don't interfere with other tests. | 
|  | remove_fatal_error_handler(); | 
|  | remove_bad_alloc_error_handler(); | 
|  | } | 
|  |  | 
|  | TEST(Error, BadAllocFatalErrorHandlersInteraction) { | 
|  | auto ErrorHandler = [](void *Data, const char *, bool) {}; | 
|  | install_bad_alloc_error_handler(ErrorHandler, nullptr); | 
|  | // The following call should not crash; related to | 
|  | // FatalBadAllocErrorHandlersInteraction: Ensure that the error does not occur | 
|  | // in the other direction. | 
|  | install_fatal_error_handler(ErrorHandler, nullptr); | 
|  |  | 
|  | // Don't interfere with other tests. | 
|  | remove_fatal_error_handler(); | 
|  | remove_bad_alloc_error_handler(); | 
|  | } | 
|  |  | 
|  | TEST(Error, ForwardToExpected) { | 
|  | auto ErrorReturningFct = [](bool Fail) { | 
|  | return Fail ? make_error<StringError>(llvm::errc::invalid_argument, | 
|  | "Some Error") | 
|  | : Error::success(); | 
|  | }; | 
|  | auto ExpectedReturningFct = [&](bool Fail) -> Expected<int> { | 
|  | auto Err = ErrorReturningFct(Fail); | 
|  | if (Err) | 
|  | return Err; | 
|  | return 42; | 
|  | }; | 
|  | std::optional<int> MaybeV; | 
|  | EXPECT_THAT_ERROR(ExpectedReturningFct(true).moveInto(MaybeV), Failed()); | 
|  | EXPECT_THAT_ERROR(ExpectedReturningFct(false).moveInto(MaybeV), Succeeded()); | 
|  | EXPECT_EQ(*MaybeV, 42); | 
|  | } | 
|  | } // namespace |