libGimbal 0.1.0
C17-Based Extended Standard Library and Cross-Language Runtime Framework
Loading...
Searching...
No Matches
gimbal_test.h
Go to the documentation of this file.
1/*! \file
2 * \brief Test module-wide include
3 * \ingroup testing
4 *
5 * \author Falco Girgis
6 */
7
8#ifndef GIMBAL_TEST_H
9#define GIMBAL_TEST_H
10
11#include "test/gimbal_test_scenario.h"
12#include "test/gimbal_test_suite.h"
13#include "test/gimbal_test_macros.h"
14
15/*! \defgroup testing Unit Testing
16 \brief Object-oriented, C-based unit testing framework.
17
18 LibGimbal provides a built-in unit testing framework, which was architecturally inspired by QTest (which we had originally used for testing), with output
19 similar to a combination between QTest and GTest. Since libGimbal runs everywhere, we wanted to ensure that our tests could also run anywhere as well.
20 The testing framework leverages the meta type system and error management back-end to implement a powerful object-oriented testing framework. We use it
21 extensively on both desktop enironments and for embedded platforms such as the Sega Dreamcast and Sony PSVita.
22
23 A unit test program typically comprises a single top-level GblTestScenario object, to which GblTestSuite objects are added. A GblTestSuite represents a
24 sequentially-executing set of test cases.
25
26 \tableofcontents
27
28 ##Features
29 - Timing
30 - Memory utilization
31 - Memory leak tracing
32 - Dynamic test construction/scheduling
33
34 ## Code Samples
35
36 ### Sample Test Case
37 \code{.c}
38 static GBL_RESULT GblUuidTestSuite_initV4_(GblTestSuite* pSelf, GblContext* pCtx) {
39 GBL_UNUSED(pSelf);
40 GBL_API_BEGIN(pCtx);
41
42 GblUuid uuids[GBL_UUID_TEST_SUITE__V4_COUNT];
43
44 for(int u = 0; u < GBL_UUID_TEST_SUITE__V4_COUNT; ++u) {
45 GBL_API_VERIFY_CALL(GblUuid_genV4(&uuids[u]));
46
47 GBL_TEST_COMPARE(GblUuid_version(&uuids[u]), 4);
48 GBL_TEST_VERIFY(!GblUuid_isNil(&uuids[u]));
49
50 for(int u2 = 0; u2 < u-1; ++u2) {
51 GBL_TEST_VERIFY(GblUuid_compare(&uuids[u], &uuids[u2]) != 0);
52 }
53
54 GBL_TEST_COMPARE(GblUuid_compare(&uuids[u], &uuids[u]), 0);
55 }
56
57 GBL_API_END();
58 }
59 \endcode
60
61 ### Registering a Test Suite
62 \code{.c}
63 GBL_EXPORT GblType GblUuidTestSuite_type(void) {
64 static GblType type = GBL_INVALID_TYPE;
65
66 const static GblTestCase cases[] = {
67 { "versionInvalid", GblUuidTestSuite_versionInvalid_ },
68 { "compareInvalid", GblUuidTestSuite_compareInvalid_ },
69 { "isNilInvalid", GblUuidTestSuite_isNilInvalid_ },
70 { "initNilInvalid", GblUuidTestSuite_initNilInvalid_ },
71 { "initNil", GblUuidTestSuite_initNil_ },
72 { "initV4", GblUuidTestSuite_initV4_ },
73 { "initV4Invalid", GblUuidTestSuite_initV4Invalid_ },
74 { "initFromStringInvalid", GblUuidTestSuite_initFromStringInvalid_ },
75 { "initFromString", GblUuidTestSuite_initFromString_ },
76 { "toString", GblUuidTestSuite_toString_ },
77 { NULL, NULL }
78 };
79
80 const static GblTestSuiteVTable vTable = {
81 .pCases = cases
82 .pFnSuiteInit = GblUuidTestSuite_init_, // any initialization logic before first test case runs
83 . pFnSuiteFinal = GblUuidTestSuite_final_ // any finalization logic after last test case runs
84 };
85
86 if(type == GBL_INVALID_TYPE) {
87 type = GblTestSuite_register(GblQuark_internStatic("UuidTestSuite"),
88 &vTable,
89 sizeof(GblUuidTestSuite),
90 0,
91 GBL_TYPE_FLAGS_NONE);
92 }
93 return type;
94 }
95 \endcode
96 ### Running A Test Scenario
97
98 \code{.c}
99 int main(int argc, char* pArgv[]) {
100 // Create top-level test scenario
101 GblTestScenario* pScenario = GblTestScenario_create("LibGimbalTests");
102 // Set the log filter mask
103 GblContext_setLogFilter(GBL_CONTEXT(pScenario), GBL_LOG_LEVEL_INFO | GBL_LOG_LEVEL_WARNING | GBL_LOG_LEVEL_ERROR );
104 // Create a single test suite (its constructor registers itstest cases)
105 GblUuidTestSuite* pSuite = GBL_OBJECT_CREATE(GblUuidTestSuite);
106 // Enqueue the test suite
107 GblTestScenario_enqueueSuite(pScenario, GBL_TEST_SUITE(pSuite));
108 // Run the test scenario (which runs its test suites (which run their test cases))
109 const GBL_RESULT result = GblTestScenario_run(pScenario, argc, pArgv);
110 // Clean up after ourselves
111 GblTestScenario_destroy(pScenario);
112 // Check result
113 return GBL_RESULT_SUCCESS(result)? 0 : -1;
114 }
115 \endcode
116
117 ## Sample Output
118 ### Completing a GblTestSuite:
119
120 * ********* Starting TestSuite [RefTestSuite] *********
121 * [ INIT ]: RefTestSuite
122 * [ RUN ]: RefTestSuite::allocEmpty
123 * [ PASS ]: RefTestSuite::allocEmpty (0.011 ms)
124 * [ RUN ]: RefTestSuite::alloc
125 * [ PASS ]: RefTestSuite::alloc (0.016 ms)
126 * [ RUN ]: RefTestSuite::allocWithContext
127 * [ PASS ]: RefTestSuite::allocWithContext (0.012 ms)
128 * [ RUN ]: RefTestSuite::acquire
129 * [ PASS ]: RefTestSuite::acquire (0.010 ms)
130 * [ RUN ]: RefTestSuite::release
131 * [ PASS ]: RefTestSuite::release (0.007 ms)
132 * [ RUN ]: RefTestSuite::destructFail
133 * [ PASS ]: RefTestSuite::destructFail (0.016 ms)
134 * [ RUN ]: RefTestSuite::destruct
135 * [ PASS ]: RefTestSuite::destruct (0.018 ms)
136 * [ FINAL ]: RefTestSuite
137 * Totals: 7 passed, 0 failed, 0 skipped, 0.090ms, 0/2 leaked (0/544 bytes)
138 * ********* Finished TestSuite [RefTestSuite] *********
139
140 ### Completing the GblTestScenario:
141
142 * [GblTestScenario] Ending Scenario: [libGimbalTests]
143 * Test Suite Totals
144 * Total : 24
145 * Passed : 24
146 * Skipped : 0
147 * Failed : 0
148 * Test Case Totals
149 * Total : 429
150 * Passed : 429
151 * Skipped : 0
152 * Failed : 0
153 * Total Time : 67.737ms
154 * ********************* [ PASS ] *********************
155
156*/
157
158#endif // GIMBAL_TEST_H