浏览代码

basic type unittests pass

Tobias Waldekranz.com 8 年之前
父节点
当前提交
21292b4bb7
共有 5 个文件被更改,包括 271 次插入238 次删除
  1. 6 1
      ply.c
  2. 104 218
      type.c
  3. 9 7
      type.h
  4. 81 12
      type_test.c
  5. 71 0
      unittest.h

+ 6 - 1
ply.c

63
 	/* prog->globals = ctx->globals; */
63
 	/* prog->globals = ctx->globals; */
64
 
64
 
65
 	prog->probe = "k:SyS_read";
65
 	prog->probe = "k:SyS_read";
66
-	/* { @t[0] = time(); @reads[pid()] = quantize(arg2) } */
66
+
67
+	/* { 
68
+	 * 	@t[0] = time();
69
+	 * 	@reads[pid()] = quantize(arg2)
70
+	 * }
71
+	 */
67
 	prog->ast =
72
 	prog->ast =
68
 		node_expr("",
73
 		node_expr("",
69
 			  node_expr("=",
74
 			  node_expr("=",

+ 104 - 218
type.c

57
 		fputs("struct ", fp);
57
 		fputs("struct ", fp);
58
 		fputs(t->sou.name, fp);
58
 		fputs(t->sou.name, fp);
59
 		break;
59
 		break;
60
-	case T_UNION:
61
-		fputs("union ", fp);
62
-		fputs(t->sou.name, fp);
63
-		break;
60
+	/* case T_UNION: */
61
+	/* 	fputs("union ", fp); */
62
+	/* 	fputs(t->sou.name, fp); */
63
+	/* 	break; */
64
 	case T_FUNC:
64
 	case T_FUNC:
65
 		type_dump_func(t, fp);
65
 		type_dump_func(t, fp);
66
 		break;
66
 		break;
97
 		break;
97
 		break;
98
 
98
 
99
 	case T_STRUCT:
99
 	case T_STRUCT:
100
-	case T_UNION:
100
+	/* case T_UNION: */
101
 		type_dump_cdecl_sou(t, fp);
101
 		type_dump_cdecl_sou(t, fp);
102
 		break;
102
 		break;
103
 
103
 
124
 /* 	} */
124
 /* 	} */
125
 /* } */
125
 /* } */
126
 
126
 
127
-/* struct type *type_map_of(struct type *ktype, struct type *vtype) */
128
-/* { */
129
-/* 	struct type *t; */
130
-/* 	size_t i; */
131
-
132
-/* 	for (i = 0; i < types.len; i++) { */
133
-/* 		t = types.type[i]; */
134
-/* 		if ((t->ttype == T_MAP) */
135
-/* 		    && (t->map.ktype == ktype) */
136
-/* 		    && (t->map.vtype == vtype)) */
137
-/* 			return t; */
138
-/* 	} */
139
-
140
-/* 	t = calloc(1, sizeof(*t)); */
141
-/* 	t->ttype = T_MAP; */
142
-/* 	t->map.vtype = vtype; */
143
-/* 	t->map.ktype = ktype; */
144
-/* 	type_add(t); */
145
-/* 	return t; */
146
-/* } */
147
-
148
-/* struct type *type_ptr_of(struct type *type) */
149
-/* { */
150
-/* 	struct type *t; */
151
-/* 	size_t i; */
152
-
153
-/* 	for (i = 0; i < types.len; i++) { */
154
-/* 		t = types.type[i]; */
155
-/* 		if ((t->ttype == T_POINTER) */
156
-/* 		    && (t->pointer.type == type)) */
157
-/* 			return t; */
158
-/* 	} */
159
-
160
-/* 	t = calloc(1, sizeof(*t)); */
161
-/* 	t->ttype = T_POINTER; */
162
-/* 	t->pointer.type = type; */
163
-/* 	type_add(t); */
164
-/* 	return t; */
165
-/* } */
166
 
127
 
167
 
128
 
168
 struct type *type_normalize(struct type *t)
129
 struct type *type_normalize(struct type *t)
199
 
160
 
200
 		return type_compatible(a->array.type, b->array.type);
161
 		return type_compatible(a->array.type, b->array.type);
201
 	case T_STRUCT:
162
 	case T_STRUCT:
202
-	case T_UNION:
163
+	/* case T_UNION: */
203
 		return !strcmp(a->sou.name, b->sou.name);
164
 		return !strcmp(a->sou.name, b->sou.name);
204
 	case T_FUNC:
165
 	case T_FUNC:
205
 		return type_compatible(a->func.type, b->func.type);
166
 		return type_compatible(a->func.type, b->func.type);
214
 	return 0;
175
 	return 0;
215
 }
176
 }
216
 
177
 
217
-/* void type_size_set_sou(struct type *t) */
218
-/* { */
219
-/* 	struct tfield *f; */
220
-/* 	size_t size = 0; */
221
-
222
-/* 	if (!t->sou.fields) */
223
-/* 		return; */
224
-
225
-/* 	for (f = t->sou.fields; f->name; f++) { */
226
-/* 		/\* size of all members is now known yet, abort *\/ */
227
-/* 		if (!f->type->size) */
228
-/* 			return; */
229
-
230
-/* 		if (!t->sou.packed) */
231
-/* 			size += size % f->type->size; */
232
-
233
-/* 		size += f->type->size; */
234
-/* 		f->offset = size; */
235
-/* 	} */
236
-
237
-/* 	if (!t->sou.packed && size) { */
238
-/* 		/\* align complete struct to requirements of first */
239
-/* 		 * member, if struct keep going downwards *\/ */
240
-/* 		f = t->sou.fields; */
241
-/* 		while (f->type->ttype == T_STRUCT) */
242
-/* 			f = f->type->sou.fields; */
243
-
244
-/* 		size += size % f->type->size; */
245
-/* 	} */
246
-
247
-/* 	t->size = size; */
248
-/* } */
249
-
250
-/* void type_size_set(struct type *t) */
251
-/* { */
252
-/* 	switch (t->ttype) { */
253
-/* 	case T_TYPEDEF: */
254
-/* 		t->size = t->tdef.type->size; */
255
-/* 		break; */
256
-/* 	case T_STRUCT: */
257
-/* 	case T_UNION: */
258
-/* 		type_size_set_sou(t); */
259
-/* 		break; */
260
-/* 	case T_FUNC: */
261
-/* 		t->size = t->func.type->size; */
262
-/* 		assert(t->func.generate_ir); */
263
-/* 		break; */
264
-/* 	case T_SCALAR: */
265
-/* 		break; */
266
-/* 	case T_POINTER: */
267
-/* 		t->size = sizeof(void *); */
268
-/* 		break; */
269
-/* 	case T_ARRAY: */
270
-/* 		t->size = t->array.len * t->array.type->size; */
271
-/* 		break; */
272
-/* 	case T_MAP: */
273
-/* 		/\* map fds are s64:s *\/ */
274
-/* 		t->size = 8; */
275
-/* 		break; */
276
-/* 	} */
277
-/* } */
278
-
279
-static ssize_t type_alignof_union(struct type *t)
178
+static ssize_t type_alignof_struct(struct type *t)
280
 {
179
 {
281
-	ssize_t amax = -EINVAL;
282
 	struct tfield *f;
180
 	struct tfield *f;
181
+	ssize_t falign, align = -EINVAL;
283
 
182
 
284
-	for (f = t->sou.fields; f->type != T_VOID; f++) {
285
-		ssize_t a;
183
+	tfields_foreach(f, t->sou.fields) {
184
+		falign = type_alignof(f->type);
286
 
185
 
287
-		a = type_alignof(f->type);
288
-		if (a < 0)
289
-			return a;
186
+		if (falign < 0)
187
+			return falign;
290
 
188
 
291
-		if (a > amax)
292
-			amax = a;
189
+		if (falign > align)
190
+			align = falign;
293
 	}
191
 	}
294
 
192
 
295
-	return amax;
193
+	return align;
296
 }
194
 }
297
 
195
 
298
 ssize_t type_alignof(struct type *t)
196
 ssize_t type_alignof(struct type *t)
309
 	case T_ARRAY:
207
 	case T_ARRAY:
310
 		return type_alignof(t->array.type);
208
 		return type_alignof(t->array.type);
311
 	case T_STRUCT:
209
 	case T_STRUCT:
312
-		if (!t->sou.fields)
313
-			return type_alignof(&t_void);
314
-		return type_alignof(t->sou.fields->type);
315
-	case T_UNION:
316
-		if (!t->sou.fields)
317
-			return type_alignof(&t_void);
318
-		return type_alignof_union(t);
210
+		return type_alignof_struct(t);
319
 	}
211
 	}
320
 
212
 
321
 	return -EINVAL;
213
 	return -EINVAL;
322
 }
214
 }
323
 
215
 
324
-static ssize_t type_sizeof_struct(struct type *t)
216
+ssize_t type_offset_size_of(struct type *t, const char *field)
325
 {
217
 {
326
 	struct tfield *f;
218
 	struct tfield *f;
327
-	size_t size = 0;
328
-	ssize_t fsize;
219
+	size_t offset = 0;
220
+	ssize_t fsize, falign;
221
+
222
+	assert(t->ttype == T_STRUCT);
329
 
223
 
330
 	if (!t->sou.fields)
224
 	if (!t->sou.fields)
331
-		return 0;
225
+		return -ENOENT;
332
 
226
 
333
-	for (f = t->sou.fields; f->name; f++) {
334
-		/* size of all members is now known yet, abort */
227
+	tfields_foreach(f, t->sou.fields) {
335
 		fsize = type_sizeof(f->type);
228
 		fsize = type_sizeof(f->type);
336
 		if (fsize < 0)
229
 		if (fsize < 0)
337
 			return fsize;
230
 			return fsize;
338
 
231
 
339
-		size += fsize;
232
+		falign = type_alignof(f->type);
233
+		if (falign < 0)
234
+			return falign;
340
 
235
 
341
-		if (!t->sou.packed)
342
-			size += size % type_alignof(f->type);
343
-	}
236
+		if (!t->sou.packed && (falign > 1))
237
+			offset += falign - (offset % falign);
344
 
238
 
345
-	if (!t->sou.packed && size)
346
-		size += size % type_alignof(t);
239
+		if (field && !strcmp(f->name, field))
240
+			return offset;
347
 
241
 
348
-	return size;
349
-}
242
+		offset += fsize;
243
+	}
350
 
244
 
351
-static ssize_t type_sizeof_union(struct type *t)
352
-{
353
-	struct tfield *f;
354
-	ssize_t size = 0;
245
+	if (field)
246
+		return -ENOENT;
355
 
247
 
356
-	if (!t->sou.fields)
357
-		return 0;
248
+	if (!t->sou.packed && offset && (falign > 1))
249
+		offset += falign - (offset % falign);
358
 
250
 
359
-	for (f = t->sou.fields; f->name; f++) {
360
-		ssize_t z, a;
361
-
362
-		z = type_sizeof(f->type);
363
-		a = t->sou.packed ? type_alignof(f->type) : 0;
364
-		if ((z < 0) || (a < 0))
365
-			return -EINVAL;
251
+	return offset;
252
+	
253
+}
366
 
254
 
367
-		z += z % a;
368
-		if (z > size)
369
-			size = z;
370
-	}
255
+ssize_t type_offsetof(struct type *t, const char *field)
256
+{
257
+	return type_offset_size_of(t, field);
258
+}
371
 
259
 
372
-	return size;
260
+ssize_t type_sizeof_struct(struct type *t)
261
+{
262
+	return type_offset_size_of(t, NULL);
373
 }
263
 }
374
 
264
 
375
 ssize_t type_sizeof(struct type *t)
265
 ssize_t type_sizeof(struct type *t)
388
 		return t->array.len * type_sizeof(t->array.type);
278
 		return t->array.len * type_sizeof(t->array.type);
389
 	case T_STRUCT:
279
 	case T_STRUCT:
390
 		return type_sizeof_struct(t);
280
 		return type_sizeof_struct(t);
391
-	case T_UNION:
392
-		return type_sizeof_union(t);
393
 	case T_MAP:
281
 	case T_MAP:
394
 		return sizeof(int);
282
 		return sizeof(int);
395
 	}
283
 	}
397
 	return -EINVAL;
285
 	return -EINVAL;
398
 }
286
 }
399
 
287
 
400
-/* int type_walk_fields(struct tfield *f, twalk_fn pre, twalk_fn post, void *ctx) */
401
-/* { */
402
-/* 	if (!f) */
403
-/* 		return 0; */
404
-
405
-/* 	while (f->type != T_VOID) { */
406
-/* 		if (pre && (err = pre(f->type, ctx))) */
407
-/* 			return err; */
408
-
409
-/* 		err = type_walk(f->type, pre, post, ctx); */
410
-/* 		if (err) */
411
-/* 			return err; */
412
-
413
-/* 		if (post && (err = post(f->type, ctx))) */
414
-/* 			return err; */
415
-/* 	} */
416
-/* } */
417
-
418
-/* int type_walk(struct type *t, twalk_fn pre, twalk_fn post, void *ctx) */
419
-/* { */
420
-/* 	int err; */
421
-
422
-/* 	if (pre && (err = pre(t, ctx))) */
423
-/* 		return err; */
424
-		
425
-/* 	switch (t->ttype){ */
426
-/* 	case T_VOID: */
427
-/* 	case T_SCALAR: */
428
-/* 		break; */
429
-/* 	case T_TYPEDEF: */
430
-/* 		err = type_walk(t->tdef.type, pre, post, ctx); */
431
-/* 		break; */
432
-/* 	case T_POINTER: */
433
-/* 		err = type_walk(t->ptr.type, pre, post, ctx); */
434
-/* 		break; */
435
-/* 	case T_ARRAY: */
436
-/* 		err = type_walk(t->array.type, pre, post, ctx); */
437
-/* 		break; */
438
-/* 	case T_STRUCT: */
439
-/* 	case T_UNION: */
440
-/* 		err = type_walk_fields(t->sou.fields, pre, post, ctx); */
441
-/* 		break; */
442
-/* 	case T_FUNC: */
443
-/* 		err = type_walk_fields(t->func.args, pre, post, ctx); */
444
-/* 		break; */
445
-/* 	case T_MAP: */
446
-/* 		err = type_walk(t->map.ktype, pre, post, ctx); */
447
-/* 		if (err) */
448
-/* 			break; */
449
-
450
-/* 		err = type_walk(t->map.vtype, pre, post, ctx); */
451
-/* 		break; */
452
-/* 	} */
453
-
454
-/* 	if (err) */
455
-/* 		return err; */
456
-	
457
-/* 	if (post && (err = post(t, ctx))) */
458
-/* 		return err; */
459
-/* } */
460
 
288
 
461
 
289
 
462
 int all_types_cmp(const void *_a, const void *_b)
290
 int all_types_cmp(const void *_a, const void *_b)
472
 	size_t len;
300
 	size_t len;
473
 } all_types;
301
 } all_types;
474
 
302
 
303
+#define types_foreach(_t) \
304
+	for ((_t) = all_types.types[0]; (_t) <= all_types.types[all_types.len]; (_t)++)
305
+
475
 int type_add(struct type *t)
306
 int type_add(struct type *t)
476
 {
307
 {
477
 	if (bsearch(t, all_types.types, all_types.len,
308
 	if (bsearch(t, all_types.types, all_types.len,
501
 	return 0;
332
 	return 0;
502
 }
333
 }
503
 
334
 
335
+struct type *type_array_of(struct type *type, size_t len)
336
+{
337
+	struct type *t;
338
+
339
+	types_foreach(t) {
340
+		if ((t->ttype == T_ARRAY)
341
+		    && (t->array.type == type)
342
+		    && (t->array.len == len))
343
+			return t;
344
+	}
345
+
346
+	t = calloc(1, sizeof(*t));
347
+	t->ttype = T_ARRAY;
348
+	t->array.type = type;
349
+	t->array.len = len;
350
+	type_add(t);
351
+	return t;
352
+}
353
+
354
+struct type *type_map_of(struct type *ktype, struct type *vtype)
355
+{
356
+	struct type *t;
357
+
358
+	types_foreach(t) {
359
+		if ((t->ttype == T_MAP)
360
+		    && (t->map.ktype == ktype)
361
+		    && (t->map.vtype == vtype))
362
+			return t;
363
+	}
364
+
365
+	t = calloc(1, sizeof(*t));
366
+	t->ttype = T_MAP;
367
+	t->map.vtype = vtype;
368
+	t->map.ktype = ktype;
369
+	type_add(t);
370
+	return t;
371
+}
372
+
373
+struct type *type_ptr_of(struct type *type)
374
+{
375
+	struct type *t;
376
+
377
+	types_foreach(t) {
378
+		if ((t->ttype == T_POINTER)
379
+		    && (t->ptr.type == type))
380
+			return t;
381
+	}
382
+
383
+	t = calloc(1, sizeof(*t));
384
+	t->ttype = T_POINTER;
385
+	t->ptr.type = type;
386
+	type_add(t);
387
+	return t;
388
+}
389
+
504
 #define is_signed(_t) (((_t)(-1)) < 0)
390
 #define is_signed(_t) (((_t)(-1)) < 0)
505
 
391
 
506
 #define builtin_scalar(_t) {				\
392
 #define builtin_scalar(_t) {				\

+ 9 - 7
type.h

38
 	int optional:1;
38
 	int optional:1;
39
 };
39
 };
40
 
40
 
41
+#define tfields_foreach(_f, _fields) \
42
+	for ((_f) = (_fields); (_f)->type->ttype != T_VOID; (_f)++)
43
+
41
 struct tstruct {
44
 struct tstruct {
42
 	char *name;
45
 	char *name;
43
 
46
 
58
 	T_ARRAY,
61
 	T_ARRAY,
59
 	T_MAP,
62
 	T_MAP,
60
 	T_STRUCT,
63
 	T_STRUCT,
61
-	T_UNION,
64
+	/* T_UNION, TODO */
62
 	T_FUNC,
65
 	T_FUNC,
63
 };
66
 };
64
 
67
 
75
 	};
78
 	};
76
 };
79
 };
77
 
80
 
78
-/* struct type *type_map_of(struct type *ktype, struct type *vtype); */
79
-/* struct type *type_ptr_of(struct type *type); */
80
-
81
 int type_equal     (struct type *a, struct type *b);
81
 int type_equal     (struct type *a, struct type *b);
82
 int type_compatible(struct type *a, struct type *b);
82
 int type_compatible(struct type *a, struct type *b);
83
 
83
 
85
 void type_dump_cdecl(struct type *t, FILE *fp);
85
 void type_dump_cdecl(struct type *t, FILE *fp);
86
 
86
 
87
 ssize_t type_alignof(struct type *t);
87
 ssize_t type_alignof(struct type *t);
88
+ssize_t type_offsetof(struct type *t, const char *field);
88
 ssize_t type_sizeof(struct type *t);
89
 ssize_t type_sizeof(struct type *t);
89
 
90
 
90
-/* typedef int (*twalk_fn)(struct type *, void *); */
91
-/* int type_walk(struct type *t, twalk_fn pre, twalk_fn post, void *ctx); */
92
-
93
 
91
 
94
 int type_add(struct type *t);
92
 int type_add(struct type *t);
95
 int type_add_list(struct type **ts);
93
 int type_add_list(struct type **ts);
96
 
94
 
95
+struct type *type_array_of(struct type *type, size_t len);
96
+struct type *type_map_of(struct type *ktype, struct type *vtype);
97
+struct type *type_ptr_of(struct type *type);
98
+
97
 
99
 
98
 /* built-in types */
100
 /* built-in types */
99
 
101
 

+ 81 - 12
type_test.c

1
-#include <assert.h>
2
-
3
 #include "type.h"
1
 #include "type.h"
2
+#include "unittest.h"
3
+
4
+static int sizeof_basic(void *_null)
5
+{
6
+	struct type *voidp, *map;
7
+
8
+	unittest_eq(type_sizeof(&t_void),  sizeof(void));
9
+	unittest_eq(type_sizeof(&t_char),  sizeof(char));
10
+	unittest_eq(type_sizeof(&t_short), sizeof(short));
11
+	unittest_eq(type_sizeof(&t_int),   sizeof(int));
12
+	unittest_eq(type_sizeof(&t_long),  sizeof(long));
13
+	unittest_eq(type_sizeof(&t_llong), sizeof(long long));
14
+
15
+	voidp = type_ptr_of(&t_void);
16
+	unittest_eq(type_sizeof(voidp), sizeof(void *));
17
+
18
+	map = type_map_of(&t_short, &t_short);
19
+	unittest_eq(type_sizeof(map), sizeof(int));
20
+	
21
+	return 0;
22
+}
23
+UNITTEST(sizeof_basic);
24
+
25
+static int alignof_basic(void *_null)
26
+{
27
+	struct type *voidp, *map, *array;
28
+
29
+	unittest_eq(type_alignof(&t_void),  __alignof__(void));
30
+	unittest_eq(type_alignof(&t_char),  __alignof__(char));
31
+	unittest_eq(type_alignof(&t_short), __alignof__(short));
32
+	unittest_eq(type_alignof(&t_int),   __alignof__(int));
33
+	unittest_eq(type_alignof(&t_long),  __alignof__(long));
34
+	unittest_eq(type_alignof(&t_llong), __alignof__(long long));
4
 
35
 
5
-typedef void (*unittest_fn)(void)
6
-#define unittest __attribute__((section("unittest"))) static void
36
+	voidp = type_ptr_of(&t_void);
37
+	unittest_eq(type_alignof(voidp), __alignof__(void *));
7
 
38
 
8
-unittest test_sizeof_builtins(void)
39
+	map = type_map_of(&t_short, &t_short);
40
+	unittest_eq(type_alignof(map), __alignof__(int));
41
+
42
+	array = type_array_of(&t_int, 5);
43
+	unittest_eq(type_alignof(array), __alignof__(int[5]));
44
+
45
+	return 0;
46
+}
47
+UNITTEST(alignof_basic);
48
+
49
+struct t1 {
50
+	char  a;
51
+	int   b[5];
52
+	char  c[3];
53
+	short d;
54
+} *t1 = NULL;
55
+
56
+static int struct_basic(void *_null)
9
 {
57
 {
10
-	assert(type_sizeof(&t_void) == sizeof(int));
58
+	struct tfield t1_fields[] = {
59
+		{ .name = "a", .type = &t_char },
60
+		{ .name = "b", .type = type_array_of(&t_int, 5) },
61
+		{ .name = "c", .type = type_array_of(&t_char, 3) },
62
+		{ .name = "d", .type = &t_short },
63
+
64
+		{ .type = &t_void }
65
+	};
66
+	struct type t_t1 = {
67
+		.ttype = T_STRUCT,
68
+		.sou = { .name = "t1", .fields = t1_fields },
69
+	};
70
+
71
+	unittest_eq(type_offsetof(&t_t1, "a"), offsetof(struct t1, a));
72
+	unittest_eq(type_offsetof(&t_t1, "b"), offsetof(struct t1, b));
73
+	unittest_eq(type_offsetof(&t_t1, "c"), offsetof(struct t1, c));
74
+	unittest_eq(type_offsetof(&t_t1, "d"), offsetof(struct t1, d));
75
+
76
+	unittest_eq(type_alignof(&t_t1), __alignof__(struct t1));
77
+	unittest_eq(type_sizeof(&t_t1), sizeof(struct t1));
78
+	return 0;
11
 }
79
 }
80
+UNITTEST(struct_basic);
12
 
81
 
13
 int main(void)
82
 int main(void)
14
 {
83
 {
15
-	unittest_fn test_fn;
16
-	int err;
84
+	struct unittest_ctx ctx = {
85
+		.keep_going = 1,
86
+		.verbose = 1,
17
 
87
 
18
-	for (test_fn = &__start_unittest; test_fn < &__stop_unittest; testfn++) {
19
-		test_fn();
20
-	}
88
+		.ctx = NULL,
89
+	};
21
 
90
 
22
-	return 0;
91
+	return unittests_run(&ctx) ? 1 : 0;
23
 }
92
 }

+ 71 - 0
unittest.h

1
+#ifndef _UNITTEST_H
2
+#define _UNITTEST_H
3
+
4
+#include <stdio.h>
5
+
6
+struct unittest {
7
+	const char *name;
8
+	int (*fn)(void *ctx);
9
+};
10
+
11
+#define UNITTEST(_fn) __attribute__((section("unittests"))) \
12
+	static struct unittest _fn ## _desc = {		    \
13
+		.name = #_fn,				    \
14
+		.fn = _fn,				    \
15
+	}
16
+
17
+extern struct unittest __start_unittests;
18
+extern struct unittest __stop_unittests;
19
+
20
+#define unittest_foreach(_t) \
21
+	for ((_t) = &__start_unittests; (_t) < &__stop_unittests; (_t)++)
22
+
23
+struct unittest_ctx {
24
+	int keep_going:1;
25
+	int verbose:1;
26
+
27
+	void *ctx;
28
+};
29
+
30
+static inline int unittests_run(struct unittest_ctx *ctx)
31
+{
32
+	struct unittest *t;
33
+	int err, ret = 0;
34
+
35
+	unittest_foreach(t) {
36
+		if (ctx->verbose) {
37
+			printf("%-40s\t", t->name);
38
+			fflush(stdout);
39
+		}
40
+
41
+		err = t->fn(ctx->ctx);
42
+
43
+		if (!err) {
44
+			if (ctx->verbose)
45
+				printf("pass\n");
46
+			continue;
47
+		} 
48
+
49
+		if (!ctx->verbose) {
50
+			printf("%-40s\t", t->name);
51
+			fflush(stdout);
52
+		}
53
+
54
+		printf("\n%40s\tFAIL\n", "");
55
+
56
+		if (!ctx->keep_going)
57
+			return err;
58
+		else if (!ret)
59
+			ret = err;
60
+	}
61
+
62
+	return ret;
63
+}
64
+
65
+#define unittest_eq(_a, _b) if ((_a) != (_b)) {				\
66
+		printf("\n\t%s == %s (%lld != %lld)",			\
67
+		       #_a, #_b, (long long)(_a), (long long)(_b));	\
68
+		return -1;						\
69
+	}
70
+
71
+#endif	/* _UNITTEST_H */