diff options
| author | Matthias Melcher <github@matthiasm.com> | 2023-02-23 15:42:05 +0100 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2023-02-23 15:42:05 +0100 |
| commit | 9f87af8ad9a3d8112518b6bbb5b6075881a5b9a2 (patch) | |
| tree | fe96512734abb7b29bc6b8fac9816d7cc0c4ae3f /test/unittests.h | |
| parent | 92818939267fc7fbb6a33d86fb78576f55ce6aca (diff) | |
Fl_String refactoring and extension (#683)
- add true unittest and Fl_String testing
- interface and printout are similar to gtest
without requiring external linkage.
just run `unittest --core`.
- new Fl_String API
- extended API to fl_input_str and fl_password_str
- co-authored-by: Albrecht Schlosser <albrechts.fltk@online.de>
Diffstat (limited to 'test/unittests.h')
| -rw-r--r-- | test/unittests.h | 174 |
1 files changed, 173 insertions, 1 deletions
diff --git a/test/unittests.h b/test/unittests.h index 8d04f15ca..cee1dfc3f 100644 --- a/test/unittests.h +++ b/test/unittests.h @@ -20,6 +20,10 @@ #include <FL/Fl.H> #include <FL/Fl_Double_Window.H> +#include <stdarg.h> + +class Fl_Simple_Terminal; + // WINDOW/WIDGET SIZES const int UT_MAINWIN_W = 700; // main window w() const int UT_MAINWIN_H = 400; // main window h() @@ -50,7 +54,8 @@ enum { UT_TEST_VIEWPORT, UT_TEST_SCROLLBARSIZE, UT_TEST_SCHEMES, - UT_TEST_SIMPLE_TERMINAL + UT_TEST_SIMPLE_TERMINAL, + UT_TEST_CORE, }; // This class helps to automatically register a new test with the unittest app. @@ -74,6 +79,173 @@ private: static UnitTest* test_list_[]; }; +// The following classes and macros implement a subset of the Google Test API +// without creating any external dependencies. +// +// There is nothing to initialise or set up. Just by including these classes, +// we can create tests anywhere inside the app by simply writing: +// +// TEST(Math, Addition) { +// EXPECT_EQ(3+3, 6); +// return true; +// } +// TEST(Math, Multiplication) { +// EXPECT_EQ(3*3, 9); +// return true; +// } +// RUN_ALL_TESTS(); +// +// The test suite must only be run once. + +typedef bool (*Ut_Test_Call)(); + +/** + Implement a single test which can in turn contain many EXPECT_* macros. + Ut_Test classes are automatically created using the TEST(suite_name, test_name) + macro. Tests with identical suite names are grouped into a single suite. + */ +class Ut_Test { + friend class Ut_Suite; + const char *name_; + Ut_Test_Call call_; + bool failed_; + bool done_; +public: + Ut_Test(const char *suitename, const char *testname, Ut_Test_Call call); + bool run(const char *suite); + void print_failed(const char *suite); +}; + +/** + Implement test registry and the grouping of tests into a suite. This class + holds a number of static elements that register an arbitrary number of tests + and groups them into suites via the TEST() macro. + */ +class Ut_Suite { + static Ut_Suite **suite_list_; + static int suite_list_size_; + static int num_tests_; + static int num_passed_; + static int num_failed_; + + Ut_Test **test_list_; + int test_list_size_; + const char *name_; + bool done_; + Ut_Suite(const char *name); +public: + void add(Ut_Test *test); + int size() { return test_list_size_; } + int run(); + void print_suite_epilog(); + void print_failed(); + static Ut_Suite *locate(const char *name); + static int run_all_tests(); + static bool run_next_test(); + static void printf(const char *format, ...); + static void log_bool(const char *file, int line, const char *cond, bool result, bool expected); + static void log_string(const char *file, int line, const char *cond, const char *result, const char *expected); + static void log_int(const char *file, int line, const char *cond, int result, const char *expected); + static void print_prolog(); + static void print_epilog(); + static void color(int); + static int failed() { return num_failed_; } + static const char *red; + static const char *green; + static const char *normal; + static Fl_Simple_Terminal *tty; +}; + +#define UT_CONCAT_(prefix, suffix) prefix##suffix +#define UT_CONCAT(prefix, suffix) UT_CONCAT_(prefix, suffix) + +/** Create a test function and register it with the test suites. + \param[in] SUITE naming of the test suite for grouping + \param[in] CASE name this test + */ +#define TEST(SUITE, CASE) \ + static bool UT_CONCAT(test_call_, __LINE__)(); \ + Ut_Test UT_CONCAT(test__, __LINE__)(#SUITE, #CASE, UT_CONCAT(test_call_, __LINE__)); \ + static bool UT_CONCAT(test_call_, __LINE__)() + +/** Create a test case where the result is expected to be a boolena with the value true */ +#define EXPECT_TRUE(COND) \ + bool UT_CONCAT(cond, __LINE__) = COND; \ + if (UT_CONCAT(cond, __LINE__) != true) { \ + Ut_Suite::log_bool(__FILE__, __LINE__, #COND, UT_CONCAT(cond, __LINE__), true); \ + return false; \ + } + +/** Create a test case for string comparison. NULL is ok for both arguments. */ +#define EXPECT_STREQ(A, B) \ + const char *UT_CONCAT(a, __LINE__) = A; \ + const char *UT_CONCAT(b, __LINE__) = B; \ + if ( (UT_CONCAT(a, __LINE__)==NULL && UT_CONCAT(b, __LINE__)!=NULL) \ + || (UT_CONCAT(a, __LINE__)!=NULL && UT_CONCAT(b, __LINE__)==NULL) \ + || (UT_CONCAT(b, __LINE__)!=NULL && strcmp(UT_CONCAT(a, __LINE__), UT_CONCAT(b, __LINE__))!=0) ) { \ + Ut_Suite::log_string(__FILE__, __LINE__, #A, UT_CONCAT(a, __LINE__), #B); \ + return false; \ + } + +/** Create a test case for integer comparison. */ +#define EXPECT_EQ(A, B) \ + int UT_CONCAT(a, __LINE__) = A; \ + int UT_CONCAT(b, __LINE__) = B; \ + if (UT_CONCAT(a, __LINE__) != UT_CONCAT(b, __LINE__)) { \ + Ut_Suite::log_int(__FILE__, __LINE__, #A, UT_CONCAT(a, __LINE__), #B); \ + return false; \ + } + +/** Create a test case for integer comparison. */ +#define EXPECT_NE(A, B) \ + int UT_CONCAT(a, __LINE__) = A; \ + int UT_CONCAT(b, __LINE__) = B; \ + if (UT_CONCAT(a, __LINE__) == UT_CONCAT(b, __LINE__)) { \ + Ut_Suite::log_int(__FILE__, __LINE__, #A, UT_CONCAT(a, __LINE__), #B); \ + return false; \ + } + +/** Create a test case for integer comparison. */ +#define EXPECT_LT(A, B) \ + int UT_CONCAT(a, __LINE__) = A; \ + int UT_CONCAT(b, __LINE__) = B; \ + if (UT_CONCAT(a, __LINE__) >= UT_CONCAT(b, __LINE__)) { \ + Ut_Suite::log_int(__FILE__, __LINE__, #A, UT_CONCAT(a, __LINE__), #B); \ + return false; \ + } + +/** Create a test case for integer comparison. */ +#define EXPECT_LE(A, B) \ + int UT_CONCAT(a, __LINE__) = A; \ + int UT_CONCAT(b, __LINE__) = B; \ + if (UT_CONCAT(a, __LINE__) > UT_CONCAT(b, __LINE__)) { \ + Ut_Suite::log_int(__FILE__, __LINE__, #A, UT_CONCAT(a, __LINE__), #B); \ + return false; \ + } + +/** Create a test case for integer comparison. */ +#define EXPECT_GT(A, B) \ + int UT_CONCAT(a, __LINE__) = A; \ + int UT_CONCAT(b, __LINE__) = B; \ + if (UT_CONCAT(a, __LINE__) <= UT_CONCAT(b, __LINE__)) { \ + Ut_Suite::log_int(__FILE__, __LINE__, #A, UT_CONCAT(a, __LINE__), #B); \ + return false; \ + } + +/** Create a test case for integer comparison. */ +#define EXPECT_GE(A, B) \ + int UT_CONCAT(a, __LINE__) = A; \ + int UT_CONCAT(b, __LINE__) = B; \ + if (UT_CONCAT(a, __LINE__) < UT_CONCAT(b, __LINE__)) { \ + Ut_Suite::log_int(__FILE__, __LINE__, #A, UT_CONCAT(a, __LINE__), #B); \ + return false; \ + } + +/** Run all registered suits and their tests, and return the number of failed tests. */ +#define RUN_ALL_TESTS() \ + Ut_Suite::run_all_tests() + + // The main window needs an additional drawing feature in order to support // the viewport alignment test. class Ut_Main_Window : public Fl_Double_Window { |
