mirror of https://github.com/fltk/fltk
262 lines
8.3 KiB
C++
262 lines
8.3 KiB
C++
//
|
|
// 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
|