| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260 |
- // Part of the Carbon Language project, under the Apache License v2.0 with LLVM
- // Exceptions. See /LICENSE for license information.
- // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
- #include "common/error.h"
- #include <gtest/gtest.h>
- #include <concepts>
- #include <memory>
- #include "common/error_test_helpers.h"
- #include "common/raw_string_ostream.h"
- namespace Carbon {
- namespace {
- using ::Carbon::Testing::IsError;
- using ::Carbon::Testing::IsSuccess;
- using ::testing::_;
- using ::testing::Eq;
- TEST(ErrorTest, Error) {
- Error err("test");
- EXPECT_EQ(err.message(), "test");
- }
- TEST(ErrorTest, ErrorEmptyString) {
- ASSERT_DEATH({ Error err(""); }, "CHECK failure at");
- }
- auto IndirectError() -> Error { return Error("test"); }
- TEST(ErrorTest, IndirectError) { EXPECT_EQ(IndirectError().message(), "test"); }
- TEST(ErrorTest, ErrorBuilderOperatorImplicitCast) {
- ErrorOr<int> result = ErrorBuilder() << "msg";
- EXPECT_THAT(result, IsError("msg"));
- }
- // Make sure a custom error type can be forward declared and used with `ErrorOr`
- // until the `ErrorOr` is required to be complete itself.
- class CustomError;
- auto TestFunction() -> ErrorOr<int, CustomError>;
- class CustomError : public ErrorBase<CustomError> {
- public:
- auto Print(llvm::raw_ostream& os) const -> void {
- os << "Custom test error!";
- }
- };
- auto TestFunction() -> ErrorOr<int, CustomError> { return CustomError(); }
- TEST(ErrorTest, UseErrorOrWithCustomError) {
- // Uses `TestFunction` to ensure it compiles correctly with forward
- // declarations above.
- EXPECT_THAT(TestFunction(), IsError("Custom test error!"));
- }
- template <typename ErrorT>
- class ErrorOrTest : public ::testing::Test {
- public:
- auto ErrorStr() -> std::string {
- if constexpr (std::same_as<ErrorT, Error>) {
- return "test error";
- } else if constexpr (std::same_as<ErrorT, CustomError>) {
- return CustomError().ToString();
- } else {
- static_assert(false, "Unsupported custom error type!");
- }
- }
- auto MakeError() -> ErrorT {
- if constexpr (std::same_as<ErrorT, Error>) {
- return Error("test error");
- } else if constexpr (std::same_as<ErrorT, CustomError>) {
- return CustomError();
- } else {
- static_assert(false, "Unsupported custom error type!");
- }
- }
- };
- using ErrorOrTestParams = ::testing::Types<Error, CustomError>;
- TYPED_TEST_SUITE(ErrorOrTest, ErrorOrTestParams);
- TYPED_TEST(ErrorOrTest, ErrorOr) {
- using TestErrorOr = ErrorOr<int, TypeParam>;
- TestErrorOr err(this->MakeError());
- EXPECT_THAT(err, IsError(this->ErrorStr()));
- }
- TYPED_TEST(ErrorOrTest, ErrorOrValue) {
- using TestErrorOr = ErrorOr<int, TypeParam>;
- EXPECT_TRUE(TestErrorOr(0).ok());
- }
- template <typename ErrorT, typename Fixture>
- auto IndirectErrorOrTest(Fixture& fixture) -> ErrorOr<int, ErrorT> {
- return fixture.MakeError();
- }
- TYPED_TEST(ErrorOrTest, IndirectErrorOr) {
- EXPECT_FALSE(IndirectErrorOrTest<TypeParam>(*this).ok());
- }
- struct Val {
- int val;
- };
- TYPED_TEST(ErrorOrTest, ErrorOrArrowOp) {
- using TestErrorOr = ErrorOr<Val, TypeParam>;
- TestErrorOr err({1});
- EXPECT_EQ(err->val, 1);
- }
- TYPED_TEST(ErrorOrTest, ErrorOrReference) {
- using TestErrorOr = ErrorOr<Val&, TypeParam>;
- Val val = {1};
- TestErrorOr maybe_val(val);
- EXPECT_EQ(maybe_val->val, 1);
- }
- template <typename ErrorT>
- auto IndirectErrorOrSuccessTest() -> ErrorOr<Success, ErrorT> {
- return Success();
- }
- TYPED_TEST(ErrorOrTest, IndirectErrorOrSuccess) {
- EXPECT_TRUE(IndirectErrorOrSuccessTest<TypeParam>().ok());
- }
- TYPED_TEST(ErrorOrTest, MoveValue) {
- using TestErrorOr = ErrorOr<std::unique_ptr<int>, TypeParam>;
- auto make_value = []() -> TestErrorOr { return std::make_unique<int>(42); };
- std::unique_ptr<int> p = *make_value();
- EXPECT_THAT(*p, Eq(42));
- auto result = make_value();
- std::unique_ptr<int> p2 = *std::move(result);
- EXPECT_THAT(*p2, Eq(42));
- }
- TYPED_TEST(ErrorOrTest, UnprintableValue) {
- struct X {
- int i;
- };
- using TestErrorOr = ErrorOr<X, TypeParam>;
- TestErrorOr value(X{.i = 42});
- EXPECT_THAT(value, IsSuccess(_));
- TestErrorOr error = this->MakeError();
- EXPECT_THAT(error, IsError(this->ErrorStr()));
- }
- TYPED_TEST(ErrorOrTest, ReturnIfErrorNoError) {
- using TestErrorOr = ErrorOr<Success, TypeParam>;
- auto result = []() -> TestErrorOr {
- CARBON_RETURN_IF_ERROR(TestErrorOr(Success()));
- CARBON_RETURN_IF_ERROR(TestErrorOr(Success()));
- return Success();
- }();
- EXPECT_TRUE(result.ok());
- }
- TYPED_TEST(ErrorOrTest, ReturnIfErrorHasError) {
- using TestErrorOr = ErrorOr<Success, TypeParam>;
- auto result = [this]() -> TestErrorOr {
- CARBON_RETURN_IF_ERROR(TestErrorOr(Success()));
- CARBON_RETURN_IF_ERROR(TestErrorOr(this->MakeError()));
- return Success();
- }();
- EXPECT_THAT(result, IsError(this->ErrorStr()));
- }
- TYPED_TEST(ErrorOrTest, AssignOrReturnNoError) {
- using TestErrorOr = ErrorOr<int, TypeParam>;
- auto result = []() -> TestErrorOr {
- CARBON_ASSIGN_OR_RETURN(int a, TestErrorOr(1));
- CARBON_ASSIGN_OR_RETURN(const int b, TestErrorOr(2));
- int c = 0;
- CARBON_ASSIGN_OR_RETURN(c, TestErrorOr(3));
- return a + b + c;
- }();
- EXPECT_THAT(result, IsSuccess(Eq(6)));
- }
- TYPED_TEST(ErrorOrTest, AssignOrReturnHasDirectError) {
- using TestErrorOr = ErrorOr<int, TypeParam>;
- auto result = [this]() -> TestErrorOr {
- CARBON_RETURN_IF_ERROR(TestErrorOr(this->MakeError()));
- return 0;
- }();
- EXPECT_THAT(result, IsError(this->ErrorStr()));
- }
- TYPED_TEST(ErrorOrTest, AssignOrReturnHasErrorInExpected) {
- using TestErrorOr = ErrorOr<int, TypeParam>;
- auto result = [this]() -> TestErrorOr {
- CARBON_ASSIGN_OR_RETURN(int a, TestErrorOr(this->MakeError()));
- return a;
- }();
- EXPECT_THAT(result, IsError(this->ErrorStr()));
- }
- class AnotherCustomError : public ErrorBase<AnotherCustomError> {
- public:
- auto Print(llvm::raw_ostream& os) const -> void {
- os << "Another custom test error!";
- }
- explicit operator CustomError() { return CustomError(); }
- };
- TYPED_TEST(ErrorOrTest, AssignOrReturnNoErrorAcrossErrorTypes) {
- using TestErrorOr = ErrorOr<int, TypeParam>;
- auto result = []() -> ErrorOr<int> {
- CARBON_ASSIGN_OR_RETURN(int a, TestErrorOr(1));
- CARBON_ASSIGN_OR_RETURN(const int b, []() -> TestErrorOr {
- CARBON_ASSIGN_OR_RETURN(int inner, (ErrorOr<int, AnotherCustomError>(2)));
- return inner;
- }());
- int c = 0;
- CARBON_ASSIGN_OR_RETURN(c, TestErrorOr(3));
- return a + b + c;
- }();
- EXPECT_THAT(result, IsSuccess(Eq(6)));
- }
- TYPED_TEST(ErrorOrTest, AssignOrReturnErrorAcrossErrorTypes) {
- using TestErrorOr = ErrorOr<int, TypeParam>;
- auto result = []() -> ErrorOr<int> {
- CARBON_ASSIGN_OR_RETURN(int a, TestErrorOr(1));
- CARBON_ASSIGN_OR_RETURN(const int b, []() -> TestErrorOr {
- CARBON_ASSIGN_OR_RETURN(
- int inner, (ErrorOr<int, AnotherCustomError>(AnotherCustomError())));
- return inner;
- }());
- int c = 0;
- CARBON_ASSIGN_OR_RETURN(c, TestErrorOr(3));
- return a + b + c;
- }();
- // When directly using the `Error` type, the explicit custom type above has
- // its message preserved. When testing against `CustomError`, that one
- // overrides the message.
- if constexpr (std::same_as<TypeParam, Error>) {
- EXPECT_THAT(result, IsError("Another custom test error!"));
- } else {
- EXPECT_THAT(result, IsError("Custom test error!"));
- }
- }
- } // namespace
- } // namespace Carbon
|