00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022 #ifndef OM_HGUARD_TESTSUITE_H
00023 #define OM_HGUARD_TESTSUITE_H
00024
00025 #include "noreturn.h"
00026
00027 #include "output.h"
00028
00029 #include "stringutils.h"
00030
00031 #include <iomanip>
00032 #include <map>
00033 #include <sstream>
00034 #include <string>
00035 #include <vector>
00036
00037 #include <float.h>
00038
00041 class TestFail { };
00042
00048 class TestSkip { };
00049
00052
00053 #define FAIL_TEST(a) do { TestFail testfail; \
00054 if (verbose) { tout << a << '\n'; } \
00055 throw testfail; } while (0)
00056
00059
00060 #define SKIP_TEST(a) do { TestSkip testskip; \
00061 if (verbose) { tout << a << '\n'; } \
00062 throw testskip; } while (0)
00063
00065 typedef bool (*test_func)();
00066
00068 struct test_desc {
00070 const char *name;
00071
00073 test_func run;
00074 };
00075
00077
00078
00079
00080
00081 extern bool verbose;
00082
00084
00085
00086 extern const char * expected_exception;
00087
00091 extern std::ostringstream tout;
00092
00094 class test_driver {
00096 void write_and_clear_tout();
00097
00098 public:
00102 struct result {
00104 unsigned int succeeded;
00105
00107 unsigned int failed;
00108
00110 unsigned int skipped;
00111
00112 result() : succeeded(0), failed(0), skipped(0) { }
00113
00114 result & operator+=(const result & o) {
00115 succeeded += o.succeeded;
00116 failed += o.failed;
00117 skipped += o.skipped;
00118 return *this;
00119 }
00120
00121 void reset() {
00122 succeeded = 0;
00123 failed = 0;
00124 skipped = 0;
00125 }
00126 };
00127
00136 static void add_command_line_option(const std::string &l, char s,
00137 std::string * arg);
00138
00144 static void parse_command_line(int argc, char **argv);
00145
00146 XAPIAN_NORETURN(static void usage());
00147
00148 static int run(const test_desc *tests);
00149
00154 test_driver(const test_desc *tests_);
00155
00158 result run_tests();
00159
00162 result run_tests(std::vector<std::string>::const_iterator b,
00163 std::vector<std::string>::const_iterator e);
00164
00168 static std::string get_srcdir();
00169
00170
00171 static result subtotal;
00172
00173
00174 static result total;
00175
00177 static void report(const test_driver::result &r, const std::string &desc);
00178
00179 private:
00181 test_driver(const test_driver &);
00182 test_driver & operator = (const test_driver &);
00183
00184 typedef enum { PASS = 1, FAIL = 0, SKIP = -1 } test_result;
00185
00186 static std::map<int, std::string *> short_opts;
00187
00188 static std::string opt_help;
00189
00190 static std::vector<std::string> test_names;
00191
00198 test_result runtest(const test_desc *test);
00199
00207 result do_run_tests(std::vector<std::string>::const_iterator b,
00208 std::vector<std::string>::const_iterator e);
00209
00210
00211 static bool abort_on_error;
00212
00213
00214 std::ostream out;
00215
00216
00217 const test_desc *tests;
00218
00219
00220 static int runs;
00221
00222
00223 static std::string argv0;
00224
00225
00226 static std::string col_red, col_green, col_yellow, col_reset;
00227
00228
00229
00230 static bool use_cr;
00231 };
00232
00234 #define TESTCASE_LOCN(a) __FILE__":"STRINGIZE(__LINE__)": "STRINGIZE(a)
00235
00240 #define TEST_AND_EXPLAIN(a, b) do {\
00241 if (!(a)) FAIL_TEST(TESTCASE_LOCN(a) << std::endl << b << std::endl);\
00242 } while (0)
00243
00245 #define TEST(a) TEST_AND_EXPLAIN(a, "")
00246
00247
00248 #define TEST_REL(A,R,B) TEST((A) R (B))
00249
00251 #define TEST_EQUAL(a, b) TEST_AND_EXPLAIN(((a) == (b)), \
00252 "Expected `"STRINGIZE(a)"' and `"STRINGIZE(b)"' to be equal:" \
00253 " were " << (a) << " and " << (b))
00254
00260 #define TEST_STRINGS_EQUAL(a, b) TEST_AND_EXPLAIN(((a) == (b)), \
00261 "Expected "STRINGIZE(a)" and "STRINGIZE(b)" to be equal, were:\n\"" \
00262 << (a) << "\"\n\"" << (b) << '"')
00263
00265 extern bool TEST_EQUAL_DOUBLE_(double a, double b);
00266
00268 #define TEST_EQUAL_DOUBLE(a, b) TEST_AND_EXPLAIN(TEST_EQUAL_DOUBLE_((a), (b)), \
00269 "Expected `"STRINGIZE(a)"' and `"STRINGIZE(b)"' to be (nearly) equal:" \
00270 " were " << setprecision(DBL_DIG) << (a) << " and " << (b) << ")" << setprecision(6))
00271
00273 #define TEST_NOT_EQUAL_DOUBLE(a, b) TEST_AND_EXPLAIN(!TEST_EQUAL_DOUBLE_((a), (b)), \
00274 "Expected `"STRINGIZE(a)"' and `"STRINGIZE(b)"' not to be (nearly) equal:" \
00275 " were " << setprecision(DBL_DIG) << (a) << " and " << (b) << ")" << setprecision(6))
00276
00278 #define TEST_NOT_EQUAL(a, b) TEST_AND_EXPLAIN(((a) != (b)), \
00279 "Expected `"STRINGIZE(a)"' and `"STRINGIZE(b)"' not to be equal:" \
00280 " were " << (a) << " and " << (b))
00281
00283 #define TEST_GREATER_OR_EQUAL(a, b) TEST_AND_EXPLAIN(((a) >= (b)), \
00284 "Expected `"STRINGIZE(a)"' to be greater than or equal to `"STRINGIZE(b)"':" \
00285 " were " << (a) << " and " << (b))
00286
00288 #define TEST_GREATER(a, b) TEST_AND_EXPLAIN(((a) > (b)), \
00289 "Expected `"STRINGIZE(a)"' to be greater than `"STRINGIZE(b)"':" \
00290 " were " << (a) << " and " << (b))
00291
00293 #define TEST_LESSER_OR_EQUAL(a, b) TEST_AND_EXPLAIN(((a) <= (b)), \
00294 "Expected `"STRINGIZE(a)"' to be less than or equal to `"STRINGIZE(b)"':" \
00295 " were " << (a) << " and " << (b))
00296
00298 #define TEST_LESSER(a, b) TEST_AND_EXPLAIN(((a) < (b)), \
00299 "Expected `"STRINGIZE(a)"' to be less than than `"STRINGIZE(b)"':" \
00300 " were " << (a) << " and " << (b))
00301
00302 #endif // OM_HGUARD_TESTSUITE_H