asoma.dev
· the C reference for libose
libose
the C library every o.se host is built on
Loading...
Searching...
No Matches
test
ose_test
ose_test_unit.h
Go to the documentation of this file.
1
/*
2
Copyright (c) 2020-23 John MacCallum Permission is hereby granted,
3
free of charge, to any person obtaining a copy of this software
4
and associated documentation files (the "Software"), to deal in
5
the Software without restriction, including without limitation the
6
rights to use, copy, modify, merge, publish, distribute,
7
sublicense, and/or sell copies of the Software, and to permit
8
persons to whom the Software is furnished to do so, subject to the
9
following conditions:
10
11
The above copyright notice and this permission notice shall be
12
included in all copies or substantial portions of the Software.
13
14
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
18
HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
19
WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
21
DEALINGS IN THE SOFTWARE.
22
*/
23
29
59
60
#include "ose_test_bundle_literal.h"
61
#include "ose_test_vm_literal.h"
62
73
#define UNIT_TEST_FUNCTION(fn) TEST_FUNCTION(ut_, fn)
74
85
#define SKIP_UNIT_TEST_FUNCTION(fn) SKIP_TEST_FUNCTION(fn)
86
95
void
printb
(
const
char
*
const
b)
96
{
97
if
(b){
98
// prevent load of misaligned address runtime error
99
char
buf[8];
100
char
*p = align(buf);
101
for
(
int
i = 0; i < 4; i++){
102
p[i] = b[i];
103
}
104
int32_t s = htonl(*((int32_t *)p));
105
for
(int32_t i = 0; i < s + 4; i++){
106
if
(b[i] <= 32 || b[i] > 127){
107
printf(
"\\x%02x"
, b[i]);
108
}
else
{
109
printf(
"%c"
, b[i]);
110
}
111
}
112
}
else
{
113
printf(
"NULL"
);
114
}
115
}
116
135
/* A FAILING SUITE HAS TO STOP.
136
*
137
* On 2026-09-09 ut_ose_context printed one failing assertion -- the same
138
* line, over and over, at full speed -- into a redirected log for about two
139
* hours and filled a 1TB disk. The macro below prints ONCE per failure, so
140
* that cannot happen unless control returns to a UNIT_TEST that has already
141
* run: a longjmp into a frame that has gone. Whatever the route, the harness
142
* had no bound at all, and a test suite that can consume a disk is a worse
143
* failure than whatever it was trying to report.
144
*
145
* This is the bound, not the diagnosis. It costs nothing on a passing run
146
* and turns an unbounded spin into an exit with a message.
147
*/
148
#ifndef OSE_TEST_MAX_FAILURES
149
#define OSE_TEST_MAX_FAILURES 200
150
#endif
151
152
#define UNIT_TEST_IMPL(test, \
153
expected_result, \
154
desc, \
155
file, \
156
func, \
157
line) \
158
{ \
159
testctr++; \
160
int32_t r = ASSERTION_FAILED; \
161
if(!setjmp(env)){ \
162
r = test; \
163
} \
164
if(r != expected_result){ \
165
printf(ANSI_COLOR_RED \
166
"TEST %d FAILED: " \
167
ANSI_COLOR_RESET \
168
"%s:%s:%d:\n" \
169
"expected %d, but got %d\n", \
170
testctr, \
171
file, func, line, \
172
expected_result, r); \
173
failctr++; \
174
if(failctr > OSE_TEST_MAX_FAILURES){ \
175
printf("ABANDONED: %d failures in one test " \
176
"function -- see OSE_TEST_MAX_FAILURES\n", \
177
failctr); \
178
fflush(stdout); \
179
exit(1); \
180
} \
181
}else if(verbose){ \
182
printf(ANSI_COLOR_GREEN \
183
"TEST %d PASSED:\n" \
184
ANSI_COLOR_RESET \
185
"%s = %d\n", \
186
testctr, #test, expected_result); \
187
} \
188
} \
189
201
#define UNIT_TEST(test, expected_result, desc) \
202
UNIT_TEST_IMPL(test, expected_result, desc, \
203
__FILE__, __func__, __LINE__);
204
217
#define UNIT_TEST_WITH_SIMPLE_BUNDLE(b, \
218
test, \
219
expected_result, \
220
desc) \
221
{ \
222
char buf[MAX_BNDLSIZE] __attribute__ ((aligned (16))); \
223
char *p = NULL; \
224
ose_bundle bundle; \
225
/* NO ROOM TO GROW, ON EVERY PLATFORM. A bundle's \
226
total size is the word 8 bytes before it, and this \
227
bundle used to start 4 bytes into buf -- so that \
228
word was whatever the stack held below buf. On a \
229
Mac it happened to allow a resize and on Linux it \
230
did not, and eight int64 cases failed only in CI. \
231
It is zero now: a test that resizes needs \
232
UNIT_TEST_WITH_CONTEXT_BUNDLE, and fails anywhere \
233
without it. */
\
234
if(b){ \
235
p = buf; \
236
memset(buf, 0, sizeof(buf)); \
237
memcpy(p + 4, b, sizeof(b)); \
238
bundle = ose_makeBundle(p + 8); \
239
}else{ \
240
/* for testing NULL pointer input */
\
241
bundle = ose_makeBundle(p); \
242
} \
243
if(verbose){ \
244
printf("bundle = "); \
245
printb(b); \
246
printf("\n"); \
247
} \
248
UNIT_TEST(test, expected_result, desc); \
249
}
250
251
#define UNIT_TEST_WITH_CONTEXT_BUNDLE_IMPL(testbndl, \
252
bundle_literal, \
253
bundle_literal_size, \
254
copy_offset, \
255
call_offset, \
256
test, \
257
expected_result, \
258
desc) \
259
{ \
260
ose_bundle bundle = (ose_bundle){NULL}; \
261
char buf[bundle_literal_size + 4] \
262
__attribute__ ((aligned (16))); \
263
/* Start from a known state rather than whatever the stack holds. \
264
\
265
Note this is hygiene, not a fix for the cache: this fixture cannot \
266
be used with anything that touches the context cache at all. The \
267
cache slots are addressed 560 bytes below the working bundle \
268
pointer, and this literal places that pointer only 128 bytes into \
269
buf -- so cache reads and writes land 432 bytes *before* the \
270
array, outside it entirely, where zeroing cannot reach them. Since \
271
ose_context_getFirstOffsetForMatch calls whatever non-zero value \
272
it finds in that slot, the result is a segfault wherever that \
273
stack memory is not already zero. Measured, not inferred. */
\
274
memset(buf, 0, sizeof(buf)); \
275
if(testbndl){ \
276
memcpy(buf, bundle_literal, bundle_literal_size + 4); \
277
char *p = buf + copy_offset; \
278
bundle.b = buf + call_offset; \
279
int32_t sizeofb = sizeof(testbndl); \
280
int32_t size1 = ose_ntohl(*((int32_t *)(p - 4))); \
281
int32_t size2 = ose_ntohl(*((int32_t *)(p + size1))); \
282
*((int32_t *)(p + size1)) = 0; \
283
memcpy(p - 4, testbndl, sizeofb); \
284
*((int32_t *)(p + (sizeofb - 4))) \
285
= ose_htonl(size2 - (sizeofb - 20)); \
286
}else{ \
287
} \
288
UNIT_TEST(test, expected_result, desc); \
289
if(verbose){ \
290
printf("result bundle = "); \
291
printb(bundle.b); \
292
printf("\n"); \
293
} \
294
}
295
308
#define UNIT_TEST_WITH_CONTEXT_BUNDLE(testbndl, \
309
test, \
310
expected_result, \
311
desc) \
312
UNIT_TEST_WITH_CONTEXT_BUNDLE_IMPL(testbndl, \
313
ose_test_bundle_bytes, \
314
OSE_TEST_BUNDLE_TOTAL_SIZE - 4, \
315
OSE_TEST_BUNDLE_WORKING_OFFSET, \
316
OSE_TEST_BUNDLE_WORKING_OFFSET, \
317
test, \
318
expected_result, \
319
desc)
320
353
#define UNIT_TEST_WITH_VM(testbndl, \
354
test, \
355
expected_result, \
356
desc) \
357
UNIT_TEST_WITH_CONTEXT_BUNDLE_IMPL(testbndl, \
358
ose_test_vm_bytes, \
359
OSE_TEST_VM_TOTAL_SIZE - 4, \
360
OSE_TEST_VM_STACK_BUNDLE_OFFSET, \
361
OSE_TEST_VM_WORKING_BUNDLE_OFFSET, \
362
test, \
363
expected_result, \
364
desc)
365
379
#define UNIT_TEST_BUNDLE_TRANSFORM(testfn, \
380
testbndl, \
381
resultbndl, \
382
desc) \
383
if(verbose){ \
384
printf("test bundle = "); \
385
printb(testbndl); \
386
printf("\n"); \
387
printf("expected result = "); \
388
printb(resultbndl); \
389
printf("\n"); \
390
} \
391
UNIT_TEST_WITH_CONTEXT_BUNDLE( \
392
testbndl, \
393
(testfn(bundle), \
394
COMPARE_BUNDLES(resultbndl, \
395
ose_getBundlePtr(bundle) - 4)), \
396
0, \
397
desc);
398
431
#define UNIT_TEST_BUNDLE_ERRNO(testfn, \
432
testbndl, \
433
errno, \
434
desc) \
435
UNIT_TEST_WITH_CONTEXT_BUNDLE( \
436
testbndl, \
437
(testfn(bundle), \
438
ose_errno_get(bundle)), \
439
errno, \
440
desc);
441
459
#define UNIT_TEST_BUNDLE_TRANSFORM_ARGS(testfn, \
460
testbndl, \
461
resultbndl, \
462
desc, \
463
...) \
464
UNIT_TEST_WITH_CONTEXT_BUNDLE( \
465
testbndl, \
466
(testfn(bundle, __VA_ARGS__), \
467
COMPARE_BUNDLES(resultbndl, \
468
ose_getBundlePtr(bundle) - 4)), \
469
0, \
470
desc);
471
486
#define UNIT_TEST_BUNDLE_TRANSFORM_TRIGGER_ASSERTION(testfn, \
487
testbndl, \
488
desc) \
489
UNIT_TEST_WITH_CONTEXT_BUNDLE(testbndl, \
490
(testfn(bundle), 0), \
491
ASSERTION_FAILED, \
492
desc);
493
509
#define UNIT_TEST_BUNDLE_TRANSFORM_TRIGGER_ASSERTION_ARGS(testfn, \
510
testbndl, \
511
desc, \
512
...) \
513
UNIT_TEST_WITH_CONTEXT_BUNDLE(testbndl, \
514
(testfn(bundle, __VA_ARGS__), 0), \
515
ASSERTION_FAILED, \
516
desc);
517
532
#define UNIT_TEST_VM_ERRNO(testfn, \
533
testbndl, \
534
errno, \
535
desc) \
536
UNIT_TEST_WITH_VM(testbndl, \
537
(testfn(bundle), \
538
ose_errno_get(bundle)), \
539
errno, \
540
desc)
541
556
#define UNIT_TEST_VM_STACK_COMPARE(testfn, \
557
testbndl, \
558
resultbndl, \
559
desc) \
560
UNIT_TEST_WITH_VM(testbndl, \
561
(testfn(bundle), \
562
ose_errno_get(bundle) == OSE_ERR_NONE \
563
&& !COMPARE_BUNDLES(resultbndl, \
564
buf + OSE_TEST_VM_STACK_BUNDLE_OFFSET - 4)), \
565
1, \
566
desc)
567
568
575
#define SKIP_UNIT_TEST_WITH_BUNDLE(b, test, expected_result) \
576
SKIP_TEST(test, expected_result)
577
584
#define SKIP_UNIT_TEST(test, expected_result) \
585
SKIP_TEST(test, expected_result)
printb
void printb(const char *const b)
Print each byte of a bundle.
Definition
ose_test_unit.h:95