libose
Loading...
Searching...
No Matches
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
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
95void 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 if(b){ \
226 p = buf; \
227 memcpy(p, b, sizeof(b)); \
228 bundle = ose_makeBundle(p + 4); \
229 }else{ \
230 /* for testing NULL pointer input */ \
231 bundle = ose_makeBundle(p); \
232 } \
233 if(verbose){ \
234 printf("bundle = "); \
235 printb(b); \
236 printf("\n"); \
237 } \
238 UNIT_TEST(test, expected_result, desc); \
239 }
240
241#define UNIT_TEST_WITH_CONTEXT_BUNDLE_IMPL(testbndl, \
242 bundle_literal, \
243 bundle_literal_size, \
244 copy_offset, \
245 call_offset, \
246 test, \
247 expected_result, \
248 desc) \
249 { \
250 ose_bundle bundle = (ose_bundle){NULL}; \
251 char buf[bundle_literal_size + 4] \
252 __attribute__ ((aligned (16))); \
253 /* Start from a known state rather than whatever the stack holds. \
254 \
255 Note this is hygiene, not a fix for the cache: this fixture cannot \
256 be used with anything that touches the context cache at all. The \
257 cache slots are addressed 560 bytes below the working bundle \
258 pointer, and this literal places that pointer only 128 bytes into \
259 buf -- so cache reads and writes land 432 bytes *before* the \
260 array, outside it entirely, where zeroing cannot reach them. Since \
261 ose_context_getFirstOffsetForMatch calls whatever non-zero value \
262 it finds in that slot, the result is a segfault wherever that \
263 stack memory is not already zero. Measured, not inferred. */ \
264 memset(buf, 0, sizeof(buf)); \
265 if(testbndl){ \
266 memcpy(buf, bundle_literal, bundle_literal_size + 4); \
267 char *p = buf + copy_offset; \
268 bundle.b = buf + call_offset; \
269 int32_t sizeofb = sizeof(testbndl); \
270 int32_t size1 = ose_ntohl(*((int32_t *)(p - 4))); \
271 int32_t size2 = ose_ntohl(*((int32_t *)(p + size1))); \
272 *((int32_t *)(p + size1)) = 0; \
273 memcpy(p - 4, testbndl, sizeofb); \
274 *((int32_t *)(p + (sizeofb - 4))) \
275 = ose_htonl(size2 - (sizeofb - 20)); \
276 }else{ \
277 } \
278 UNIT_TEST(test, expected_result, desc); \
279 if(verbose){ \
280 printf("result bundle = "); \
281 printb(bundle.b); \
282 printf("\n"); \
283 } \
284 }
285
298#define UNIT_TEST_WITH_CONTEXT_BUNDLE(testbndl, \
299 test, \
300 expected_result, \
301 desc) \
302 UNIT_TEST_WITH_CONTEXT_BUNDLE_IMPL(testbndl, \
303 ose_test_bundle_bytes, \
304 OSE_TEST_BUNDLE_TOTAL_SIZE - 4, \
305 OSE_TEST_BUNDLE_WORKING_OFFSET, \
306 OSE_TEST_BUNDLE_WORKING_OFFSET, \
307 test, \
308 expected_result, \
309 desc)
310
343#define UNIT_TEST_WITH_VM(testbndl, \
344 test, \
345 expected_result, \
346 desc) \
347 UNIT_TEST_WITH_CONTEXT_BUNDLE_IMPL(testbndl, \
348 ose_test_vm_bytes, \
349 OSE_TEST_VM_TOTAL_SIZE - 4, \
350 OSE_TEST_VM_STACK_BUNDLE_OFFSET, \
351 OSE_TEST_VM_WORKING_BUNDLE_OFFSET, \
352 test, \
353 expected_result, \
354 desc)
355
369#define UNIT_TEST_BUNDLE_TRANSFORM(testfn, \
370 testbndl, \
371 resultbndl, \
372 desc) \
373 if(verbose){ \
374 printf("test bundle = "); \
375 printb(testbndl); \
376 printf("\n"); \
377 printf("expected result = "); \
378 printb(resultbndl); \
379 printf("\n"); \
380 } \
381 UNIT_TEST_WITH_CONTEXT_BUNDLE( \
382 testbndl, \
383 (testfn(bundle), \
384 COMPARE_BUNDLES(resultbndl, \
385 ose_getBundlePtr(bundle) - 4)), \
386 0, \
387 desc);
388
421#define UNIT_TEST_BUNDLE_ERRNO(testfn, \
422 testbndl, \
423 errno, \
424 desc) \
425 UNIT_TEST_WITH_CONTEXT_BUNDLE( \
426 testbndl, \
427 (testfn(bundle), \
428 ose_errno_get(bundle)), \
429 errno, \
430 desc);
431
449#define UNIT_TEST_BUNDLE_TRANSFORM_ARGS(testfn, \
450 testbndl, \
451 resultbndl, \
452 desc, \
453 ...) \
454 UNIT_TEST_WITH_CONTEXT_BUNDLE( \
455 testbndl, \
456 (testfn(bundle, __VA_ARGS__), \
457 COMPARE_BUNDLES(resultbndl, \
458 ose_getBundlePtr(bundle) - 4)), \
459 0, \
460 desc);
461
476#define UNIT_TEST_BUNDLE_TRANSFORM_TRIGGER_ASSERTION(testfn, \
477 testbndl, \
478 desc) \
479 UNIT_TEST_WITH_CONTEXT_BUNDLE(testbndl, \
480 (testfn(bundle), 0), \
481 ASSERTION_FAILED, \
482 desc);
483
499#define UNIT_TEST_BUNDLE_TRANSFORM_TRIGGER_ASSERTION_ARGS(testfn, \
500 testbndl, \
501 desc, \
502 ...) \
503 UNIT_TEST_WITH_CONTEXT_BUNDLE(testbndl, \
504 (testfn(bundle, __VA_ARGS__), 0), \
505 ASSERTION_FAILED, \
506 desc);
507
522#define UNIT_TEST_VM_ERRNO(testfn, \
523 testbndl, \
524 errno, \
525 desc) \
526 UNIT_TEST_WITH_VM(testbndl, \
527 (testfn(bundle), \
528 ose_errno_get(bundle)), \
529 errno, \
530 desc)
531
546#define UNIT_TEST_VM_STACK_COMPARE(testfn, \
547 testbndl, \
548 resultbndl, \
549 desc) \
550 UNIT_TEST_WITH_VM(testbndl, \
551 (testfn(bundle), \
552 ose_errno_get(bundle) == OSE_ERR_NONE \
553 && !COMPARE_BUNDLES(resultbndl, \
554 buf + OSE_TEST_VM_STACK_BUNDLE_OFFSET - 4)), \
555 1, \
556 desc)
557
565#define SKIP_UNIT_TEST_WITH_BUNDLE(b, test, expected_result) \
566 SKIP_TEST(test, expected_result)
567
574#define SKIP_UNIT_TEST(test, expected_result) \
575 SKIP_TEST(test, expected_result)
void printb(const char *const b)
Print each byte of a bundle.
Definition ose_test_unit.h:95