CodeQL / Analyze (actions) (push) Canceled after 0s
CodeQL / Analyze (python) (push) Canceled after 0s
pre-commit / pre-commit (push) Canceled after 0s
Multi-Arch CI / setup (push) Canceled after 0s
Publish build_manylinux_x86_64 images / publish_build_manylinux_x86_64 (push) Canceled after 0s
Setup (Multi-Arch) / setup (push) Canceled after 0s
Multi-Arch CI / Linux::${{ fromJSON(needs.setup.outputs.linux_build_config || '{}').build_variant_label || 'skip' }} (push) Canceled after 0s
Publish TheRock Docker image / build-and-push-image (push) Canceled after 0s
Publish no_rocm_image_ubi10 image / publish_no_rocm_image_ubi10 (push) Canceled after 0s
Multi-Arch CI / Windows::${{ fromJSON(needs.setup.outputs.windows_build_config || '{}').build_variant_label || 'skip' }} (push) Canceled after 0s
Publish TheRock Docker image / build-and-push-image (push) Canceled after 0s
Multi-Arch CI / Manifest Diff (push) Canceled after 0s
TheRock Manifest Diff Report / Generate Manifest Diff Report (push) Canceled after 0s
Multi-Arch CI / CI Summary (push) Canceled after 0s
Publish no_rocm_image_ubuntu24_04 images / publish_no_rocm_image_ubuntu24_04 (push) Canceled after 0s
Publish no_rocm_image_ubuntu24_04_ocl_rt images / publish_no_rocm_image_ubuntu24_04_ocl_rt (push) Canceled after 0s
Publish TheRock Docker image / build-and-push-image (push) Canceled after 0s
Publish TheRock Docker image / build-and-push-image (push) Canceled after 0s
Publish no_rocm_image_ubuntu24_04 images / publish_no_rocm_image_ubuntu24_04_rocgdb (push) Canceled after 0s
Publish no_rocm_image_ubuntu24_04_rocgdb images / publish_no_rocm_image_ubuntu24_04_rocgdb (push) Canceled after 0s
Publish no_rocm_image_ubuntu24_04 images / publish_no_rocm_image_ubuntu24_04_ocl_rt (push) Canceled after 0s
Publish TheRock Docker image / build-and-push-image (push) Canceled after 0s
Unit Tests / Unit Tests :: ubuntu-24.04 (push) Canceled after 0s
Unit Tests / Unit Tests :: windows-2022 (push) Canceled after 0s
Publish no_rocm_image_ubuntu24_04 images / publish_no_rocm_image_ubuntu24_04_media (push) Canceled after 0s
Unit Tests / Unit Tests Summary (push) Canceled after 0s
Publish no_rocm_image_ubuntu24_04 images / publish_no_rocm_image_ubuntu24_04_openmpi (push) Canceled after 0s
214 lines
6.7 KiB
C++
214 lines
6.7 KiB
C++
//===- ErrorExceptionInterorTest.cpp --------------------------------------===//
|
|
//
|
|
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
|
// See https://llvm.org/LICENSE.txt for license information.
|
|
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
|
//
|
|
//===----------------------------------------------------------------------===//
|
|
//
|
|
// Test interoperability between errors and exceptions.
|
|
//
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
#include "orc-rt-c/config.h"
|
|
#include "orc-rt/Error.h"
|
|
#include "gtest/gtest.h"
|
|
|
|
#include <system_error>
|
|
|
|
using namespace orc_rt;
|
|
|
|
namespace {
|
|
|
|
class CustomError : public ErrorExtends<CustomError, ErrorInfoBase> {
|
|
public:
|
|
std::string toString() const noexcept override { return "CustomError"; }
|
|
};
|
|
|
|
} // anonymous namespace
|
|
|
|
#if ORC_RT_ENABLE_EXCEPTIONS
|
|
#define EXCEPTION_TEST(X) \
|
|
do { \
|
|
X; \
|
|
} while (false)
|
|
#else
|
|
#define EXCEPTION_TEST(X) GTEST_SKIP() << "Exceptions disabled"
|
|
#endif
|
|
|
|
TEST(ErrorExceptionInterorTest, SuccessDoesntThrow) {
|
|
// Test that Error::success values don't throw when throwOnFailure is called.
|
|
EXCEPTION_TEST({
|
|
try {
|
|
auto E = Error::success();
|
|
E.throwOnFailure();
|
|
} catch (...) {
|
|
ADD_FAILURE() << "Unexpected throw";
|
|
}
|
|
});
|
|
}
|
|
|
|
TEST(ErrorExceptionInteropTest, VoidReturnSuccess) {
|
|
// Test that runCapturingExceptions returns Error::success for void()
|
|
// function objects.
|
|
EXCEPTION_TEST({
|
|
bool Executed = false;
|
|
auto Result = runCapturingExceptions([&]() { Executed = true; });
|
|
static_assert(std::is_same_v<decltype(Result), Error>,
|
|
"Expected return type to be Error");
|
|
EXPECT_FALSE(Result); // Error::success() evaluates to false
|
|
EXPECT_TRUE(Executed);
|
|
});
|
|
}
|
|
|
|
TEST(ErrorExceptionInteropTest, ErrorReturnPreserved) {
|
|
// Test that plain Errors returned from runCapturingExceptions are returned
|
|
// as expected.
|
|
EXCEPTION_TEST({
|
|
auto Result = runCapturingExceptions(
|
|
[]() -> Error { return make_error<StringError>("original error"); });
|
|
EXPECT_TRUE(!!Result);
|
|
EXPECT_EQ(toString(std::move(Result)), "original error");
|
|
});
|
|
}
|
|
|
|
TEST(ErrorExceptionInteropTest, NonFallibleTReturnWrapped) {
|
|
// Test that; for function types returning a non-Error, non-Expected type T;
|
|
// runCapturingExceptions returns an Expected<T>.
|
|
EXCEPTION_TEST({
|
|
auto Result = runCapturingExceptions([]() { return 42; });
|
|
static_assert(std::is_same_v<decltype(Result), Expected<int>>,
|
|
"Expected return type to be Expected<int>");
|
|
EXPECT_TRUE(!!Result);
|
|
EXPECT_EQ(*Result, 42);
|
|
});
|
|
}
|
|
|
|
TEST(ErrorExceptionInteropTest, ExpectedReturnPreserved) {
|
|
// Test that Expected success values are returned as expected.
|
|
EXCEPTION_TEST({
|
|
auto Result = runCapturingExceptions([]() -> Expected<int> { return 42; });
|
|
EXPECT_TRUE(!!Result);
|
|
EXPECT_EQ(*Result, 42);
|
|
});
|
|
}
|
|
|
|
TEST(ErrorExceptionInteropTest, CatchThrownInt) {
|
|
// Check that we can capture a thrown exception into an Error and recognize it
|
|
// as a thrown exception.
|
|
EXCEPTION_TEST({
|
|
auto E = runCapturingExceptions([]() { throw 42; });
|
|
EXPECT_TRUE(!!E);
|
|
EXPECT_TRUE(E.isA<ExceptionError>());
|
|
consumeError(std::move(E));
|
|
});
|
|
}
|
|
|
|
TEST(ErrorExceptionInteropTest, RoundTripExceptionThroughError) {
|
|
// Check that we can rethrow an exception that has been captured into an
|
|
// error without affecting the dynamic type or value (e.g. we don't actually
|
|
// rethrow the wrong type / value).
|
|
EXCEPTION_TEST({
|
|
int Result = 0;
|
|
try {
|
|
auto E = runCapturingExceptions([]() { throw 42; });
|
|
EXPECT_TRUE(!!E);
|
|
E.throwOnFailure();
|
|
} catch (int N) {
|
|
Result = N;
|
|
} catch (...) {
|
|
ADD_FAILURE() << "Caught unexpected error type";
|
|
}
|
|
EXPECT_EQ(Result, 42);
|
|
});
|
|
}
|
|
|
|
static std::string peekAtErrorMessage(Error &Err) {
|
|
std::string Msg;
|
|
Err = handleErrors(std::move(Err), [&](std::unique_ptr<ErrorInfoBase> EIB) {
|
|
Msg = EIB->toString();
|
|
return make_error(std::move(EIB));
|
|
});
|
|
return Msg;
|
|
}
|
|
|
|
TEST(ErrorExceptionInteropTest, RoundTripErrorThroughException) {
|
|
// Test Error → Exception → Error preserves type and message
|
|
EXCEPTION_TEST({
|
|
auto OriginalErr = make_error<StringError>("hello, error!");
|
|
std::string OriginalMsg = peekAtErrorMessage(OriginalErr);
|
|
|
|
Error RecoveredErr = Error::success();
|
|
try {
|
|
OriginalErr.throwOnFailure();
|
|
} catch (ErrorInfoBase &EIB) {
|
|
ErrorAsOutParameter _(RecoveredErr);
|
|
RecoveredErr = restore_error(std::move(EIB));
|
|
} catch (...) {
|
|
ADD_FAILURE() << "Caught unexpected error type";
|
|
}
|
|
|
|
EXPECT_TRUE(RecoveredErr.isA<StringError>());
|
|
EXPECT_EQ(toString(std::move(RecoveredErr)), OriginalMsg);
|
|
});
|
|
}
|
|
|
|
TEST(ErrorExceptionInteropTest, ThrowErrorAndCatchAsException) {
|
|
// Check that we can create an Error value, throw it as an exception, and
|
|
// match its dynamic type to a catch handler.
|
|
EXCEPTION_TEST({
|
|
bool HandlerRan = false;
|
|
std::string Msg;
|
|
try {
|
|
auto E = make_error<CustomError>();
|
|
E.throwOnFailure();
|
|
} catch (CustomError &E) {
|
|
HandlerRan = true;
|
|
} catch (ErrorInfoBase &E) {
|
|
ADD_FAILURE() << "Failed to downcase error to dynamic type";
|
|
} catch (...) {
|
|
ADD_FAILURE() << "Caught unexpected error type";
|
|
}
|
|
});
|
|
}
|
|
|
|
TEST(ErrorExceptionInteropTest, ErrorExceptionToString) {
|
|
/// Check that exceptions can be converted to Strings as exepcted.
|
|
EXCEPTION_TEST({
|
|
|
|
{
|
|
// std::exception should be converted by calling `.what()`;
|
|
class MyException : public std::exception {
|
|
public:
|
|
~MyException() override {}
|
|
const char *what() const noexcept override { return "what"; }
|
|
};
|
|
|
|
EXPECT_EQ(toString(runCapturingExceptions([]() { throw MyException(); })),
|
|
"what");
|
|
}
|
|
|
|
{
|
|
// std::error_code should be converted by calling `.message()`.
|
|
auto EC = std::make_error_code(std::errc::cross_device_link);
|
|
std::string ECErrMsg = EC.message();
|
|
EXPECT_EQ(toString(runCapturingExceptions([&]() { throw EC; })),
|
|
ECErrMsg);
|
|
}
|
|
|
|
{
|
|
// std::string should be converted by copying its value.
|
|
std::string ErrMsg = "foo";
|
|
EXPECT_EQ(toString(runCapturingExceptions([&]() { throw ErrMsg; })),
|
|
ErrMsg);
|
|
}
|
|
|
|
{
|
|
// Check that exceptions of other types produce the expected
|
|
// "unrecognized type" error message:
|
|
EXPECT_EQ(toString(runCapturingExceptions([]() { throw 42; })),
|
|
"C++ exception of unknown type");
|
|
}
|
|
});
|
|
}
|