11169586dSLang Hames //===-- error_test.cpp --sssssssss-----------------------------------------===// 21169586dSLang Hames // 31169586dSLang Hames // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 41169586dSLang Hames // See https://llvm.org/LICENSE.txt for license information. 51169586dSLang Hames // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 61169586dSLang Hames // 71169586dSLang Hames //===----------------------------------------------------------------------===// 81169586dSLang Hames // 91169586dSLang Hames // This file is a part of the ORC runtime. 101169586dSLang Hames // 111169586dSLang Hames // Note: 121169586dSLang Hames // This unit test was adapted from 131169586dSLang Hames // llvm/unittests/Support/ExtensibleRTTITest.cpp 141169586dSLang Hames // 151169586dSLang Hames //===----------------------------------------------------------------------===// 161169586dSLang Hames 171169586dSLang Hames #include "error.h" 181169586dSLang Hames #include "gtest/gtest.h" 191169586dSLang Hames 20*dbd81ba2SMikhail Goncharov using namespace orc_rt; 211169586dSLang Hames 221169586dSLang Hames namespace { 231169586dSLang Hames 241169586dSLang Hames class CustomError : public RTTIExtends<CustomError, ErrorInfoBase> { 251169586dSLang Hames public: 261169586dSLang Hames CustomError(int V1) : V1(V1) {} 271169586dSLang Hames std::string toString() const override { 281169586dSLang Hames return "CustomError V1 = " + std::to_string(V1); 291169586dSLang Hames } 301169586dSLang Hames int getV1() const { return V1; } 311169586dSLang Hames 321169586dSLang Hames protected: 331169586dSLang Hames int V1; 341169586dSLang Hames }; 351169586dSLang Hames 361169586dSLang Hames class CustomSubError : public RTTIExtends<CustomSubError, CustomError> { 371169586dSLang Hames public: 381169586dSLang Hames CustomSubError(int V1, std::string V2) 391169586dSLang Hames : RTTIExtends<CustomSubError, CustomError>(V1), V2(std::move(V2)) {} 401169586dSLang Hames std::string toString() const override { 411169586dSLang Hames return "CustomSubError V1 = " + std::to_string(V1) + ", " + V2; 421169586dSLang Hames } 431169586dSLang Hames const std::string &getV2() const { return V2; } 441169586dSLang Hames 451169586dSLang Hames protected: 461169586dSLang Hames std::string V2; 471169586dSLang Hames }; 481169586dSLang Hames 491169586dSLang Hames } // end anonymous namespace 501169586dSLang Hames 511169586dSLang Hames // Test that a checked success value doesn't cause any issues. 521169586dSLang Hames TEST(Error, CheckedSuccess) { 531169586dSLang Hames Error E = Error::success(); 541169586dSLang Hames EXPECT_FALSE(E) << "Unexpected error while testing Error 'Success'"; 551169586dSLang Hames } 561169586dSLang Hames 571169586dSLang Hames // Check that a consumed success value doesn't cause any issues. 581169586dSLang Hames TEST(Error, ConsumeSuccess) { consumeError(Error::success()); } 591169586dSLang Hames 601169586dSLang Hames TEST(Error, ConsumeError) { 611169586dSLang Hames Error E = make_error<CustomError>(42); 621169586dSLang Hames if (E) { 631169586dSLang Hames consumeError(std::move(E)); 641169586dSLang Hames } else 651169586dSLang Hames ADD_FAILURE() << "Error failure value should convert to true"; 661169586dSLang Hames } 671169586dSLang Hames 681169586dSLang Hames // Test that unchecked success values cause an abort. 691169586dSLang Hames TEST(Error, UncheckedSuccess) { 701169586dSLang Hames EXPECT_DEATH({ Error E = Error::success(); }, 711169586dSLang Hames "Error must be checked prior to destruction") 721169586dSLang Hames << "Unchecked Error Succes value did not cause abort()"; 731169586dSLang Hames } 741169586dSLang Hames 751169586dSLang Hames // Test that a checked but unhandled error causes an abort. 761169586dSLang Hames TEST(Error, CheckedButUnhandledError) { 771169586dSLang Hames auto DropUnhandledError = []() { 781169586dSLang Hames Error E = make_error<CustomError>(42); 791169586dSLang Hames (void)!E; 801169586dSLang Hames }; 811169586dSLang Hames EXPECT_DEATH(DropUnhandledError(), 821169586dSLang Hames "Error must be checked prior to destruction") 831169586dSLang Hames << "Unhandled Error failure value did not cause an abort()"; 841169586dSLang Hames } 851169586dSLang Hames 861169586dSLang Hames // Test that error_cast works as expected. 871169586dSLang Hames TEST(Error, BasicErrorCast) { 881169586dSLang Hames { 891169586dSLang Hames // Check casting base error value to base error type. 901169586dSLang Hames auto E = make_error<CustomError>(42); 911169586dSLang Hames if (auto CSE = error_cast<CustomSubError>(E)) { 921169586dSLang Hames ADD_FAILURE() << "Derived cast incorrectly matched base error"; 931169586dSLang Hames } else if (auto CE = error_cast<CustomError>(E)) { 941169586dSLang Hames EXPECT_EQ(CE->getV1(), 42) << "Unexpected wrapped value"; 951169586dSLang Hames } else 961169586dSLang Hames ADD_FAILURE() << "Unexpected error value"; 971169586dSLang Hames } 981169586dSLang Hames 991169586dSLang Hames { 1001169586dSLang Hames // Check casting derived error value to base error type. 1011169586dSLang Hames auto E = make_error<CustomSubError>(42, "foo"); 1021169586dSLang Hames if (auto CE = error_cast<CustomError>(E)) { 1031169586dSLang Hames EXPECT_EQ(CE->getV1(), 42) << "Unexpected wrapped value"; 1041169586dSLang Hames } else 1051169586dSLang Hames ADD_FAILURE() << "Unexpected error value"; 1061169586dSLang Hames } 1071169586dSLang Hames 1081169586dSLang Hames { 1091169586dSLang Hames // Check casting derived error value to derived error type. 1101169586dSLang Hames auto E = make_error<CustomSubError>(42, "foo"); 1111169586dSLang Hames if (auto CSE = error_cast<CustomSubError>(E)) { 1121169586dSLang Hames EXPECT_EQ(CSE->getV1(), 42) << "Unexpected wrapped value"; 1131169586dSLang Hames EXPECT_EQ(CSE->getV2(), "foo") << "Unexpected wrapped value"; 1141169586dSLang Hames } else 1151169586dSLang Hames ADD_FAILURE() << "Unexpected error value"; 1161169586dSLang Hames } 1171169586dSLang Hames } 1181169586dSLang Hames 1191169586dSLang Hames // ErrorAsOutParameter tester. 1201169586dSLang Hames static void errAsOutParamHelper(Error &Err) { 1211169586dSLang Hames ErrorAsOutParameter ErrAsOutParam(&Err); 1221169586dSLang Hames // Verify that checked flag is raised - assignment should not crash. 1231169586dSLang Hames Err = Error::success(); 1241169586dSLang Hames // Raise the checked bit manually - caller should still have to test the 1251169586dSLang Hames // error. 1261169586dSLang Hames (void)!!Err; 1271169586dSLang Hames } 1281169586dSLang Hames 1291169586dSLang Hames // Test that ErrorAsOutParameter sets the checked flag on construction. 1301169586dSLang Hames TEST(Error, ErrorAsOutParameterChecked) { 1311169586dSLang Hames Error E = Error::success(); 1321169586dSLang Hames errAsOutParamHelper(E); 1331169586dSLang Hames (void)!!E; 1341169586dSLang Hames } 1351169586dSLang Hames 1361169586dSLang Hames // Test that ErrorAsOutParameter clears the checked flag on destruction. 1371169586dSLang Hames TEST(Error, ErrorAsOutParameterUnchecked) { 1381169586dSLang Hames EXPECT_DEATH( 1391169586dSLang Hames { 1401169586dSLang Hames Error E = Error::success(); 1411169586dSLang Hames errAsOutParamHelper(E); 1421169586dSLang Hames }, 1431169586dSLang Hames "Error must be checked prior to destruction") 1441169586dSLang Hames << "ErrorAsOutParameter did not clear the checked flag on destruction."; 1451169586dSLang Hames } 1461169586dSLang Hames 1471169586dSLang Hames // Check 'Error::isA<T>' method handling. 1481169586dSLang Hames TEST(Error, IsAHandling) { 1491169586dSLang Hames // Check 'isA' handling. 1501169586dSLang Hames Error E = make_error<CustomError>(42); 1511169586dSLang Hames Error F = make_error<CustomSubError>(42, "foo"); 1521169586dSLang Hames Error G = Error::success(); 1531169586dSLang Hames 1541169586dSLang Hames EXPECT_TRUE(E.isA<CustomError>()); 1551169586dSLang Hames EXPECT_FALSE(E.isA<CustomSubError>()); 1561169586dSLang Hames EXPECT_TRUE(F.isA<CustomError>()); 1571169586dSLang Hames EXPECT_TRUE(F.isA<CustomSubError>()); 1581169586dSLang Hames EXPECT_FALSE(G.isA<CustomError>()); 1591169586dSLang Hames 1601169586dSLang Hames consumeError(std::move(E)); 1611169586dSLang Hames consumeError(std::move(F)); 1621169586dSLang Hames consumeError(std::move(G)); 1631169586dSLang Hames } 1641169586dSLang Hames 1651169586dSLang Hames TEST(Error, StringError) { 1661169586dSLang Hames auto E = make_error<StringError>("foo"); 1671169586dSLang Hames if (auto SE = error_cast<StringError>(E)) { 1681169586dSLang Hames EXPECT_EQ(SE->toString(), "foo") << "Unexpected StringError value"; 1691169586dSLang Hames } else 1701169586dSLang Hames ADD_FAILURE() << "Expected StringError value"; 1711169586dSLang Hames } 1721169586dSLang Hames 1731169586dSLang Hames // Test Checked Expected<T> in success mode. 1741169586dSLang Hames TEST(Error, CheckedExpectedInSuccessMode) { 1751169586dSLang Hames Expected<int> A = 7; 1761169586dSLang Hames EXPECT_TRUE(!!A) << "Expected with non-error value doesn't convert to 'true'"; 1771169586dSLang Hames // Access is safe in second test, since we checked the error in the first. 1781169586dSLang Hames EXPECT_EQ(*A, 7) << "Incorrect Expected non-error value"; 1791169586dSLang Hames } 1801169586dSLang Hames 1811169586dSLang Hames // Test Expected with reference type. 1821169586dSLang Hames TEST(Error, ExpectedWithReferenceType) { 1831169586dSLang Hames int A = 7; 1841169586dSLang Hames Expected<int &> B = A; 1851169586dSLang Hames // 'Check' B. 1861169586dSLang Hames (void)!!B; 1871169586dSLang Hames int &C = *B; 1881169586dSLang Hames EXPECT_EQ(&A, &C) << "Expected failed to propagate reference"; 1891169586dSLang Hames } 1901169586dSLang Hames 1911169586dSLang Hames // Test Unchecked Expected<T> in success mode. 1921169586dSLang Hames // We expect this to blow up the same way Error would. 1931169586dSLang Hames // Test runs in debug mode only. 1941169586dSLang Hames TEST(Error, UncheckedExpectedInSuccessModeDestruction) { 1951169586dSLang Hames EXPECT_DEATH({ Expected<int> A = 7; }, 1961169586dSLang Hames "Expected<T> must be checked before access or destruction.") 1971169586dSLang Hames << "Unchecekd Expected<T> success value did not cause an abort()."; 1981169586dSLang Hames } 1991169586dSLang Hames 2001169586dSLang Hames // Test Unchecked Expected<T> in success mode. 2011169586dSLang Hames // We expect this to blow up the same way Error would. 2021169586dSLang Hames // Test runs in debug mode only. 2031169586dSLang Hames TEST(Error, UncheckedExpectedInSuccessModeAccess) { 2041169586dSLang Hames EXPECT_DEATH( 2051169586dSLang Hames { 2061169586dSLang Hames Expected<int> A = 7; 2071169586dSLang Hames *A; 2081169586dSLang Hames }, 2091169586dSLang Hames "Expected<T> must be checked before access or destruction.") 2101169586dSLang Hames << "Unchecekd Expected<T> success value did not cause an abort()."; 2111169586dSLang Hames } 2121169586dSLang Hames 2131169586dSLang Hames // Test Unchecked Expected<T> in success mode. 2141169586dSLang Hames // We expect this to blow up the same way Error would. 2151169586dSLang Hames // Test runs in debug mode only. 2161169586dSLang Hames TEST(Error, UncheckedExpectedInSuccessModeAssignment) { 2171169586dSLang Hames EXPECT_DEATH( 2181169586dSLang Hames { 2191169586dSLang Hames Expected<int> A = 7; 2201169586dSLang Hames A = 7; 2211169586dSLang Hames }, 2221169586dSLang Hames "Expected<T> must be checked before access or destruction.") 2231169586dSLang Hames << "Unchecekd Expected<T> success value did not cause an abort()."; 2241169586dSLang Hames } 2251169586dSLang Hames 2261169586dSLang Hames // Test Expected<T> in failure mode. 2271169586dSLang Hames TEST(Error, ExpectedInFailureMode) { 2281169586dSLang Hames Expected<int> A = make_error<CustomError>(42); 2291169586dSLang Hames EXPECT_FALSE(!!A) << "Expected with error value doesn't convert to 'false'"; 2301169586dSLang Hames Error E = A.takeError(); 2311169586dSLang Hames EXPECT_TRUE(E.isA<CustomError>()) << "Incorrect Expected error value"; 2321169586dSLang Hames consumeError(std::move(E)); 2331169586dSLang Hames } 2341169586dSLang Hames 2351169586dSLang Hames // Check that an Expected instance with an error value doesn't allow access to 2361169586dSLang Hames // operator*. 2371169586dSLang Hames // Test runs in debug mode only. 2381169586dSLang Hames TEST(Error, AccessExpectedInFailureMode) { 2391169586dSLang Hames Expected<int> A = make_error<CustomError>(42); 2401169586dSLang Hames EXPECT_DEATH(*A, "Expected<T> must be checked before access or destruction.") 2411169586dSLang Hames << "Incorrect Expected error value"; 2421169586dSLang Hames consumeError(A.takeError()); 2431169586dSLang Hames } 2441169586dSLang Hames 2451169586dSLang Hames // Check that an Expected instance with an error triggers an abort if 2461169586dSLang Hames // unhandled. 2471169586dSLang Hames // Test runs in debug mode only. 2481169586dSLang Hames TEST(Error, UnhandledExpectedInFailureMode) { 2491169586dSLang Hames EXPECT_DEATH({ Expected<int> A = make_error<CustomError>(42); }, 2501169586dSLang Hames "Expected<T> must be checked before access or destruction.") 2511169586dSLang Hames << "Unchecked Expected<T> failure value did not cause an abort()"; 2521169586dSLang Hames } 2531169586dSLang Hames 2541169586dSLang Hames // Test covariance of Expected. 2551169586dSLang Hames TEST(Error, ExpectedCovariance) { 2561169586dSLang Hames class B {}; 2571169586dSLang Hames class D : public B {}; 2581169586dSLang Hames 2591169586dSLang Hames Expected<B *> A1(Expected<D *>(nullptr)); 2601169586dSLang Hames // Check A1 by converting to bool before assigning to it. 2611169586dSLang Hames (void)!!A1; 2621169586dSLang Hames A1 = Expected<D *>(nullptr); 2631169586dSLang Hames // Check A1 again before destruction. 2641169586dSLang Hames (void)!!A1; 2651169586dSLang Hames 2661169586dSLang Hames Expected<std::unique_ptr<B>> A2(Expected<std::unique_ptr<D>>(nullptr)); 2671169586dSLang Hames // Check A2 by converting to bool before assigning to it. 2681169586dSLang Hames (void)!!A2; 2691169586dSLang Hames A2 = Expected<std::unique_ptr<D>>(nullptr); 2701169586dSLang Hames // Check A2 again before destruction. 2711169586dSLang Hames (void)!!A2; 2721169586dSLang Hames } 2731169586dSLang Hames 2741169586dSLang Hames // Test that the ExitOnError utility works as expected. 2751169586dSLang Hames TEST(Error, CantFailSuccess) { 2761169586dSLang Hames cantFail(Error::success()); 2771169586dSLang Hames 2781169586dSLang Hames int X = cantFail(Expected<int>(42)); 2791169586dSLang Hames EXPECT_EQ(X, 42) << "Expected value modified by cantFail"; 2801169586dSLang Hames 2811169586dSLang Hames int Dummy = 42; 2821169586dSLang Hames int &Y = cantFail(Expected<int &>(Dummy)); 2831169586dSLang Hames EXPECT_EQ(&Dummy, &Y) << "Reference mangled by cantFail"; 2841169586dSLang Hames } 2851169586dSLang Hames 2861169586dSLang Hames // Test that cantFail results in a crash if you pass it a failure value. 2871169586dSLang Hames TEST(Error, CantFailDeath) { 2881169586dSLang Hames EXPECT_DEATH(cantFail(make_error<StringError>("foo")), 2891169586dSLang Hames "cantFail called on failure value") 2901169586dSLang Hames << "cantFail(Error) did not cause an abort for failure value"; 2911169586dSLang Hames 2921169586dSLang Hames EXPECT_DEATH(cantFail(Expected<int>(make_error<StringError>("foo"))), 2931169586dSLang Hames "cantFail called on failure value") 2941169586dSLang Hames << "cantFail(Expected<int>) did not cause an abort for failure value"; 2951169586dSLang Hames } 296