sdk-world v2026.11.05
PS2 SDK - world tier (copyleft-allowed, non-essential packages)
Loading...
Searching...
No Matches
tap.c
1/*
2libtap - Write tests in C
3Copyright 2012 Jake Gelbman <gelbman@gmail.com>
4This file is licensed under the LGPL
5*/
6
7#define _DEFAULT_SOURCE 1
8
9#include <stdio.h>
10#include <stdlib.h>
11#include <stdarg.h>
12#include <string.h>
13#include "tap.h"
14
15static int expected_tests = NO_PLAN;
16static int failed_tests;
17static int current_test;
18static char *todo_mesg;
19
20static char *
21vstrdupf (const char *fmt, va_list args) {
22 char *str;
23 int size;
24 va_list args2;
25 va_copy(args2, args);
26 if (!fmt)
27 fmt = "";
28 size = vsnprintf(NULL, 0, fmt, args2) + 2;
29 str = malloc(size);
30 if (!str) {
31 perror("malloc error");
32 exit(1);
33 }
34 vsprintf(str, fmt, args);
35 va_end(args2);
36 return str;
37}
38
39void
40tap_plan (int tests, const char *fmt, ...) {
41 expected_tests = tests;
42 if (tests == SKIP_ALL) {
43 char *why;
44 va_list args;
45 va_start(args, fmt);
46 why = vstrdupf(fmt, args);
47 va_end(args);
48 printf("1..0 ");
49 diag("SKIP %s\n", why);
50 exit(0);
51 }
52 if (tests != NO_PLAN) {
53 printf("1..%d\n", tests);
54 }
55}
56
57int
58vok_at_loc (const char *file, int line, int test, const char *fmt,
59 va_list args)
60{
61 char *name = vstrdupf(fmt, args);
62 if (!test) {
63 printf("not ");
64 }
65 printf("ok %d", ++current_test);
66 if (*name)
67 printf(" - %s", name);
68 if (todo_mesg) {
69 printf(" # TODO");
70 if (*todo_mesg)
71 printf(" %s", todo_mesg);
72 }
73 printf("\n");
74 if (!test) {
75 printf("# Failed ");
76 if (todo_mesg)
77 printf("(TODO) ");
78 printf("test ");
79 if (*name)
80 printf("'%s'\n# ", name);
81 printf("at %s line %d.\n", file, line);
82 if (!todo_mesg)
83 failed_tests++;
84 }
85 free(name);
86 return test;
87}
88
89int
90ok_at_loc (const char *file, int line, int test, const char *fmt, ...) {
91 va_list args;
92 va_start(args, fmt);
93 vok_at_loc(file, line, test, fmt, args);
94 va_end(args);
95 return test;
96}
97
98static int
99mystrcmp (const char *a, const char *b) {
100 return a == b ? 0 : !a ? -1 : !b ? 1 : strcmp(a, b);
101}
102
103#define eq(a, b) (!mystrcmp(a, b))
104#define ne(a, b) (mystrcmp(a, b))
105
106int
107is_at_loc (const char *file, int line, const char *got, const char *expected,
108 const char *fmt, ...)
109{
110 int test = eq(got, expected);
111 va_list args;
112 va_start(args, fmt);
113 vok_at_loc(file, line, test, fmt, args);
114 va_end(args);
115 if (!test) {
116 diag(" got: '%s'", got);
117 diag(" expected: '%s'", expected);
118 }
119 return test;
120}
121
122int
123isnt_at_loc (const char *file, int line, const char *got, const char *expected,
124 const char *fmt, ...)
125{
126 int test = ne(got, expected);
127 va_list args;
128 va_start(args, fmt);
129 vok_at_loc(file, line, test, fmt, args);
130 va_end(args);
131 if (!test) {
132 diag(" got: '%s'", got);
133 diag(" expected: anything else");
134 }
135 return test;
136}
137
138int
139cmp_ok_at_loc (const char *file, int line, int a, const char *op, int b,
140 const char *fmt, ...)
141{
142 int test = eq(op, "||") ? a || b
143 : eq(op, "&&") ? a && b
144 : eq(op, "|") ? a | b
145 : eq(op, "^") ? a ^ b
146 : eq(op, "&") ? a & b
147 : eq(op, "==") ? a == b
148 : eq(op, "!=") ? a != b
149 : eq(op, "<") ? a < b
150 : eq(op, ">") ? a > b
151 : eq(op, "<=") ? a <= b
152 : eq(op, ">=") ? a >= b
153 : eq(op, "<<") ? a << b
154 : eq(op, ">>") ? a >> b
155 : eq(op, "+") ? a + b
156 : eq(op, "-") ? a - b
157 : eq(op, "*") ? a * b
158 : eq(op, "/") ? a / b
159 : eq(op, "%") ? a % b
160 : diag("unrecognized operator '%s'", op);
161 va_list args;
162 va_start(args, fmt);
163 vok_at_loc(file, line, test, fmt, args);
164 va_end(args);
165 if (!test) {
166 diag(" %d", a);
167 diag(" %s", op);
168 diag(" %d", b);
169 }
170 return test;
171}
172
173static int
174find_mem_diff (const char *a, const char *b, size_t n, size_t *offset) {
175 size_t i;
176 if (a == b)
177 return 0;
178 if (!a || !b)
179 return 2;
180 for (i = 0; i < n; i++) {
181 if (a[i] != b[i]) {
182 *offset = i;
183 return 1;
184 }
185 }
186 return 0;
187}
188
189int
190cmp_mem_at_loc (const char *file, int line, const void *got,
191 const void *expected, size_t n, const char *fmt, ...)
192{
193 size_t offset;
194 int diff = find_mem_diff(got, expected, n, &offset);
195 va_list args;
196 va_start(args, fmt);
197 vok_at_loc(file, line, !diff, fmt, args);
198 va_end(args);
199 if (diff == 1) {
200 diag(" Difference starts at offset %d", offset);
201 diag(" got: 0x%02x", ((unsigned char *)got)[offset]);
202 diag(" expected: 0x%02x", ((unsigned char *)expected)[offset]);
203 }
204 else if (diff == 2) {
205 diag(" got: %s", got ? "not NULL" : "NULL");
206 diag(" expected: %s", expected ? "not NULL" : "NULL");
207 }
208 return !diff;
209}
210
211int
212diag (const char *fmt, ...) {
213 va_list args;
214 char *mesg, *line;
215 int i;
216 va_start(args, fmt);
217 if (!fmt) {
218 va_end(args);
219 return 0;
220 }
221 mesg = vstrdupf(fmt, args);
222 line = mesg;
223 for (i = 0; *line; i++) {
224 char c = mesg[i];
225 if (!c || c == '\n') {
226 mesg[i] = '\0';
227 printf("# %s\n", line);
228 if (!c)
229 break;
230 mesg[i] = c;
231 line = mesg + i + 1;
232 }
233 }
234 free(mesg);
235 va_end(args);
236 return 0;
237}
238
239int
240exit_status () {
241 int retval = 0;
242 if (expected_tests == NO_PLAN) {
243 printf("1..%d\n", current_test);
244 }
245 else if (current_test != expected_tests) {
246 diag("Looks like you planned %d test%s but ran %d.",
247 expected_tests, expected_tests > 1 ? "s" : "", current_test);
248 retval = 2;
249 }
250 if (failed_tests) {
251 diag("Looks like you failed %d test%s of %d run.",
252 failed_tests, failed_tests > 1 ? "s" : "", current_test);
253 retval = 1;
254 }
255 return retval;
256}
257
258int
259bail_out (int ignore, const char *fmt, ...) {
260 va_list args;
261 (void) ignore;
262 va_start(args, fmt);
263 printf("Bail out! ");
264 vprintf(fmt, args);
265 printf("\n");
266 va_end(args);
267 exit(255);
268 return 0;
269}
270
271void
272tap_skip (int n, const char *fmt, ...) {
273 char *why;
274 va_list args;
275 va_start(args, fmt);
276 why = vstrdupf(fmt, args);
277 va_end(args);
278 while (n --> 0) {
279 printf("ok %d ", ++current_test);
280 diag("skip %s\n", why);
281 }
282 free(why);
283}
284
285void
286tap_todo (int ignore, const char *fmt, ...) {
287 va_list args;
288 (void) ignore;
289 va_start(args, fmt);
290 todo_mesg = vstrdupf(fmt, args);
291 va_end(args);
292}
293
294void
295tap_end_todo () {
296 free(todo_mesg);
297 todo_mesg = NULL;
298}
299
300#if !defined(_WIN32) && !defined(_EE)
301#include <sys/mman.h>
302#include <sys/param.h>
303#include <regex.h>
304
305#ifndef MAP_ANONYMOUS
306#ifdef MAP_ANON
307#define MAP_ANONYMOUS MAP_ANON
308#else
309#error "System does not support mapping anonymous pages"
310#endif
311#endif
312
313/* Create a shared memory int to keep track of whether a piece of code executed
314dies. to be used in the dies_ok and lives_ok macros. */
315int
316tap_test_died (int status) {
317 static int *test_died = NULL;
318 int prev;
319 if (!test_died) {
320 test_died = mmap(0, sizeof (int), PROT_READ | PROT_WRITE,
321 MAP_SHARED | MAP_ANONYMOUS, -1, 0);
322 *test_died = 0;
323 }
324 prev = *test_died;
325 *test_died = status;
326 return prev;
327}
328
329int
330like_at_loc (int for_match, const char *file, int line, const char *got,
331 const char *expected, const char *fmt, ...)
332{
333 int test;
334 regex_t re;
335 va_list args;
336 int err = regcomp(&re, expected, REG_EXTENDED);
337 if (err) {
338 char errbuf[256];
339 regerror(err, &re, errbuf, sizeof errbuf);
340 fprintf(stderr, "Unable to compile regex '%s': %s at %s line %d\n",
341 expected, errbuf, file, line);
342 exit(255);
343 }
344 err = regexec(&re, got, 0, NULL, 0);
345 regfree(&re);
346 test = for_match ? !err : err;
347 va_start(args, fmt);
348 vok_at_loc(file, line, test, fmt, args);
349 va_end(args);
350 if (!test) {
351 if (for_match) {
352 diag(" '%s'", got);
353 diag(" doesn't match: '%s'", expected);
354 }
355 else {
356 diag(" '%s'", got);
357 diag(" matches: '%s'", expected);
358 }
359 }
360 return test;
361}
362#endif