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