Make --benchmark_list_tests respect --benchmark_format (#2245)

* Make --benchmark_list_tests respect --benchmark_format via reporter List() (#1642)

* Export FindBenchmarksInternal for shared-library test link; fix include order
diff --git a/include/benchmark/reporter.h b/include/benchmark/reporter.h
index be242be..3faa21d 100644
--- a/include/benchmark/reporter.h
+++ b/include/benchmark/reporter.h
@@ -36,6 +36,10 @@
 
 namespace benchmark {
 
+namespace internal {
+class BenchmarkInstance;
+}  // namespace internal
+
 struct BENCHMARK_EXPORT BenchmarkName {
   std::string function_name;
   std::string args;
@@ -132,6 +136,11 @@
   virtual void ReportRuns(const std::vector<Run>& report) = 0;
   virtual void Finalize() {}
 
+  // Called instead of running the benchmarks when `--benchmark_list_tests`
+  // is specified, with the benchmarks that were selected to run. The default
+  // implementation prints one benchmark name per line without any markup.
+  virtual void List(const std::vector<internal::BenchmarkInstance>& benchmarks);
+
   void SetOutputStream(std::ostream* out) {
     assert(out);
     output_stream_ = out;
@@ -181,6 +190,8 @@
   bool ReportContext(const Context& context) override;
   void ReportRuns(const std::vector<Run>& reports) override;
   void Finalize() override;
+  void List(
+      const std::vector<internal::BenchmarkInstance>& benchmarks) override;
 
  private:
   void PrintRunData(const Run& run);
@@ -194,6 +205,8 @@
   CSVReporter() : printed_header_(false) {}
   bool ReportContext(const Context& context) override;
   void ReportRuns(const std::vector<Run>& reports) override;
+  void List(
+      const std::vector<internal::BenchmarkInstance>& benchmarks) override;
 
  private:
   void PrintRunData(const Run& run);
diff --git a/src/benchmark.cc b/src/benchmark.cc
index 7217fc4..9128029 100644
--- a/src/benchmark.cc
+++ b/src/benchmark.cc
@@ -677,9 +677,7 @@
   }
 
   if (FLAGS_benchmark_list_tests) {
-    for (auto const& benchmark : benchmarks) {
-      Out << benchmark.name().str() << "\n";
-    }
+    display_reporter->List(benchmarks);
   } else {
     internal::RunBenchmarks(benchmarks, display_reporter, file_reporter);
   }
diff --git a/src/benchmark_api_internal.h b/src/benchmark_api_internal.h
index 0f356da..0dd950c 100644
--- a/src/benchmark_api_internal.h
+++ b/src/benchmark_api_internal.h
@@ -77,6 +77,7 @@
   callback_function teardown_;
 };
 
+BENCHMARK_EXPORT
 bool FindBenchmarksInternal(const std::string& re,
                             std::vector<BenchmarkInstance>* benchmarks,
                             std::ostream* Err);
diff --git a/src/csv_reporter.cc b/src/csv_reporter.cc
index 1665ac5..3e21d11 100644
--- a/src/csv_reporter.cc
+++ b/src/csv_reporter.cc
@@ -18,6 +18,7 @@
 
 #include "benchmark/export.h"
 #include "benchmark/reporter.h"
+#include "benchmark_api_internal.h"
 #include "check.h"
 #include "complexity.h"
 
@@ -168,4 +169,14 @@
   Out << '\n';
 }
 
+BENCHMARK_EXPORT
+void CSVReporter::List(
+    const std::vector<internal::BenchmarkInstance>& benchmarks) {
+  std::ostream& out = GetOutputStream();
+  out << "name\n";
+  for (const internal::BenchmarkInstance& benchmark : benchmarks) {
+    out << CsvEscape(benchmark.name().str()) << "\n";
+  }
+}
+
 }  // end namespace benchmark
diff --git a/src/json_reporter.cc b/src/json_reporter.cc
index ef4636e..37da17b 100644
--- a/src/json_reporter.cc
+++ b/src/json_reporter.cc
@@ -26,6 +26,7 @@
 #include "benchmark/export.h"
 #include "benchmark/reporter.h"
 #include "benchmark/types.h"
+#include "benchmark_api_internal.h"
 #include "complexity.h"
 #include "string_util.h"
 #include "timers.h"
@@ -343,4 +344,24 @@
   out << '\n';
 }
 
+void JSONReporter::List(
+    const std::vector<internal::BenchmarkInstance>& benchmarks) {
+  std::ostream& out = GetOutputStream();
+  std::string inner_indent(2, ' ');
+  std::string indent(4, ' ');
+  std::string entry_indent(6, ' ');
+
+  // Mirror the structure of the regular output so that consumers can read
+  // the names from the same "benchmarks" array in both modes.
+  out << "{\n" << inner_indent << "\"benchmarks\": [";
+  bool first = true;
+  for (const internal::BenchmarkInstance& benchmark : benchmarks) {
+    out << (first ? "\n" : ",\n") << indent << "{\n";
+    out << entry_indent << FormatKV("name", benchmark.name().str()) << "\n";
+    out << indent << "}";
+    first = false;
+  }
+  out << "\n" << inner_indent << "]\n}\n";
+}
+
 }  // end namespace benchmark
diff --git a/src/reporter.cc b/src/reporter.cc
index 73ca8d0..298ff1a 100644
--- a/src/reporter.cc
+++ b/src/reporter.cc
@@ -23,6 +23,7 @@
 
 #include "benchmark/benchmark_api.h"
 #include "benchmark/sysinfo.h"
+#include "benchmark_api_internal.h"
 #include "check.h"
 #include "string_util.h"
 #include "timers.h"
@@ -133,4 +134,12 @@
   return new_time;
 }
 
+void BenchmarkReporter::List(
+    const std::vector<internal::BenchmarkInstance>& benchmarks) {
+  std::ostream& out = GetOutputStream();
+  for (const internal::BenchmarkInstance& benchmark : benchmarks) {
+    out << benchmark.name().str() << "\n";
+  }
+}
+
 }  // end namespace benchmark
diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt
index 280113c..fe88841 100644
--- a/test/CMakeLists.txt
+++ b/test/CMakeLists.txt
@@ -256,6 +256,7 @@
   add_gtest(statistics_gtest)
   add_gtest(string_util_gtest)
   add_gtest(perf_counters_gtest)
+  add_gtest(reporter_list_gtest)
   add_gtest(time_unit_gtest)
   add_gtest(min_time_parse_gtest)
   add_gtest(profiler_manager_gtest)
diff --git a/test/reporter_list_gtest.cc b/test/reporter_list_gtest.cc
new file mode 100644
index 0000000..74d5d02
--- /dev/null
+++ b/test/reporter_list_gtest.cc
@@ -0,0 +1,87 @@
+#include <sstream>
+#include <string>
+#include <vector>
+
+#include "../src/benchmark_api_internal.h"
+#include "benchmark/benchmark.h"
+#include "gtest/gtest.h"
+
+namespace benchmark {
+namespace internal {
+namespace {
+
+void BM_ReporterListDummy(::benchmark::State& state) {
+  for (auto _ : state) {
+  }
+}
+
+// Registers two benchmarks (once) and returns the matching instances, the
+// same way RunSpecifiedBenchmarks() selects them for --benchmark_list_tests.
+const std::vector<BenchmarkInstance>& ListTestBenchmarks() {
+  static const std::vector<BenchmarkInstance>* const benchmarks = [] {
+    RegisterBenchmark("BM_ReporterListFirst", BM_ReporterListDummy);
+    RegisterBenchmark("BM_ReporterListSecond", BM_ReporterListDummy);
+    auto* result = new std::vector<BenchmarkInstance>();
+    std::ostringstream err_stream;
+    FindBenchmarksInternal("BM_ReporterList.*", result, &err_stream);
+    return result;
+  }();
+  return *benchmarks;
+}
+
+template <typename Reporter>
+std::string ListedOutput() {
+  Reporter reporter;
+  std::ostringstream out;
+  reporter.SetOutputStream(&out);
+  reporter.List(ListTestBenchmarks());
+  return out.str();
+}
+
+TEST(ReporterListTest, FindsRegisteredBenchmarks) {
+  ASSERT_EQ(ListTestBenchmarks().size(), 2u);
+}
+
+TEST(ReporterListTest, DefaultListsOneNamePerLine) {
+  EXPECT_EQ(ListedOutput<ConsoleReporter>(),
+            "BM_ReporterListFirst\nBM_ReporterListSecond\n");
+}
+
+TEST(ReporterListTest, JSONListsNamesInBenchmarksArray) {
+  EXPECT_EQ(ListedOutput<JSONReporter>(),
+            "{\n"
+            "  \"benchmarks\": [\n"
+            "    {\n"
+            "      \"name\": \"BM_ReporterListFirst\"\n"
+            "    },\n"
+            "    {\n"
+            "      \"name\": \"BM_ReporterListSecond\"\n"
+            "    }\n"
+            "  ]\n"
+            "}\n");
+}
+
+TEST(ReporterListTest, JSONListsNoBenchmarks) {
+  JSONReporter reporter;
+  std::ostringstream out;
+  reporter.SetOutputStream(&out);
+  reporter.List({});
+  EXPECT_EQ(out.str(),
+            "{\n"
+            "  \"benchmarks\": [\n"
+            "  ]\n"
+            "}\n");
+}
+
+TEST(ReporterListTest, CSVListsNameColumn) {
+  BENCHMARK_DISABLE_DEPRECATED_WARNING
+  EXPECT_EQ(ListedOutput<CSVReporter>(),
+            "name\n"
+            "\"BM_ReporterListFirst\"\n"
+            "\"BM_ReporterListSecond\"\n");
+  BENCHMARK_RESTORE_DEPRECATED_WARNING
+}
+
+}  // namespace
+}  // namespace internal
+}  // namespace benchmark