forked from OSchip/llvm-project
[llvm][Testing/ADT] Implement `IsStringMapEntry` testing matcher for verifying the entries in a `StringMap`.
Reviewed By: gribozavr2, ymandel, sgatev Differential Revision: https://reviews.llvm.org/D132753
This commit is contained in:
parent
2562991c36
commit
f6b66cbc7d
|
@ -102,6 +102,8 @@ class StringMapEntry final : public StringMapEntryStorage<ValueTy> {
|
|||
public:
|
||||
using StringMapEntryStorage<ValueTy>::StringMapEntryStorage;
|
||||
|
||||
using ValueType = ValueTy;
|
||||
|
||||
StringRef getKey() const {
|
||||
return StringRef(getKeyData(), this->getKeyLength());
|
||||
}
|
||||
|
|
|
@ -10,6 +10,7 @@
|
|||
#define LLVM_TESTING_ADT_STRINGMAPENTRY_H_
|
||||
|
||||
#include "llvm/ADT/StringMapEntry.h"
|
||||
#include "gmock/gmock.h"
|
||||
#include <ostream>
|
||||
#include <type_traits>
|
||||
|
||||
|
@ -39,6 +40,90 @@ std::ostream &operator<<(std::ostream &OS, const StringMapEntry<T> &E) {
|
|||
return OS << "}";
|
||||
}
|
||||
|
||||
namespace detail {
|
||||
|
||||
template <typename StringMapEntryT>
|
||||
class StringMapEntryMatcherImpl
|
||||
: public testing::MatcherInterface<StringMapEntryT> {
|
||||
public:
|
||||
using ValueT = typename std::remove_reference_t<StringMapEntryT>::ValueType;
|
||||
|
||||
template <typename KeyMatcherT, typename ValueMatcherT>
|
||||
StringMapEntryMatcherImpl(KeyMatcherT KeyMatcherArg,
|
||||
ValueMatcherT ValueMatcherArg)
|
||||
: KeyMatcher(
|
||||
testing::SafeMatcherCast<const std::string &>(KeyMatcherArg)),
|
||||
ValueMatcher(
|
||||
testing::SafeMatcherCast<const ValueT &>(ValueMatcherArg)) {}
|
||||
|
||||
void DescribeTo(std::ostream *OS) const override {
|
||||
*OS << "has a string key that ";
|
||||
KeyMatcher.DescribeTo(OS);
|
||||
*OS << ", and has a value that ";
|
||||
ValueMatcher.DescribeTo(OS);
|
||||
}
|
||||
|
||||
void DescribeNegationTo(std::ostream *OS) const override {
|
||||
*OS << "has a string key that ";
|
||||
KeyMatcher.DescribeNegationTo(OS);
|
||||
*OS << ", or has a value that ";
|
||||
ValueMatcher.DescribeNegationTo(OS);
|
||||
}
|
||||
|
||||
bool
|
||||
MatchAndExplain(StringMapEntryT Entry,
|
||||
testing::MatchResultListener *ResultListener) const override {
|
||||
testing::StringMatchResultListener KeyListener;
|
||||
if (!KeyMatcher.MatchAndExplain(Entry.getKey().data(), &KeyListener)) {
|
||||
*ResultListener << ("which has a string key " +
|
||||
(KeyListener.str().empty() ? "that doesn't match"
|
||||
: KeyListener.str()));
|
||||
return false;
|
||||
}
|
||||
testing::StringMatchResultListener ValueListener;
|
||||
if (!ValueMatcher.MatchAndExplain(Entry.getValue(), &ValueListener)) {
|
||||
*ResultListener << ("which has a value " + (ValueListener.str().empty()
|
||||
? "that doesn't match"
|
||||
: ValueListener.str()));
|
||||
return false;
|
||||
}
|
||||
*ResultListener << "which is a match";
|
||||
return true;
|
||||
}
|
||||
|
||||
private:
|
||||
const testing::Matcher<const std::string &> KeyMatcher;
|
||||
const testing::Matcher<const ValueT &> ValueMatcher;
|
||||
};
|
||||
|
||||
template <typename KeyMatcherT, typename ValueMatcherT>
|
||||
class StringMapEntryMatcher {
|
||||
public:
|
||||
StringMapEntryMatcher(KeyMatcherT KMArg, ValueMatcherT VMArg)
|
||||
: KM(std::move(KMArg)), VM(std::move(VMArg)) {}
|
||||
|
||||
template <typename StringMapEntryT>
|
||||
operator testing::Matcher<StringMapEntryT>() const { // NOLINT
|
||||
return testing::Matcher<StringMapEntryT>(
|
||||
new StringMapEntryMatcherImpl<const StringMapEntryT &>(KM, VM));
|
||||
}
|
||||
|
||||
private:
|
||||
const KeyMatcherT KM;
|
||||
const ValueMatcherT VM;
|
||||
};
|
||||
|
||||
} // namespace detail
|
||||
|
||||
/// Returns a gMock matcher that matches a `StringMapEntry` whose string key
|
||||
/// matches `KeyMatcher`, and whose value matches `ValueMatcher`.
|
||||
template <typename KeyMatcherT, typename ValueMatcherT>
|
||||
detail::StringMapEntryMatcher<KeyMatcherT, ValueMatcherT>
|
||||
IsStringMapEntry(KeyMatcherT KM, ValueMatcherT VM) {
|
||||
return detail::StringMapEntryMatcher<KeyMatcherT, ValueMatcherT>(
|
||||
std::move(KM), std::move(VM));
|
||||
}
|
||||
|
||||
} // namespace llvm
|
||||
|
||||
#endif
|
||||
|
|
|
@ -3,5 +3,6 @@ set(LLVM_LINK_COMPONENTS
|
|||
)
|
||||
|
||||
add_llvm_unittest(TestingADTTests
|
||||
StringMapEntryTest.cpp
|
||||
StringMapTest.cpp
|
||||
)
|
||||
|
|
|
@ -0,0 +1,88 @@
|
|||
//===- StringMapEntryTest.cpp ---------------------------------------------===//
|
||||
//
|
||||
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
||||
// See https://llvm.org/LICENSE.txt for license information.
|
||||
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#include "llvm/Testing/ADT/StringMapEntry.h"
|
||||
#include "llvm/ADT/StringMap.h"
|
||||
|
||||
#include "gtest/gtest.h"
|
||||
#include <sstream>
|
||||
|
||||
namespace llvm {
|
||||
namespace {
|
||||
|
||||
using testing::Gt;
|
||||
using testing::Matcher;
|
||||
using testing::StrCaseEq;
|
||||
using testing::StringMatchResultListener;
|
||||
using testing::UnorderedElementsAre;
|
||||
|
||||
template <typename T> std::string Describe(const Matcher<T> &M, bool Match) {
|
||||
std::stringstream SS;
|
||||
if (Match) {
|
||||
M.DescribeTo(&SS);
|
||||
} else {
|
||||
M.DescribeNegationTo(&SS);
|
||||
}
|
||||
return SS.str();
|
||||
}
|
||||
|
||||
template <typename T, typename V>
|
||||
std::string ExplainMatch(const Matcher<T> &Matcher, const V &Value) {
|
||||
StringMatchResultListener Listener;
|
||||
Matcher.MatchAndExplain(Value, &Listener);
|
||||
return Listener.str();
|
||||
}
|
||||
|
||||
TEST(IsStringMapEntryTest, InnerMatchersAreExactValues) {
|
||||
llvm::StringMap<int> Map = {{"A", 1}};
|
||||
EXPECT_THAT(*Map.find("A"), IsStringMapEntry("A", 1));
|
||||
}
|
||||
|
||||
TEST(IsStringMapEntryTest, InnerMatchersAreOtherMatchers) {
|
||||
llvm::StringMap<int> Map = {{"A", 1}};
|
||||
EXPECT_THAT(*Map.find("A"), IsStringMapEntry(StrCaseEq("a"), Gt(0)));
|
||||
}
|
||||
|
||||
TEST(IsStringMapEntryTest, UseAsInnerMatcher) {
|
||||
llvm::StringMap<int> Map = {{"A", 1}, {"B", 2}};
|
||||
EXPECT_THAT(Map, UnorderedElementsAre(IsStringMapEntry("A", 1),
|
||||
IsStringMapEntry("B", 2)));
|
||||
}
|
||||
|
||||
TEST(IsStringMapEntryTest, DescribeSelf) {
|
||||
Matcher<llvm::StringMapEntry<int>> M = IsStringMapEntry("A", 1);
|
||||
EXPECT_EQ(
|
||||
R"(has a string key that is equal to "A", and has a value that is equal to 1)",
|
||||
Describe(M, true));
|
||||
EXPECT_EQ(
|
||||
R"(has a string key that isn't equal to "A", or has a value that isn't equal to 1)",
|
||||
Describe(M, false));
|
||||
}
|
||||
|
||||
TEST(IsStringMapEntryTest, ExplainSelfMatchSuccess) {
|
||||
llvm::StringMap<int> Map = {{"A", 1}};
|
||||
Matcher<llvm::StringMapEntry<int>> M = IsStringMapEntry("A", 1);
|
||||
EXPECT_EQ(R"(which is a match)", ExplainMatch(M, *Map.find("A")));
|
||||
}
|
||||
|
||||
TEST(IsStringMapEntryTest, ExplainSelfMatchFailsOnKey) {
|
||||
llvm::StringMap<int> Map = {{"B", 1}};
|
||||
Matcher<llvm::StringMapEntry<int>> M = IsStringMapEntry("A", 1);
|
||||
EXPECT_EQ(R"(which has a string key that doesn't match)",
|
||||
ExplainMatch(M, *Map.find("B")));
|
||||
}
|
||||
|
||||
TEST(IsStringMapEntryTest, ExplainSelfMatchFailsOnValue) {
|
||||
llvm::StringMap<int> Map = {{"A", 2}};
|
||||
Matcher<llvm::StringMapEntry<int>> M = IsStringMapEntry("A", 1);
|
||||
EXPECT_EQ(R"(which has a value that doesn't match)",
|
||||
ExplainMatch(M, *Map.find("A")));
|
||||
}
|
||||
|
||||
} // namespace
|
||||
} // namespace llvm
|
|
@ -4188,7 +4188,10 @@ cc_library(
|
|||
"include/llvm/Testing/ADT/*.h",
|
||||
]),
|
||||
copts = llvm_copts,
|
||||
deps = [":Support"],
|
||||
deps = [
|
||||
":Support",
|
||||
":gmock",
|
||||
],
|
||||
)
|
||||
|
||||
cc_library(
|
||||
|
|
Loading…
Reference in New Issue