Lang Hames | f7f6d3e | 2016-03-16 01:02:46 +0000 | [diff] [blame] | 1 | //===----- unittests/ErrorTest.cpp - Error.h tests ------------------------===// |
| 2 | // |
| 3 | // The LLVM Compiler Infrastructure |
| 4 | // |
| 5 | // This file is distributed under the University of Illinois Open Source |
| 6 | // License. See LICENSE.TXT for details. |
| 7 | // |
| 8 | //===----------------------------------------------------------------------===// |
| 9 | |
| 10 | #include "llvm/Support/Error.h" |
| 11 | #include "llvm/Support/Errc.h" |
Lang Hames | e7aad35 | 2016-03-23 23:57:28 +0000 | [diff] [blame] | 12 | #include "llvm/Support/ErrorHandling.h" |
Lang Hames | f7f6d3e | 2016-03-16 01:02:46 +0000 | [diff] [blame] | 13 | #include "gtest/gtest.h" |
| 14 | #include <memory> |
| 15 | |
| 16 | using namespace llvm; |
| 17 | |
| 18 | namespace { |
| 19 | |
Lang Hames | f7f6d3e | 2016-03-16 01:02:46 +0000 | [diff] [blame] | 20 | // Custom error class with a default base class and some random 'info' attached. |
| 21 | class CustomError : public ErrorInfo<CustomError> { |
| 22 | public: |
| 23 | // Create an error with some info attached. |
| 24 | CustomError(int Info) : Info(Info) {} |
| 25 | |
| 26 | // Get the info attached to this error. |
| 27 | int getInfo() const { return Info; } |
| 28 | |
| 29 | // Log this error to a stream. |
| 30 | void log(raw_ostream &OS) const override { |
| 31 | OS << "CustomError { " << getInfo() << "}"; |
| 32 | } |
| 33 | |
Lang Hames | e7aad35 | 2016-03-23 23:57:28 +0000 | [diff] [blame] | 34 | std::error_code convertToErrorCode() const override { |
| 35 | llvm_unreachable("CustomError doesn't support ECError conversion"); |
| 36 | } |
| 37 | |
Lang Hames | f7f6d3e | 2016-03-16 01:02:46 +0000 | [diff] [blame] | 38 | protected: |
| 39 | // This error is subclassed below, but we can't use inheriting constructors |
| 40 | // yet, so we can't propagate the constructors through ErrorInfo. Instead |
| 41 | // we have to have a default constructor and have the subclass initialize all |
| 42 | // fields. |
| 43 | CustomError() : Info(0) {} |
| 44 | |
| 45 | int Info; |
| 46 | }; |
| 47 | |
| 48 | // Custom error class with a custom base class and some additional random |
| 49 | // 'info'. |
| 50 | class CustomSubError : public ErrorInfo<CustomSubError, CustomError> { |
| 51 | public: |
| 52 | // Create a sub-error with some info attached. |
| 53 | CustomSubError(int Info, int ExtraInfo) : ExtraInfo(ExtraInfo) { |
| 54 | this->Info = Info; |
| 55 | } |
| 56 | |
| 57 | // Get the extra info attached to this error. |
| 58 | int getExtraInfo() const { return ExtraInfo; } |
| 59 | |
| 60 | // Log this error to a stream. |
| 61 | void log(raw_ostream &OS) const override { |
| 62 | OS << "CustomSubError { " << getInfo() << ", " << getExtraInfo() << "}"; |
| 63 | } |
| 64 | |
Lang Hames | e7aad35 | 2016-03-23 23:57:28 +0000 | [diff] [blame] | 65 | std::error_code convertToErrorCode() const override { |
| 66 | llvm_unreachable("CustomSubError doesn't support ECError conversion"); |
| 67 | } |
| 68 | |
Lang Hames | f7f6d3e | 2016-03-16 01:02:46 +0000 | [diff] [blame] | 69 | protected: |
| 70 | int ExtraInfo; |
| 71 | }; |
| 72 | |
Lang Hames | f7f6d3e | 2016-03-16 01:02:46 +0000 | [diff] [blame] | 73 | static Error handleCustomError(const CustomError &CE) { return Error(); } |
| 74 | |
| 75 | static void handleCustomErrorVoid(const CustomError &CE) {} |
| 76 | |
| 77 | static Error handleCustomErrorUP(std::unique_ptr<CustomError> CE) { |
| 78 | return Error(); |
| 79 | } |
| 80 | |
| 81 | static void handleCustomErrorUPVoid(std::unique_ptr<CustomError> CE) {} |
| 82 | |
Lang Hames | 01864a2 | 2016-03-18 00:12:37 +0000 | [diff] [blame] | 83 | // Test that success values implicitly convert to false, and don't cause crashes |
| 84 | // once they've been implicitly converted. |
| 85 | TEST(Error, CheckedSuccess) { |
| 86 | Error E; |
| 87 | EXPECT_FALSE(E) << "Unexpected error while testing Error 'Success'"; |
| 88 | } |
| 89 | |
| 90 | // Test that unchecked succes values cause an abort. |
| 91 | #ifndef NDEBUG |
| 92 | TEST(Error, UncheckedSuccess) { |
| 93 | EXPECT_DEATH({ Error E; }, "Program aborted due to an unhandled Error:") |
| 94 | << "Unchecked Error Succes value did not cause abort()"; |
| 95 | } |
| 96 | #endif |
| 97 | |
Lang Hames | f7f6d3e | 2016-03-16 01:02:46 +0000 | [diff] [blame] | 98 | // Check that we abort on unhandled failure cases. (Force conversion to bool |
| 99 | // to make sure that we don't accidentally treat checked errors as handled). |
| 100 | // Test runs in debug mode only. |
| 101 | #ifndef NDEBUG |
Lang Hames | 01864a2 | 2016-03-18 00:12:37 +0000 | [diff] [blame] | 102 | TEST(Error, UncheckedError) { |
| 103 | auto DropUnhandledError = []() { |
| 104 | Error E = make_error<CustomError>(42); |
| 105 | (void)!E; |
| 106 | }; |
| 107 | EXPECT_DEATH(DropUnhandledError(), |
| 108 | "Program aborted due to an unhandled Error:") |
| 109 | << "Unhandled Error failure value did not cause abort()"; |
| 110 | } |
Lang Hames | f7f6d3e | 2016-03-16 01:02:46 +0000 | [diff] [blame] | 111 | #endif |
| 112 | |
Lang Hames | 01864a2 | 2016-03-18 00:12:37 +0000 | [diff] [blame] | 113 | // Check 'Error::isA<T>' method handling. |
| 114 | TEST(Error, IsAHandling) { |
Lang Hames | f7f6d3e | 2016-03-16 01:02:46 +0000 | [diff] [blame] | 115 | // Check 'isA' handling. |
Lang Hames | 01864a2 | 2016-03-18 00:12:37 +0000 | [diff] [blame] | 116 | Error E = make_error<CustomError>(1); |
| 117 | Error F = make_error<CustomSubError>(1, 2); |
| 118 | Error G = Error::success(); |
Lang Hames | f7f6d3e | 2016-03-16 01:02:46 +0000 | [diff] [blame] | 119 | |
Lang Hames | 01864a2 | 2016-03-18 00:12:37 +0000 | [diff] [blame] | 120 | EXPECT_TRUE(E.isA<CustomError>()); |
| 121 | EXPECT_FALSE(E.isA<CustomSubError>()); |
| 122 | EXPECT_TRUE(F.isA<CustomError>()); |
| 123 | EXPECT_TRUE(F.isA<CustomSubError>()); |
| 124 | EXPECT_FALSE(G.isA<CustomError>()); |
Lang Hames | f7f6d3e | 2016-03-16 01:02:46 +0000 | [diff] [blame] | 125 | |
Lang Hames | 01864a2 | 2016-03-18 00:12:37 +0000 | [diff] [blame] | 126 | consumeError(std::move(E)); |
| 127 | consumeError(std::move(F)); |
| 128 | consumeError(std::move(G)); |
| 129 | } |
Lang Hames | f7f6d3e | 2016-03-16 01:02:46 +0000 | [diff] [blame] | 130 | |
Lang Hames | 01864a2 | 2016-03-18 00:12:37 +0000 | [diff] [blame] | 131 | // Check that we can handle a custom error. |
| 132 | TEST(Error, HandleCustomError) { |
| 133 | int CaughtErrorInfo = 0; |
| 134 | handleAllErrors(make_error<CustomError>(42), [&](const CustomError &CE) { |
| 135 | CaughtErrorInfo = CE.getInfo(); |
| 136 | }); |
Lang Hames | f7f6d3e | 2016-03-16 01:02:46 +0000 | [diff] [blame] | 137 | |
Lang Hames | 01864a2 | 2016-03-18 00:12:37 +0000 | [diff] [blame] | 138 | EXPECT_TRUE(CaughtErrorInfo == 42) << "Wrong result from CustomError handler"; |
| 139 | } |
Lang Hames | f7f6d3e | 2016-03-16 01:02:46 +0000 | [diff] [blame] | 140 | |
Lang Hames | 01864a2 | 2016-03-18 00:12:37 +0000 | [diff] [blame] | 141 | // Check that handler type deduction also works for handlers |
| 142 | // of the following types: |
| 143 | // void (const Err&) |
| 144 | // Error (const Err&) mutable |
| 145 | // void (const Err&) mutable |
| 146 | // Error (Err&) |
| 147 | // void (Err&) |
| 148 | // Error (Err&) mutable |
| 149 | // void (Err&) mutable |
| 150 | // Error (unique_ptr<Err>) |
| 151 | // void (unique_ptr<Err>) |
| 152 | // Error (unique_ptr<Err>) mutable |
| 153 | // void (unique_ptr<Err>) mutable |
| 154 | TEST(Error, HandlerTypeDeduction) { |
Lang Hames | f7f6d3e | 2016-03-16 01:02:46 +0000 | [diff] [blame] | 155 | |
| 156 | handleAllErrors(make_error<CustomError>(42), [](const CustomError &CE) {}); |
| 157 | |
| 158 | handleAllErrors( |
| 159 | make_error<CustomError>(42), |
| 160 | [](const CustomError &CE) mutable { return Error::success(); }); |
| 161 | |
| 162 | handleAllErrors(make_error<CustomError>(42), |
| 163 | [](const CustomError &CE) mutable {}); |
| 164 | |
| 165 | handleAllErrors(make_error<CustomError>(42), |
| 166 | [](CustomError &CE) { return Error::success(); }); |
| 167 | |
| 168 | handleAllErrors(make_error<CustomError>(42), [](CustomError &CE) {}); |
| 169 | |
| 170 | handleAllErrors(make_error<CustomError>(42), |
| 171 | [](CustomError &CE) mutable { return Error::success(); }); |
| 172 | |
| 173 | handleAllErrors(make_error<CustomError>(42), [](CustomError &CE) mutable {}); |
| 174 | |
| 175 | handleAllErrors( |
| 176 | make_error<CustomError>(42), |
| 177 | [](std::unique_ptr<CustomError> CE) { return Error::success(); }); |
| 178 | |
| 179 | handleAllErrors(make_error<CustomError>(42), |
| 180 | [](std::unique_ptr<CustomError> CE) {}); |
| 181 | |
| 182 | handleAllErrors( |
| 183 | make_error<CustomError>(42), |
| 184 | [](std::unique_ptr<CustomError> CE) mutable { return Error::success(); }); |
| 185 | |
| 186 | handleAllErrors(make_error<CustomError>(42), |
| 187 | [](std::unique_ptr<CustomError> CE) mutable {}); |
| 188 | |
| 189 | // Check that named handlers of type 'Error (const Err&)' work. |
| 190 | handleAllErrors(make_error<CustomError>(42), handleCustomError); |
| 191 | |
| 192 | // Check that named handlers of type 'void (const Err&)' work. |
| 193 | handleAllErrors(make_error<CustomError>(42), handleCustomErrorVoid); |
| 194 | |
| 195 | // Check that named handlers of type 'Error (std::unique_ptr<Err>)' work. |
| 196 | handleAllErrors(make_error<CustomError>(42), handleCustomErrorUP); |
| 197 | |
| 198 | // Check that named handlers of type 'Error (std::unique_ptr<Err>)' work. |
| 199 | handleAllErrors(make_error<CustomError>(42), handleCustomErrorUPVoid); |
Lang Hames | f7f6d3e | 2016-03-16 01:02:46 +0000 | [diff] [blame] | 200 | } |
| 201 | |
Lang Hames | 01864a2 | 2016-03-18 00:12:37 +0000 | [diff] [blame] | 202 | // Test that we can handle errors with custom base classes. |
| 203 | TEST(Error, HandleCustomErrorWithCustomBaseClass) { |
| 204 | int CaughtErrorInfo = 0; |
| 205 | int CaughtErrorExtraInfo = 0; |
| 206 | handleAllErrors(make_error<CustomSubError>(42, 7), |
| 207 | [&](const CustomSubError &SE) { |
| 208 | CaughtErrorInfo = SE.getInfo(); |
| 209 | CaughtErrorExtraInfo = SE.getExtraInfo(); |
| 210 | }); |
Lang Hames | f7f6d3e | 2016-03-16 01:02:46 +0000 | [diff] [blame] | 211 | |
Lang Hames | 01864a2 | 2016-03-18 00:12:37 +0000 | [diff] [blame] | 212 | EXPECT_TRUE(CaughtErrorInfo == 42 && CaughtErrorExtraInfo == 7) |
| 213 | << "Wrong result from CustomSubError handler"; |
| 214 | } |
Lang Hames | f7f6d3e | 2016-03-16 01:02:46 +0000 | [diff] [blame] | 215 | |
Lang Hames | 01864a2 | 2016-03-18 00:12:37 +0000 | [diff] [blame] | 216 | // Check that we trigger only the first handler that applies. |
| 217 | TEST(Error, FirstHandlerOnly) { |
| 218 | int DummyInfo = 0; |
| 219 | int CaughtErrorInfo = 0; |
| 220 | int CaughtErrorExtraInfo = 0; |
Lang Hames | f7f6d3e | 2016-03-16 01:02:46 +0000 | [diff] [blame] | 221 | |
Lang Hames | 01864a2 | 2016-03-18 00:12:37 +0000 | [diff] [blame] | 222 | handleAllErrors(make_error<CustomSubError>(42, 7), |
| 223 | [&](const CustomSubError &SE) { |
| 224 | CaughtErrorInfo = SE.getInfo(); |
| 225 | CaughtErrorExtraInfo = SE.getExtraInfo(); |
| 226 | }, |
| 227 | [&](const CustomError &CE) { DummyInfo = CE.getInfo(); }); |
Lang Hames | f7f6d3e | 2016-03-16 01:02:46 +0000 | [diff] [blame] | 228 | |
Lang Hames | 01864a2 | 2016-03-18 00:12:37 +0000 | [diff] [blame] | 229 | EXPECT_TRUE(CaughtErrorInfo == 42 && CaughtErrorExtraInfo == 7 && |
| 230 | DummyInfo == 0) |
| 231 | << "Activated the wrong Error handler(s)"; |
| 232 | } |
| 233 | |
| 234 | // Check that general handlers shadow specific ones. |
| 235 | TEST(Error, HandlerShadowing) { |
| 236 | int CaughtErrorInfo = 0; |
| 237 | int DummyInfo = 0; |
| 238 | int DummyExtraInfo = 0; |
| 239 | |
| 240 | handleAllErrors( |
| 241 | make_error<CustomSubError>(42, 7), |
| 242 | [&](const CustomError &CE) { CaughtErrorInfo = CE.getInfo(); }, |
| 243 | [&](const CustomSubError &SE) { |
| 244 | DummyInfo = SE.getInfo(); |
| 245 | DummyExtraInfo = SE.getExtraInfo(); |
| 246 | }); |
| 247 | |
| 248 | EXPECT_TRUE(CaughtErrorInfo = 42 && DummyInfo == 0 && DummyExtraInfo == 0) |
| 249 | << "General Error handler did not shadow specific handler"; |
| 250 | } |
| 251 | |
| 252 | // Test joinErrors. |
| 253 | TEST(Error, CheckJoinErrors) { |
| 254 | int CustomErrorInfo1 = 0; |
| 255 | int CustomErrorInfo2 = 0; |
| 256 | int CustomErrorExtraInfo = 0; |
| 257 | Error E = |
| 258 | joinErrors(make_error<CustomError>(7), make_error<CustomSubError>(42, 7)); |
| 259 | |
| 260 | handleAllErrors(std::move(E), |
| 261 | [&](const CustomSubError &SE) { |
| 262 | CustomErrorInfo2 = SE.getInfo(); |
| 263 | CustomErrorExtraInfo = SE.getExtraInfo(); |
| 264 | }, |
| 265 | [&](const CustomError &CE) { |
| 266 | // Assert that the CustomError instance above is handled |
| 267 | // before the |
| 268 | // CustomSubError - joinErrors should preserve error |
| 269 | // ordering. |
| 270 | EXPECT_EQ(CustomErrorInfo2, 0) |
| 271 | << "CustomErrorInfo2 should be 0 here. " |
| 272 | "joinErrors failed to preserve ordering.\n"; |
| 273 | CustomErrorInfo1 = CE.getInfo(); |
| 274 | }); |
| 275 | |
| 276 | EXPECT_TRUE(CustomErrorInfo1 == 7 && CustomErrorInfo2 == 42 && |
| 277 | CustomErrorExtraInfo == 7) |
| 278 | << "Failed handling compound Error."; |
| 279 | } |
| 280 | |
| 281 | // Test that we can consume success values. |
| 282 | TEST(Error, ConsumeSuccess) { |
| 283 | Error E; |
| 284 | consumeError(std::move(E)); |
| 285 | } |
| 286 | |
| 287 | TEST(Error, ConsumeError) { |
| 288 | Error E = make_error<CustomError>(7); |
| 289 | consumeError(std::move(E)); |
| 290 | } |
Lang Hames | f7f6d3e | 2016-03-16 01:02:46 +0000 | [diff] [blame] | 291 | |
| 292 | // Test that handleAllUnhandledErrors crashes if an error is not caught. |
| 293 | // Test runs in debug mode only. |
| 294 | #ifndef NDEBUG |
Lang Hames | 01864a2 | 2016-03-18 00:12:37 +0000 | [diff] [blame] | 295 | TEST(Error, FailureToHandle) { |
| 296 | auto FailToHandle = []() { |
| 297 | handleAllErrors(make_error<CustomError>(7), [&](const CustomSubError &SE) { |
| 298 | errs() << "This should never be called"; |
| 299 | exit(1); |
| 300 | }); |
| 301 | }; |
Lang Hames | f7f6d3e | 2016-03-16 01:02:46 +0000 | [diff] [blame] | 302 | |
Lang Hames | 01864a2 | 2016-03-18 00:12:37 +0000 | [diff] [blame] | 303 | EXPECT_DEATH(FailToHandle(), "Program aborted due to an unhandled Error:") |
| 304 | << "Unhandled Error in handleAllErrors call did not cause an " |
| 305 | "abort()"; |
| 306 | } |
Lang Hames | f7f6d3e | 2016-03-16 01:02:46 +0000 | [diff] [blame] | 307 | #endif |
| 308 | |
| 309 | // Test that handleAllUnhandledErrors crashes if an error is returned from a |
| 310 | // handler. |
| 311 | // Test runs in debug mode only. |
| 312 | #ifndef NDEBUG |
Lang Hames | 01864a2 | 2016-03-18 00:12:37 +0000 | [diff] [blame] | 313 | TEST(Error, FailureFromHandler) { |
| 314 | auto ReturnErrorFromHandler = []() { |
| 315 | handleAllErrors(make_error<CustomError>(7), |
| 316 | [&](std::unique_ptr<CustomSubError> SE) { |
| 317 | return Error(std::move(SE)); |
| 318 | }); |
| 319 | }; |
Lang Hames | f7f6d3e | 2016-03-16 01:02:46 +0000 | [diff] [blame] | 320 | |
Lang Hames | 01864a2 | 2016-03-18 00:12:37 +0000 | [diff] [blame] | 321 | EXPECT_DEATH(ReturnErrorFromHandler(), |
| 322 | "Program aborted due to an unhandled Error:") |
| 323 | << " Error returned from handler in handleAllErrors call did not " |
| 324 | "cause abort()"; |
| 325 | } |
Lang Hames | f7f6d3e | 2016-03-16 01:02:46 +0000 | [diff] [blame] | 326 | #endif |
| 327 | |
Lang Hames | 01864a2 | 2016-03-18 00:12:37 +0000 | [diff] [blame] | 328 | // Test that we can return values from handleErrors. |
| 329 | TEST(Error, CatchErrorFromHandler) { |
| 330 | int ErrorInfo = 0; |
Lang Hames | f7f6d3e | 2016-03-16 01:02:46 +0000 | [diff] [blame] | 331 | |
Lang Hames | 01864a2 | 2016-03-18 00:12:37 +0000 | [diff] [blame] | 332 | Error E = handleErrors( |
| 333 | make_error<CustomError>(7), |
| 334 | [&](std::unique_ptr<CustomError> CE) { return Error(std::move(CE)); }); |
Lang Hames | f7f6d3e | 2016-03-16 01:02:46 +0000 | [diff] [blame] | 335 | |
Lang Hames | 01864a2 | 2016-03-18 00:12:37 +0000 | [diff] [blame] | 336 | handleAllErrors(std::move(E), |
| 337 | [&](const CustomError &CE) { ErrorInfo = CE.getInfo(); }); |
Lang Hames | f7f6d3e | 2016-03-16 01:02:46 +0000 | [diff] [blame] | 338 | |
Lang Hames | 01864a2 | 2016-03-18 00:12:37 +0000 | [diff] [blame] | 339 | EXPECT_EQ(ErrorInfo, 7) |
| 340 | << "Failed to handle Error returned from handleErrors."; |
Lang Hames | f7f6d3e | 2016-03-16 01:02:46 +0000 | [diff] [blame] | 341 | } |
| 342 | |
Lang Hames | 01864a2 | 2016-03-18 00:12:37 +0000 | [diff] [blame] | 343 | // Test that the ExitOnError utility works as expected. |
| 344 | TEST(Error, ExitOnError) { |
| 345 | ExitOnError ExitOnErr; |
| 346 | ExitOnErr.setBanner("Error in tool:"); |
| 347 | ExitOnErr.setExitCodeMapper([](const Error &E) { |
| 348 | if (E.isA<CustomSubError>()) |
| 349 | return 2; |
| 350 | return 1; |
| 351 | }); |
Lang Hames | f7f6d3e | 2016-03-16 01:02:46 +0000 | [diff] [blame] | 352 | |
Lang Hames | 01864a2 | 2016-03-18 00:12:37 +0000 | [diff] [blame] | 353 | // Make sure we don't bail on success. |
| 354 | ExitOnErr(Error::success()); |
| 355 | EXPECT_EQ(ExitOnErr(Expected<int>(7)), 7) |
| 356 | << "exitOnError returned an invalid value for Expected"; |
Lang Hames | f7f6d3e | 2016-03-16 01:02:46 +0000 | [diff] [blame] | 357 | |
Lang Hames | 01864a2 | 2016-03-18 00:12:37 +0000 | [diff] [blame] | 358 | // Exit tests. |
| 359 | EXPECT_EXIT(ExitOnErr(make_error<CustomError>(7)), |
| 360 | ::testing::ExitedWithCode(1), "Error in tool:") |
| 361 | << "exitOnError returned an unexpected error result"; |
Lang Hames | f7f6d3e | 2016-03-16 01:02:46 +0000 | [diff] [blame] | 362 | |
Lang Hames | 01864a2 | 2016-03-18 00:12:37 +0000 | [diff] [blame] | 363 | EXPECT_EXIT(ExitOnErr(Expected<int>(make_error<CustomSubError>(0, 0))), |
| 364 | ::testing::ExitedWithCode(2), "Error in tool:") |
| 365 | << "exitOnError returned an unexpected error result"; |
| 366 | } |
Lang Hames | f7f6d3e | 2016-03-16 01:02:46 +0000 | [diff] [blame] | 367 | |
Lang Hames | 01864a2 | 2016-03-18 00:12:37 +0000 | [diff] [blame] | 368 | // Test Expected<T> in success mode. |
| 369 | TEST(Error, ExpectedInSuccessMode) { |
| 370 | Expected<int> A = 7; |
| 371 | EXPECT_TRUE(!!A) << "Expected with non-error value doesn't convert to 'true'"; |
| 372 | EXPECT_EQ(*A, 7) << "Incorrect Expected non-error value"; |
| 373 | } |
| 374 | |
| 375 | // Test Expected<T> in failure mode. |
| 376 | TEST(Error, ExpectedInFailureMode) { |
| 377 | Expected<int> A = make_error<CustomError>(42); |
| 378 | EXPECT_FALSE(!!A) << "Expected with error value doesn't convert to 'false'"; |
| 379 | Error E = A.takeError(); |
| 380 | EXPECT_TRUE(E.isA<CustomError>()) << "Incorrect Expected error value"; |
| 381 | consumeError(std::move(E)); |
| 382 | } |
Lang Hames | f7f6d3e | 2016-03-16 01:02:46 +0000 | [diff] [blame] | 383 | |
| 384 | // Check that an Expected instance with an error value doesn't allow access to |
| 385 | // operator*. |
| 386 | // Test runs in debug mode only. |
| 387 | #ifndef NDEBUG |
Lang Hames | 01864a2 | 2016-03-18 00:12:37 +0000 | [diff] [blame] | 388 | TEST(Error, AccessExpectedInFailureMode) { |
| 389 | Expected<int> A = make_error<CustomError>(42); |
| 390 | EXPECT_DEATH(*A, "!HasError && \"Cannot get value when an error exists!\"") |
| 391 | << "Incorrect Expected error value"; |
| 392 | consumeError(A.takeError()); |
| 393 | } |
Lang Hames | f7f6d3e | 2016-03-16 01:02:46 +0000 | [diff] [blame] | 394 | #endif |
| 395 | |
| 396 | // Check that an Expected instance with an error triggers an abort if |
| 397 | // unhandled. |
| 398 | // Test runs in debug mode only. |
| 399 | #ifndef NDEBUG |
Lang Hames | 01864a2 | 2016-03-18 00:12:37 +0000 | [diff] [blame] | 400 | TEST(Error, UnhandledExpectedInFailureMode) { |
Lang Hames | f7f6d3e | 2016-03-16 01:02:46 +0000 | [diff] [blame] | 401 | EXPECT_DEATH({ Expected<int> A = make_error<CustomError>(42); }, |
| 402 | "Program aborted due to an unhandled Error:") |
| 403 | << "Unchecked Expected<T> failure value did not cause an abort()"; |
Lang Hames | 01864a2 | 2016-03-18 00:12:37 +0000 | [diff] [blame] | 404 | } |
Lang Hames | f7f6d3e | 2016-03-16 01:02:46 +0000 | [diff] [blame] | 405 | #endif |
| 406 | |
Lang Hames | 01864a2 | 2016-03-18 00:12:37 +0000 | [diff] [blame] | 407 | // Test covariance of Expected. |
| 408 | TEST(Error, ExpectedCovariance) { |
| 409 | class B {}; |
| 410 | class D : public B {}; |
Lang Hames | f7f6d3e | 2016-03-16 01:02:46 +0000 | [diff] [blame] | 411 | |
Lang Hames | 01864a2 | 2016-03-18 00:12:37 +0000 | [diff] [blame] | 412 | Expected<B *> A1(Expected<D *>(nullptr)); |
| 413 | A1 = Expected<D *>(nullptr); |
Lang Hames | f7f6d3e | 2016-03-16 01:02:46 +0000 | [diff] [blame] | 414 | |
Lang Hames | 01864a2 | 2016-03-18 00:12:37 +0000 | [diff] [blame] | 415 | Expected<std::unique_ptr<B>> A2(Expected<std::unique_ptr<D>>(nullptr)); |
| 416 | A2 = Expected<std::unique_ptr<D>>(nullptr); |
Lang Hames | f7f6d3e | 2016-03-16 01:02:46 +0000 | [diff] [blame] | 417 | } |
| 418 | |
| 419 | TEST(Error, ECError) { |
Lang Hames | f7f6d3e | 2016-03-16 01:02:46 +0000 | [diff] [blame] | 420 | // Round-trip a success value to check that it converts correctly. |
| 421 | EXPECT_EQ(errorToErrorCode(errorCodeToError(std::error_code())), |
| 422 | std::error_code()) |
| 423 | << "std::error_code() should round-trip via Error conversions"; |
| 424 | |
| 425 | // Round-trip an error value to check that it converts correctly. |
| 426 | EXPECT_EQ(errorToErrorCode(errorCodeToError(errc::invalid_argument)), |
| 427 | errc::invalid_argument) |
| 428 | << "std::error_code error value should round-trip via Error " |
| 429 | "conversions"; |
| 430 | } |
| 431 | |
| 432 | } // end anon namespace |