error_test.cpp 7.6 KB

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