summaryrefslogtreecommitdiff
path: root/test/unittests.h
diff options
context:
space:
mode:
authorMatthias Melcher <github@matthiasm.com>2023-02-23 15:42:05 +0100
committerGitHub <noreply@github.com>2023-02-23 15:42:05 +0100
commit9f87af8ad9a3d8112518b6bbb5b6075881a5b9a2 (patch)
treefe96512734abb7b29bc6b8fac9816d7cc0c4ae3f /test/unittests.h
parent92818939267fc7fbb6a33d86fb78576f55ce6aca (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.h174
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 {