summaryrefslogtreecommitdiff
path: root/test/unittests.h
blob: 006e9c5885d473e086e8dc0b06a7e85391fe29ac (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
//
// Unit tests for the Fast Light Tool Kit (FLTK).
//
// Copyright 1998-2022 by Bill Spitzak and others.
//
// This library is free software. Distribution and use rights are outlined in
// the file "COPYING" which should have been included with this file.  If this
// file is missing or damaged, see the license at:
//
//     https://www.fltk.org/COPYING.php
//
// Please see the following page on how to report bugs and issues:
//
//     https://www.fltk.org/bugs.php
//

#ifndef UNITTESTS_H
#define UNITTESTS_H 1

#include <FL/Fl.H>
#include <FL/Fl_Double_Window.H>

#include <stdarg.h>

class Fl_Terminal;

// WINDOW/WIDGET SIZES
const int UT_MAINWIN_W  = 700;                                // main window w()
const int UT_MAINWIN_H  = 600;                                // main window h()
const int UT_BROWSER_X  = 10;                                 // browser x()
const int UT_BROWSER_Y  = 25;                                 // browser y()
const int UT_BROWSER_W  = 150;                                // browser w()
const int UT_BROWSER_H  = (UT_MAINWIN_H-35);                  // browser h()
const int UT_TESTAREA_X = (UT_BROWSER_W + 20);                // test area x()
const int UT_TESTAREA_Y = 25;                                 // test area y()
const int UT_TESTAREA_W = (UT_MAINWIN_W - UT_BROWSER_W - 30); // test area w()
const int UT_TESTAREA_H = UT_BROWSER_H;                       // test area h()

typedef void (*UnitTestCallback)(const char*, class Fl_Group*);

extern class Ut_Main_Window*  mainwin;
extern class Fl_Hold_Browser* browser;

enum {
  UT_TEST_ABOUT = 0,
  UT_TEST_POINTS,
  UT_TEST_FAST_SHAPES,
  UT_TEST_CIRCLES,
  UT_TEST_COMPLEX_SHAPES,
  UT_TEST_TEXT,
  UT_TEST_UNICODE,
  UT_TEST_SYBOL,
  UT_TEST_IMAGES,
  UT_TEST_VIEWPORT,
  UT_TEST_SCROLLBARSIZE,
  UT_TEST_SCHEMES,
  UT_TEST_SIMPLE_TERMINAL,
  UT_TEST_CORE
};

// This class helps to automatically register a new test with the unittest app.
// Please see the examples on how this is used.
class UnitTest {
public:
  UnitTest(int index, const char *label, Fl_Widget* (*create)());
  ~UnitTest();
  const char* label();
  void create();
  void show();
  void hide();
  static int num_tests() { return num_tests_; }
  static UnitTest* test(int i) { return test_list_[i]; }
private:
  char* label_;
  Fl_Widget* (*create_)();
  Fl_Widget* widget_;
  static void add(int index, UnitTest* t);
  static int num_tests_;
  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_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 {
public:
  Ut_Main_Window(int w, int h, const char *l=0L);
  void draw_alignment_indicators();
  void draw() FL_OVERRIDE;
  void test_alignment(int v);
private:
  int draw_alignment_test_;
};

#endif