/* * Copyright (C) 2024 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #pragma once #include #include #include #include namespace android::error { /** * Example Usage: * Given a function with signature * Result foo() * Matchers can be used as follows: * EXPECT_THAT(foo(), IsOkAnd(Eq(T{}))); * EXPECT_THAT(foo(), IsErrorAnd(Eq(U{}))); */ template class IsOkAndImpl : public ::testing::MatcherInterface { public: using ValueT = std::remove_reference_t::value_type; template explicit IsOkAndImpl(InnerMatcher innerMatcher) : inner_matcher_(::testing::SafeMatcherCast( std::forward(innerMatcher))) {} bool MatchAndExplain(ExpectedT val, ::testing::MatchResultListener* listener) const { if (!val.has_value()) { *listener << "which has error " << ::testing::PrintToString(val.error()); return false; } const auto res = inner_matcher_.MatchAndExplain(val.value(), listener); if (!res) { *listener << "which has value " << ::testing::PrintToString(val.value()); } return res; } void DescribeTo(std::ostream* os) const { *os << "contains expected value which "; inner_matcher_.DescribeTo(os); } void DescribeNegationTo(std::ostream* os) const { *os << "does not contain expected, or contains expected value which "; inner_matcher_.DescribeNegationTo(os); } private: ::testing::Matcher inner_matcher_; }; template class IsOkAnd { public: explicit IsOkAnd(InnerMatcher innerMatcher) : inner_matcher_(std::move(innerMatcher)) {} template operator ::testing::Matcher() const { return ::testing::Matcher{new IsOkAndImpl(inner_matcher_)}; } private: InnerMatcher inner_matcher_; }; template class IsErrorAndImpl : public ::testing::MatcherInterface { public: using ErrorT = typename std::remove_reference_t::error_type; template explicit IsErrorAndImpl(InnerMatcher innerMatcher) : inner_matcher_(::testing::SafeMatcherCast( std::forward(innerMatcher))) {} bool MatchAndExplain(ExpectedT val, ::testing::MatchResultListener* listener) const { if (val.has_value()) { *listener << "which has value " << ::testing::PrintToString(val.value()); return false; } const auto res = inner_matcher_.MatchAndExplain(val.error(), listener); if (!res) { *listener << "which has error " << ::testing::PrintToString(val.error()); } return res; } void DescribeTo(std::ostream* os) const { *os << "contains error value which "; inner_matcher_.DescribeTo(os); } void DescribeNegationTo(std::ostream* os) const { *os << "does not contain error value, or contains error value which "; inner_matcher_.DescribeNegationTo(os); } private: ::testing::Matcher inner_matcher_; }; template class IsErrorAnd { public: explicit IsErrorAnd(InnerMatcher innerMatcher) : inner_matcher_(std::move(innerMatcher)) {} template operator ::testing::Matcher() const { return ::testing::Matcher{new IsErrorAndImpl(inner_matcher_)}; } private: InnerMatcher inner_matcher_; }; } // namespace android::error