1 /* 2 * Copyright (C) 2024 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 #pragma once 18 19 #include <gmock/gmock.h> 20 #include <gtest/gtest.h> 21 22 #include <ostream> 23 #include <type_traits> 24 25 namespace android::error { 26 27 /** 28 * Example Usage: 29 * Given a function with signature 30 * Result<T, U> foo() 31 * Matchers can be used as follows: 32 * EXPECT_THAT(foo(), IsOkAnd(Eq(T{}))); 33 * EXPECT_THAT(foo(), IsErrorAnd(Eq(U{}))); 34 */ 35 template <typename ExpectedT> 36 class IsOkAndImpl : public ::testing::MatcherInterface<ExpectedT> { 37 public: 38 using ValueT = std::remove_reference_t<ExpectedT>::value_type; 39 40 template <typename InnerMatcher> IsOkAndImpl(InnerMatcher innerMatcher)41 explicit IsOkAndImpl(InnerMatcher innerMatcher) 42 : inner_matcher_(::testing::SafeMatcherCast<const ValueT&>( 43 std::forward<InnerMatcher>(innerMatcher))) {} 44 MatchAndExplain(ExpectedT val,::testing::MatchResultListener * listener)45 bool MatchAndExplain(ExpectedT val, ::testing::MatchResultListener* listener) const { 46 if (!val.has_value()) { 47 *listener << "which has error " << ::testing::PrintToString(val.error()); 48 return false; 49 } 50 const auto res = inner_matcher_.MatchAndExplain(val.value(), listener); 51 if (!res) { 52 *listener << "which has value " << ::testing::PrintToString(val.value()); 53 } 54 return res; 55 } 56 DescribeTo(std::ostream * os)57 void DescribeTo(std::ostream* os) const { 58 *os << "contains expected value which "; 59 inner_matcher_.DescribeTo(os); 60 } 61 DescribeNegationTo(std::ostream * os)62 void DescribeNegationTo(std::ostream* os) const { 63 *os << "does not contain expected, or contains expected value which "; 64 inner_matcher_.DescribeNegationTo(os); 65 } 66 67 private: 68 ::testing::Matcher<const ValueT&> inner_matcher_; 69 }; 70 71 template <typename InnerMatcher> 72 class IsOkAnd { 73 public: IsOkAnd(InnerMatcher innerMatcher)74 explicit IsOkAnd(InnerMatcher innerMatcher) : inner_matcher_(std::move(innerMatcher)) {} 75 76 template <typename T> 77 operator ::testing::Matcher<T>() const { 78 return ::testing::Matcher<T>{new IsOkAndImpl<const T&>(inner_matcher_)}; 79 } 80 81 private: 82 InnerMatcher inner_matcher_; 83 }; 84 85 template <typename ExpectedT> 86 class IsErrorAndImpl : public ::testing::MatcherInterface<ExpectedT> { 87 public: 88 using ErrorT = typename std::remove_reference_t<ExpectedT>::error_type; 89 90 template <typename InnerMatcher> IsErrorAndImpl(InnerMatcher innerMatcher)91 explicit IsErrorAndImpl(InnerMatcher innerMatcher) 92 : inner_matcher_(::testing::SafeMatcherCast<const ErrorT&>( 93 std::forward<InnerMatcher>(innerMatcher))) {} 94 MatchAndExplain(ExpectedT val,::testing::MatchResultListener * listener)95 bool MatchAndExplain(ExpectedT val, ::testing::MatchResultListener* listener) const { 96 if (val.has_value()) { 97 *listener << "which has value " << ::testing::PrintToString(val.value()); 98 return false; 99 } 100 101 const auto res = inner_matcher_.MatchAndExplain(val.error(), listener); 102 if (!res) { 103 *listener << "which has error " << ::testing::PrintToString(val.error()); 104 } 105 return res; 106 } 107 DescribeTo(std::ostream * os)108 void DescribeTo(std::ostream* os) const { 109 *os << "contains error value which "; 110 inner_matcher_.DescribeTo(os); 111 } 112 DescribeNegationTo(std::ostream * os)113 void DescribeNegationTo(std::ostream* os) const { 114 *os << "does not contain error value, or contains error value which "; 115 inner_matcher_.DescribeNegationTo(os); 116 } 117 118 private: 119 ::testing::Matcher<const ErrorT&> inner_matcher_; 120 }; 121 122 template <typename InnerMatcher> 123 class IsErrorAnd { 124 public: IsErrorAnd(InnerMatcher innerMatcher)125 explicit IsErrorAnd(InnerMatcher innerMatcher) : inner_matcher_(std::move(innerMatcher)) {} 126 127 template <typename T> 128 operator ::testing::Matcher<T>() const { 129 return ::testing::Matcher<T>{new IsErrorAndImpl<const T&>(inner_matcher_)}; 130 } 131 132 private: 133 InnerMatcher inner_matcher_; 134 }; 135 136 } // namespace android::error 137