[llvm] f6b66cb - [llvm][Testing/ADT] Implement `IsStringMapEntry` testing matcher for verifying the entries in a `StringMap`.

Wei Yi Tee via llvm-commits llvm-commits at lists.llvm.org
Thu Sep 1 10:31:27 PDT 2022


Author: Wei Yi Tee
Date: 2022-09-01T17:30:41Z
New Revision: f6b66cbc7df17c12ea2e5819705caf4e9e88747e

URL: https://github.com/llvm/llvm-project/commit/f6b66cbc7df17c12ea2e5819705caf4e9e88747e
DIFF: https://github.com/llvm/llvm-project/commit/f6b66cbc7df17c12ea2e5819705caf4e9e88747e.diff

LOG: [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

Added: 
    llvm/unittests/Testing/ADT/StringMapEntryTest.cpp

Modified: 
    llvm/include/llvm/ADT/StringMapEntry.h
    llvm/include/llvm/Testing/ADT/StringMapEntry.h
    llvm/unittests/Testing/ADT/CMakeLists.txt
    utils/bazel/llvm-project-overlay/llvm/BUILD.bazel

Removed: 
    


################################################################################
diff  --git a/llvm/include/llvm/ADT/StringMapEntry.h b/llvm/include/llvm/ADT/StringMapEntry.h
index d580cdcedc1b1..664340683fc6b 100644
--- a/llvm/include/llvm/ADT/StringMapEntry.h
+++ b/llvm/include/llvm/ADT/StringMapEntry.h
@@ -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());
   }

diff  --git a/llvm/include/llvm/Testing/ADT/StringMapEntry.h b/llvm/include/llvm/Testing/ADT/StringMapEntry.h
index 0f7582cebcdbf..7649c30078181 100644
--- a/llvm/include/llvm/Testing/ADT/StringMapEntry.h
+++ b/llvm/include/llvm/Testing/ADT/StringMapEntry.h
@@ -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

diff  --git a/llvm/unittests/Testing/ADT/CMakeLists.txt b/llvm/unittests/Testing/ADT/CMakeLists.txt
index f57b61b9f3476..47d9e3afb58b5 100644
--- a/llvm/unittests/Testing/ADT/CMakeLists.txt
+++ b/llvm/unittests/Testing/ADT/CMakeLists.txt
@@ -3,5 +3,6 @@ set(LLVM_LINK_COMPONENTS
   )
 
 add_llvm_unittest(TestingADTTests
+  StringMapEntryTest.cpp
   StringMapTest.cpp
   )

diff  --git a/llvm/unittests/Testing/ADT/StringMapEntryTest.cpp b/llvm/unittests/Testing/ADT/StringMapEntryTest.cpp
new file mode 100644
index 0000000000000..4bc77410ea70c
--- /dev/null
+++ b/llvm/unittests/Testing/ADT/StringMapEntryTest.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

diff  --git a/utils/bazel/llvm-project-overlay/llvm/BUILD.bazel b/utils/bazel/llvm-project-overlay/llvm/BUILD.bazel
index 9bcb08f5ef73a..9bc56e9acd075 100644
--- a/utils/bazel/llvm-project-overlay/llvm/BUILD.bazel
+++ b/utils/bazel/llvm-project-overlay/llvm/BUILD.bazel
@@ -4188,7 +4188,10 @@ cc_library(
         "include/llvm/Testing/ADT/*.h",
     ]),
     copts = llvm_copts,
-    deps = [":Support"],
+    deps = [
+        ":Support",
+        ":gmock",
+    ],
 )
 
 cc_library(


        


More information about the llvm-commits mailing list