error_test.cpp 7.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260
  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 <memory>
  8. #include "common/error_test_helpers.h"
  9. #include "common/raw_string_ostream.h"
  10. namespace Carbon {
  11. namespace {
  12. using ::Carbon::Testing::IsError;
  13. using ::Carbon::Testing::IsSuccess;
  14. using ::testing::_;
  15. using ::testing::Eq;
  16. TEST(ErrorTest, Error) {
  17. Error err("test");
  18. EXPECT_EQ(err.message(), "test");
  19. }
  20. TEST(ErrorTest, ErrorEmptyString) {
  21. ASSERT_DEATH({ Error err(""); }, "CHECK failure at");
  22. }
  23. auto IndirectError() -> Error { return Error("test"); }
  24. TEST(ErrorTest, IndirectError) { EXPECT_EQ(IndirectError().message(), "test"); }
  25. TEST(ErrorTest, ErrorBuilderOperatorImplicitCast) {
  26. ErrorOr<int> result = ErrorBuilder() << "msg";
  27. EXPECT_THAT(result, IsError("msg"));
  28. }
  29. // Make sure a custom error type can be forward declared and used with `ErrorOr`
  30. // until the `ErrorOr` is required to be complete itself.
  31. class CustomError;
  32. auto TestFunction() -> ErrorOr<int, CustomError>;
  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. auto TestFunction() -> ErrorOr<int, CustomError> { return CustomError(); }
  40. TEST(ErrorTest, UseErrorOrWithCustomError) {
  41. // Uses `TestFunction` to ensure it compiles correctly with forward
  42. // declarations above.
  43. EXPECT_THAT(TestFunction(), IsError("Custom test error!"));
  44. }
  45. template <typename ErrorT>
  46. class ErrorOrTest : public ::testing::Test {
  47. public:
  48. auto ErrorStr() -> std::string {
  49. if constexpr (std::same_as<ErrorT, Error>) {
  50. return "test error";
  51. } else if constexpr (std::same_as<ErrorT, CustomError>) {
  52. return CustomError().ToString();
  53. } else {
  54. static_assert(false, "Unsupported custom error type!");
  55. }
  56. }
  57. auto MakeError() -> ErrorT {
  58. if constexpr (std::same_as<ErrorT, Error>) {
  59. return Error("test error");
  60. } else if constexpr (std::same_as<ErrorT, CustomError>) {
  61. return CustomError();
  62. } else {
  63. static_assert(false, "Unsupported custom error type!");
  64. }
  65. }
  66. };
  67. using ErrorOrTestParams = ::testing::Types<Error, CustomError>;
  68. TYPED_TEST_SUITE(ErrorOrTest, ErrorOrTestParams);
  69. TYPED_TEST(ErrorOrTest, ErrorOr) {
  70. using TestErrorOr = ErrorOr<int, TypeParam>;
  71. TestErrorOr err(this->MakeError());
  72. EXPECT_THAT(err, IsError(this->ErrorStr()));
  73. }
  74. TYPED_TEST(ErrorOrTest, ErrorOrValue) {
  75. using TestErrorOr = ErrorOr<int, TypeParam>;
  76. EXPECT_TRUE(TestErrorOr(0).ok());
  77. }
  78. template <typename ErrorT, typename Fixture>
  79. auto IndirectErrorOrTest(Fixture& fixture) -> ErrorOr<int, ErrorT> {
  80. return fixture.MakeError();
  81. }
  82. TYPED_TEST(ErrorOrTest, IndirectErrorOr) {
  83. EXPECT_FALSE(IndirectErrorOrTest<TypeParam>(*this).ok());
  84. }
  85. struct Val {
  86. int val;
  87. };
  88. TYPED_TEST(ErrorOrTest, ErrorOrArrowOp) {
  89. using TestErrorOr = ErrorOr<Val, TypeParam>;
  90. TestErrorOr err({1});
  91. EXPECT_EQ(err->val, 1);
  92. }
  93. TYPED_TEST(ErrorOrTest, ErrorOrReference) {
  94. using TestErrorOr = ErrorOr<Val&, TypeParam>;
  95. Val val = {1};
  96. TestErrorOr maybe_val(val);
  97. EXPECT_EQ(maybe_val->val, 1);
  98. }
  99. template <typename ErrorT>
  100. auto IndirectErrorOrSuccessTest() -> ErrorOr<Success, ErrorT> {
  101. return Success();
  102. }
  103. TYPED_TEST(ErrorOrTest, IndirectErrorOrSuccess) {
  104. EXPECT_TRUE(IndirectErrorOrSuccessTest<TypeParam>().ok());
  105. }
  106. TYPED_TEST(ErrorOrTest, MoveValue) {
  107. using TestErrorOr = ErrorOr<std::unique_ptr<int>, TypeParam>;
  108. auto make_value = []() -> TestErrorOr { return std::make_unique<int>(42); };
  109. std::unique_ptr<int> p = *make_value();
  110. EXPECT_THAT(*p, Eq(42));
  111. auto result = make_value();
  112. std::unique_ptr<int> p2 = *std::move(result);
  113. EXPECT_THAT(*p2, Eq(42));
  114. }
  115. TYPED_TEST(ErrorOrTest, UnprintableValue) {
  116. struct X {
  117. int i;
  118. };
  119. using TestErrorOr = ErrorOr<X, TypeParam>;
  120. TestErrorOr value(X{.i = 42});
  121. EXPECT_THAT(value, IsSuccess(_));
  122. TestErrorOr error = this->MakeError();
  123. EXPECT_THAT(error, IsError(this->ErrorStr()));
  124. }
  125. TYPED_TEST(ErrorOrTest, ReturnIfErrorNoError) {
  126. using TestErrorOr = ErrorOr<Success, TypeParam>;
  127. auto result = []() -> TestErrorOr {
  128. CARBON_RETURN_IF_ERROR(TestErrorOr(Success()));
  129. CARBON_RETURN_IF_ERROR(TestErrorOr(Success()));
  130. return Success();
  131. }();
  132. EXPECT_TRUE(result.ok());
  133. }
  134. TYPED_TEST(ErrorOrTest, ReturnIfErrorHasError) {
  135. using TestErrorOr = ErrorOr<Success, TypeParam>;
  136. auto result = [this]() -> TestErrorOr {
  137. CARBON_RETURN_IF_ERROR(TestErrorOr(Success()));
  138. CARBON_RETURN_IF_ERROR(TestErrorOr(this->MakeError()));
  139. return Success();
  140. }();
  141. EXPECT_THAT(result, IsError(this->ErrorStr()));
  142. }
  143. TYPED_TEST(ErrorOrTest, AssignOrReturnNoError) {
  144. using TestErrorOr = ErrorOr<int, TypeParam>;
  145. auto result = []() -> TestErrorOr {
  146. CARBON_ASSIGN_OR_RETURN(int a, TestErrorOr(1));
  147. CARBON_ASSIGN_OR_RETURN(const int b, TestErrorOr(2));
  148. int c = 0;
  149. CARBON_ASSIGN_OR_RETURN(c, TestErrorOr(3));
  150. return a + b + c;
  151. }();
  152. EXPECT_THAT(result, IsSuccess(Eq(6)));
  153. }
  154. TYPED_TEST(ErrorOrTest, AssignOrReturnHasDirectError) {
  155. using TestErrorOr = ErrorOr<int, TypeParam>;
  156. auto result = [this]() -> TestErrorOr {
  157. CARBON_RETURN_IF_ERROR(TestErrorOr(this->MakeError()));
  158. return 0;
  159. }();
  160. EXPECT_THAT(result, IsError(this->ErrorStr()));
  161. }
  162. TYPED_TEST(ErrorOrTest, AssignOrReturnHasErrorInExpected) {
  163. using TestErrorOr = ErrorOr<int, TypeParam>;
  164. auto result = [this]() -> TestErrorOr {
  165. CARBON_ASSIGN_OR_RETURN(int a, TestErrorOr(this->MakeError()));
  166. return a;
  167. }();
  168. EXPECT_THAT(result, IsError(this->ErrorStr()));
  169. }
  170. class AnotherCustomError : public ErrorBase<AnotherCustomError> {
  171. public:
  172. auto Print(llvm::raw_ostream& os) const -> void {
  173. os << "Another custom test error!";
  174. }
  175. explicit operator CustomError() { return CustomError(); }
  176. };
  177. TYPED_TEST(ErrorOrTest, AssignOrReturnNoErrorAcrossErrorTypes) {
  178. using TestErrorOr = ErrorOr<int, TypeParam>;
  179. auto result = []() -> ErrorOr<int> {
  180. CARBON_ASSIGN_OR_RETURN(int a, TestErrorOr(1));
  181. CARBON_ASSIGN_OR_RETURN(const int b, []() -> TestErrorOr {
  182. CARBON_ASSIGN_OR_RETURN(int inner, (ErrorOr<int, AnotherCustomError>(2)));
  183. return inner;
  184. }());
  185. int c = 0;
  186. CARBON_ASSIGN_OR_RETURN(c, TestErrorOr(3));
  187. return a + b + c;
  188. }();
  189. EXPECT_THAT(result, IsSuccess(Eq(6)));
  190. }
  191. TYPED_TEST(ErrorOrTest, AssignOrReturnErrorAcrossErrorTypes) {
  192. using TestErrorOr = ErrorOr<int, TypeParam>;
  193. auto result = []() -> ErrorOr<int> {
  194. CARBON_ASSIGN_OR_RETURN(int a, TestErrorOr(1));
  195. CARBON_ASSIGN_OR_RETURN(const int b, []() -> TestErrorOr {
  196. CARBON_ASSIGN_OR_RETURN(
  197. int inner, (ErrorOr<int, AnotherCustomError>(AnotherCustomError())));
  198. return inner;
  199. }());
  200. int c = 0;
  201. CARBON_ASSIGN_OR_RETURN(c, TestErrorOr(3));
  202. return a + b + c;
  203. }();
  204. // When directly using the `Error` type, the explicit custom type above has
  205. // its message preserved. When testing against `CustomError`, that one
  206. // overrides the message.
  207. if constexpr (std::same_as<TypeParam, Error>) {
  208. EXPECT_THAT(result, IsError("Another custom test error!"));
  209. } else {
  210. EXPECT_THAT(result, IsError("Custom test error!"));
  211. }
  212. }
  213. } // namespace
  214. } // namespace Carbon