aboutsummaryrefslogtreecommitdiff
path: root/llvm/unittests/Support/ErrorTest.cpp
diff options
context:
space:
mode:
authorAlexandre Ganea <alexandre.ganea@ubisoft.com>2018-08-30 13:10:42 +0000
committerAlexandre Ganea <alexandre.ganea@ubisoft.com>2018-08-30 13:10:42 +0000
commite11f221786c9c70a0ccdfdfff454dc552abd9a21 (patch)
tree78bc9d2eb19c1f26bae0ae9f54ec2644a7bad39f /llvm/unittests/Support/ErrorTest.cpp
parent2fab235316e6e35300e632fe1cf1312aeaa7d68c (diff)
downloadllvm-e11f221786c9c70a0ccdfdfff454dc552abd9a21.zip
llvm-e11f221786c9c70a0ccdfdfff454dc552abd9a21.tar.gz
llvm-e11f221786c9c70a0ccdfdfff454dc552abd9a21.tar.bz2
[Error] Add FileError helper; upgrade StringError behavior
FileError is meant to encapsulate both an Error and a file name/path. It should be used in cases where an Error occurs deep down the call chain, and we want to return it to the caller along with the file name. StringError was updated to display the error messages in different ways. These can be: 1. display the error_code message, and convert to the same error_code (ECError behavior) 2. display an arbitrary string, and convert to a provided error_code (current StringError behavior) 3. display both an error_code message and a string, in this order; and convert to the same error_code These behaviors can be triggered depending on the constructor. The goal is to use StringError as a base class, when a library needs to provide a explicit Error type. Differential Revision: https://reviews.llvm.org/D50807 llvm-svn: 341064
Diffstat (limited to 'llvm/unittests/Support/ErrorTest.cpp')
-rw-r--r--llvm/unittests/Support/ErrorTest.cpp112
1 files changed, 111 insertions, 1 deletions
diff --git a/llvm/unittests/Support/ErrorTest.cpp b/llvm/unittests/Support/ErrorTest.cpp
index 0b1a489..d3d26df 100644
--- a/llvm/unittests/Support/ErrorTest.cpp
+++ b/llvm/unittests/Support/ErrorTest.cpp
@@ -13,6 +13,7 @@
#include "llvm/ADT/Twine.h"
#include "llvm/Support/Errc.h"
#include "llvm/Support/ErrorHandling.h"
+#include "llvm/Support/ManagedStatic.h"
#include "llvm/Testing/Support/Error.h"
#include "gtest/gtest-spi.h"
#include "gtest/gtest.h"
@@ -104,7 +105,7 @@ TEST(Error, CheckedSuccess) {
EXPECT_FALSE(E) << "Unexpected error while testing Error 'Success'";
}
-// Test that unchecked succes values cause an abort.
+// Test that unchecked success values cause an abort.
#if LLVM_ENABLE_ABI_BREAKING_CHECKS
TEST(Error, UncheckedSuccess) {
EXPECT_DEATH({ Error E = Error::success(); },
@@ -864,4 +865,113 @@ TEST(Error, C_API) {
EXPECT_TRUE(GotCE) << "Failed to round-trip ErrorList via C API";
}
+TEST(Error, FileErrorTest) {
+#if !defined(NDEBUG) && GTEST_HAS_DEATH_TEST
+ EXPECT_DEATH(
+ {
+ Error S = Error::success();
+ createFileError("file.bin", std::move(S));
+ },
+ "");
+#endif
+ Error E1 = make_error<CustomError>(1);
+ Error FE1 = createFileError("file.bin", std::move(E1));
+ EXPECT_EQ(toString(std::move(FE1)).compare("'file.bin': CustomError {1}"), 0);
+
+ Error E2 = make_error<CustomError>(2);
+ Error FE2 = createFileError("file.bin", std::move(E2));
+ handleAllErrors(std::move(FE2), [](const FileError &F) {
+ EXPECT_EQ(F.message().compare("'file.bin': CustomError {2}"), 0);
+ });
+
+ Error E3 = make_error<CustomError>(3);
+ Error FE3 = createFileError("file.bin", std::move(E3));
+ auto E31 = handleErrors(std::move(FE3), [](std::unique_ptr<FileError> F) {
+ return F->takeError();
+ });
+ handleAllErrors(std::move(E31), [](const CustomError &C) {
+ EXPECT_EQ(C.message().compare("CustomError {3}"), 0);
+ });
+
+ Error FE4 =
+ joinErrors(createFileError("file.bin", make_error<CustomError>(41)),
+ createFileError("file2.bin", make_error<CustomError>(42)));
+ EXPECT_EQ(toString(std::move(FE4))
+ .compare("'file.bin': CustomError {41}\n"
+ "'file2.bin': CustomError {42}"),
+ 0);
+}
+
+enum class test_error_code {
+ unspecified = 1,
+ error_1,
+ error_2,
+};
+
} // end anon namespace
+
+namespace std {
+ template <>
+ struct is_error_code_enum<test_error_code> : std::true_type {};
+} // namespace std
+
+namespace {
+
+const std::error_category &TErrorCategory();
+
+inline std::error_code make_error_code(test_error_code E) {
+ return std::error_code(static_cast<int>(E), TErrorCategory());
+}
+
+class TestDebugError : public ErrorInfo<TestDebugError, StringError> {
+public:
+ using ErrorInfo<TestDebugError, StringError >::ErrorInfo; // inherit constructors
+ TestDebugError(const Twine &S) : ErrorInfo(S, test_error_code::unspecified) {}
+ static char ID;
+};
+
+class TestErrorCategory : public std::error_category {
+public:
+ const char *name() const noexcept override { return "error"; }
+ std::string message(int Condition) const override {
+ switch (static_cast<test_error_code>(Condition)) {
+ case test_error_code::unspecified:
+ return "An unknown error has occurred.";
+ case test_error_code::error_1:
+ return "Error 1.";
+ case test_error_code::error_2:
+ return "Error 2.";
+ }
+ llvm_unreachable("Unrecognized test_error_code");
+ }
+};
+
+static llvm::ManagedStatic<TestErrorCategory> TestErrCategory;
+const std::error_category &TErrorCategory() { return *TestErrCategory; }
+
+char TestDebugError::ID;
+
+TEST(Error, SubtypeStringErrorTest) {
+ auto E1 = make_error<TestDebugError>(test_error_code::error_1);
+ EXPECT_EQ(toString(std::move(E1)).compare("Error 1."), 0);
+
+ auto E2 = make_error<TestDebugError>(test_error_code::error_1,
+ "Detailed information");
+ EXPECT_EQ(toString(std::move(E2)).compare("Error 1. Detailed information"),
+ 0);
+
+ auto E3 = make_error<TestDebugError>(test_error_code::error_2);
+ handleAllErrors(std::move(E3), [](const TestDebugError &F) {
+ EXPECT_EQ(F.message().compare("Error 2."), 0);
+ });
+
+ auto E4 = joinErrors(make_error<TestDebugError>(test_error_code::error_1,
+ "Detailed information"),
+ make_error<TestDebugError>(test_error_code::error_2));
+ EXPECT_EQ(toString(std::move(E4))
+ .compare("Error 1. Detailed information\n"
+ "Error 2."),
+ 0);
+}
+
+} // namespace