error_test.cpp 6.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226
  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. TEST(ErrorTest, StreamError) {
  28. Error result = ErrorBuilder("TestFunc") << "msg";
  29. RawStringOstream result_stream;
  30. result_stream << result;
  31. EXPECT_EQ(result_stream.TakeStr(), "TestFunc: msg");
  32. }
  33. class CustomError : public ErrorBase<CustomError> {
  34. public:
  35. auto Print(llvm::raw_ostream& os) const -> void {
  36. os << "Custom test error!";
  37. }
  38. };
  39. template <typename ErrorT>
  40. class ErrorOrTest : public ::testing::Test {
  41. public:
  42. auto ErrorStr() -> std::string {
  43. if constexpr (std::same_as<ErrorT, Error>) {
  44. return "test error";
  45. } else if constexpr (std::same_as<ErrorT, CustomError>) {
  46. return CustomError().ToString();
  47. } else {
  48. static_assert(false, "Unsupported custom error type!");
  49. }
  50. }
  51. auto MakeError() -> ErrorT {
  52. if constexpr (std::same_as<ErrorT, Error>) {
  53. return Error("test error");
  54. } else if constexpr (std::same_as<ErrorT, CustomError>) {
  55. return CustomError();
  56. } else {
  57. static_assert(false, "Unsupported custom error type!");
  58. }
  59. }
  60. };
  61. using ErrorOrTestParams = ::testing::Types<Error, CustomError>;
  62. TYPED_TEST_SUITE(ErrorOrTest, ErrorOrTestParams);
  63. TYPED_TEST(ErrorOrTest, ErrorOr) {
  64. using TestErrorOr = ErrorOr<int, TypeParam>;
  65. TestErrorOr err(this->MakeError());
  66. EXPECT_THAT(err, IsError(this->ErrorStr()));
  67. }
  68. TYPED_TEST(ErrorOrTest, ErrorOrValue) {
  69. using TestErrorOr = ErrorOr<int, TypeParam>;
  70. EXPECT_TRUE(TestErrorOr(0).ok());
  71. }
  72. template <typename ErrorT, typename Fixture>
  73. auto IndirectErrorOrTest(Fixture& fixture) -> ErrorOr<int, ErrorT> {
  74. return fixture.MakeError();
  75. }
  76. TYPED_TEST(ErrorOrTest, IndirectErrorOr) {
  77. EXPECT_FALSE(IndirectErrorOrTest<TypeParam>(*this).ok());
  78. }
  79. struct Val {
  80. int val;
  81. };
  82. TYPED_TEST(ErrorOrTest, ErrorOrArrowOp) {
  83. using TestErrorOr = ErrorOr<Val, TypeParam>;
  84. TestErrorOr err({1});
  85. EXPECT_EQ(err->val, 1);
  86. }
  87. TYPED_TEST(ErrorOrTest, ErrorOrReference) {
  88. using TestErrorOr = ErrorOr<Val&, TypeParam>;
  89. Val val = {1};
  90. TestErrorOr maybe_val(val);
  91. EXPECT_EQ(maybe_val->val, 1);
  92. }
  93. template <typename ErrorT>
  94. auto IndirectErrorOrSuccessTest() -> ErrorOr<Success, ErrorT> {
  95. return Success();
  96. }
  97. TYPED_TEST(ErrorOrTest, IndirectErrorOrSuccess) {
  98. EXPECT_TRUE(IndirectErrorOrSuccessTest<TypeParam>().ok());
  99. }
  100. TYPED_TEST(ErrorOrTest, ReturnIfErrorNoError) {
  101. using TestErrorOr = ErrorOr<Success, TypeParam>;
  102. auto result = []() -> TestErrorOr {
  103. CARBON_RETURN_IF_ERROR(TestErrorOr(Success()));
  104. CARBON_RETURN_IF_ERROR(TestErrorOr(Success()));
  105. return Success();
  106. }();
  107. EXPECT_TRUE(result.ok());
  108. }
  109. TYPED_TEST(ErrorOrTest, ReturnIfErrorHasError) {
  110. using TestErrorOr = ErrorOr<Success, TypeParam>;
  111. auto result = [this]() -> TestErrorOr {
  112. CARBON_RETURN_IF_ERROR(TestErrorOr(Success()));
  113. CARBON_RETURN_IF_ERROR(TestErrorOr(this->MakeError()));
  114. return Success();
  115. }();
  116. EXPECT_THAT(result, IsError(this->ErrorStr()));
  117. }
  118. TYPED_TEST(ErrorOrTest, AssignOrReturnNoError) {
  119. using TestErrorOr = ErrorOr<int, TypeParam>;
  120. auto result = []() -> TestErrorOr {
  121. CARBON_ASSIGN_OR_RETURN(int a, TestErrorOr(1));
  122. CARBON_ASSIGN_OR_RETURN(const int b, TestErrorOr(2));
  123. int c = 0;
  124. CARBON_ASSIGN_OR_RETURN(c, TestErrorOr(3));
  125. return a + b + c;
  126. }();
  127. EXPECT_THAT(result, IsSuccess(Eq(6)));
  128. }
  129. TYPED_TEST(ErrorOrTest, AssignOrReturnHasDirectError) {
  130. using TestErrorOr = ErrorOr<int, TypeParam>;
  131. auto result = [this]() -> TestErrorOr {
  132. CARBON_RETURN_IF_ERROR(TestErrorOr(this->MakeError()));
  133. return 0;
  134. }();
  135. EXPECT_THAT(result, IsError(this->ErrorStr()));
  136. }
  137. TYPED_TEST(ErrorOrTest, AssignOrReturnHasErrorInExpected) {
  138. using TestErrorOr = ErrorOr<int, TypeParam>;
  139. auto result = [this]() -> TestErrorOr {
  140. CARBON_ASSIGN_OR_RETURN(int a, TestErrorOr(this->MakeError()));
  141. return a;
  142. }();
  143. EXPECT_THAT(result, IsError(this->ErrorStr()));
  144. }
  145. class AnotherCustomError : public ErrorBase<AnotherCustomError> {
  146. public:
  147. auto Print(llvm::raw_ostream& os) const -> void {
  148. os << "Another custom test error!";
  149. }
  150. explicit operator CustomError() { return CustomError(); }
  151. };
  152. TYPED_TEST(ErrorOrTest, AssignOrReturnNoErrorAcrossErrorTypes) {
  153. using TestErrorOr = ErrorOr<int, TypeParam>;
  154. auto result = []() -> ErrorOr<int> {
  155. CARBON_ASSIGN_OR_RETURN(int a, TestErrorOr(1));
  156. CARBON_ASSIGN_OR_RETURN(const int b, []() -> TestErrorOr {
  157. CARBON_ASSIGN_OR_RETURN(int inner, (ErrorOr<int, AnotherCustomError>(2)));
  158. return inner;
  159. }());
  160. int c = 0;
  161. CARBON_ASSIGN_OR_RETURN(c, TestErrorOr(3));
  162. return a + b + c;
  163. }();
  164. EXPECT_THAT(result, IsSuccess(Eq(6)));
  165. }
  166. TYPED_TEST(ErrorOrTest, AssignOrReturnErrorAcrossErrorTypes) {
  167. using TestErrorOr = ErrorOr<int, TypeParam>;
  168. auto result = []() -> ErrorOr<int> {
  169. CARBON_ASSIGN_OR_RETURN(int a, TestErrorOr(1));
  170. CARBON_ASSIGN_OR_RETURN(const int b, []() -> TestErrorOr {
  171. CARBON_ASSIGN_OR_RETURN(
  172. int inner, (ErrorOr<int, AnotherCustomError>(AnotherCustomError())));
  173. return inner;
  174. }());
  175. int c = 0;
  176. CARBON_ASSIGN_OR_RETURN(c, TestErrorOr(3));
  177. return a + b + c;
  178. }();
  179. // When directly using the `Error` type, the explicit custom type above has
  180. // its message preserved. When testing against `CustomError`, that one
  181. // overrides the message.
  182. if constexpr (std::same_as<TypeParam, Error>) {
  183. EXPECT_THAT(result, IsError("Another custom test error!"));
  184. } else {
  185. EXPECT_THAT(result, IsError("Custom test error!"));
  186. }
  187. }
  188. } // namespace
  189. } // namespace Carbon