[llvm][ADT] Overload output stream operator `<<` for `StringMapEntry` and `StringMap`.
authorWei Yi Tee <wyt@google.com>
Wed, 31 Aug 2022 17:21:33 +0000 (17:21 +0000)
committerWei Yi Tee <wyt@google.com>
Wed, 31 Aug 2022 17:37:58 +0000 (17:37 +0000)
Printing support enables the production of more useful error messages in unit testing e.g. when using matchers such as `UnorderedElementsAre()` to inspect the contents of a `StringMap`.

Reviewed By: gribozavr2, sgatev, ymandel

Differential Revision: https://reviews.llvm.org/D132747

llvm/include/llvm/Testing/ADT/StringMap.h [new file with mode: 0644]
llvm/include/llvm/Testing/ADT/StringMapEntry.h [new file with mode: 0644]
llvm/unittests/Testing/ADT/CMakeLists.txt [new file with mode: 0644]
llvm/unittests/Testing/ADT/StringMapTest.cpp [new file with mode: 0644]
llvm/unittests/Testing/CMakeLists.txt
utils/bazel/llvm-project-overlay/llvm/BUILD.bazel
utils/bazel/llvm-project-overlay/llvm/unittests/BUILD.bazel

diff --git a/llvm/include/llvm/Testing/ADT/StringMap.h b/llvm/include/llvm/Testing/ADT/StringMap.h
new file mode 100644 (file)
index 0000000..e205b2d
--- /dev/null
@@ -0,0 +1,46 @@
+//===- llvm/Testing/ADT/StringMap.h ---------------------------------------===//
+//
+// 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
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_TESTING_ADT_STRINGMAP_H_
+#define LLVM_TESTING_ADT_STRINGMAP_H_
+
+#include "llvm/ADT/STLExtras.h"
+#include "llvm/ADT/StringMap.h"
+#include "llvm/Support/FormatVariadic.h"
+#include "llvm/Testing/ADT/StringMapEntry.h"
+#include <ostream>
+#include <sstream>
+
+namespace llvm {
+
+/// Support for printing to std::ostream, for use with e.g. producing more
+/// useful error messages with Google Test.
+template <typename T>
+std::ostream &operator<<(std::ostream &OS, const StringMap<T> &M) {
+  if (M.empty()) {
+    return OS << "{ }";
+  }
+
+  std::vector<std::string> Lines;
+  for (const auto &E : M) {
+    std::ostringstream SS;
+    SS << E << ",";
+    Lines.push_back(SS.str());
+  }
+  llvm::sort(Lines);
+  Lines.insert(Lines.begin(), "{");
+  Lines.insert(Lines.end(), "}");
+
+  return OS << llvm::formatv("{0:$[\n]}",
+                             make_range(Lines.begin(), Lines.end()))
+                   .str();
+}
+
+} // namespace llvm
+
+#endif
diff --git a/llvm/include/llvm/Testing/ADT/StringMapEntry.h b/llvm/include/llvm/Testing/ADT/StringMapEntry.h
new file mode 100644 (file)
index 0000000..0f7582c
--- /dev/null
@@ -0,0 +1,44 @@
+//===- llvm/Testing/ADT/StringMapEntry.h ----------------------------------===//
+//
+// 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
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_TESTING_ADT_STRINGMAPENTRY_H_
+#define LLVM_TESTING_ADT_STRINGMAPENTRY_H_
+
+#include "llvm/ADT/StringMapEntry.h"
+#include <ostream>
+#include <type_traits>
+
+namespace llvm {
+namespace detail {
+
+template <typename T, typename = std::void_t<>>
+struct CanOutputToOStream : std::false_type {};
+
+template <typename T>
+struct CanOutputToOStream<T, std::void_t<decltype(std::declval<std::ostream &>()
+                                                  << std::declval<T>())>>
+    : std::true_type {};
+
+} // namespace detail
+
+/// Support for printing to std::ostream, for use with e.g. producing more
+/// useful error messages with Google Test.
+template <typename T>
+std::ostream &operator<<(std::ostream &OS, const StringMapEntry<T> &E) {
+  OS << "{\"" << E.getKey().data() << "\": ";
+  if constexpr (detail::CanOutputToOStream<decltype(E.getValue())>::value) {
+    OS << E.getValue();
+  } else {
+    OS << "non-printable value";
+  }
+  return OS << "}";
+}
+
+} // namespace llvm
+
+#endif
diff --git a/llvm/unittests/Testing/ADT/CMakeLists.txt b/llvm/unittests/Testing/ADT/CMakeLists.txt
new file mode 100644 (file)
index 0000000..f57b61b
--- /dev/null
@@ -0,0 +1,7 @@
+set(LLVM_LINK_COMPONENTS
+  Support
+  )
+
+add_llvm_unittest(TestingADTTests
+  StringMapTest.cpp
+  )
diff --git a/llvm/unittests/Testing/ADT/StringMapTest.cpp b/llvm/unittests/Testing/ADT/StringMapTest.cpp
new file mode 100644 (file)
index 0000000..06bbaee
--- /dev/null
@@ -0,0 +1,55 @@
+//===- StringMapTest.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/StringMap.h"
+#include "llvm/ADT/StringMap.h"
+
+#include "gtest/gtest.h"
+#include <sstream>
+
+namespace llvm {
+namespace {
+
+TEST(StringMapTest, StringMapStream) {
+  std::ostringstream OS;
+  StringMap<int> Map;
+  Map["A"] = 42;
+  Map["Z"] = 35;
+  Map["B"] = 7;
+  OS << Map;
+
+  EXPECT_EQ(OS.str(), R"({
+{"A": 42},
+{"B": 7},
+{"Z": 35},
+})");
+}
+
+TEST(StringMapTest, NestedStringMapStream) {
+  std::ostringstream OS;
+  StringMap<StringMap<int>> Map;
+  Map["Z"];
+  Map["A"]["Apple"] = 5;
+  Map["B"]["Bee"] = 3;
+  Map["A"]["Axe"] = 3;
+  OS << Map;
+
+  EXPECT_EQ(OS.str(), R"({
+{"A": {
+{"Apple": 5},
+{"Axe": 3},
+}},
+{"B": {
+{"Bee": 3},
+}},
+{"Z": { }},
+})");
+}
+
+} // namespace
+} // namespace llvm
index 7255836..9bcb08f 100644 (file)
@@ -4182,6 +4182,16 @@ py_binary(
 )
 
 cc_library(
+    name = "TestingADT",
+    testonly = True,
+    hdrs = glob([
+        "include/llvm/Testing/ADT/*.h",
+    ]),
+    copts = llvm_copts,
+    deps = [":Support"],
+)
+
+cc_library(
     name = "TestingSupport",
     testonly = True,
     srcs = glob([
index 34445a5..e5e992b 100644 (file)
@@ -645,6 +645,23 @@ cc_test(
 )
 
 cc_test(
+    name = "testing_adt_tests",
+    size = "small",
+    srcs = glob(
+        [
+            "Testing/ADT/*.cpp",
+        ],
+        allow_empty = False,
+    ),
+    deps = [
+        "//llvm:Support",
+        "//llvm:TestingADT",
+        "//llvm:gtest",
+        "//llvm:gtest_main",
+    ],
+)
+
+cc_test(
     name = "transforms_tests",
     size = "small",
     srcs = glob(