tests/harness/testsuite.h

Go to the documentation of this file.
00001 /* testsuite.h: a generic test suite engine
00002  *
00003  * Copyright 1999,2000,2001 BrightStation PLC
00004  * Copyright 2002,2003,2005,2006,2007,2008 Olly Betts
00005  *
00006  * This program is free software; you can redistribute it and/or
00007  * modify it under the terms of the GNU General Public License as
00008  * published by the Free Software Foundation; either version 2 of the
00009  * License, or (at your option) any later version.
00010  *
00011  * This program is distributed in the hope that it will be useful,
00012  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00013  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00014  * GNU General Public License for more details.
00015  *
00016  * You should have received a copy of the GNU General Public License
00017  * along with this program; if not, write to the Free Software
00018  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301
00019  * USA
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" // For STRINGIZE().
00030 
00031 #include <iomanip>
00032 #include <map>
00033 #include <sstream>
00034 #include <string>
00035 #include <vector>
00036 
00037 #include <float.h> // For DBL_DIG.
00038 
00041 class TestFail { };
00042 
00048 class TestSkip { };
00049 
00052 // Don't bracket a, because it may have <<'s in it
00053 #define FAIL_TEST(a) do { TestFail testfail; \
00054                           if (verbose) { tout << a << '\n'; } \
00055                           throw testfail; } while (0)
00056 
00059 // Don't bracket a, because it may have <<'s in it
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 //  If verbose is set, then the test harness will display diagnostic output
00079 //  for tests which fail or skip.  Individual tests may use this flag to avoid
00080 //  needless generation of diagnostic output in cases when it's expensive.
00081 extern bool verbose;
00082 
00084 //  Used to detect if such an exception was mishandled by a the
00085 //  compiler/runtime.
00086 extern const char * expected_exception;
00087 
00091 extern std::ostringstream tout;
00092 
00094 class test_driver {
00095     public:
00099         struct result {
00101             unsigned int succeeded;
00102 
00104             unsigned int failed;
00105 
00107             unsigned int skipped;
00108 
00109             result() : succeeded(0), failed(0), skipped(0) { }
00110 
00111             result & operator+=(const result & o) {
00112                 succeeded += o.succeeded;
00113                 failed += o.failed;
00114                 skipped += o.skipped;
00115                 return *this;
00116             }
00117 
00118             void reset() {
00119                 succeeded = 0;
00120                 failed = 0;
00121                 skipped = 0;
00122             }
00123         };
00124 
00133         static void add_command_line_option(const std::string &l, char s,
00134                                             std::string * arg);
00135 
00141         static void parse_command_line(int argc, char **argv);
00142 
00143         XAPIAN_NORETURN(static void usage());
00144 
00145         static int run(const test_desc *tests);
00146 
00151         test_driver(const test_desc *tests_);
00152 
00155         result run_tests();
00156 
00159         result run_tests(std::vector<std::string>::const_iterator b,
00160                          std::vector<std::string>::const_iterator e);
00161 
00165         static std::string get_srcdir();
00166 
00167         // Running subtotal for current backend.
00168         static result subtotal;
00169 
00170         // Running total for the whole test run.
00171         static result total;
00172 
00174         static void report(const test_driver::result &r, const std::string &desc);
00175 
00176     private:
00178         test_driver(const test_driver &);
00179         test_driver & operator = (const test_driver &);
00180 
00181         typedef enum { PASS = 1, FAIL = 0, SKIP = -1 } test_result;
00182 
00183         static std::map<int, std::string *> short_opts;
00184 
00185         static std::string opt_help;
00186 
00187         static std::vector<std::string> test_names;
00188 
00195         test_result runtest(const test_desc *test);
00196 
00204         result do_run_tests(std::vector<std::string>::const_iterator b,
00205                             std::vector<std::string>::const_iterator e);
00206 
00207         // abort tests at the first failure
00208         static bool abort_on_error;
00209 
00210         // the default stream to output to
00211         std::ostream out;
00212 
00213         // the list of tests to run.
00214         const test_desc *tests;
00215 
00216         // how many test runs we've done - no summary if just one run
00217         static int runs;
00218 
00219         // program name
00220         static std::string argv0;
00221 
00222         // strings to use for colouring - empty if output isn't a tty
00223         static std::string col_red, col_green, col_yellow, col_reset;
00224 
00225         // use \r to not advance a line when a test passes (this only
00226         // really makes sense if the output is a tty)
00227         static bool use_cr;
00228 };
00229 
00231 #define TESTCASE_LOCN(a) __FILE__":"STRINGIZE(__LINE__)": "STRINGIZE(a)
00232 
00237 #define TEST_AND_EXPLAIN(a, b) do {\
00238         if (!(a)) FAIL_TEST(TESTCASE_LOCN(a) << std::endl << b << std::endl);\
00239     } while (0)
00240 
00242 #define TEST(a) TEST_AND_EXPLAIN(a, "")
00243 
00245 #define TEST_EQUAL(a, b) TEST_AND_EXPLAIN(((a) == (b)), \
00246         "Expected `"STRINGIZE(a)"' and `"STRINGIZE(b)"' to be equal:" \
00247         " were " << (a) << " and " << (b))
00248 
00254 #define TEST_STRINGS_EQUAL(a, b) TEST_AND_EXPLAIN(((a) == (b)), \
00255         "Expected "STRINGIZE(a)" and "STRINGIZE(b)" to be equal, were:\n\"" \
00256         << (a) << "\"\n\"" << (b) << '"')
00257 
00259 extern bool TEST_EQUAL_DOUBLE_(double a, double b);
00260 
00262 #define TEST_EQUAL_DOUBLE(a, b) TEST_AND_EXPLAIN(TEST_EQUAL_DOUBLE_((a), (b)), \
00263         "Expected `"STRINGIZE(a)"' and `"STRINGIZE(b)"' to be (nearly) equal:" \
00264         " were " << setprecision(DBL_DIG) << (a) << " and " << (b) << ")" << setprecision(6))
00265 
00267 #define TEST_NOT_EQUAL_DOUBLE(a, b) TEST_AND_EXPLAIN(!TEST_EQUAL_DOUBLE_((a), (b)), \
00268         "Expected `"STRINGIZE(a)"' and `"STRINGIZE(b)"' not to be (nearly) equal:" \
00269         " were " << setprecision(DBL_DIG) << (a) << " and " << (b) << ")" << setprecision(6))
00270 
00272 #define TEST_NOT_EQUAL(a, b) TEST_AND_EXPLAIN(((a) != (b)), \
00273         "Expected `"STRINGIZE(a)"' and `"STRINGIZE(b)"' not to be equal:" \
00274         " were " << (a) << " and " << (b))
00275 
00277 #define TEST_GREATER_OR_EQUAL(a, b) TEST_AND_EXPLAIN(((a) >= (b)), \
00278         "Expected `"STRINGIZE(a)"' to be greater than or equal to `"STRINGIZE(b)"':" \
00279         " were " << (a) << " and " << (b))
00280 
00282 #define TEST_GREATER(a, b) TEST_AND_EXPLAIN(((a) > (b)), \
00283         "Expected `"STRINGIZE(a)"' to be greater than `"STRINGIZE(b)"':" \
00284         " were " << (a) << " and " << (b))
00285 
00287 #define TEST_LESSER_OR_EQUAL(a, b) TEST_AND_EXPLAIN(((a) <= (b)), \
00288         "Expected `"STRINGIZE(a)"' to be less than or equal to `"STRINGIZE(b)"':" \
00289         " were " << (a) << " and " << (b))
00290 
00292 #define TEST_LESSER(a, b) TEST_AND_EXPLAIN(((a) < (b)), \
00293         "Expected `"STRINGIZE(a)"' to be less than than `"STRINGIZE(b)"':" \
00294         " were " << (a) << " and " << (b))
00295 
00296 #endif // OM_HGUARD_TESTSUITE_H

Documentation for Xapian (version 1.0.10).
Generated on 24 Dec 2008 by Doxygen 1.5.2.