1
2#undef NDEBUG
3#include <cassert>
4#include <vector>
5
6#include "../src/check.h"  // NOTE: check.h is for internal use only!
7#include "benchmark/benchmark.h"
8
9namespace {
10
11class TestReporter : public benchmark::ConsoleReporter {
12 public:
13  void ReportRuns(const std::vector<Run>& report) override {
14    all_runs_.insert(all_runs_.end(), begin(report), end(report));
15    ConsoleReporter::ReportRuns(report);
16  }
17
18  std::vector<Run> all_runs_;
19};
20
21struct TestCase {
22  const std::string name;
23  const std::string label;
24  // Note: not explicit as we rely on it being converted through ADD_CASES.
25  TestCase(const std::string& xname) : TestCase(xname, "") {}
26  TestCase(const std::string& xname, const std::string& xlabel)
27      : name(xname), label(xlabel) {}
28
29  typedef benchmark::BenchmarkReporter::Run Run;
30
31  void CheckRun(Run const& run) const {
32    // clang-format off
33    BM_CHECK(name == run.benchmark_name()) << "expected " << name << " got "
34                                      << run.benchmark_name();
35    if (!label.empty()) {
36      BM_CHECK(run.report_label == label) << "expected " << label << " got "
37                                       << run.report_label;
38    } else {
39      BM_CHECK(run.report_label.empty());
40    }
41    // clang-format on
42  }
43};
44
45std::vector<TestCase> ExpectedResults;
46
47int AddCases(std::initializer_list<TestCase> const& v) {
48  for (const auto& N : v) {
49    ExpectedResults.push_back(N);
50  }
51  return 0;
52}
53
54#define CONCAT(x, y) CONCAT2(x, y)
55#define CONCAT2(x, y) x##y
56#define ADD_CASES(...) int CONCAT(dummy, __LINE__) = AddCases({__VA_ARGS__})
57
58}  // end namespace
59
60typedef benchmark::internal::Benchmark* ReturnVal;
61
62//----------------------------------------------------------------------------//
63// Test RegisterBenchmark with no additional arguments
64//----------------------------------------------------------------------------//
65void BM_function(benchmark::State& state) {
66  for (auto _ : state) {
67  }
68}
69BENCHMARK(BM_function);
70ReturnVal dummy = benchmark::RegisterBenchmark(
71    "BM_function_manual_registration", BM_function);
72ADD_CASES({"BM_function"}, {"BM_function_manual_registration"});
73
74//----------------------------------------------------------------------------//
75// Test RegisterBenchmark with additional arguments
76// Note: GCC <= 4.8 do not support this form of RegisterBenchmark because they
77//       reject the variadic pack expansion of lambda captures.
78//----------------------------------------------------------------------------//
79#ifndef BENCHMARK_HAS_NO_VARIADIC_REGISTER_BENCHMARK
80
81void BM_extra_args(benchmark::State& st, const char* label) {
82  for (auto _ : st) {
83  }
84  st.SetLabel(label);
85}
86int RegisterFromFunction() {
87  std::pair<const char*, const char*> cases[] = {
88      {"test1", "One"}, {"test2", "Two"}, {"test3", "Three"}};
89  for (auto const& c : cases)
90    benchmark::RegisterBenchmark(c.first, &BM_extra_args, c.second);
91  return 0;
92}
93int dummy2 = RegisterFromFunction();
94ADD_CASES({"test1", "One"}, {"test2", "Two"}, {"test3", "Three"});
95
96#endif  // BENCHMARK_HAS_NO_VARIADIC_REGISTER_BENCHMARK
97
98//----------------------------------------------------------------------------//
99// Test RegisterBenchmark with DISABLED_ benchmark
100//----------------------------------------------------------------------------//
101void DISABLED_BM_function(benchmark::State& state) {
102  for (auto _ : state) {
103  }
104}
105BENCHMARK(DISABLED_BM_function);
106ReturnVal dummy3 = benchmark::RegisterBenchmark("DISABLED_BM_function_manual",
107                                                DISABLED_BM_function);
108// No need to add cases because we don't expect them to run.
109
110//----------------------------------------------------------------------------//
111// Test RegisterBenchmark with different callable types
112//----------------------------------------------------------------------------//
113
114struct CustomFixture {
115  void operator()(benchmark::State& st) {
116    for (auto _ : st) {
117    }
118  }
119};
120
121void TestRegistrationAtRuntime() {
122#ifdef BENCHMARK_HAS_CXX11
123  {
124    CustomFixture fx;
125    benchmark::RegisterBenchmark("custom_fixture", fx);
126    AddCases({std::string("custom_fixture")});
127  }
128#endif
129#ifndef BENCHMARK_HAS_NO_VARIADIC_REGISTER_BENCHMARK
130  {
131    const char* x = "42";
132    auto capturing_lam = [=](benchmark::State& st) {
133      for (auto _ : st) {
134      }
135      st.SetLabel(x);
136    };
137    benchmark::RegisterBenchmark("lambda_benchmark", capturing_lam);
138    AddCases({{"lambda_benchmark", x}});
139  }
140#endif
141}
142
143// Test that all benchmarks, registered at either during static init or runtime,
144// are run and the results are passed to the reported.
145void RunTestOne() {
146  TestRegistrationAtRuntime();
147
148  TestReporter test_reporter;
149  benchmark::RunSpecifiedBenchmarks(&test_reporter);
150
151  typedef benchmark::BenchmarkReporter::Run Run;
152  auto EB = ExpectedResults.begin();
153
154  for (Run const& run : test_reporter.all_runs_) {
155    assert(EB != ExpectedResults.end());
156    EB->CheckRun(run);
157    ++EB;
158  }
159  assert(EB == ExpectedResults.end());
160}
161
162// Test that ClearRegisteredBenchmarks() clears all previously registered
163// benchmarks.
164// Also test that new benchmarks can be registered and ran afterwards.
165void RunTestTwo() {
166  assert(ExpectedResults.size() != 0 &&
167         "must have at least one registered benchmark");
168  ExpectedResults.clear();
169  benchmark::ClearRegisteredBenchmarks();
170
171  TestReporter test_reporter;
172  size_t num_ran = benchmark::RunSpecifiedBenchmarks(&test_reporter);
173  assert(num_ran == 0);
174  assert(test_reporter.all_runs_.begin() == test_reporter.all_runs_.end());
175
176  TestRegistrationAtRuntime();
177  num_ran = benchmark::RunSpecifiedBenchmarks(&test_reporter);
178  assert(num_ran == ExpectedResults.size());
179
180  typedef benchmark::BenchmarkReporter::Run Run;
181  auto EB = ExpectedResults.begin();
182
183  for (Run const& run : test_reporter.all_runs_) {
184    assert(EB != ExpectedResults.end());
185    EB->CheckRun(run);
186    ++EB;
187  }
188  assert(EB == ExpectedResults.end());
189}
190
191int main(int argc, char* argv[]) {
192  benchmark::Initialize(&argc, argv);
193
194  RunTestOne();
195  RunTestTwo();
196}
197