1 //===-- error_test.cpp --sssssssss-----------------------------------------===// 2 // 3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4 // See https://llvm.org/LICENSE.txt for license information. 5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6 // 7 //===----------------------------------------------------------------------===// 8 // 9 // This file is a part of the ORC runtime. 10 // 11 // Note: 12 // This unit test was adapted from 13 // llvm/unittests/Support/ExtensibleRTTITest.cpp 14 // 15 //===----------------------------------------------------------------------===// 16 17 #include "error.h" 18 #include "gtest/gtest.h" 19 20 using namespace __orc_rt; 21 22 namespace { 23 24 class CustomError : public RTTIExtends<CustomError, ErrorInfoBase> { 25 public: 26 CustomError(int V1) : V1(V1) {} 27 std::string toString() const override { 28 return "CustomError V1 = " + std::to_string(V1); 29 } 30 int getV1() const { return V1; } 31 32 protected: 33 int V1; 34 }; 35 36 class CustomSubError : public RTTIExtends<CustomSubError, CustomError> { 37 public: 38 CustomSubError(int V1, std::string V2) 39 : RTTIExtends<CustomSubError, CustomError>(V1), V2(std::move(V2)) {} 40 std::string toString() const override { 41 return "CustomSubError V1 = " + std::to_string(V1) + ", " + V2; 42 } 43 const std::string &getV2() const { return V2; } 44 45 protected: 46 std::string V2; 47 }; 48 49 } // end anonymous namespace 50 51 // Test that a checked success value doesn't cause any issues. 52 TEST(Error, CheckedSuccess) { 53 Error E = Error::success(); 54 EXPECT_FALSE(E) << "Unexpected error while testing Error 'Success'"; 55 } 56 57 // Check that a consumed success value doesn't cause any issues. 58 TEST(Error, ConsumeSuccess) { consumeError(Error::success()); } 59 60 TEST(Error, ConsumeError) { 61 Error E = make_error<CustomError>(42); 62 if (E) { 63 consumeError(std::move(E)); 64 } else 65 ADD_FAILURE() << "Error failure value should convert to true"; 66 } 67 68 // Test that unchecked success values cause an abort. 69 TEST(Error, UncheckedSuccess) { 70 EXPECT_DEATH({ Error E = Error::success(); }, 71 "Error must be checked prior to destruction") 72 << "Unchecked Error Succes value did not cause abort()"; 73 } 74 75 // Test that a checked but unhandled error causes an abort. 76 TEST(Error, CheckedButUnhandledError) { 77 auto DropUnhandledError = []() { 78 Error E = make_error<CustomError>(42); 79 (void)!E; 80 }; 81 EXPECT_DEATH(DropUnhandledError(), 82 "Error must be checked prior to destruction") 83 << "Unhandled Error failure value did not cause an abort()"; 84 } 85 86 // Test that error_cast works as expected. 87 TEST(Error, BasicErrorCast) { 88 { 89 // Check casting base error value to base error type. 90 auto E = make_error<CustomError>(42); 91 if (auto CSE = error_cast<CustomSubError>(E)) { 92 ADD_FAILURE() << "Derived cast incorrectly matched base error"; 93 } else if (auto CE = error_cast<CustomError>(E)) { 94 EXPECT_EQ(CE->getV1(), 42) << "Unexpected wrapped value"; 95 } else 96 ADD_FAILURE() << "Unexpected error value"; 97 } 98 99 { 100 // Check casting derived error value to base error type. 101 auto E = make_error<CustomSubError>(42, "foo"); 102 if (auto CE = error_cast<CustomError>(E)) { 103 EXPECT_EQ(CE->getV1(), 42) << "Unexpected wrapped value"; 104 } else 105 ADD_FAILURE() << "Unexpected error value"; 106 } 107 108 { 109 // Check casting derived error value to derived error type. 110 auto E = make_error<CustomSubError>(42, "foo"); 111 if (auto CSE = error_cast<CustomSubError>(E)) { 112 EXPECT_EQ(CSE->getV1(), 42) << "Unexpected wrapped value"; 113 EXPECT_EQ(CSE->getV2(), "foo") << "Unexpected wrapped value"; 114 } else 115 ADD_FAILURE() << "Unexpected error value"; 116 } 117 } 118 119 // ErrorAsOutParameter tester. 120 static void errAsOutParamHelper(Error &Err) { 121 ErrorAsOutParameter ErrAsOutParam(&Err); 122 // Verify that checked flag is raised - assignment should not crash. 123 Err = Error::success(); 124 // Raise the checked bit manually - caller should still have to test the 125 // error. 126 (void)!!Err; 127 } 128 129 // Test that ErrorAsOutParameter sets the checked flag on construction. 130 TEST(Error, ErrorAsOutParameterChecked) { 131 Error E = Error::success(); 132 errAsOutParamHelper(E); 133 (void)!!E; 134 } 135 136 // Test that ErrorAsOutParameter clears the checked flag on destruction. 137 TEST(Error, ErrorAsOutParameterUnchecked) { 138 EXPECT_DEATH( 139 { 140 Error E = Error::success(); 141 errAsOutParamHelper(E); 142 }, 143 "Error must be checked prior to destruction") 144 << "ErrorAsOutParameter did not clear the checked flag on destruction."; 145 } 146 147 // Check 'Error::isA<T>' method handling. 148 TEST(Error, IsAHandling) { 149 // Check 'isA' handling. 150 Error E = make_error<CustomError>(42); 151 Error F = make_error<CustomSubError>(42, "foo"); 152 Error G = Error::success(); 153 154 EXPECT_TRUE(E.isA<CustomError>()); 155 EXPECT_FALSE(E.isA<CustomSubError>()); 156 EXPECT_TRUE(F.isA<CustomError>()); 157 EXPECT_TRUE(F.isA<CustomSubError>()); 158 EXPECT_FALSE(G.isA<CustomError>()); 159 160 consumeError(std::move(E)); 161 consumeError(std::move(F)); 162 consumeError(std::move(G)); 163 } 164 165 TEST(Error, StringError) { 166 auto E = make_error<StringError>("foo"); 167 if (auto SE = error_cast<StringError>(E)) { 168 EXPECT_EQ(SE->toString(), "foo") << "Unexpected StringError value"; 169 } else 170 ADD_FAILURE() << "Expected StringError value"; 171 } 172 173 // Test Checked Expected<T> in success mode. 174 TEST(Error, CheckedExpectedInSuccessMode) { 175 Expected<int> A = 7; 176 EXPECT_TRUE(!!A) << "Expected with non-error value doesn't convert to 'true'"; 177 // Access is safe in second test, since we checked the error in the first. 178 EXPECT_EQ(*A, 7) << "Incorrect Expected non-error value"; 179 } 180 181 // Test Expected with reference type. 182 TEST(Error, ExpectedWithReferenceType) { 183 int A = 7; 184 Expected<int &> B = A; 185 // 'Check' B. 186 (void)!!B; 187 int &C = *B; 188 EXPECT_EQ(&A, &C) << "Expected failed to propagate reference"; 189 } 190 191 // Test Unchecked Expected<T> in success mode. 192 // We expect this to blow up the same way Error would. 193 // Test runs in debug mode only. 194 TEST(Error, UncheckedExpectedInSuccessModeDestruction) { 195 EXPECT_DEATH({ Expected<int> A = 7; }, 196 "Expected<T> must be checked before access or destruction.") 197 << "Unchecekd Expected<T> success value did not cause an abort()."; 198 } 199 200 // Test Unchecked Expected<T> in success mode. 201 // We expect this to blow up the same way Error would. 202 // Test runs in debug mode only. 203 TEST(Error, UncheckedExpectedInSuccessModeAccess) { 204 EXPECT_DEATH( 205 { 206 Expected<int> A = 7; 207 *A; 208 }, 209 "Expected<T> must be checked before access or destruction.") 210 << "Unchecekd Expected<T> success value did not cause an abort()."; 211 } 212 213 // Test Unchecked Expected<T> in success mode. 214 // We expect this to blow up the same way Error would. 215 // Test runs in debug mode only. 216 TEST(Error, UncheckedExpectedInSuccessModeAssignment) { 217 EXPECT_DEATH( 218 { 219 Expected<int> A = 7; 220 A = 7; 221 }, 222 "Expected<T> must be checked before access or destruction.") 223 << "Unchecekd Expected<T> success value did not cause an abort()."; 224 } 225 226 // Test Expected<T> in failure mode. 227 TEST(Error, ExpectedInFailureMode) { 228 Expected<int> A = make_error<CustomError>(42); 229 EXPECT_FALSE(!!A) << "Expected with error value doesn't convert to 'false'"; 230 Error E = A.takeError(); 231 EXPECT_TRUE(E.isA<CustomError>()) << "Incorrect Expected error value"; 232 consumeError(std::move(E)); 233 } 234 235 // Check that an Expected instance with an error value doesn't allow access to 236 // operator*. 237 // Test runs in debug mode only. 238 TEST(Error, AccessExpectedInFailureMode) { 239 Expected<int> A = make_error<CustomError>(42); 240 EXPECT_DEATH(*A, "Expected<T> must be checked before access or destruction.") 241 << "Incorrect Expected error value"; 242 consumeError(A.takeError()); 243 } 244 245 // Check that an Expected instance with an error triggers an abort if 246 // unhandled. 247 // Test runs in debug mode only. 248 TEST(Error, UnhandledExpectedInFailureMode) { 249 EXPECT_DEATH({ Expected<int> A = make_error<CustomError>(42); }, 250 "Expected<T> must be checked before access or destruction.") 251 << "Unchecked Expected<T> failure value did not cause an abort()"; 252 } 253 254 // Test covariance of Expected. 255 TEST(Error, ExpectedCovariance) { 256 class B {}; 257 class D : public B {}; 258 259 Expected<B *> A1(Expected<D *>(nullptr)); 260 // Check A1 by converting to bool before assigning to it. 261 (void)!!A1; 262 A1 = Expected<D *>(nullptr); 263 // Check A1 again before destruction. 264 (void)!!A1; 265 266 Expected<std::unique_ptr<B>> A2(Expected<std::unique_ptr<D>>(nullptr)); 267 // Check A2 by converting to bool before assigning to it. 268 (void)!!A2; 269 A2 = Expected<std::unique_ptr<D>>(nullptr); 270 // Check A2 again before destruction. 271 (void)!!A2; 272 } 273 274 // Test that the ExitOnError utility works as expected. 275 TEST(Error, CantFailSuccess) { 276 cantFail(Error::success()); 277 278 int X = cantFail(Expected<int>(42)); 279 EXPECT_EQ(X, 42) << "Expected value modified by cantFail"; 280 281 int Dummy = 42; 282 int &Y = cantFail(Expected<int &>(Dummy)); 283 EXPECT_EQ(&Dummy, &Y) << "Reference mangled by cantFail"; 284 } 285 286 // Test that cantFail results in a crash if you pass it a failure value. 287 TEST(Error, CantFailDeath) { 288 EXPECT_DEATH(cantFail(make_error<StringError>("foo")), 289 "cantFail called on failure value") 290 << "cantFail(Error) did not cause an abort for failure value"; 291 292 EXPECT_DEATH(cantFail(Expected<int>(make_error<StringError>("foo"))), 293 "cantFail called on failure value") 294 << "cantFail(Expected<int>) did not cause an abort for failure value"; 295 } 296