1*dbb99499SAndroid Build Coastguard Worker #ifndef TEST_OUTPUT_TEST_H
2*dbb99499SAndroid Build Coastguard Worker #define TEST_OUTPUT_TEST_H
3*dbb99499SAndroid Build Coastguard Worker
4*dbb99499SAndroid Build Coastguard Worker #undef NDEBUG
5*dbb99499SAndroid Build Coastguard Worker #include <functional>
6*dbb99499SAndroid Build Coastguard Worker #include <initializer_list>
7*dbb99499SAndroid Build Coastguard Worker #include <memory>
8*dbb99499SAndroid Build Coastguard Worker #include <sstream>
9*dbb99499SAndroid Build Coastguard Worker #include <string>
10*dbb99499SAndroid Build Coastguard Worker #include <utility>
11*dbb99499SAndroid Build Coastguard Worker #include <vector>
12*dbb99499SAndroid Build Coastguard Worker
13*dbb99499SAndroid Build Coastguard Worker #include "../src/re.h"
14*dbb99499SAndroid Build Coastguard Worker #include "benchmark/benchmark.h"
15*dbb99499SAndroid Build Coastguard Worker
16*dbb99499SAndroid Build Coastguard Worker #define CONCAT2(x, y) x##y
17*dbb99499SAndroid Build Coastguard Worker #define CONCAT(x, y) CONCAT2(x, y)
18*dbb99499SAndroid Build Coastguard Worker
19*dbb99499SAndroid Build Coastguard Worker #define ADD_CASES(...) int CONCAT(dummy, __LINE__) = ::AddCases(__VA_ARGS__)
20*dbb99499SAndroid Build Coastguard Worker
21*dbb99499SAndroid Build Coastguard Worker #define SET_SUBSTITUTIONS(...) \
22*dbb99499SAndroid Build Coastguard Worker int CONCAT(dummy, __LINE__) = ::SetSubstitutions(__VA_ARGS__)
23*dbb99499SAndroid Build Coastguard Worker
24*dbb99499SAndroid Build Coastguard Worker enum MatchRules {
25*dbb99499SAndroid Build Coastguard Worker MR_Default, // Skip non-matching lines until a match is found.
26*dbb99499SAndroid Build Coastguard Worker MR_Next, // Match must occur on the next line.
27*dbb99499SAndroid Build Coastguard Worker MR_Not // No line between the current position and the next match matches
28*dbb99499SAndroid Build Coastguard Worker // the regex
29*dbb99499SAndroid Build Coastguard Worker };
30*dbb99499SAndroid Build Coastguard Worker
31*dbb99499SAndroid Build Coastguard Worker struct TestCase {
32*dbb99499SAndroid Build Coastguard Worker TestCase(std::string re, int rule = MR_Default);
33*dbb99499SAndroid Build Coastguard Worker
34*dbb99499SAndroid Build Coastguard Worker std::string regex_str;
35*dbb99499SAndroid Build Coastguard Worker int match_rule;
36*dbb99499SAndroid Build Coastguard Worker std::string substituted_regex;
37*dbb99499SAndroid Build Coastguard Worker std::shared_ptr<benchmark::Regex> regex;
38*dbb99499SAndroid Build Coastguard Worker };
39*dbb99499SAndroid Build Coastguard Worker
40*dbb99499SAndroid Build Coastguard Worker enum TestCaseID {
41*dbb99499SAndroid Build Coastguard Worker TC_ConsoleOut,
42*dbb99499SAndroid Build Coastguard Worker TC_ConsoleErr,
43*dbb99499SAndroid Build Coastguard Worker TC_JSONOut,
44*dbb99499SAndroid Build Coastguard Worker TC_JSONErr,
45*dbb99499SAndroid Build Coastguard Worker TC_CSVOut,
46*dbb99499SAndroid Build Coastguard Worker TC_CSVErr,
47*dbb99499SAndroid Build Coastguard Worker
48*dbb99499SAndroid Build Coastguard Worker TC_NumID // PRIVATE
49*dbb99499SAndroid Build Coastguard Worker };
50*dbb99499SAndroid Build Coastguard Worker
51*dbb99499SAndroid Build Coastguard Worker // Add a list of test cases to be run against the output specified by
52*dbb99499SAndroid Build Coastguard Worker // 'ID'
53*dbb99499SAndroid Build Coastguard Worker int AddCases(TestCaseID ID, std::initializer_list<TestCase> il);
54*dbb99499SAndroid Build Coastguard Worker
55*dbb99499SAndroid Build Coastguard Worker // Add or set a list of substitutions to be performed on constructed regex's
56*dbb99499SAndroid Build Coastguard Worker // See 'output_test_helper.cc' for a list of default substitutions.
57*dbb99499SAndroid Build Coastguard Worker int SetSubstitutions(
58*dbb99499SAndroid Build Coastguard Worker std::initializer_list<std::pair<std::string, std::string>> il);
59*dbb99499SAndroid Build Coastguard Worker
60*dbb99499SAndroid Build Coastguard Worker // Run all output tests.
61*dbb99499SAndroid Build Coastguard Worker void RunOutputTests(int argc, char* argv[]);
62*dbb99499SAndroid Build Coastguard Worker
63*dbb99499SAndroid Build Coastguard Worker // Count the number of 'pat' substrings in the 'haystack' string.
64*dbb99499SAndroid Build Coastguard Worker int SubstrCnt(const std::string& haystack, const std::string& pat);
65*dbb99499SAndroid Build Coastguard Worker
66*dbb99499SAndroid Build Coastguard Worker // Run registered benchmarks with file reporter enabled, and return the content
67*dbb99499SAndroid Build Coastguard Worker // outputted by the file reporter.
68*dbb99499SAndroid Build Coastguard Worker std::string GetFileReporterOutput(int argc, char* argv[]);
69*dbb99499SAndroid Build Coastguard Worker
70*dbb99499SAndroid Build Coastguard Worker // ========================================================================= //
71*dbb99499SAndroid Build Coastguard Worker // ------------------------- Results checking ------------------------------ //
72*dbb99499SAndroid Build Coastguard Worker // ========================================================================= //
73*dbb99499SAndroid Build Coastguard Worker
74*dbb99499SAndroid Build Coastguard Worker // Call this macro to register a benchmark for checking its results. This
75*dbb99499SAndroid Build Coastguard Worker // should be all that's needed. It subscribes a function to check the (CSV)
76*dbb99499SAndroid Build Coastguard Worker // results of a benchmark. This is done only after verifying that the output
77*dbb99499SAndroid Build Coastguard Worker // strings are really as expected.
78*dbb99499SAndroid Build Coastguard Worker // bm_name_pattern: a name or a regex pattern which will be matched against
79*dbb99499SAndroid Build Coastguard Worker // all the benchmark names. Matching benchmarks
80*dbb99499SAndroid Build Coastguard Worker // will be the subject of a call to checker_function
81*dbb99499SAndroid Build Coastguard Worker // checker_function: should be of type ResultsCheckFn (see below)
82*dbb99499SAndroid Build Coastguard Worker #define CHECK_BENCHMARK_RESULTS(bm_name_pattern, checker_function) \
83*dbb99499SAndroid Build Coastguard Worker size_t CONCAT(dummy, __LINE__) = AddChecker(bm_name_pattern, checker_function)
84*dbb99499SAndroid Build Coastguard Worker
85*dbb99499SAndroid Build Coastguard Worker struct Results;
86*dbb99499SAndroid Build Coastguard Worker typedef std::function<void(Results const&)> ResultsCheckFn;
87*dbb99499SAndroid Build Coastguard Worker
88*dbb99499SAndroid Build Coastguard Worker size_t AddChecker(const std::string& bm_name_pattern, const ResultsCheckFn& fn);
89*dbb99499SAndroid Build Coastguard Worker
90*dbb99499SAndroid Build Coastguard Worker // Class holding the results of a benchmark.
91*dbb99499SAndroid Build Coastguard Worker // It is passed in calls to checker functions.
92*dbb99499SAndroid Build Coastguard Worker struct Results {
93*dbb99499SAndroid Build Coastguard Worker // the benchmark name
94*dbb99499SAndroid Build Coastguard Worker std::string name;
95*dbb99499SAndroid Build Coastguard Worker // the benchmark fields
96*dbb99499SAndroid Build Coastguard Worker std::map<std::string, std::string> values;
97*dbb99499SAndroid Build Coastguard Worker
ResultsResults98*dbb99499SAndroid Build Coastguard Worker Results(const std::string& n) : name(n) {}
99*dbb99499SAndroid Build Coastguard Worker
100*dbb99499SAndroid Build Coastguard Worker int NumThreads() const;
101*dbb99499SAndroid Build Coastguard Worker
102*dbb99499SAndroid Build Coastguard Worker double NumIterations() const;
103*dbb99499SAndroid Build Coastguard Worker
104*dbb99499SAndroid Build Coastguard Worker typedef enum { kCpuTime, kRealTime } BenchmarkTime;
105*dbb99499SAndroid Build Coastguard Worker
106*dbb99499SAndroid Build Coastguard Worker // get cpu_time or real_time in seconds
107*dbb99499SAndroid Build Coastguard Worker double GetTime(BenchmarkTime which) const;
108*dbb99499SAndroid Build Coastguard Worker
109*dbb99499SAndroid Build Coastguard Worker // get the real_time duration of the benchmark in seconds.
110*dbb99499SAndroid Build Coastguard Worker // it is better to use fuzzy float checks for this, as the float
111*dbb99499SAndroid Build Coastguard Worker // ASCII formatting is lossy.
DurationRealTimeResults112*dbb99499SAndroid Build Coastguard Worker double DurationRealTime() const {
113*dbb99499SAndroid Build Coastguard Worker return NumIterations() * GetTime(kRealTime);
114*dbb99499SAndroid Build Coastguard Worker }
115*dbb99499SAndroid Build Coastguard Worker // get the cpu_time duration of the benchmark in seconds
DurationCPUTimeResults116*dbb99499SAndroid Build Coastguard Worker double DurationCPUTime() const { return NumIterations() * GetTime(kCpuTime); }
117*dbb99499SAndroid Build Coastguard Worker
118*dbb99499SAndroid Build Coastguard Worker // get the string for a result by name, or nullptr if the name
119*dbb99499SAndroid Build Coastguard Worker // is not found
GetResults120*dbb99499SAndroid Build Coastguard Worker const std::string* Get(const std::string& entry_name) const {
121*dbb99499SAndroid Build Coastguard Worker auto it = values.find(entry_name);
122*dbb99499SAndroid Build Coastguard Worker if (it == values.end()) return nullptr;
123*dbb99499SAndroid Build Coastguard Worker return &it->second;
124*dbb99499SAndroid Build Coastguard Worker }
125*dbb99499SAndroid Build Coastguard Worker
126*dbb99499SAndroid Build Coastguard Worker // get a result by name, parsed as a specific type.
127*dbb99499SAndroid Build Coastguard Worker // NOTE: for counters, use GetCounterAs instead.
128*dbb99499SAndroid Build Coastguard Worker template <class T>
129*dbb99499SAndroid Build Coastguard Worker T GetAs(const std::string& entry_name) const;
130*dbb99499SAndroid Build Coastguard Worker
131*dbb99499SAndroid Build Coastguard Worker // counters are written as doubles, so they have to be read first
132*dbb99499SAndroid Build Coastguard Worker // as a double, and only then converted to the asked type.
133*dbb99499SAndroid Build Coastguard Worker template <class T>
GetCounterAsResults134*dbb99499SAndroid Build Coastguard Worker T GetCounterAs(const std::string& entry_name) const {
135*dbb99499SAndroid Build Coastguard Worker double dval = GetAs<double>(entry_name);
136*dbb99499SAndroid Build Coastguard Worker T tval = static_cast<T>(dval);
137*dbb99499SAndroid Build Coastguard Worker return tval;
138*dbb99499SAndroid Build Coastguard Worker }
139*dbb99499SAndroid Build Coastguard Worker };
140*dbb99499SAndroid Build Coastguard Worker
141*dbb99499SAndroid Build Coastguard Worker template <class T>
GetAs(const std::string & entry_name)142*dbb99499SAndroid Build Coastguard Worker T Results::GetAs(const std::string& entry_name) const {
143*dbb99499SAndroid Build Coastguard Worker auto* sv = Get(entry_name);
144*dbb99499SAndroid Build Coastguard Worker BM_CHECK(sv != nullptr && !sv->empty());
145*dbb99499SAndroid Build Coastguard Worker std::stringstream ss;
146*dbb99499SAndroid Build Coastguard Worker ss << *sv;
147*dbb99499SAndroid Build Coastguard Worker T out;
148*dbb99499SAndroid Build Coastguard Worker ss >> out;
149*dbb99499SAndroid Build Coastguard Worker BM_CHECK(!ss.fail());
150*dbb99499SAndroid Build Coastguard Worker return out;
151*dbb99499SAndroid Build Coastguard Worker }
152*dbb99499SAndroid Build Coastguard Worker
153*dbb99499SAndroid Build Coastguard Worker //----------------------------------
154*dbb99499SAndroid Build Coastguard Worker // Macros to help in result checking. Do not use them with arguments causing
155*dbb99499SAndroid Build Coastguard Worker // side-effects.
156*dbb99499SAndroid Build Coastguard Worker
157*dbb99499SAndroid Build Coastguard Worker // clang-format off
158*dbb99499SAndroid Build Coastguard Worker
159*dbb99499SAndroid Build Coastguard Worker #define CHECK_RESULT_VALUE_IMPL(entry, getfn, var_type, var_name, relationship, value) \
160*dbb99499SAndroid Build Coastguard Worker CONCAT(BM_CHECK_, relationship) \
161*dbb99499SAndroid Build Coastguard Worker (entry.getfn< var_type >(var_name), (value)) << "\n" \
162*dbb99499SAndroid Build Coastguard Worker << __FILE__ << ":" << __LINE__ << ": " << (entry).name << ":\n" \
163*dbb99499SAndroid Build Coastguard Worker << __FILE__ << ":" << __LINE__ << ": " \
164*dbb99499SAndroid Build Coastguard Worker << "expected (" << #var_type << ")" << (var_name) \
165*dbb99499SAndroid Build Coastguard Worker << "=" << (entry).getfn< var_type >(var_name) \
166*dbb99499SAndroid Build Coastguard Worker << " to be " #relationship " to " << (value) << "\n"
167*dbb99499SAndroid Build Coastguard Worker
168*dbb99499SAndroid Build Coastguard Worker // check with tolerance. eps_factor is the tolerance window, which is
169*dbb99499SAndroid Build Coastguard Worker // interpreted relative to value (eg, 0.1 means 10% of value).
170*dbb99499SAndroid Build Coastguard Worker #define CHECK_FLOAT_RESULT_VALUE_IMPL(entry, getfn, var_type, var_name, relationship, value, eps_factor) \
171*dbb99499SAndroid Build Coastguard Worker CONCAT(BM_CHECK_FLOAT_, relationship) \
172*dbb99499SAndroid Build Coastguard Worker (entry.getfn< var_type >(var_name), (value), (eps_factor) * (value)) << "\n" \
173*dbb99499SAndroid Build Coastguard Worker << __FILE__ << ":" << __LINE__ << ": " << (entry).name << ":\n" \
174*dbb99499SAndroid Build Coastguard Worker << __FILE__ << ":" << __LINE__ << ": " \
175*dbb99499SAndroid Build Coastguard Worker << "expected (" << #var_type << ")" << (var_name) \
176*dbb99499SAndroid Build Coastguard Worker << "=" << (entry).getfn< var_type >(var_name) \
177*dbb99499SAndroid Build Coastguard Worker << " to be " #relationship " to " << (value) << "\n" \
178*dbb99499SAndroid Build Coastguard Worker << __FILE__ << ":" << __LINE__ << ": " \
179*dbb99499SAndroid Build Coastguard Worker << "with tolerance of " << (eps_factor) * (value) \
180*dbb99499SAndroid Build Coastguard Worker << " (" << (eps_factor)*100. << "%), " \
181*dbb99499SAndroid Build Coastguard Worker << "but delta was " << ((entry).getfn< var_type >(var_name) - (value)) \
182*dbb99499SAndroid Build Coastguard Worker << " (" << (((entry).getfn< var_type >(var_name) - (value)) \
183*dbb99499SAndroid Build Coastguard Worker / \
184*dbb99499SAndroid Build Coastguard Worker ((value) > 1.e-5 || value < -1.e-5 ? value : 1.e-5)*100.) \
185*dbb99499SAndroid Build Coastguard Worker << "%)"
186*dbb99499SAndroid Build Coastguard Worker
187*dbb99499SAndroid Build Coastguard Worker #define CHECK_RESULT_VALUE(entry, var_type, var_name, relationship, value) \
188*dbb99499SAndroid Build Coastguard Worker CHECK_RESULT_VALUE_IMPL(entry, GetAs, var_type, var_name, relationship, value)
189*dbb99499SAndroid Build Coastguard Worker
190*dbb99499SAndroid Build Coastguard Worker #define CHECK_COUNTER_VALUE(entry, var_type, var_name, relationship, value) \
191*dbb99499SAndroid Build Coastguard Worker CHECK_RESULT_VALUE_IMPL(entry, GetCounterAs, var_type, var_name, relationship, value)
192*dbb99499SAndroid Build Coastguard Worker
193*dbb99499SAndroid Build Coastguard Worker #define CHECK_FLOAT_RESULT_VALUE(entry, var_name, relationship, value, eps_factor) \
194*dbb99499SAndroid Build Coastguard Worker CHECK_FLOAT_RESULT_VALUE_IMPL(entry, GetAs, double, var_name, relationship, value, eps_factor)
195*dbb99499SAndroid Build Coastguard Worker
196*dbb99499SAndroid Build Coastguard Worker #define CHECK_FLOAT_COUNTER_VALUE(entry, var_name, relationship, value, eps_factor) \
197*dbb99499SAndroid Build Coastguard Worker CHECK_FLOAT_RESULT_VALUE_IMPL(entry, GetCounterAs, double, var_name, relationship, value, eps_factor)
198*dbb99499SAndroid Build Coastguard Worker
199*dbb99499SAndroid Build Coastguard Worker // clang-format on
200*dbb99499SAndroid Build Coastguard Worker
201*dbb99499SAndroid Build Coastguard Worker // ========================================================================= //
202*dbb99499SAndroid Build Coastguard Worker // --------------------------- Misc Utilities ------------------------------ //
203*dbb99499SAndroid Build Coastguard Worker // ========================================================================= //
204*dbb99499SAndroid Build Coastguard Worker
205*dbb99499SAndroid Build Coastguard Worker namespace {
206*dbb99499SAndroid Build Coastguard Worker
207*dbb99499SAndroid Build Coastguard Worker const char* const dec_re = "[0-9]*[.]?[0-9]+([eE][-+][0-9]+)?";
208*dbb99499SAndroid Build Coastguard Worker
209*dbb99499SAndroid Build Coastguard Worker } // end namespace
210*dbb99499SAndroid Build Coastguard Worker
211*dbb99499SAndroid Build Coastguard Worker #endif // TEST_OUTPUT_TEST_H
212