Home | History | Annotate | Download | only in test
      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 
      9 namespace {
     10 
     11 class TestReporter : public benchmark::ConsoleReporter {
     12  public:
     13   virtual bool ReportContext(const Context& context) {
     14     return ConsoleReporter::ReportContext(context);
     15   };
     16 
     17   virtual void ReportRuns(const std::vector<Run>& report) {
     18     all_runs_.insert(all_runs_.end(), begin(report), end(report));
     19     ConsoleReporter::ReportRuns(report);
     20   }
     21 
     22   TestReporter() {}
     23   virtual ~TestReporter() {}
     24 
     25   mutable std::vector<Run> all_runs_;
     26 };
     27 
     28 struct TestCase {
     29   std::string name;
     30   bool error_occurred;
     31   std::string error_message;
     32 
     33   typedef benchmark::BenchmarkReporter::Run Run;
     34 
     35   void CheckRun(Run const& run) const {
     36     CHECK(name == run.benchmark_name) << "expected " << name << " got "
     37                                       << run.benchmark_name;
     38     CHECK(error_occurred == run.error_occurred);
     39     CHECK(error_message == run.error_message);
     40     if (error_occurred) {
     41       // CHECK(run.iterations == 0);
     42     } else {
     43       CHECK(run.iterations != 0);
     44     }
     45   }
     46 };
     47 
     48 std::vector<TestCase> ExpectedResults;
     49 
     50 int AddCases(const char* base_name, std::initializer_list<TestCase> const& v) {
     51   for (auto TC : v) {
     52     TC.name = base_name + TC.name;
     53     ExpectedResults.push_back(std::move(TC));
     54   }
     55   return 0;
     56 }
     57 
     58 #define CONCAT(x, y) CONCAT2(x, y)
     59 #define CONCAT2(x, y) x##y
     60 #define ADD_CASES(...) int CONCAT(dummy, __LINE__) = AddCases(__VA_ARGS__)
     61 
     62 }  // end namespace
     63 
     64 void BM_error_before_running(benchmark::State& state) {
     65   state.SkipWithError("error message");
     66   while (state.KeepRunning()) {
     67     assert(false);
     68   }
     69 }
     70 BENCHMARK(BM_error_before_running);
     71 ADD_CASES("BM_error_before_running", {{"", true, "error message"}});
     72 
     73 void BM_error_before_running_range_for(benchmark::State& state) {
     74   state.SkipWithError("error message");
     75   for (auto _ : state) {
     76     assert(false);
     77   }
     78 }
     79 BENCHMARK(BM_error_before_running_range_for);
     80 ADD_CASES("BM_error_before_running_range_for", {{"", true, "error message"}});
     81 
     82 void BM_error_during_running(benchmark::State& state) {
     83   int first_iter = true;
     84   while (state.KeepRunning()) {
     85     if (state.range(0) == 1 && state.thread_index <= (state.threads / 2)) {
     86       assert(first_iter);
     87       first_iter = false;
     88       state.SkipWithError("error message");
     89     } else {
     90       state.PauseTiming();
     91       state.ResumeTiming();
     92     }
     93   }
     94 }
     95 BENCHMARK(BM_error_during_running)->Arg(1)->Arg(2)->ThreadRange(1, 8);
     96 ADD_CASES("BM_error_during_running", {{"/1/threads:1", true, "error message"},
     97                                       {"/1/threads:2", true, "error message"},
     98                                       {"/1/threads:4", true, "error message"},
     99                                       {"/1/threads:8", true, "error message"},
    100                                       {"/2/threads:1", false, ""},
    101                                       {"/2/threads:2", false, ""},
    102                                       {"/2/threads:4", false, ""},
    103                                       {"/2/threads:8", false, ""}});
    104 
    105 void BM_error_during_running_ranged_for(benchmark::State& state) {
    106   assert(state.max_iterations > 3 && "test requires at least a few iterations");
    107   int first_iter = true;
    108   // NOTE: Users should not write the for loop explicitly.
    109   for (auto It = state.begin(), End = state.end(); It != End; ++It) {
    110     if (state.range(0) == 1) {
    111       assert(first_iter);
    112       first_iter = false;
    113       state.SkipWithError("error message");
    114       // Test the unfortunate but documented behavior that the ranged-for loop
    115       // doesn't automatically terminate when SkipWithError is set.
    116       assert(++It != End);
    117       break; // Required behavior
    118     }
    119   }
    120 }
    121 BENCHMARK(BM_error_during_running_ranged_for)->Arg(1)->Arg(2)->Iterations(5);
    122 ADD_CASES("BM_error_during_running_ranged_for",
    123           {{"/1/iterations:5", true, "error message"},
    124            {"/2/iterations:5", false, ""}});
    125 
    126 
    127 
    128 void BM_error_after_running(benchmark::State& state) {
    129   for (auto _ : state) {
    130     benchmark::DoNotOptimize(state.iterations());
    131   }
    132   if (state.thread_index <= (state.threads / 2))
    133     state.SkipWithError("error message");
    134 }
    135 BENCHMARK(BM_error_after_running)->ThreadRange(1, 8);
    136 ADD_CASES("BM_error_after_running", {{"/threads:1", true, "error message"},
    137                                      {"/threads:2", true, "error message"},
    138                                      {"/threads:4", true, "error message"},
    139                                      {"/threads:8", true, "error message"}});
    140 
    141 void BM_error_while_paused(benchmark::State& state) {
    142   bool first_iter = true;
    143   while (state.KeepRunning()) {
    144     if (state.range(0) == 1 && state.thread_index <= (state.threads / 2)) {
    145       assert(first_iter);
    146       first_iter = false;
    147       state.PauseTiming();
    148       state.SkipWithError("error message");
    149     } else {
    150       state.PauseTiming();
    151       state.ResumeTiming();
    152     }
    153   }
    154 }
    155 BENCHMARK(BM_error_while_paused)->Arg(1)->Arg(2)->ThreadRange(1, 8);
    156 ADD_CASES("BM_error_while_paused", {{"/1/threads:1", true, "error message"},
    157                                     {"/1/threads:2", true, "error message"},
    158                                     {"/1/threads:4", true, "error message"},
    159                                     {"/1/threads:8", true, "error message"},
    160                                     {"/2/threads:1", false, ""},
    161                                     {"/2/threads:2", false, ""},
    162                                     {"/2/threads:4", false, ""},
    163                                     {"/2/threads:8", false, ""}});
    164 
    165 int main(int argc, char* argv[]) {
    166   benchmark::Initialize(&argc, argv);
    167 
    168   TestReporter test_reporter;
    169   benchmark::RunSpecifiedBenchmarks(&test_reporter);
    170 
    171   typedef benchmark::BenchmarkReporter::Run Run;
    172   auto EB = ExpectedResults.begin();
    173 
    174   for (Run const& run : test_reporter.all_runs_) {
    175     assert(EB != ExpectedResults.end());
    176     EB->CheckRun(run);
    177     ++EB;
    178   }
    179   assert(EB == ExpectedResults.end());
    180 
    181   return 0;
    182 }
    183