1 //===- llvm/Testing/ADT/StringMapEntry.h ----------------------------------===// 2 // 3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4 // See https://llvm.org/LICENSE.txt for license information. 5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6 // 7 //===----------------------------------------------------------------------===// 8 9 #ifndef LLVM_TESTING_ADT_STRINGMAPENTRY_H_ 10 #define LLVM_TESTING_ADT_STRINGMAPENTRY_H_ 11 12 #include "llvm/ADT/StringMapEntry.h" 13 #include "gmock/gmock.h" 14 #include <ostream> 15 #include <type_traits> 16 17 namespace llvm { 18 namespace detail { 19 20 template <typename T, typename = std::void_t<>> 21 struct CanOutputToOStream : std::false_type {}; 22 23 template <typename T> 24 struct CanOutputToOStream<T, std::void_t<decltype(std::declval<std::ostream &>() 25 << std::declval<T>())>> 26 : std::true_type {}; 27 28 } // namespace detail 29 30 /// Support for printing to std::ostream, for use with e.g. producing more 31 /// useful error messages with Google Test. 32 template <typename T> 33 std::ostream &operator<<(std::ostream &OS, const StringMapEntry<T> &E) { 34 OS << "{\"" << E.getKey().data() << "\": "; 35 if constexpr (detail::CanOutputToOStream<decltype(E.getValue())>::value) { 36 OS << E.getValue(); 37 } else { 38 OS << "non-printable value"; 39 } 40 return OS << "}"; 41 } 42 43 namespace detail { 44 45 template <typename StringMapEntryT> 46 class StringMapEntryMatcherImpl 47 : public testing::MatcherInterface<StringMapEntryT> { 48 public: 49 using ValueT = typename std::remove_reference_t<StringMapEntryT>::ValueType; 50 51 template <typename KeyMatcherT, typename ValueMatcherT> 52 StringMapEntryMatcherImpl(KeyMatcherT KeyMatcherArg, 53 ValueMatcherT ValueMatcherArg) 54 : KeyMatcher( 55 testing::SafeMatcherCast<const std::string &>(KeyMatcherArg)), 56 ValueMatcher( 57 testing::SafeMatcherCast<const ValueT &>(ValueMatcherArg)) {} 58 59 void DescribeTo(std::ostream *OS) const override { 60 *OS << "has a string key that "; 61 KeyMatcher.DescribeTo(OS); 62 *OS << ", and has a value that "; 63 ValueMatcher.DescribeTo(OS); 64 } 65 66 void DescribeNegationTo(std::ostream *OS) const override { 67 *OS << "has a string key that "; 68 KeyMatcher.DescribeNegationTo(OS); 69 *OS << ", or has a value that "; 70 ValueMatcher.DescribeNegationTo(OS); 71 } 72 73 bool 74 MatchAndExplain(StringMapEntryT Entry, 75 testing::MatchResultListener *ResultListener) const override { 76 testing::StringMatchResultListener KeyListener; 77 if (!KeyMatcher.MatchAndExplain(Entry.getKey().data(), &KeyListener)) { 78 *ResultListener << ("which has a string key " + 79 (KeyListener.str().empty() ? "that doesn't match" 80 : KeyListener.str())); 81 return false; 82 } 83 testing::StringMatchResultListener ValueListener; 84 if (!ValueMatcher.MatchAndExplain(Entry.getValue(), &ValueListener)) { 85 *ResultListener << ("which has a value " + (ValueListener.str().empty() 86 ? "that doesn't match" 87 : ValueListener.str())); 88 return false; 89 } 90 *ResultListener << "which is a match"; 91 return true; 92 } 93 94 private: 95 const testing::Matcher<const std::string &> KeyMatcher; 96 const testing::Matcher<const ValueT &> ValueMatcher; 97 }; 98 99 template <typename KeyMatcherT, typename ValueMatcherT> 100 class StringMapEntryMatcher { 101 public: 102 StringMapEntryMatcher(KeyMatcherT KMArg, ValueMatcherT VMArg) 103 : KM(std::move(KMArg)), VM(std::move(VMArg)) {} 104 105 template <typename StringMapEntryT> 106 operator testing::Matcher<StringMapEntryT>() const { // NOLINT 107 return testing::Matcher<StringMapEntryT>( 108 new StringMapEntryMatcherImpl<const StringMapEntryT &>(KM, VM)); 109 } 110 111 private: 112 const KeyMatcherT KM; 113 const ValueMatcherT VM; 114 }; 115 116 } // namespace detail 117 118 /// Returns a gMock matcher that matches a `StringMapEntry` whose string key 119 /// matches `KeyMatcher`, and whose value matches `ValueMatcher`. 120 template <typename KeyMatcherT, typename ValueMatcherT> 121 detail::StringMapEntryMatcher<KeyMatcherT, ValueMatcherT> 122 IsStringMapEntry(KeyMatcherT KM, ValueMatcherT VM) { 123 return detail::StringMapEntryMatcher<KeyMatcherT, ValueMatcherT>( 124 std::move(KM), std::move(VM)); 125 } 126 127 } // namespace llvm 128 129 #endif 130