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