Tchatator413
TripEnArvor instant messaging protocol - JSON-based
Loading...
Searching...
No Matches
stb_test.h
Go to the documentation of this file.
1
8
9#ifndef STB_TEST_H_
10#define STB_TEST_H_
11
12#ifndef STB_TEST_DEFINITION
14#define STB_TEST_DEFINITION
15#endif
16
17#include <stdbool.h>
18#include <stdio.h>
19
20#ifdef __GNUC__
21#define _STBTEST_ATTR_FORMAT(archetype, string_index, first_to_check) __attribute__((format(archetype, string_index, first_to_check)))
22#else
23#define _STBTEST_ATTR_FORMAT(archetype, string_index, first_to_check)
24#endif // __GNUC__
25
27struct test {
28 char const *name;
29 struct _stbtest_case *cases;
30};
31
33 bool ok;
34 unsigned line;
35 char const *expr; // can be null
36 char *name;
37 char *file;
38};
39
46STB_TEST_DEFINITION struct test test_start(char const *name);
47
49#define test_fail(test, name, ...) _stbtest_test_case(__LINE__, __FILE_NAME__, (test), false, "(fail)", (name)__VA_OPT__(, ) __VA_ARGS__)
51#define test_case(test, expr, name, ...) _stbtest_test_case(__LINE__, __FILE_NAME__, (test), (expr), #expr, (name)__VA_OPT__(, ) __VA_ARGS__)
53#define test_case_wide(test, expr, name, ...) _stbtest_test_case(__LINE__, __FILE_NAME__, (test), (expr), NULL, (name)__VA_OPT__(, ) __VA_ARGS__)
54
55STB_TEST_DEFINITION bool _stbtest_test_case(unsigned line, char const *file, struct test *test, bool ok, char const *expr, char const *fmt_name, ...)
56 _STBTEST_ATTR_FORMAT(printf, 6, 7);
57
68STB_TEST_DEFINITION bool test_end(struct test *test, FILE *output);
69
70#endif // STB_TEST_H_
71
72#ifdef STB_TEST_IMPLEMENTATION
73
74#include <stb_ds.h>
75
76#include <math.h>
77#include <stdarg.h>
78
79#define _stbtest_digit_count(n, base) ((n) == 0 ? 1 : (int)(log(n) / log(base)) + 1)
80
81struct test test_start(char const *name) {
82 return (struct test) {
83 .name = name,
84 .cases = NULL,
85 };
86}
87
88bool _stbtest_test_case(unsigned line, char const *file, struct test *test, bool ok, char const *expr, char const *fmt_name, ...) {
89 va_list ap;
90
91 va_start(ap, fmt_name);
92 size_t name_size = vsnprintf(NULL, 0, fmt_name, ap) + 1;
93 va_end(ap);
94
95 char *name = malloc(sizeof *name * name_size);
96 if (!name) abort();
97
98 va_start(ap, fmt_name);
99 vsnprintf(name, name_size, fmt_name, ap);
100 va_end(ap);
101
102 arrput(test->cases,
103 ((struct _stbtest_case) {
104 .ok = ok,
105 .line = line,
106 .expr = expr,
107 .name = name,
108 .file = file,
109 }));
110
111 return ok;
112}
113
114bool test_end(struct test *test, FILE *output) {
115 // Establish case success counts and column lengths
116 int i, nb_ko = 0, nb_ok = 0;
117
118 int col_len_file = sizeof "file";
119 int col_len_expr = sizeof "expr";
120 int col_len_name = sizeof "info";
121
122 for (i = 0; i < arrlenu(test->cases); ++i) {
123 struct _stbtest_case const *c = &test->cases[i];
124 c->ok ? ++nb_ok : ++nb_ko;
125 if (c->expr) {
126 size_t len;
127 if ((len = strlen(c->file)) > col_len_file) col_len_file = len;
128 if ((len = strlen(c->expr)) > col_len_expr) col_len_expr = len;
129 if ((len = strlen(c->name)) > col_len_name) col_len_name = len;
130 }
131 }
132
133 // Print summary
134 fprintf(output, "test %s: %d ko, %d ok, %d total: %s\n",
135 nb_ko == 0 ? "\033[32;49msuccess\033[39;49m" : "\033[31;49mfailure\033[39;49m",
136 nb_ko,
137 nb_ok,
138 nb_ko + nb_ok,
139 test->name);
140
141 // Show table if test failed
142 if (nb_ko != 0) {
143 int const col_len_num = _stbtest_digit_count(arrlenu(test->cases), 10);
144 int const col_len_line = _stbtest_digit_count(arrlast(test->cases).line, 10);
145
146 for (i = 0; i < col_len_num; ++i)
147 putc('#', output);
148 fprintf(output, " | OK | %-*s | %*s | %-*s | %-*s |\n",
149 col_len_file, "file",
150 col_len_line, "L",
151 col_len_expr, "expr",
152 col_len_name, "info");
153
154 for (i = 0; i < col_len_num; ++i)
155 putc('-', output);
156 fputs(" | -- | ", output);
157 for (i = 0; i < col_len_file; ++i)
158 putc('-', output);
159 fputs(" | ", output);
160 for (i = 0; i < col_len_line; ++i)
161 putc('-', output);
162 fputs(" | ", output);
163 for (i = 0; i < col_len_expr; ++i)
164 putc('-', output);
165 fputs(" | ", output);
166 for (i = 0; i < col_len_name; ++i)
167 putc('-', output);
168 fputs(" |\n", output);
169
170 // Print cases
171
172 for (i = 0; i < arrlenu(test->cases); ++i) {
173 struct _stbtest_case const *const c = &test->cases[i];
174 char const *ok = c->ok ? "\033[32;49mOK\033[39;49m" : "\033[31;49mKO\033[39;49m";
175 if (c->expr)
176 fprintf(output, "%*d | %s | %-*s | %*u | %-*s | %-*s |\n",
177 col_len_num, i, ok,
178 col_len_file, c->file,
179 col_len_line, c->line,
180 col_len_expr, c->expr,
181 col_len_name, c->name);
182 else
183 fprintf(output, "%*d | %s | %-*s | %*u | %s\n",
184 col_len_num, i, ok,
185 col_len_file, c->file,
186 col_len_line, c->line,
187 c->name);
188 }
189 }
190
191 // Deallocate
192 for (i = 0; i < arrlenu(test->cases); ++i)
193 free(test->cases[i].name); // Free test
194 arrfree(test->cases);
195
196 return nb_ko == 0;
197}
198
199#endif // STB_TEST_IMPLEMENTATION
#define STB_TEST_DEFINITION
Defines modifier keywords for the definitions. Example value: static inline.
Definition stb_test.h:14
STB_TEST_DEFINITION bool STB_TEST_DEFINITION bool test_end(struct test *test, FILE *output)
Finish a test suite and prints the results to the provided output stream.
STB_TEST_DEFINITION struct test test_start(char const *name)
Start a new test suite with the given name.
Represents a test suite with a name and a collection of test cases.
Definition stb_test.h:27