1f7f6d3e9SLang Hames //===----- unittests/ErrorTest.cpp - Error.h tests ------------------------===// 2f7f6d3e9SLang Hames // 32946cd70SChandler Carruth // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 42946cd70SChandler Carruth // See https://llvm.org/LICENSE.txt for license information. 52946cd70SChandler Carruth // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6f7f6d3e9SLang Hames // 7f7f6d3e9SLang Hames //===----------------------------------------------------------------------===// 8f7f6d3e9SLang Hames 9f7f6d3e9SLang Hames #include "llvm/Support/Error.h" 1000fb14daSLang Hames #include "llvm-c/Error.h" 11c5e0bbd7SLang Hames 12c5e0bbd7SLang Hames #include "llvm/ADT/Twine.h" 13f7f6d3e9SLang Hames #include "llvm/Support/Errc.h" 14e7aad357SLang Hames #include "llvm/Support/ErrorHandling.h" 15e11f2217SAlexandre Ganea #include "llvm/Support/ManagedStatic.h" 16e8354fe6SPavel Labath #include "llvm/Testing/Support/Error.h" 17e8354fe6SPavel Labath #include "gtest/gtest-spi.h" 18f7f6d3e9SLang Hames #include "gtest/gtest.h" 19f7f6d3e9SLang Hames #include <memory> 20f7f6d3e9SLang Hames 21f7f6d3e9SLang Hames using namespace llvm; 22f7f6d3e9SLang Hames 23f7f6d3e9SLang Hames namespace { 24f7f6d3e9SLang Hames 25f7f6d3e9SLang Hames // Custom error class with a default base class and some random 'info' attached. 26f7f6d3e9SLang Hames class CustomError : public ErrorInfo<CustomError> { 27f7f6d3e9SLang Hames public: 28f7f6d3e9SLang Hames // Create an error with some info attached. 29f7f6d3e9SLang Hames CustomError(int Info) : Info(Info) {} 30f7f6d3e9SLang Hames 31f7f6d3e9SLang Hames // Get the info attached to this error. 32f7f6d3e9SLang Hames int getInfo() const { return Info; } 33f7f6d3e9SLang Hames 34f7f6d3e9SLang Hames // Log this error to a stream. 35f7f6d3e9SLang Hames void log(raw_ostream &OS) const override { 36f7f6d3e9SLang Hames OS << "CustomError {" << getInfo() << "}"; 37f7f6d3e9SLang Hames } 38f7f6d3e9SLang Hames 39e7aad357SLang Hames std::error_code convertToErrorCode() const override { 40e7aad357SLang Hames llvm_unreachable("CustomError doesn't support ECError conversion"); 41e7aad357SLang Hames } 42e7aad357SLang Hames 43a15b76b3SReid Kleckner // Used by ErrorInfo::classID. 44a15b76b3SReid Kleckner static char ID; 45a15b76b3SReid Kleckner 46f7f6d3e9SLang Hames protected: 47f7f6d3e9SLang Hames // This error is subclassed below, but we can't use inheriting constructors 48f7f6d3e9SLang Hames // yet, so we can't propagate the constructors through ErrorInfo. Instead 49f7f6d3e9SLang Hames // we have to have a default constructor and have the subclass initialize all 50f7f6d3e9SLang Hames // fields. 51f7f6d3e9SLang Hames CustomError() : Info(0) {} 52f7f6d3e9SLang Hames 53f7f6d3e9SLang Hames int Info; 54f7f6d3e9SLang Hames }; 55f7f6d3e9SLang Hames 56a15b76b3SReid Kleckner char CustomError::ID = 0; 57a15b76b3SReid Kleckner 58f7f6d3e9SLang Hames // Custom error class with a custom base class and some additional random 59f7f6d3e9SLang Hames // 'info'. 60f7f6d3e9SLang Hames class CustomSubError : public ErrorInfo<CustomSubError, CustomError> { 61f7f6d3e9SLang Hames public: 62f7f6d3e9SLang Hames // Create a sub-error with some info attached. 63f7f6d3e9SLang Hames CustomSubError(int Info, int ExtraInfo) : ExtraInfo(ExtraInfo) { 64f7f6d3e9SLang Hames this->Info = Info; 65f7f6d3e9SLang Hames } 66f7f6d3e9SLang Hames 67f7f6d3e9SLang Hames // Get the extra info attached to this error. 68f7f6d3e9SLang Hames int getExtraInfo() const { return ExtraInfo; } 69f7f6d3e9SLang Hames 70f7f6d3e9SLang Hames // Log this error to a stream. 71f7f6d3e9SLang Hames void log(raw_ostream &OS) const override { 72f7f6d3e9SLang Hames OS << "CustomSubError { " << getInfo() << ", " << getExtraInfo() << "}"; 73f7f6d3e9SLang Hames } 74f7f6d3e9SLang Hames 75e7aad357SLang Hames std::error_code convertToErrorCode() const override { 76e7aad357SLang Hames llvm_unreachable("CustomSubError doesn't support ECError conversion"); 77e7aad357SLang Hames } 78e7aad357SLang Hames 79a15b76b3SReid Kleckner // Used by ErrorInfo::classID. 80a15b76b3SReid Kleckner static char ID; 81a15b76b3SReid Kleckner 82f7f6d3e9SLang Hames protected: 83f7f6d3e9SLang Hames int ExtraInfo; 84f7f6d3e9SLang Hames }; 85f7f6d3e9SLang Hames 86a15b76b3SReid Kleckner char CustomSubError::ID = 0; 87a15b76b3SReid Kleckner 8841af4309SMehdi Amini static Error handleCustomError(const CustomError &CE) { 8941af4309SMehdi Amini return Error::success(); 9041af4309SMehdi Amini } 91f7f6d3e9SLang Hames 92f7f6d3e9SLang Hames static void handleCustomErrorVoid(const CustomError &CE) {} 93f7f6d3e9SLang Hames 94f7f6d3e9SLang Hames static Error handleCustomErrorUP(std::unique_ptr<CustomError> CE) { 9541af4309SMehdi Amini return Error::success(); 96f7f6d3e9SLang Hames } 97f7f6d3e9SLang Hames 98f7f6d3e9SLang Hames static void handleCustomErrorUPVoid(std::unique_ptr<CustomError> CE) {} 99f7f6d3e9SLang Hames 10001864a2dSLang Hames // Test that success values implicitly convert to false, and don't cause crashes 10101864a2dSLang Hames // once they've been implicitly converted. 10201864a2dSLang Hames TEST(Error, CheckedSuccess) { 103c1edf566SMehdi Amini Error E = Error::success(); 10401864a2dSLang Hames EXPECT_FALSE(E) << "Unexpected error while testing Error 'Success'"; 10501864a2dSLang Hames } 10601864a2dSLang Hames 107e11f2217SAlexandre Ganea // Test that unchecked success values cause an abort. 108cb79c079SMehdi Amini #if LLVM_ENABLE_ABI_BREAKING_CHECKS 10901864a2dSLang Hames TEST(Error, UncheckedSuccess) { 110c1edf566SMehdi Amini EXPECT_DEATH({ Error E = Error::success(); }, 111c1edf566SMehdi Amini "Program aborted due to an unhandled Error:") 11201864a2dSLang Hames << "Unchecked Error Succes value did not cause abort()"; 11301864a2dSLang Hames } 11401864a2dSLang Hames #endif 11501864a2dSLang Hames 116d1af8fceSLang Hames // ErrorAsOutParameter tester. 117d1af8fceSLang Hames void errAsOutParamHelper(Error &Err) { 1185e51a2e3SLang Hames ErrorAsOutParameter ErrAsOutParam(&Err); 119d1af8fceSLang Hames // Verify that checked flag is raised - assignment should not crash. 120d1af8fceSLang Hames Err = Error::success(); 121d1af8fceSLang Hames // Raise the checked bit manually - caller should still have to test the 122d1af8fceSLang Hames // error. 123d1af8fceSLang Hames (void)!!Err; 124d0ac31a7SLang Hames } 125d0ac31a7SLang Hames 126d1af8fceSLang Hames // Test that ErrorAsOutParameter sets the checked flag on construction. 127d1af8fceSLang Hames TEST(Error, ErrorAsOutParameterChecked) { 128c1edf566SMehdi Amini Error E = Error::success(); 129d1af8fceSLang Hames errAsOutParamHelper(E); 130d1af8fceSLang Hames (void)!!E; 131d1af8fceSLang Hames } 132d1af8fceSLang Hames 133d1af8fceSLang Hames // Test that ErrorAsOutParameter clears the checked flag on destruction. 134cb79c079SMehdi Amini #if LLVM_ENABLE_ABI_BREAKING_CHECKS 135d1af8fceSLang Hames TEST(Error, ErrorAsOutParameterUnchecked) { 136c1edf566SMehdi Amini EXPECT_DEATH({ Error E = Error::success(); errAsOutParamHelper(E); }, 137d1af8fceSLang Hames "Program aborted due to an unhandled Error:") 138d1af8fceSLang Hames << "ErrorAsOutParameter did not clear the checked flag on destruction."; 139d1af8fceSLang Hames } 140d1af8fceSLang Hames #endif 141d1af8fceSLang Hames 142f7f6d3e9SLang Hames // Check that we abort on unhandled failure cases. (Force conversion to bool 143f7f6d3e9SLang Hames // to make sure that we don't accidentally treat checked errors as handled). 144f7f6d3e9SLang Hames // Test runs in debug mode only. 145cb79c079SMehdi Amini #if LLVM_ENABLE_ABI_BREAKING_CHECKS 14601864a2dSLang Hames TEST(Error, UncheckedError) { 147f7f6d3e9SLang Hames auto DropUnhandledError = []() { 148f7f6d3e9SLang Hames Error E = make_error<CustomError>(42); 149f7f6d3e9SLang Hames (void)!E; 150f7f6d3e9SLang Hames }; 151f7f6d3e9SLang Hames EXPECT_DEATH(DropUnhandledError(), 152f7f6d3e9SLang Hames "Program aborted due to an unhandled Error:") 153f7f6d3e9SLang Hames << "Unhandled Error failure value did not cause abort()"; 154f7f6d3e9SLang Hames } 155f7f6d3e9SLang Hames #endif 156f7f6d3e9SLang Hames 15701864a2dSLang Hames // Check 'Error::isA<T>' method handling. 15801864a2dSLang Hames TEST(Error, IsAHandling) { 159f7f6d3e9SLang Hames // Check 'isA' handling. 160f7f6d3e9SLang Hames Error E = make_error<CustomError>(1); 161f7f6d3e9SLang Hames Error F = make_error<CustomSubError>(1, 2); 16201a3cf4dSLang Hames Error G = Error::success(); 163f7f6d3e9SLang Hames 164f7f6d3e9SLang Hames EXPECT_TRUE(E.isA<CustomError>()); 165f7f6d3e9SLang Hames EXPECT_FALSE(E.isA<CustomSubError>()); 166f7f6d3e9SLang Hames EXPECT_TRUE(F.isA<CustomError>()); 167f7f6d3e9SLang Hames EXPECT_TRUE(F.isA<CustomSubError>()); 16801a3cf4dSLang Hames EXPECT_FALSE(G.isA<CustomError>()); 169f7f6d3e9SLang Hames 170f7f6d3e9SLang Hames consumeError(std::move(E)); 171f7f6d3e9SLang Hames consumeError(std::move(F)); 17201a3cf4dSLang Hames consumeError(std::move(G)); 173f7f6d3e9SLang Hames } 174f7f6d3e9SLang Hames 175f7f6d3e9SLang Hames // Check that we can handle a custom error. 17601864a2dSLang Hames TEST(Error, HandleCustomError) { 177f7f6d3e9SLang Hames int CaughtErrorInfo = 0; 178f7f6d3e9SLang Hames handleAllErrors(make_error<CustomError>(42), [&](const CustomError &CE) { 179f7f6d3e9SLang Hames CaughtErrorInfo = CE.getInfo(); 180f7f6d3e9SLang Hames }); 181f7f6d3e9SLang Hames 18238ac4093SArchibald Elliott EXPECT_EQ(CaughtErrorInfo, 42) << "Wrong result from CustomError handler"; 183f7f6d3e9SLang Hames } 184f7f6d3e9SLang Hames 185f7f6d3e9SLang Hames // Check that handler type deduction also works for handlers 186f7f6d3e9SLang Hames // of the following types: 187f7f6d3e9SLang Hames // void (const Err&) 188f7f6d3e9SLang Hames // Error (const Err&) mutable 189f7f6d3e9SLang Hames // void (const Err&) mutable 190f7f6d3e9SLang Hames // Error (Err&) 191f7f6d3e9SLang Hames // void (Err&) 192f7f6d3e9SLang Hames // Error (Err&) mutable 193f7f6d3e9SLang Hames // void (Err&) mutable 194f7f6d3e9SLang Hames // Error (unique_ptr<Err>) 195f7f6d3e9SLang Hames // void (unique_ptr<Err>) 196f7f6d3e9SLang Hames // Error (unique_ptr<Err>) mutable 197f7f6d3e9SLang Hames // void (unique_ptr<Err>) mutable 19801864a2dSLang Hames TEST(Error, HandlerTypeDeduction) { 199f7f6d3e9SLang Hames 200f7f6d3e9SLang Hames handleAllErrors(make_error<CustomError>(42), [](const CustomError &CE) {}); 201f7f6d3e9SLang Hames 202f7f6d3e9SLang Hames handleAllErrors( 203f7f6d3e9SLang Hames make_error<CustomError>(42), 204c1edf566SMehdi Amini [](const CustomError &CE) mutable -> Error { return Error::success(); }); 205f7f6d3e9SLang Hames 206f7f6d3e9SLang Hames handleAllErrors(make_error<CustomError>(42), 207f7f6d3e9SLang Hames [](const CustomError &CE) mutable {}); 208f7f6d3e9SLang Hames 209f7f6d3e9SLang Hames handleAllErrors(make_error<CustomError>(42), 210c1edf566SMehdi Amini [](CustomError &CE) -> Error { return Error::success(); }); 211f7f6d3e9SLang Hames 212f7f6d3e9SLang Hames handleAllErrors(make_error<CustomError>(42), [](CustomError &CE) {}); 213f7f6d3e9SLang Hames 214f7f6d3e9SLang Hames handleAllErrors(make_error<CustomError>(42), 215c1edf566SMehdi Amini [](CustomError &CE) mutable -> Error { return Error::success(); }); 216f7f6d3e9SLang Hames 217f7f6d3e9SLang Hames handleAllErrors(make_error<CustomError>(42), [](CustomError &CE) mutable {}); 218f7f6d3e9SLang Hames 219f7f6d3e9SLang Hames handleAllErrors( 220f7f6d3e9SLang Hames make_error<CustomError>(42), 221c1edf566SMehdi Amini [](std::unique_ptr<CustomError> CE) -> Error { return Error::success(); }); 222f7f6d3e9SLang Hames 223f7f6d3e9SLang Hames handleAllErrors(make_error<CustomError>(42), 224f7f6d3e9SLang Hames [](std::unique_ptr<CustomError> CE) {}); 225f7f6d3e9SLang Hames 226f7f6d3e9SLang Hames handleAllErrors( 227f7f6d3e9SLang Hames make_error<CustomError>(42), 228c1edf566SMehdi Amini [](std::unique_ptr<CustomError> CE) mutable -> Error { return Error::success(); }); 229f7f6d3e9SLang Hames 230f7f6d3e9SLang Hames handleAllErrors(make_error<CustomError>(42), 231f7f6d3e9SLang Hames [](std::unique_ptr<CustomError> CE) mutable {}); 232f7f6d3e9SLang Hames 233f7f6d3e9SLang Hames // Check that named handlers of type 'Error (const Err&)' work. 234f7f6d3e9SLang Hames handleAllErrors(make_error<CustomError>(42), handleCustomError); 235f7f6d3e9SLang Hames 236f7f6d3e9SLang Hames // Check that named handlers of type 'void (const Err&)' work. 237f7f6d3e9SLang Hames handleAllErrors(make_error<CustomError>(42), handleCustomErrorVoid); 238f7f6d3e9SLang Hames 239f7f6d3e9SLang Hames // Check that named handlers of type 'Error (std::unique_ptr<Err>)' work. 240f7f6d3e9SLang Hames handleAllErrors(make_error<CustomError>(42), handleCustomErrorUP); 241f7f6d3e9SLang Hames 242f7f6d3e9SLang Hames // Check that named handlers of type 'Error (std::unique_ptr<Err>)' work. 243f7f6d3e9SLang Hames handleAllErrors(make_error<CustomError>(42), handleCustomErrorUPVoid); 24401864a2dSLang Hames } 245f7f6d3e9SLang Hames 24601864a2dSLang Hames // Test that we can handle errors with custom base classes. 24701864a2dSLang Hames TEST(Error, HandleCustomErrorWithCustomBaseClass) { 248f7f6d3e9SLang Hames int CaughtErrorInfo = 0; 249f7f6d3e9SLang Hames int CaughtErrorExtraInfo = 0; 250f7f6d3e9SLang Hames handleAllErrors(make_error<CustomSubError>(42, 7), 251f7f6d3e9SLang Hames [&](const CustomSubError &SE) { 252f7f6d3e9SLang Hames CaughtErrorInfo = SE.getInfo(); 253f7f6d3e9SLang Hames CaughtErrorExtraInfo = SE.getExtraInfo(); 254f7f6d3e9SLang Hames }); 255f7f6d3e9SLang Hames 25638ac4093SArchibald Elliott EXPECT_EQ(CaughtErrorInfo, 42) << "Wrong result from CustomSubError handler"; 25738ac4093SArchibald Elliott EXPECT_EQ(CaughtErrorExtraInfo, 7) 258f7f6d3e9SLang Hames << "Wrong result from CustomSubError handler"; 259f7f6d3e9SLang Hames } 260f7f6d3e9SLang Hames 261f7f6d3e9SLang Hames // Check that we trigger only the first handler that applies. 26201864a2dSLang Hames TEST(Error, FirstHandlerOnly) { 263f7f6d3e9SLang Hames int DummyInfo = 0; 264f7f6d3e9SLang Hames int CaughtErrorInfo = 0; 265f7f6d3e9SLang Hames int CaughtErrorExtraInfo = 0; 266f7f6d3e9SLang Hames 267f7f6d3e9SLang Hames handleAllErrors(make_error<CustomSubError>(42, 7), 268f7f6d3e9SLang Hames [&](const CustomSubError &SE) { 269f7f6d3e9SLang Hames CaughtErrorInfo = SE.getInfo(); 270f7f6d3e9SLang Hames CaughtErrorExtraInfo = SE.getExtraInfo(); 271f7f6d3e9SLang Hames }, 272f7f6d3e9SLang Hames [&](const CustomError &CE) { DummyInfo = CE.getInfo(); }); 273f7f6d3e9SLang Hames 27438ac4093SArchibald Elliott EXPECT_EQ(CaughtErrorInfo, 42) << "Activated the wrong Error handler(s)"; 27538ac4093SArchibald Elliott EXPECT_EQ(CaughtErrorExtraInfo, 7) << "Activated the wrong Error handler(s)"; 27638ac4093SArchibald Elliott EXPECT_EQ(DummyInfo, 0) << "Activated the wrong Error handler(s)"; 277f7f6d3e9SLang Hames } 278f7f6d3e9SLang Hames 279f7f6d3e9SLang Hames // Check that general handlers shadow specific ones. 28001864a2dSLang Hames TEST(Error, HandlerShadowing) { 281f7f6d3e9SLang Hames int CaughtErrorInfo = 0; 282f7f6d3e9SLang Hames int DummyInfo = 0; 283f7f6d3e9SLang Hames int DummyExtraInfo = 0; 284f7f6d3e9SLang Hames 285f7f6d3e9SLang Hames handleAllErrors( 286f7f6d3e9SLang Hames make_error<CustomSubError>(42, 7), 287f7f6d3e9SLang Hames [&](const CustomError &CE) { CaughtErrorInfo = CE.getInfo(); }, 288f7f6d3e9SLang Hames [&](const CustomSubError &SE) { 289f7f6d3e9SLang Hames DummyInfo = SE.getInfo(); 290f7f6d3e9SLang Hames DummyExtraInfo = SE.getExtraInfo(); 291f7f6d3e9SLang Hames }); 292f7f6d3e9SLang Hames 29338ac4093SArchibald Elliott EXPECT_EQ(CaughtErrorInfo, 42) 29438ac4093SArchibald Elliott << "General Error handler did not shadow specific handler"; 29538ac4093SArchibald Elliott EXPECT_EQ(DummyInfo, 0) 29638ac4093SArchibald Elliott << "General Error handler did not shadow specific handler"; 29738ac4093SArchibald Elliott EXPECT_EQ(DummyExtraInfo, 0) 298f7f6d3e9SLang Hames << "General Error handler did not shadow specific handler"; 299f7f6d3e9SLang Hames } 300f7f6d3e9SLang Hames 30101864a2dSLang Hames // Test joinErrors. 30201864a2dSLang Hames TEST(Error, CheckJoinErrors) { 303f7f6d3e9SLang Hames int CustomErrorInfo1 = 0; 304f7f6d3e9SLang Hames int CustomErrorInfo2 = 0; 305f7f6d3e9SLang Hames int CustomErrorExtraInfo = 0; 30601864a2dSLang Hames Error E = 30701864a2dSLang Hames joinErrors(make_error<CustomError>(7), make_error<CustomSubError>(42, 7)); 308f7f6d3e9SLang Hames 309f7f6d3e9SLang Hames handleAllErrors(std::move(E), 310f7f6d3e9SLang Hames [&](const CustomSubError &SE) { 311f7f6d3e9SLang Hames CustomErrorInfo2 = SE.getInfo(); 312f7f6d3e9SLang Hames CustomErrorExtraInfo = SE.getExtraInfo(); 313f7f6d3e9SLang Hames }, 314f7f6d3e9SLang Hames [&](const CustomError &CE) { 315f7f6d3e9SLang Hames // Assert that the CustomError instance above is handled 316f7f6d3e9SLang Hames // before the 317f7f6d3e9SLang Hames // CustomSubError - joinErrors should preserve error 318f7f6d3e9SLang Hames // ordering. 319f7f6d3e9SLang Hames EXPECT_EQ(CustomErrorInfo2, 0) 320f7f6d3e9SLang Hames << "CustomErrorInfo2 should be 0 here. " 321f7f6d3e9SLang Hames "joinErrors failed to preserve ordering.\n"; 322f7f6d3e9SLang Hames CustomErrorInfo1 = CE.getInfo(); 323f7f6d3e9SLang Hames }); 324f7f6d3e9SLang Hames 32538ac4093SArchibald Elliott EXPECT_EQ(CustomErrorInfo1, 7) << "Failed handling compound Error."; 32638ac4093SArchibald Elliott EXPECT_EQ(CustomErrorInfo2, 42) << "Failed handling compound Error."; 32738ac4093SArchibald Elliott EXPECT_EQ(CustomErrorExtraInfo, 7) << "Failed handling compound Error."; 328759b30edSLang Hames 329759b30edSLang Hames // Test appending a single item to a list. 330759b30edSLang Hames { 331759b30edSLang Hames int Sum = 0; 332759b30edSLang Hames handleAllErrors( 333759b30edSLang Hames joinErrors( 334759b30edSLang Hames joinErrors(make_error<CustomError>(7), 335759b30edSLang Hames make_error<CustomError>(7)), 336759b30edSLang Hames make_error<CustomError>(7)), 337759b30edSLang Hames [&](const CustomError &CE) { 338759b30edSLang Hames Sum += CE.getInfo(); 339759b30edSLang Hames }); 340759b30edSLang Hames EXPECT_EQ(Sum, 21) << "Failed to correctly append error to error list."; 341759b30edSLang Hames } 342759b30edSLang Hames 343759b30edSLang Hames // Test prepending a single item to a list. 344759b30edSLang Hames { 345759b30edSLang Hames int Sum = 0; 346759b30edSLang Hames handleAllErrors( 347759b30edSLang Hames joinErrors( 348759b30edSLang Hames make_error<CustomError>(7), 349759b30edSLang Hames joinErrors(make_error<CustomError>(7), 350759b30edSLang Hames make_error<CustomError>(7))), 351759b30edSLang Hames [&](const CustomError &CE) { 352759b30edSLang Hames Sum += CE.getInfo(); 353759b30edSLang Hames }); 354759b30edSLang Hames EXPECT_EQ(Sum, 21) << "Failed to correctly prepend error to error list."; 355759b30edSLang Hames } 356759b30edSLang Hames 357759b30edSLang Hames // Test concatenating two error lists. 358759b30edSLang Hames { 359759b30edSLang Hames int Sum = 0; 360759b30edSLang Hames handleAllErrors( 361759b30edSLang Hames joinErrors( 362759b30edSLang Hames joinErrors( 363759b30edSLang Hames make_error<CustomError>(7), 364759b30edSLang Hames make_error<CustomError>(7)), 365759b30edSLang Hames joinErrors( 366759b30edSLang Hames make_error<CustomError>(7), 367759b30edSLang Hames make_error<CustomError>(7))), 368759b30edSLang Hames [&](const CustomError &CE) { 369759b30edSLang Hames Sum += CE.getInfo(); 370759b30edSLang Hames }); 3710ca79dcfSHiroshi Inoue EXPECT_EQ(Sum, 28) << "Failed to correctly concatenate error lists."; 372759b30edSLang Hames } 373f7f6d3e9SLang Hames } 374f7f6d3e9SLang Hames 37501864a2dSLang Hames // Test that we can consume success values. 37601864a2dSLang Hames TEST(Error, ConsumeSuccess) { 377c1edf566SMehdi Amini Error E = Error::success(); 378f7f6d3e9SLang Hames consumeError(std::move(E)); 379f7f6d3e9SLang Hames } 38001864a2dSLang Hames 38101864a2dSLang Hames TEST(Error, ConsumeError) { 382f7f6d3e9SLang Hames Error E = make_error<CustomError>(7); 383f7f6d3e9SLang Hames consumeError(std::move(E)); 384f7f6d3e9SLang Hames } 385f7f6d3e9SLang Hames 386f7f6d3e9SLang Hames // Test that handleAllUnhandledErrors crashes if an error is not caught. 387f7f6d3e9SLang Hames // Test runs in debug mode only. 388cb79c079SMehdi Amini #if LLVM_ENABLE_ABI_BREAKING_CHECKS 38901864a2dSLang Hames TEST(Error, FailureToHandle) { 390f7f6d3e9SLang Hames auto FailToHandle = []() { 39101864a2dSLang Hames handleAllErrors(make_error<CustomError>(7), [&](const CustomSubError &SE) { 392f7f6d3e9SLang Hames errs() << "This should never be called"; 393f7f6d3e9SLang Hames exit(1); 394f7f6d3e9SLang Hames }); 395f7f6d3e9SLang Hames }; 396f7f6d3e9SLang Hames 3977febf2baSLang Hames EXPECT_DEATH(FailToHandle(), 398ecb310b3SDon Hinton "Failure value returned from cantFail wrapped call\n" 399ecb310b3SDon Hinton "CustomError \\{7\\}") 400f7f6d3e9SLang Hames << "Unhandled Error in handleAllErrors call did not cause an " 401f7f6d3e9SLang Hames "abort()"; 402f7f6d3e9SLang Hames } 403f7f6d3e9SLang Hames #endif 404f7f6d3e9SLang Hames 405f7f6d3e9SLang Hames // Test that handleAllUnhandledErrors crashes if an error is returned from a 406f7f6d3e9SLang Hames // handler. 407f7f6d3e9SLang Hames // Test runs in debug mode only. 408cb79c079SMehdi Amini #if LLVM_ENABLE_ABI_BREAKING_CHECKS 40901864a2dSLang Hames TEST(Error, FailureFromHandler) { 410f7f6d3e9SLang Hames auto ReturnErrorFromHandler = []() { 411f7f6d3e9SLang Hames handleAllErrors(make_error<CustomError>(7), 412f7f6d3e9SLang Hames [&](std::unique_ptr<CustomSubError> SE) { 413f7f6d3e9SLang Hames return Error(std::move(SE)); 414f7f6d3e9SLang Hames }); 415f7f6d3e9SLang Hames }; 416f7f6d3e9SLang Hames 417f7f6d3e9SLang Hames EXPECT_DEATH(ReturnErrorFromHandler(), 418ecb310b3SDon Hinton "Failure value returned from cantFail wrapped call\n" 419ecb310b3SDon Hinton "CustomError \\{7\\}") 420f7f6d3e9SLang Hames << " Error returned from handler in handleAllErrors call did not " 421f7f6d3e9SLang Hames "cause abort()"; 422f7f6d3e9SLang Hames } 423f7f6d3e9SLang Hames #endif 424f7f6d3e9SLang Hames 425f7f6d3e9SLang Hames // Test that we can return values from handleErrors. 42601864a2dSLang Hames TEST(Error, CatchErrorFromHandler) { 427f7f6d3e9SLang Hames int ErrorInfo = 0; 428f7f6d3e9SLang Hames 429f7f6d3e9SLang Hames Error E = handleErrors( 430f7f6d3e9SLang Hames make_error<CustomError>(7), 431f7f6d3e9SLang Hames [&](std::unique_ptr<CustomError> CE) { return Error(std::move(CE)); }); 432f7f6d3e9SLang Hames 433f7f6d3e9SLang Hames handleAllErrors(std::move(E), 434f7f6d3e9SLang Hames [&](const CustomError &CE) { ErrorInfo = CE.getInfo(); }); 435f7f6d3e9SLang Hames 436f7f6d3e9SLang Hames EXPECT_EQ(ErrorInfo, 7) 437f7f6d3e9SLang Hames << "Failed to handle Error returned from handleErrors."; 438f7f6d3e9SLang Hames } 4396935c2d3SLang Hames 440c5e0bbd7SLang Hames TEST(Error, StringError) { 441c5e0bbd7SLang Hames std::string Msg; 442c5e0bbd7SLang Hames raw_string_ostream S(Msg); 44345eb84f3SJonas Devlieghere logAllUnhandledErrors( 44445eb84f3SJonas Devlieghere make_error<StringError>("foo" + Twine(42), inconvertibleErrorCode()), S); 445c5e0bbd7SLang Hames EXPECT_EQ(S.str(), "foo42\n") << "Unexpected StringError log result"; 446c5e0bbd7SLang Hames 447c5e0bbd7SLang Hames auto EC = 448c5e0bbd7SLang Hames errorToErrorCode(make_error<StringError>("", errc::invalid_argument)); 449c5e0bbd7SLang Hames EXPECT_EQ(EC, errc::invalid_argument) 450c5e0bbd7SLang Hames << "Failed to convert StringError to error_code."; 451c5e0bbd7SLang Hames } 452c5e0bbd7SLang Hames 453e58e9907SVictor Leschuk TEST(Error, createStringError) { 454e58e9907SVictor Leschuk static const char *Bar = "bar"; 455e58e9907SVictor Leschuk static const std::error_code EC = errc::invalid_argument; 456e58e9907SVictor Leschuk std::string Msg; 457e58e9907SVictor Leschuk raw_string_ostream S(Msg); 458e58e9907SVictor Leschuk logAllUnhandledErrors(createStringError(EC, "foo%s%d0x%" PRIx8, Bar, 1, 0xff), 45945eb84f3SJonas Devlieghere S); 460e58e9907SVictor Leschuk EXPECT_EQ(S.str(), "foobar10xff\n") 461e58e9907SVictor Leschuk << "Unexpected createStringError() log result"; 462e58e9907SVictor Leschuk 463e58e9907SVictor Leschuk S.flush(); 464e58e9907SVictor Leschuk Msg.clear(); 46545eb84f3SJonas Devlieghere logAllUnhandledErrors(createStringError(EC, Bar), S); 466e58e9907SVictor Leschuk EXPECT_EQ(S.str(), "bar\n") 467e58e9907SVictor Leschuk << "Unexpected createStringError() (overloaded) log result"; 468e58e9907SVictor Leschuk 469e58e9907SVictor Leschuk S.flush(); 470e58e9907SVictor Leschuk Msg.clear(); 471e58e9907SVictor Leschuk auto Res = errorToErrorCode(createStringError(EC, "foo%s", Bar)); 472e58e9907SVictor Leschuk EXPECT_EQ(Res, EC) 473e58e9907SVictor Leschuk << "Failed to convert createStringError() result to error_code."; 474e58e9907SVictor Leschuk } 475e58e9907SVictor Leschuk 47601864a2dSLang Hames // Test that the ExitOnError utility works as expected. 477*c32f8f34SYuanfang Chen TEST(ErrorDeathTest, ExitOnError) { 4786935c2d3SLang Hames ExitOnError ExitOnErr; 4796935c2d3SLang Hames ExitOnErr.setBanner("Error in tool:"); 48001864a2dSLang Hames ExitOnErr.setExitCodeMapper([](const Error &E) { 4816935c2d3SLang Hames if (E.isA<CustomSubError>()) 4826935c2d3SLang Hames return 2; 4836935c2d3SLang Hames return 1; 4846935c2d3SLang Hames }); 4856935c2d3SLang Hames 4866935c2d3SLang Hames // Make sure we don't bail on success. 4876935c2d3SLang Hames ExitOnErr(Error::success()); 4886935c2d3SLang Hames EXPECT_EQ(ExitOnErr(Expected<int>(7)), 7) 4896935c2d3SLang Hames << "exitOnError returned an invalid value for Expected"; 4906935c2d3SLang Hames 491285639f8SLang Hames int A = 7; 492285639f8SLang Hames int &B = ExitOnErr(Expected<int&>(A)); 493285639f8SLang Hames EXPECT_EQ(&A, &B) << "ExitOnError failed to propagate reference"; 494285639f8SLang Hames 4956935c2d3SLang Hames // Exit tests. 4966935c2d3SLang Hames EXPECT_EXIT(ExitOnErr(make_error<CustomError>(7)), 4976935c2d3SLang Hames ::testing::ExitedWithCode(1), "Error in tool:") 4986935c2d3SLang Hames << "exitOnError returned an unexpected error result"; 4996935c2d3SLang Hames 5006935c2d3SLang Hames EXPECT_EXIT(ExitOnErr(Expected<int>(make_error<CustomSubError>(0, 0))), 5016935c2d3SLang Hames ::testing::ExitedWithCode(2), "Error in tool:") 5026935c2d3SLang Hames << "exitOnError returned an unexpected error result"; 5036935c2d3SLang Hames } 504f7f6d3e9SLang Hames 505fd4de910SLang Hames // Test that the ExitOnError utility works as expected. 506fd4de910SLang Hames TEST(Error, CantFailSuccess) { 507fd4de910SLang Hames cantFail(Error::success()); 508fd4de910SLang Hames 509fd4de910SLang Hames int X = cantFail(Expected<int>(42)); 510fd4de910SLang Hames EXPECT_EQ(X, 42) << "Expected value modified by cantFail"; 511cd227536SLang Hames 512cd227536SLang Hames int Dummy = 42; 513cd227536SLang Hames int &Y = cantFail(Expected<int&>(Dummy)); 514cd227536SLang Hames EXPECT_EQ(&Dummy, &Y) << "Reference mangled by cantFail"; 515fd4de910SLang Hames } 516fd4de910SLang Hames 517fd4de910SLang Hames // Test that cantFail results in a crash if you pass it a failure value. 518cc14a386SStephen Hines #if LLVM_ENABLE_ABI_BREAKING_CHECKS && !defined(NDEBUG) 519fd4de910SLang Hames TEST(Error, CantFailDeath) { 520ecb310b3SDon Hinton EXPECT_DEATH(cantFail(make_error<StringError>("Original error message", 521ecb310b3SDon Hinton inconvertibleErrorCode()), 5223025e48aSLang Hames "Cantfail call failed"), 523ecb310b3SDon Hinton "Cantfail call failed\n" 524ecb310b3SDon Hinton "Original error message") 525fd4de910SLang Hames << "cantFail(Error) did not cause an abort for failure value"; 526fd4de910SLang Hames 527fd4de910SLang Hames EXPECT_DEATH( 528fd4de910SLang Hames { 529fd4de910SLang Hames auto IEC = inconvertibleErrorCode(); 530fd4de910SLang Hames int X = cantFail(Expected<int>(make_error<StringError>("foo", IEC))); 531fd4de910SLang Hames (void)X; 532fd4de910SLang Hames }, 533fd4de910SLang Hames "Failure value returned from cantFail wrapped call") 534fd4de910SLang Hames << "cantFail(Expected<int>) did not cause an abort for failure value"; 535fd4de910SLang Hames } 536fd4de910SLang Hames #endif 537fd4de910SLang Hames 538fd4de910SLang Hames 539580ca237SLang Hames // Test Checked Expected<T> in success mode. 540580ca237SLang Hames TEST(Error, CheckedExpectedInSuccessMode) { 541f7f6d3e9SLang Hames Expected<int> A = 7; 54201864a2dSLang Hames EXPECT_TRUE(!!A) << "Expected with non-error value doesn't convert to 'true'"; 543580ca237SLang Hames // Access is safe in second test, since we checked the error in the first. 544f7f6d3e9SLang Hames EXPECT_EQ(*A, 7) << "Incorrect Expected non-error value"; 545f7f6d3e9SLang Hames } 546f7f6d3e9SLang Hames 547285639f8SLang Hames // Test Expected with reference type. 548285639f8SLang Hames TEST(Error, ExpectedWithReferenceType) { 549285639f8SLang Hames int A = 7; 550285639f8SLang Hames Expected<int&> B = A; 551285639f8SLang Hames // 'Check' B. 552285639f8SLang Hames (void)!!B; 553285639f8SLang Hames int &C = *B; 554285639f8SLang Hames EXPECT_EQ(&A, &C) << "Expected failed to propagate reference"; 555285639f8SLang Hames } 556285639f8SLang Hames 557580ca237SLang Hames // Test Unchecked Expected<T> in success mode. 558580ca237SLang Hames // We expect this to blow up the same way Error would. 559580ca237SLang Hames // Test runs in debug mode only. 560cb79c079SMehdi Amini #if LLVM_ENABLE_ABI_BREAKING_CHECKS 561580ca237SLang Hames TEST(Error, UncheckedExpectedInSuccessModeDestruction) { 562580ca237SLang Hames EXPECT_DEATH({ Expected<int> A = 7; }, 563580ca237SLang Hames "Expected<T> must be checked before access or destruction.") 5647445f1e4Sxndcn << "Unchecked Expected<T> success value did not cause an abort()."; 565580ca237SLang Hames } 566580ca237SLang Hames #endif 567580ca237SLang Hames 568580ca237SLang Hames // Test Unchecked Expected<T> in success mode. 569580ca237SLang Hames // We expect this to blow up the same way Error would. 570580ca237SLang Hames // Test runs in debug mode only. 571cb79c079SMehdi Amini #if LLVM_ENABLE_ABI_BREAKING_CHECKS 572580ca237SLang Hames TEST(Error, UncheckedExpectedInSuccessModeAccess) { 5737445f1e4Sxndcn EXPECT_DEATH( 5747445f1e4Sxndcn { 5757445f1e4Sxndcn const Expected<int> A = 7; 5767445f1e4Sxndcn *A; 5777445f1e4Sxndcn }, 578580ca237SLang Hames "Expected<T> must be checked before access or destruction.") 5797445f1e4Sxndcn << "Unchecked Expected<T> success value did not cause an abort()."; 580580ca237SLang Hames } 581580ca237SLang Hames #endif 582580ca237SLang Hames 583580ca237SLang Hames // Test Unchecked Expected<T> in success mode. 584580ca237SLang Hames // We expect this to blow up the same way Error would. 585580ca237SLang Hames // Test runs in debug mode only. 586cb79c079SMehdi Amini #if LLVM_ENABLE_ABI_BREAKING_CHECKS 587580ca237SLang Hames TEST(Error, UncheckedExpectedInSuccessModeAssignment) { 5887445f1e4Sxndcn EXPECT_DEATH( 5897445f1e4Sxndcn { 5907445f1e4Sxndcn Expected<int> A = 7; 5917445f1e4Sxndcn A = 7; 5927445f1e4Sxndcn }, 593580ca237SLang Hames "Expected<T> must be checked before access or destruction.") 5947445f1e4Sxndcn << "Unchecked Expected<T> success value did not cause an abort()."; 595580ca237SLang Hames } 596580ca237SLang Hames #endif 597580ca237SLang Hames 59801864a2dSLang Hames // Test Expected<T> in failure mode. 59901864a2dSLang Hames TEST(Error, ExpectedInFailureMode) { 600f7f6d3e9SLang Hames Expected<int> A = make_error<CustomError>(42); 601f7f6d3e9SLang Hames EXPECT_FALSE(!!A) << "Expected with error value doesn't convert to 'false'"; 602f7f6d3e9SLang Hames Error E = A.takeError(); 603f7f6d3e9SLang Hames EXPECT_TRUE(E.isA<CustomError>()) << "Incorrect Expected error value"; 604f7f6d3e9SLang Hames consumeError(std::move(E)); 605f7f6d3e9SLang Hames } 606f7f6d3e9SLang Hames 607f7f6d3e9SLang Hames // Check that an Expected instance with an error value doesn't allow access to 608f7f6d3e9SLang Hames // operator*. 609f7f6d3e9SLang Hames // Test runs in debug mode only. 610cb79c079SMehdi Amini #if LLVM_ENABLE_ABI_BREAKING_CHECKS 61101864a2dSLang Hames TEST(Error, AccessExpectedInFailureMode) { 612f7f6d3e9SLang Hames Expected<int> A = make_error<CustomError>(42); 613580ca237SLang Hames EXPECT_DEATH(*A, "Expected<T> must be checked before access or destruction.") 614f7f6d3e9SLang Hames << "Incorrect Expected error value"; 615f7f6d3e9SLang Hames consumeError(A.takeError()); 616f7f6d3e9SLang Hames } 617f7f6d3e9SLang Hames #endif 618f7f6d3e9SLang Hames 619f7f6d3e9SLang Hames // Check that an Expected instance with an error triggers an abort if 620f7f6d3e9SLang Hames // unhandled. 621f7f6d3e9SLang Hames // Test runs in debug mode only. 622cb79c079SMehdi Amini #if LLVM_ENABLE_ABI_BREAKING_CHECKS 62301864a2dSLang Hames TEST(Error, UnhandledExpectedInFailureMode) { 624f7f6d3e9SLang Hames EXPECT_DEATH({ Expected<int> A = make_error<CustomError>(42); }, 625580ca237SLang Hames "Expected<T> must be checked before access or destruction.") 626f7f6d3e9SLang Hames << "Unchecked Expected<T> failure value did not cause an abort()"; 62701864a2dSLang Hames } 628f7f6d3e9SLang Hames #endif 629f7f6d3e9SLang Hames 630f7f6d3e9SLang Hames // Test covariance of Expected. 63101864a2dSLang Hames TEST(Error, ExpectedCovariance) { 632f7f6d3e9SLang Hames class B {}; 633f7f6d3e9SLang Hames class D : public B {}; 634f7f6d3e9SLang Hames 635f7f6d3e9SLang Hames Expected<B *> A1(Expected<D *>(nullptr)); 636580ca237SLang Hames // Check A1 by converting to bool before assigning to it. 637580ca237SLang Hames (void)!!A1; 638f7f6d3e9SLang Hames A1 = Expected<D *>(nullptr); 639580ca237SLang Hames // Check A1 again before destruction. 640580ca237SLang Hames (void)!!A1; 641f7f6d3e9SLang Hames 642f7f6d3e9SLang Hames Expected<std::unique_ptr<B>> A2(Expected<std::unique_ptr<D>>(nullptr)); 643580ca237SLang Hames // Check A2 by converting to bool before assigning to it. 644580ca237SLang Hames (void)!!A2; 645f7f6d3e9SLang Hames A2 = Expected<std::unique_ptr<D>>(nullptr); 646580ca237SLang Hames // Check A2 again before destruction. 647580ca237SLang Hames (void)!!A2; 648f7f6d3e9SLang Hames } 649f7f6d3e9SLang Hames 6505d06c23dSLang Hames // Test that handleExpected just returns success values. 6515d06c23dSLang Hames TEST(Error, HandleExpectedSuccess) { 6525d06c23dSLang Hames auto ValOrErr = 6535d06c23dSLang Hames handleExpected(Expected<int>(42), 6545d06c23dSLang Hames []() { return Expected<int>(43); }); 6555d06c23dSLang Hames EXPECT_TRUE(!!ValOrErr) 6565d06c23dSLang Hames << "handleExpected should have returned a success value here"; 6575d06c23dSLang Hames EXPECT_EQ(*ValOrErr, 42) 6585d06c23dSLang Hames << "handleExpected should have returned the original success value here"; 6595d06c23dSLang Hames } 6605d06c23dSLang Hames 6615d06c23dSLang Hames enum FooStrategy { Aggressive, Conservative }; 6625d06c23dSLang Hames 6635d06c23dSLang Hames static Expected<int> foo(FooStrategy S) { 6645d06c23dSLang Hames if (S == Aggressive) 6655d06c23dSLang Hames return make_error<CustomError>(7); 6665d06c23dSLang Hames return 42; 6675d06c23dSLang Hames } 6685d06c23dSLang Hames 6695d06c23dSLang Hames // Test that handleExpected invokes the error path if errors are not handled. 6705d06c23dSLang Hames TEST(Error, HandleExpectedUnhandledError) { 6715d06c23dSLang Hames // foo(Aggressive) should return a CustomError which should pass through as 6725d06c23dSLang Hames // there is no handler for CustomError. 6735d06c23dSLang Hames auto ValOrErr = 6745d06c23dSLang Hames handleExpected( 6755d06c23dSLang Hames foo(Aggressive), 6765d06c23dSLang Hames []() { return foo(Conservative); }); 6775d06c23dSLang Hames 6785d06c23dSLang Hames EXPECT_FALSE(!!ValOrErr) 6795d06c23dSLang Hames << "handleExpected should have returned an error here"; 6805d06c23dSLang Hames auto Err = ValOrErr.takeError(); 6815d06c23dSLang Hames EXPECT_TRUE(Err.isA<CustomError>()) 6825d06c23dSLang Hames << "handleExpected should have returned the CustomError generated by " 6835d06c23dSLang Hames "foo(Aggressive) here"; 6845d06c23dSLang Hames consumeError(std::move(Err)); 6855d06c23dSLang Hames } 6865d06c23dSLang Hames 6875d06c23dSLang Hames // Test that handleExpected invokes the fallback path if errors are handled. 6885d06c23dSLang Hames TEST(Error, HandleExpectedHandledError) { 6895d06c23dSLang Hames // foo(Aggressive) should return a CustomError which should handle triggering 6905d06c23dSLang Hames // the fallback path. 6915d06c23dSLang Hames auto ValOrErr = 6925d06c23dSLang Hames handleExpected( 6935d06c23dSLang Hames foo(Aggressive), 6945d06c23dSLang Hames []() { return foo(Conservative); }, 6955d06c23dSLang Hames [](const CustomError&) { /* do nothing */ }); 6965d06c23dSLang Hames 6975d06c23dSLang Hames EXPECT_TRUE(!!ValOrErr) 6985d06c23dSLang Hames << "handleExpected should have returned a success value here"; 6995d06c23dSLang Hames EXPECT_EQ(*ValOrErr, 42) 7005d06c23dSLang Hames << "handleExpected returned the wrong success value"; 7015d06c23dSLang Hames } 7025d06c23dSLang Hames 703d21a535bSLang Hames TEST(Error, ErrorCodeConversions) { 704f7f6d3e9SLang Hames // Round-trip a success value to check that it converts correctly. 705f7f6d3e9SLang Hames EXPECT_EQ(errorToErrorCode(errorCodeToError(std::error_code())), 706f7f6d3e9SLang Hames std::error_code()) 707f7f6d3e9SLang Hames << "std::error_code() should round-trip via Error conversions"; 708f7f6d3e9SLang Hames 709f7f6d3e9SLang Hames // Round-trip an error value to check that it converts correctly. 710f7f6d3e9SLang Hames EXPECT_EQ(errorToErrorCode(errorCodeToError(errc::invalid_argument)), 711f7f6d3e9SLang Hames errc::invalid_argument) 712f7f6d3e9SLang Hames << "std::error_code error value should round-trip via Error " 713f7f6d3e9SLang Hames "conversions"; 714d21a535bSLang Hames 715d21a535bSLang Hames // Round-trip a success value through ErrorOr/Expected to check that it 716d21a535bSLang Hames // converts correctly. 717d21a535bSLang Hames { 718d21a535bSLang Hames auto Orig = ErrorOr<int>(42); 719d21a535bSLang Hames auto RoundTripped = 720d21a535bSLang Hames expectedToErrorOr(errorOrToExpected(ErrorOr<int>(42))); 721d21a535bSLang Hames EXPECT_EQ(*Orig, *RoundTripped) 722d21a535bSLang Hames << "ErrorOr<T> success value should round-trip via Expected<T> " 723d21a535bSLang Hames "conversions."; 724d21a535bSLang Hames } 725d21a535bSLang Hames 726d21a535bSLang Hames // Round-trip a failure value through ErrorOr/Expected to check that it 727d21a535bSLang Hames // converts correctly. 728d21a535bSLang Hames { 729d21a535bSLang Hames auto Orig = ErrorOr<int>(errc::invalid_argument); 730d21a535bSLang Hames auto RoundTripped = 731d21a535bSLang Hames expectedToErrorOr( 732d21a535bSLang Hames errorOrToExpected(ErrorOr<int>(errc::invalid_argument))); 733d21a535bSLang Hames EXPECT_EQ(Orig.getError(), RoundTripped.getError()) 734d21a535bSLang Hames << "ErrorOr<T> failure value should round-trip via Expected<T> " 735d21a535bSLang Hames "conversions."; 736d21a535bSLang Hames } 737f7f6d3e9SLang Hames } 738f7f6d3e9SLang Hames 73927370a09SVedant Kumar // Test that error messages work. 74027370a09SVedant Kumar TEST(Error, ErrorMessage) { 741d18083c6SDavid Blaikie EXPECT_EQ(toString(Error::success()), ""); 74227370a09SVedant Kumar 74327370a09SVedant Kumar Error E1 = make_error<CustomError>(0); 744d18083c6SDavid Blaikie EXPECT_EQ(toString(std::move(E1)), "CustomError {0}"); 74527370a09SVedant Kumar 74627370a09SVedant Kumar Error E2 = make_error<CustomError>(0); 74727370a09SVedant Kumar handleAllErrors(std::move(E2), [](const CustomError &CE) { 748d18083c6SDavid Blaikie EXPECT_EQ(CE.message(), "CustomError {0}"); 74927370a09SVedant Kumar }); 75027370a09SVedant Kumar 75127370a09SVedant Kumar Error E3 = joinErrors(make_error<CustomError>(0), make_error<CustomError>(1)); 752d18083c6SDavid Blaikie EXPECT_EQ(toString(std::move(E3)), "CustomError {0}\n" 753d18083c6SDavid Blaikie "CustomError {1}"); 75427370a09SVedant Kumar } 75527370a09SVedant Kumar 7568ca99100SSam McCall TEST(Error, Stream) { 7578ca99100SSam McCall { 7588ca99100SSam McCall Error OK = Error::success(); 7598ca99100SSam McCall std::string Buf; 7608ca99100SSam McCall llvm::raw_string_ostream S(Buf); 7618ca99100SSam McCall S << OK; 7628ca99100SSam McCall EXPECT_EQ("success", S.str()); 7638ca99100SSam McCall consumeError(std::move(OK)); 7648ca99100SSam McCall } 7658ca99100SSam McCall { 7668ca99100SSam McCall Error E1 = make_error<CustomError>(0); 7678ca99100SSam McCall std::string Buf; 7688ca99100SSam McCall llvm::raw_string_ostream S(Buf); 7698ca99100SSam McCall S << E1; 7708ca99100SSam McCall EXPECT_EQ("CustomError {0}", S.str()); 7718ca99100SSam McCall consumeError(std::move(E1)); 7728ca99100SSam McCall } 7738ca99100SSam McCall } 7748ca99100SSam McCall 7759746b3aeSPavel Labath TEST(Error, SucceededMatcher) { 776e8354fe6SPavel Labath EXPECT_THAT_ERROR(Error::success(), Succeeded()); 777e8354fe6SPavel Labath EXPECT_NONFATAL_FAILURE( 778e8354fe6SPavel Labath EXPECT_THAT_ERROR(make_error<CustomError>(0), Succeeded()), 779e8354fe6SPavel Labath "Expected: succeeded\n Actual: failed (CustomError {0})"); 780e8354fe6SPavel Labath 7819746b3aeSPavel Labath EXPECT_THAT_EXPECTED(Expected<int>(0), Succeeded()); 7829746b3aeSPavel Labath EXPECT_NONFATAL_FAILURE( 7839746b3aeSPavel Labath EXPECT_THAT_EXPECTED(Expected<int>(make_error<CustomError>(0)), 7849746b3aeSPavel Labath Succeeded()), 7859746b3aeSPavel Labath "Expected: succeeded\n Actual: failed (CustomError {0})"); 7869746b3aeSPavel Labath int a = 1; 7879746b3aeSPavel Labath EXPECT_THAT_EXPECTED(Expected<int &>(a), Succeeded()); 7889746b3aeSPavel Labath } 7899746b3aeSPavel Labath 7909746b3aeSPavel Labath TEST(Error, FailedMatcher) { 791e8354fe6SPavel Labath EXPECT_THAT_ERROR(make_error<CustomError>(0), Failed()); 792e8354fe6SPavel Labath EXPECT_NONFATAL_FAILURE(EXPECT_THAT_ERROR(Error::success(), Failed()), 793e8354fe6SPavel Labath "Expected: failed\n Actual: succeeded"); 794e8354fe6SPavel Labath 795510725c2SPavel Labath EXPECT_THAT_ERROR(make_error<CustomError>(0), Failed<CustomError>()); 796510725c2SPavel Labath EXPECT_NONFATAL_FAILURE( 797510725c2SPavel Labath EXPECT_THAT_ERROR(Error::success(), Failed<CustomError>()), 798510725c2SPavel Labath "Expected: failed with Error of given type\n Actual: succeeded"); 799510725c2SPavel Labath EXPECT_NONFATAL_FAILURE( 800510725c2SPavel Labath EXPECT_THAT_ERROR(make_error<CustomError>(0), Failed<CustomSubError>()), 801510725c2SPavel Labath "Error was not of given type"); 802510725c2SPavel Labath EXPECT_NONFATAL_FAILURE( 803510725c2SPavel Labath EXPECT_THAT_ERROR( 804510725c2SPavel Labath joinErrors(make_error<CustomError>(0), make_error<CustomError>(1)), 805510725c2SPavel Labath Failed<CustomError>()), 806510725c2SPavel Labath "multiple errors"); 807510725c2SPavel Labath 808510725c2SPavel Labath EXPECT_THAT_ERROR( 809510725c2SPavel Labath make_error<CustomError>(0), 810510725c2SPavel Labath Failed<CustomError>(testing::Property(&CustomError::getInfo, 0))); 811510725c2SPavel Labath EXPECT_NONFATAL_FAILURE( 812510725c2SPavel Labath EXPECT_THAT_ERROR( 813510725c2SPavel Labath make_error<CustomError>(0), 814510725c2SPavel Labath Failed<CustomError>(testing::Property(&CustomError::getInfo, 1))), 815510725c2SPavel Labath "Expected: failed with Error of given type and the error is an object " 816510725c2SPavel Labath "whose given property is equal to 1\n" 817510725c2SPavel Labath " Actual: failed (CustomError {0})"); 818397e150dSPavel Labath EXPECT_THAT_ERROR(make_error<CustomError>(0), Failed<ErrorInfoBase>()); 819510725c2SPavel Labath 820e8354fe6SPavel Labath EXPECT_THAT_EXPECTED(Expected<int>(make_error<CustomError>(0)), Failed()); 821e8354fe6SPavel Labath EXPECT_NONFATAL_FAILURE( 822e8354fe6SPavel Labath EXPECT_THAT_EXPECTED(Expected<int>(0), Failed()), 82356c2d999SPavel Labath "Expected: failed\n Actual: succeeded with value 0"); 8249746b3aeSPavel Labath EXPECT_THAT_EXPECTED(Expected<int &>(make_error<CustomError>(0)), Failed()); 8259746b3aeSPavel Labath } 826e8354fe6SPavel Labath 8279746b3aeSPavel Labath TEST(Error, HasValueMatcher) { 828e8354fe6SPavel Labath EXPECT_THAT_EXPECTED(Expected<int>(0), HasValue(0)); 829e8354fe6SPavel Labath EXPECT_NONFATAL_FAILURE( 830e8354fe6SPavel Labath EXPECT_THAT_EXPECTED(Expected<int>(make_error<CustomError>(0)), 831e8354fe6SPavel Labath HasValue(0)), 83256c2d999SPavel Labath "Expected: succeeded with value (is equal to 0)\n" 833e8354fe6SPavel Labath " Actual: failed (CustomError {0})"); 834e8354fe6SPavel Labath EXPECT_NONFATAL_FAILURE( 835e8354fe6SPavel Labath EXPECT_THAT_EXPECTED(Expected<int>(1), HasValue(0)), 83656c2d999SPavel Labath "Expected: succeeded with value (is equal to 0)\n" 83756c2d999SPavel Labath " Actual: succeeded with value 1, (isn't equal to 0)"); 838e8354fe6SPavel Labath 839e8354fe6SPavel Labath int a = 1; 84056c2d999SPavel Labath EXPECT_THAT_EXPECTED(Expected<int &>(a), HasValue(testing::Eq(1))); 84156c2d999SPavel Labath 84256c2d999SPavel Labath EXPECT_THAT_EXPECTED(Expected<int>(1), HasValue(testing::Gt(0))); 84356c2d999SPavel Labath EXPECT_NONFATAL_FAILURE( 84456c2d999SPavel Labath EXPECT_THAT_EXPECTED(Expected<int>(0), HasValue(testing::Gt(1))), 84556c2d999SPavel Labath "Expected: succeeded with value (is > 1)\n" 84656c2d999SPavel Labath " Actual: succeeded with value 0, (isn't > 1)"); 84756c2d999SPavel Labath EXPECT_NONFATAL_FAILURE( 84856c2d999SPavel Labath EXPECT_THAT_EXPECTED(Expected<int>(make_error<CustomError>(0)), 84956c2d999SPavel Labath HasValue(testing::Gt(1))), 85056c2d999SPavel Labath "Expected: succeeded with value (is > 1)\n" 85156c2d999SPavel Labath " Actual: failed (CustomError {0})"); 852e8354fe6SPavel Labath } 853e8354fe6SPavel Labath 854b55c58a2SPavel Labath TEST(Error, FailedWithMessageMatcher) { 855b55c58a2SPavel Labath EXPECT_THAT_EXPECTED(Expected<int>(make_error<CustomError>(0)), 856b55c58a2SPavel Labath FailedWithMessage("CustomError {0}")); 857b55c58a2SPavel Labath 858b55c58a2SPavel Labath EXPECT_NONFATAL_FAILURE( 859b55c58a2SPavel Labath EXPECT_THAT_EXPECTED(Expected<int>(make_error<CustomError>(1)), 860b55c58a2SPavel Labath FailedWithMessage("CustomError {0}")), 861b55c58a2SPavel Labath "Expected: failed with Error whose message has 1 element that is equal " 862b55c58a2SPavel Labath "to \"CustomError {0}\"\n" 863b55c58a2SPavel Labath " Actual: failed (CustomError {1})"); 864b55c58a2SPavel Labath 865b55c58a2SPavel Labath EXPECT_NONFATAL_FAILURE( 866b55c58a2SPavel Labath EXPECT_THAT_EXPECTED(Expected<int>(0), 867b55c58a2SPavel Labath FailedWithMessage("CustomError {0}")), 868b55c58a2SPavel Labath "Expected: failed with Error whose message has 1 element that is equal " 869b55c58a2SPavel Labath "to \"CustomError {0}\"\n" 870b55c58a2SPavel Labath " Actual: succeeded with value 0"); 871b55c58a2SPavel Labath 872b55c58a2SPavel Labath EXPECT_NONFATAL_FAILURE( 873b55c58a2SPavel Labath EXPECT_THAT_EXPECTED(Expected<int>(make_error<CustomError>(0)), 874b55c58a2SPavel Labath FailedWithMessage("CustomError {0}", "CustomError {0}")), 875b55c58a2SPavel Labath "Expected: failed with Error whose message has 2 elements where\n" 876b55c58a2SPavel Labath "element #0 is equal to \"CustomError {0}\",\n" 877b55c58a2SPavel Labath "element #1 is equal to \"CustomError {0}\"\n" 878b55c58a2SPavel Labath " Actual: failed (CustomError {0}), which has 1 element"); 879b55c58a2SPavel Labath 880b55c58a2SPavel Labath EXPECT_NONFATAL_FAILURE( 881b55c58a2SPavel Labath EXPECT_THAT_EXPECTED( 882b55c58a2SPavel Labath Expected<int>(joinErrors(make_error<CustomError>(0), 883b55c58a2SPavel Labath make_error<CustomError>(0))), 884b55c58a2SPavel Labath FailedWithMessage("CustomError {0}")), 885b55c58a2SPavel Labath "Expected: failed with Error whose message has 1 element that is equal " 886b55c58a2SPavel Labath "to \"CustomError {0}\"\n" 887b55c58a2SPavel Labath " Actual: failed (CustomError {0}; CustomError {0}), which has 2 elements"); 888b55c58a2SPavel Labath 889b55c58a2SPavel Labath EXPECT_THAT_ERROR( 890b55c58a2SPavel Labath joinErrors(make_error<CustomError>(0), make_error<CustomError>(0)), 891b55c58a2SPavel Labath FailedWithMessageArray(testing::SizeIs(2))); 892b55c58a2SPavel Labath } 893b55c58a2SPavel Labath 89400fb14daSLang Hames TEST(Error, C_API) { 89500fb14daSLang Hames EXPECT_THAT_ERROR(unwrap(wrap(Error::success())), Succeeded()) 89600fb14daSLang Hames << "Failed to round-trip Error success value via C API"; 89700fb14daSLang Hames EXPECT_THAT_ERROR(unwrap(wrap(make_error<CustomError>(0))), 89800fb14daSLang Hames Failed<CustomError>()) 89900fb14daSLang Hames << "Failed to round-trip Error failure value via C API"; 90000fb14daSLang Hames 90100fb14daSLang Hames auto Err = 90200fb14daSLang Hames wrap(make_error<StringError>("test message", inconvertibleErrorCode())); 90300fb14daSLang Hames EXPECT_EQ(LLVMGetErrorTypeId(Err), LLVMGetStringErrorTypeId()) 90400fb14daSLang Hames << "Failed to match error type ids via C API"; 90500fb14daSLang Hames char *ErrMsg = LLVMGetErrorMessage(Err); 90600fb14daSLang Hames EXPECT_STREQ(ErrMsg, "test message") 90700fb14daSLang Hames << "Failed to roundtrip StringError error message via C API"; 90800fb14daSLang Hames LLVMDisposeErrorMessage(ErrMsg); 90900fb14daSLang Hames 91000fb14daSLang Hames bool GotCSE = false; 91100fb14daSLang Hames bool GotCE = false; 91200fb14daSLang Hames handleAllErrors( 91300fb14daSLang Hames unwrap(wrap(joinErrors(make_error<CustomSubError>(42, 7), 91400fb14daSLang Hames make_error<CustomError>(42)))), 91500fb14daSLang Hames [&](CustomSubError &CSE) { 91600fb14daSLang Hames GotCSE = true; 91700fb14daSLang Hames }, 91800fb14daSLang Hames [&](CustomError &CE) { 91900fb14daSLang Hames GotCE = true; 92000fb14daSLang Hames }); 92100fb14daSLang Hames EXPECT_TRUE(GotCSE) << "Failed to round-trip ErrorList via C API"; 92200fb14daSLang Hames EXPECT_TRUE(GotCE) << "Failed to round-trip ErrorList via C API"; 92300fb14daSLang Hames } 92400fb14daSLang Hames 925e11f2217SAlexandre Ganea TEST(Error, FileErrorTest) { 926e11f2217SAlexandre Ganea #if !defined(NDEBUG) && GTEST_HAS_DEATH_TEST 927e11f2217SAlexandre Ganea EXPECT_DEATH( 928e11f2217SAlexandre Ganea { 929e11f2217SAlexandre Ganea Error S = Error::success(); 930607a7be5SAlexandre Ganea consumeError(createFileError("file.bin", std::move(S))); 931e11f2217SAlexandre Ganea }, 932e11f2217SAlexandre Ganea ""); 933e11f2217SAlexandre Ganea #endif 93496032447SAlexandre Ganea // Not allowed, would fail at compile-time 93596032447SAlexandre Ganea //consumeError(createFileError("file.bin", ErrorSuccess())); 93696032447SAlexandre Ganea 937e11f2217SAlexandre Ganea Error E1 = make_error<CustomError>(1); 938e11f2217SAlexandre Ganea Error FE1 = createFileError("file.bin", std::move(E1)); 939d18083c6SDavid Blaikie EXPECT_EQ(toString(std::move(FE1)), "'file.bin': CustomError {1}"); 940e11f2217SAlexandre Ganea 941e11f2217SAlexandre Ganea Error E2 = make_error<CustomError>(2); 942e11f2217SAlexandre Ganea Error FE2 = createFileError("file.bin", std::move(E2)); 943e11f2217SAlexandre Ganea handleAllErrors(std::move(FE2), [](const FileError &F) { 944d18083c6SDavid Blaikie EXPECT_EQ(F.message(), "'file.bin': CustomError {2}"); 945e11f2217SAlexandre Ganea }); 946e11f2217SAlexandre Ganea 947e11f2217SAlexandre Ganea Error E3 = make_error<CustomError>(3); 948e11f2217SAlexandre Ganea Error FE3 = createFileError("file.bin", std::move(E3)); 949e11f2217SAlexandre Ganea auto E31 = handleErrors(std::move(FE3), [](std::unique_ptr<FileError> F) { 950e11f2217SAlexandre Ganea return F->takeError(); 951e11f2217SAlexandre Ganea }); 952e11f2217SAlexandre Ganea handleAllErrors(std::move(E31), [](const CustomError &C) { 953d18083c6SDavid Blaikie EXPECT_EQ(C.message(), "CustomError {3}"); 954e11f2217SAlexandre Ganea }); 955e11f2217SAlexandre Ganea 956e11f2217SAlexandre Ganea Error FE4 = 957e11f2217SAlexandre Ganea joinErrors(createFileError("file.bin", make_error<CustomError>(41)), 958e11f2217SAlexandre Ganea createFileError("file2.bin", make_error<CustomError>(42))); 959d18083c6SDavid Blaikie EXPECT_EQ(toString(std::move(FE4)), "'file.bin': CustomError {41}\n" 960d18083c6SDavid Blaikie "'file2.bin': CustomError {42}"); 9610c502507SDavid Blaikie 962f03689acSDavid Blaikie Error FE5 = createFileError("", make_error<CustomError>(5)); 963d18083c6SDavid Blaikie EXPECT_EQ(toString(std::move(FE5)), "'': CustomError {5}"); 964f03689acSDavid Blaikie 965f03689acSDavid Blaikie Error FE6 = createFileError("unused", make_error<CustomError>(6)); 966f03689acSDavid Blaikie handleAllErrors(std::move(FE6), [](std::unique_ptr<FileError> F) { 967f03689acSDavid Blaikie EXPECT_EQ(F->messageWithoutFileInfo(), "CustomError {6}"); 968f03689acSDavid Blaikie }); 969e11f2217SAlexandre Ganea } 970e11f2217SAlexandre Ganea 97179c54798SDuncan P. N. Exon Smith TEST(Error, FileErrorErrorCode) { 97279c54798SDuncan P. N. Exon Smith for (std::error_code EC : { 97379c54798SDuncan P. N. Exon Smith make_error_code(std::errc::not_supported), 97479c54798SDuncan P. N. Exon Smith make_error_code(std::errc::invalid_argument), 97579c54798SDuncan P. N. Exon Smith make_error_code(std::errc::no_such_file_or_directory), 97679c54798SDuncan P. N. Exon Smith }) { 97779c54798SDuncan P. N. Exon Smith EXPECT_EQ(EC, errorToErrorCode( 97879c54798SDuncan P. N. Exon Smith createFileError("file.bin", EC))); 97979c54798SDuncan P. N. Exon Smith EXPECT_EQ(EC, errorToErrorCode( 98079c54798SDuncan P. N. Exon Smith createFileError("file.bin", /*Line=*/5, EC))); 98179c54798SDuncan P. N. Exon Smith EXPECT_EQ(EC, errorToErrorCode( 98279c54798SDuncan P. N. Exon Smith createFileError("file.bin", errorCodeToError(EC)))); 98379c54798SDuncan P. N. Exon Smith EXPECT_EQ(EC, errorToErrorCode( 98479c54798SDuncan P. N. Exon Smith createFileError("file.bin", /*Line=*/5, errorCodeToError(EC)))); 98579c54798SDuncan P. N. Exon Smith } 98679c54798SDuncan P. N. Exon Smith 98779c54798SDuncan P. N. Exon Smith // inconvertibleErrorCode() should be wrapped to avoid a fatal error. 98879c54798SDuncan P. N. Exon Smith EXPECT_EQ( 98979c54798SDuncan P. N. Exon Smith "A file error occurred.", 99079c54798SDuncan P. N. Exon Smith errorToErrorCode(createFileError("file.bin", inconvertibleErrorCode())) 99179c54798SDuncan P. N. Exon Smith .message()); 99279c54798SDuncan P. N. Exon Smith EXPECT_EQ( 99379c54798SDuncan P. N. Exon Smith "A file error occurred.", 99479c54798SDuncan P. N. Exon Smith errorToErrorCode(createFileError("file.bin", /*Line=*/5, inconvertibleErrorCode())) 99579c54798SDuncan P. N. Exon Smith .message()); 99679c54798SDuncan P. N. Exon Smith } 99779c54798SDuncan P. N. Exon Smith 998e11f2217SAlexandre Ganea enum class test_error_code { 999e11f2217SAlexandre Ganea unspecified = 1, 1000e11f2217SAlexandre Ganea error_1, 1001e11f2217SAlexandre Ganea error_2, 1002e11f2217SAlexandre Ganea }; 1003e11f2217SAlexandre Ganea 1004f7f6d3e9SLang Hames } // end anon namespace 1005e11f2217SAlexandre Ganea 1006e11f2217SAlexandre Ganea namespace std { 1007e11f2217SAlexandre Ganea template <> 1008e11f2217SAlexandre Ganea struct is_error_code_enum<test_error_code> : std::true_type {}; 1009e11f2217SAlexandre Ganea } // namespace std 1010e11f2217SAlexandre Ganea 1011e11f2217SAlexandre Ganea namespace { 1012e11f2217SAlexandre Ganea 1013e11f2217SAlexandre Ganea const std::error_category &TErrorCategory(); 1014e11f2217SAlexandre Ganea 1015e11f2217SAlexandre Ganea inline std::error_code make_error_code(test_error_code E) { 1016e11f2217SAlexandre Ganea return std::error_code(static_cast<int>(E), TErrorCategory()); 1017e11f2217SAlexandre Ganea } 1018e11f2217SAlexandre Ganea 1019e11f2217SAlexandre Ganea class TestDebugError : public ErrorInfo<TestDebugError, StringError> { 1020e11f2217SAlexandre Ganea public: 1021e11f2217SAlexandre Ganea using ErrorInfo<TestDebugError, StringError >::ErrorInfo; // inherit constructors 1022e11f2217SAlexandre Ganea TestDebugError(const Twine &S) : ErrorInfo(S, test_error_code::unspecified) {} 1023e11f2217SAlexandre Ganea static char ID; 1024e11f2217SAlexandre Ganea }; 1025e11f2217SAlexandre Ganea 1026e11f2217SAlexandre Ganea class TestErrorCategory : public std::error_category { 1027e11f2217SAlexandre Ganea public: 10280d802a49SPavel Labath const char *name() const noexcept override { return "error"; } 1029e11f2217SAlexandre Ganea std::string message(int Condition) const override { 1030e11f2217SAlexandre Ganea switch (static_cast<test_error_code>(Condition)) { 1031e11f2217SAlexandre Ganea case test_error_code::unspecified: 1032e11f2217SAlexandre Ganea return "An unknown error has occurred."; 1033e11f2217SAlexandre Ganea case test_error_code::error_1: 1034e11f2217SAlexandre Ganea return "Error 1."; 1035e11f2217SAlexandre Ganea case test_error_code::error_2: 1036e11f2217SAlexandre Ganea return "Error 2."; 1037e11f2217SAlexandre Ganea } 1038e11f2217SAlexandre Ganea llvm_unreachable("Unrecognized test_error_code"); 1039e11f2217SAlexandre Ganea } 1040e11f2217SAlexandre Ganea }; 1041e11f2217SAlexandre Ganea 1042e11f2217SAlexandre Ganea static llvm::ManagedStatic<TestErrorCategory> TestErrCategory; 1043e11f2217SAlexandre Ganea const std::error_category &TErrorCategory() { return *TestErrCategory; } 1044e11f2217SAlexandre Ganea 1045e11f2217SAlexandre Ganea char TestDebugError::ID; 1046e11f2217SAlexandre Ganea 1047e11f2217SAlexandre Ganea TEST(Error, SubtypeStringErrorTest) { 1048e11f2217SAlexandre Ganea auto E1 = make_error<TestDebugError>(test_error_code::error_1); 1049d18083c6SDavid Blaikie EXPECT_EQ(toString(std::move(E1)), "Error 1."); 1050e11f2217SAlexandre Ganea 1051e11f2217SAlexandre Ganea auto E2 = make_error<TestDebugError>(test_error_code::error_1, 1052e11f2217SAlexandre Ganea "Detailed information"); 1053d18083c6SDavid Blaikie EXPECT_EQ(toString(std::move(E2)), "Error 1. Detailed information"); 1054e11f2217SAlexandre Ganea 1055e11f2217SAlexandre Ganea auto E3 = make_error<TestDebugError>(test_error_code::error_2); 1056e11f2217SAlexandre Ganea handleAllErrors(std::move(E3), [](const TestDebugError &F) { 1057d18083c6SDavid Blaikie EXPECT_EQ(F.message(), "Error 2."); 1058e11f2217SAlexandre Ganea }); 1059e11f2217SAlexandre Ganea 1060e11f2217SAlexandre Ganea auto E4 = joinErrors(make_error<TestDebugError>(test_error_code::error_1, 1061e11f2217SAlexandre Ganea "Detailed information"), 1062e11f2217SAlexandre Ganea make_error<TestDebugError>(test_error_code::error_2)); 1063d18083c6SDavid Blaikie EXPECT_EQ(toString(std::move(E4)), "Error 1. Detailed information\n" 1064d18083c6SDavid Blaikie "Error 2."); 1065e11f2217SAlexandre Ganea } 1066e11f2217SAlexandre Ganea 106727181cadSDuncan P. N. Exon Smith static Error createAnyError() { 106827181cadSDuncan P. N. Exon Smith return errorCodeToError(test_error_code::unspecified); 106927181cadSDuncan P. N. Exon Smith } 107027181cadSDuncan P. N. Exon Smith 107127181cadSDuncan P. N. Exon Smith struct MoveOnlyBox { 107227181cadSDuncan P. N. Exon Smith Optional<int> Box; 107327181cadSDuncan P. N. Exon Smith 107427181cadSDuncan P. N. Exon Smith explicit MoveOnlyBox(int I) : Box(I) {} 107527181cadSDuncan P. N. Exon Smith MoveOnlyBox() = default; 107627181cadSDuncan P. N. Exon Smith MoveOnlyBox(MoveOnlyBox &&) = default; 107727181cadSDuncan P. N. Exon Smith MoveOnlyBox &operator=(MoveOnlyBox &&) = default; 107827181cadSDuncan P. N. Exon Smith 107927181cadSDuncan P. N. Exon Smith MoveOnlyBox(const MoveOnlyBox &) = delete; 108027181cadSDuncan P. N. Exon Smith MoveOnlyBox &operator=(const MoveOnlyBox &) = delete; 108127181cadSDuncan P. N. Exon Smith 108227181cadSDuncan P. N. Exon Smith bool operator==(const MoveOnlyBox &RHS) const { 108327181cadSDuncan P. N. Exon Smith if (bool(Box) != bool(RHS.Box)) 108427181cadSDuncan P. N. Exon Smith return false; 108527181cadSDuncan P. N. Exon Smith return Box ? *Box == *RHS.Box : false; 108627181cadSDuncan P. N. Exon Smith } 108727181cadSDuncan P. N. Exon Smith }; 108827181cadSDuncan P. N. Exon Smith 108927181cadSDuncan P. N. Exon Smith TEST(Error, moveInto) { 109027181cadSDuncan P. N. Exon Smith // Use MoveOnlyBox as the T in Expected<T>. 109127181cadSDuncan P. N. Exon Smith auto make = [](int I) -> Expected<MoveOnlyBox> { return MoveOnlyBox(I); }; 109227181cadSDuncan P. N. Exon Smith auto makeFailure = []() -> Expected<MoveOnlyBox> { return createAnyError(); }; 109327181cadSDuncan P. N. Exon Smith 109427181cadSDuncan P. N. Exon Smith { 109527181cadSDuncan P. N. Exon Smith MoveOnlyBox V; 109627181cadSDuncan P. N. Exon Smith 109727181cadSDuncan P. N. Exon Smith // Failure with no prior value. 109827181cadSDuncan P. N. Exon Smith EXPECT_THAT_ERROR(makeFailure().moveInto(V), Failed()); 109927181cadSDuncan P. N. Exon Smith EXPECT_EQ(None, V.Box); 110027181cadSDuncan P. N. Exon Smith 110127181cadSDuncan P. N. Exon Smith // Success with no prior value. 110227181cadSDuncan P. N. Exon Smith EXPECT_THAT_ERROR(make(5).moveInto(V), Succeeded()); 110327181cadSDuncan P. N. Exon Smith EXPECT_EQ(5, V.Box); 110427181cadSDuncan P. N. Exon Smith 110527181cadSDuncan P. N. Exon Smith // Success with an existing value. 110627181cadSDuncan P. N. Exon Smith EXPECT_THAT_ERROR(make(7).moveInto(V), Succeeded()); 110727181cadSDuncan P. N. Exon Smith EXPECT_EQ(7, V.Box); 110827181cadSDuncan P. N. Exon Smith 110927181cadSDuncan P. N. Exon Smith // Failure with an existing value. Might be nice to assign a 111027181cadSDuncan P. N. Exon Smith // default-constructed value in this case, but for now it's being left 111127181cadSDuncan P. N. Exon Smith // alone. 111227181cadSDuncan P. N. Exon Smith EXPECT_THAT_ERROR(makeFailure().moveInto(V), Failed()); 111327181cadSDuncan P. N. Exon Smith EXPECT_EQ(7, V.Box); 111427181cadSDuncan P. N. Exon Smith } 111527181cadSDuncan P. N. Exon Smith 111627181cadSDuncan P. N. Exon Smith // Check that this works with optionals too. 111727181cadSDuncan P. N. Exon Smith { 111827181cadSDuncan P. N. Exon Smith // Same cases as above. 111927181cadSDuncan P. N. Exon Smith Optional<MoveOnlyBox> MaybeV; 112027181cadSDuncan P. N. Exon Smith EXPECT_THAT_ERROR(makeFailure().moveInto(MaybeV), Failed()); 112127181cadSDuncan P. N. Exon Smith EXPECT_EQ(None, MaybeV); 112227181cadSDuncan P. N. Exon Smith 112327181cadSDuncan P. N. Exon Smith EXPECT_THAT_ERROR(make(5).moveInto(MaybeV), Succeeded()); 112427181cadSDuncan P. N. Exon Smith EXPECT_EQ(MoveOnlyBox(5), MaybeV); 112527181cadSDuncan P. N. Exon Smith 112627181cadSDuncan P. N. Exon Smith EXPECT_THAT_ERROR(make(7).moveInto(MaybeV), Succeeded()); 112727181cadSDuncan P. N. Exon Smith EXPECT_EQ(MoveOnlyBox(7), MaybeV); 112827181cadSDuncan P. N. Exon Smith 112927181cadSDuncan P. N. Exon Smith EXPECT_THAT_ERROR(makeFailure().moveInto(MaybeV), Failed()); 113027181cadSDuncan P. N. Exon Smith EXPECT_EQ(MoveOnlyBox(7), MaybeV); 113127181cadSDuncan P. N. Exon Smith } 113227181cadSDuncan P. N. Exon Smith } 113327181cadSDuncan P. N. Exon Smith 1134e11f2217SAlexandre Ganea } // namespace 1135