[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:
Wei Yi Tee 2022-09-01 16:15:55 +00:00
parent 2562991c36
commit f6b66cbc7d
5 changed files with 180 additions and 1 deletions

View File

@ -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());
}

View File

@ -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

View File

@ -3,5 +3,6 @@ set(LLVM_LINK_COMPONENTS
)
add_llvm_unittest(TestingADTTests
StringMapEntryTest.cpp
StringMapTest.cpp
)

View File

@ -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

View File

@ -4188,7 +4188,10 @@ cc_library(
"include/llvm/Testing/ADT/*.h",
]),
copts = llvm_copts,
deps = [":Support"],
deps = [
":Support",
":gmock",
],
)
cc_library(