mirror of
https://github.com/carbon-language/carbon-lang.git
synced 2026-10-03 22:02:51 +01:00
This doesn't split apart the current error type into one that tracks location and one that doesn't, although that might be easier to do once we have this. Instead, this is primarily intended to support custom error types that lazily materialize the error message in case that can be avoided by completely handling the error. For example, many file system operations are *expected* to produce errors even in the hot path and we don't want to render `ENOENT` (for example) to a pretty string and instead will directly query the error to understand and handle it in code. The type parameter ordering isn't the most obvious, but helpfully allows us to default the error type in a useful way. --------- Co-authored-by: Jon Ross-Perkins <jperkins@google.com>
112 lines
3.2 KiB
C++
112 lines
3.2 KiB
C++
// 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
|
|
|
|
#ifndef CARBON_COMMON_ERROR_TEST_HELPERS_H_
|
|
#define CARBON_COMMON_ERROR_TEST_HELPERS_H_
|
|
|
|
#include <gmock/gmock.h>
|
|
|
|
#include "common/error.h"
|
|
|
|
namespace Carbon::Testing {
|
|
|
|
// Matches the message for an error state of `ErrorOr<T>`. For example:
|
|
// EXPECT_THAT(my_result, IsError(StrEq("error message")));
|
|
class IsError {
|
|
public:
|
|
// NOLINTNEXTLINE(readability-identifier-naming)
|
|
using is_gtest_matcher = void;
|
|
|
|
explicit IsError(::testing::Matcher<std::string> matcher)
|
|
: matcher_(std::move(matcher)) {}
|
|
|
|
template <typename T, typename ErrorT>
|
|
auto MatchAndExplain(const ErrorOr<T, ErrorT>& result,
|
|
::testing::MatchResultListener* listener) const -> bool {
|
|
if (result.ok()) {
|
|
*listener->stream() << "is a success";
|
|
return false;
|
|
} else {
|
|
RawStringOstream os;
|
|
os << result.error();
|
|
return matcher_.MatchAndExplain(os.TakeStr(), listener);
|
|
}
|
|
}
|
|
|
|
auto DescribeTo(std::ostream* os) const -> void {
|
|
*os << "is an error and matches ";
|
|
matcher_.DescribeTo(os);
|
|
}
|
|
|
|
auto DescribeNegationTo(std::ostream* os) const -> void {
|
|
*os << "is a success or does not match ";
|
|
matcher_.DescribeTo(os);
|
|
}
|
|
|
|
private:
|
|
::testing::Matcher<std::string> matcher_;
|
|
};
|
|
|
|
// Matches the value for a non-error state of `ErrorOr<T>`. For example:
|
|
// EXPECT_THAT(my_result, IsSuccess(Eq(3)));
|
|
template <typename InnerMatcher>
|
|
class IsSuccessMatcher {
|
|
public:
|
|
// NOLINTNEXTLINE(readability-identifier-naming)
|
|
using is_gtest_matcher = void;
|
|
|
|
explicit IsSuccessMatcher(InnerMatcher matcher)
|
|
: matcher_(std::move(matcher)) {}
|
|
|
|
template <typename T, typename ErrorT>
|
|
auto MatchAndExplain(const ErrorOr<T, ErrorT>& result,
|
|
::testing::MatchResultListener* listener) const -> bool {
|
|
if (result.ok()) {
|
|
return ::testing::Matcher<T>(matcher_).MatchAndExplain(*result, listener);
|
|
} else {
|
|
*listener->stream() << "is an error with `" << result.error() << "`";
|
|
return false;
|
|
}
|
|
}
|
|
|
|
auto DescribeTo(std::ostream* os) const -> void {
|
|
*os << "is a success and matches ";
|
|
matcher_.DescribeTo(os);
|
|
}
|
|
|
|
auto DescribeNegationTo(std::ostream* os) const -> void {
|
|
*os << "is an error or does not match ";
|
|
matcher_.DescribeTo(os);
|
|
}
|
|
|
|
private:
|
|
InnerMatcher matcher_;
|
|
};
|
|
|
|
// Wraps `IsSuccessMatcher` for the inner matcher deduction.
|
|
template <typename InnerMatcher>
|
|
auto IsSuccess(InnerMatcher matcher) -> IsSuccessMatcher<InnerMatcher> {
|
|
return IsSuccessMatcher<InnerMatcher>(matcher);
|
|
}
|
|
|
|
} // namespace Carbon::Testing
|
|
|
|
namespace Carbon {
|
|
|
|
// Supports printing `ErrorOr<T>` to `std::ostream` in tests.
|
|
template <typename T, typename ErrorT>
|
|
auto operator<<(std::ostream& out, const ErrorOr<T, ErrorT>& error_or)
|
|
-> std::ostream& {
|
|
if (error_or.ok()) {
|
|
out << llvm::formatv("ErrorOr{{.value = `{0}`}}", *error_or);
|
|
} else {
|
|
out << llvm::formatv("ErrorOr{{.error = \"{0}\"}}", error_or.error());
|
|
}
|
|
return out;
|
|
}
|
|
|
|
} // namespace Carbon
|
|
|
|
#endif // CARBON_COMMON_ERROR_TEST_HELPERS_H_
|