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