error_test.cpp 6.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219
  1. // Part of the Carbon Language project, under the Apache License v2.0 with LLVM
  2. // Exceptions. See /LICENSE for license information.
  3. // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
  4. #include "common/error.h"
  5. #include <gtest/gtest.h>
  6. #include <concepts>
  7. #include "common/error_test_helpers.h"
  8. #include "common/raw_string_ostream.h"
  9. namespace Carbon {
  10. namespace {
  11. using ::Carbon::Testing::IsError;
  12. using ::Carbon::Testing::IsSuccess;
  13. using ::testing::Eq;
  14. TEST(ErrorTest, Error) {
  15. Error err("test");
  16. EXPECT_EQ(err.message(), "test");
  17. }
  18. TEST(ErrorTest, ErrorEmptyString) {
  19. ASSERT_DEATH({ Error err(""); }, "CHECK failure at");
  20. }
  21. auto IndirectError() -> Error { return Error("test"); }
  22. TEST(ErrorTest, IndirectError) { EXPECT_EQ(IndirectError().message(), "test"); }
  23. TEST(ErrorTest, ErrorBuilderOperatorImplicitCast) {
  24. ErrorOr<int> result = ErrorBuilder() << "msg";
  25. EXPECT_THAT(result, IsError("msg"));
  26. }
  27. class CustomError : public ErrorBase<CustomError> {
  28. public:
  29. auto Print(llvm::raw_ostream& os) const -> void {
  30. os << "Custom test error!";
  31. }
  32. };
  33. template <typename ErrorT>
  34. class ErrorOrTest : public ::testing::Test {
  35. public:
  36. auto ErrorStr() -> std::string {
  37. if constexpr (std::same_as<ErrorT, Error>) {
  38. return "test error";
  39. } else if constexpr (std::same_as<ErrorT, CustomError>) {
  40. return CustomError().ToString();
  41. } else {
  42. static_assert(false, "Unsupported custom error type!");
  43. }
  44. }
  45. auto MakeError() -> ErrorT {
  46. if constexpr (std::same_as<ErrorT, Error>) {
  47. return Error("test error");
  48. } else if constexpr (std::same_as<ErrorT, CustomError>) {
  49. return CustomError();
  50. } else {
  51. static_assert(false, "Unsupported custom error type!");
  52. }
  53. }
  54. };
  55. using ErrorOrTestParams = ::testing::Types<Error, CustomError>;
  56. TYPED_TEST_SUITE(ErrorOrTest, ErrorOrTestParams);
  57. TYPED_TEST(ErrorOrTest, ErrorOr) {
  58. using TestErrorOr = ErrorOr<int, TypeParam>;
  59. TestErrorOr err(this->MakeError());
  60. EXPECT_THAT(err, IsError(this->ErrorStr()));
  61. }
  62. TYPED_TEST(ErrorOrTest, ErrorOrValue) {
  63. using TestErrorOr = ErrorOr<int, TypeParam>;
  64. EXPECT_TRUE(TestErrorOr(0).ok());
  65. }
  66. template <typename ErrorT, typename Fixture>
  67. auto IndirectErrorOrTest(Fixture& fixture) -> ErrorOr<int, ErrorT> {
  68. return fixture.MakeError();
  69. }
  70. TYPED_TEST(ErrorOrTest, IndirectErrorOr) {
  71. EXPECT_FALSE(IndirectErrorOrTest<TypeParam>(*this).ok());
  72. }
  73. struct Val {
  74. int val;
  75. };
  76. TYPED_TEST(ErrorOrTest, ErrorOrArrowOp) {
  77. using TestErrorOr = ErrorOr<Val, TypeParam>;
  78. TestErrorOr err({1});
  79. EXPECT_EQ(err->val, 1);
  80. }
  81. TYPED_TEST(ErrorOrTest, ErrorOrReference) {
  82. using TestErrorOr = ErrorOr<Val&, TypeParam>;
  83. Val val = {1};
  84. TestErrorOr maybe_val(val);
  85. EXPECT_EQ(maybe_val->val, 1);
  86. }
  87. template <typename ErrorT>
  88. auto IndirectErrorOrSuccessTest() -> ErrorOr<Success, ErrorT> {
  89. return Success();
  90. }
  91. TYPED_TEST(ErrorOrTest, IndirectErrorOrSuccess) {
  92. EXPECT_TRUE(IndirectErrorOrSuccessTest<TypeParam>().ok());
  93. }
  94. TYPED_TEST(ErrorOrTest, ReturnIfErrorNoError) {
  95. using TestErrorOr = ErrorOr<Success, TypeParam>;
  96. auto result = []() -> TestErrorOr {
  97. CARBON_RETURN_IF_ERROR(TestErrorOr(Success()));
  98. CARBON_RETURN_IF_ERROR(TestErrorOr(Success()));
  99. return Success();
  100. }();
  101. EXPECT_TRUE(result.ok());
  102. }
  103. TYPED_TEST(ErrorOrTest, ReturnIfErrorHasError) {
  104. using TestErrorOr = ErrorOr<Success, TypeParam>;
  105. auto result = [this]() -> TestErrorOr {
  106. CARBON_RETURN_IF_ERROR(TestErrorOr(Success()));
  107. CARBON_RETURN_IF_ERROR(TestErrorOr(this->MakeError()));
  108. return Success();
  109. }();
  110. EXPECT_THAT(result, IsError(this->ErrorStr()));
  111. }
  112. TYPED_TEST(ErrorOrTest, AssignOrReturnNoError) {
  113. using TestErrorOr = ErrorOr<int, TypeParam>;
  114. auto result = []() -> TestErrorOr {
  115. CARBON_ASSIGN_OR_RETURN(int a, TestErrorOr(1));
  116. CARBON_ASSIGN_OR_RETURN(const int b, TestErrorOr(2));
  117. int c = 0;
  118. CARBON_ASSIGN_OR_RETURN(c, TestErrorOr(3));
  119. return a + b + c;
  120. }();
  121. EXPECT_THAT(result, IsSuccess(Eq(6)));
  122. }
  123. TYPED_TEST(ErrorOrTest, AssignOrReturnHasDirectError) {
  124. using TestErrorOr = ErrorOr<int, TypeParam>;
  125. auto result = [this]() -> TestErrorOr {
  126. CARBON_RETURN_IF_ERROR(TestErrorOr(this->MakeError()));
  127. return 0;
  128. }();
  129. EXPECT_THAT(result, IsError(this->ErrorStr()));
  130. }
  131. TYPED_TEST(ErrorOrTest, AssignOrReturnHasErrorInExpected) {
  132. using TestErrorOr = ErrorOr<int, TypeParam>;
  133. auto result = [this]() -> TestErrorOr {
  134. CARBON_ASSIGN_OR_RETURN(int a, TestErrorOr(this->MakeError()));
  135. return a;
  136. }();
  137. EXPECT_THAT(result, IsError(this->ErrorStr()));
  138. }
  139. class AnotherCustomError : public ErrorBase<AnotherCustomError> {
  140. public:
  141. auto Print(llvm::raw_ostream& os) const -> void {
  142. os << "Another custom test error!";
  143. }
  144. explicit operator CustomError() { return CustomError(); }
  145. };
  146. TYPED_TEST(ErrorOrTest, AssignOrReturnNoErrorAcrossErrorTypes) {
  147. using TestErrorOr = ErrorOr<int, TypeParam>;
  148. auto result = []() -> ErrorOr<int> {
  149. CARBON_ASSIGN_OR_RETURN(int a, TestErrorOr(1));
  150. CARBON_ASSIGN_OR_RETURN(const int b, []() -> TestErrorOr {
  151. CARBON_ASSIGN_OR_RETURN(int inner, (ErrorOr<int, AnotherCustomError>(2)));
  152. return inner;
  153. }());
  154. int c = 0;
  155. CARBON_ASSIGN_OR_RETURN(c, TestErrorOr(3));
  156. return a + b + c;
  157. }();
  158. EXPECT_THAT(result, IsSuccess(Eq(6)));
  159. }
  160. TYPED_TEST(ErrorOrTest, AssignOrReturnErrorAcrossErrorTypes) {
  161. using TestErrorOr = ErrorOr<int, TypeParam>;
  162. auto result = []() -> ErrorOr<int> {
  163. CARBON_ASSIGN_OR_RETURN(int a, TestErrorOr(1));
  164. CARBON_ASSIGN_OR_RETURN(const int b, []() -> TestErrorOr {
  165. CARBON_ASSIGN_OR_RETURN(
  166. int inner, (ErrorOr<int, AnotherCustomError>(AnotherCustomError())));
  167. return inner;
  168. }());
  169. int c = 0;
  170. CARBON_ASSIGN_OR_RETURN(c, TestErrorOr(3));
  171. return a + b + c;
  172. }();
  173. // When directly using the `Error` type, the explicit custom type above has
  174. // its message preserved. When testing against `CustomError`, that one
  175. // overrides the message.
  176. if constexpr (std::same_as<TypeParam, Error>) {
  177. EXPECT_THAT(result, IsError("Another custom test error!"));
  178. } else {
  179. EXPECT_THAT(result, IsError("Custom test error!"));
  180. }
  181. }
  182. } // namespace
  183. } // namespace Carbon