28
|
1 /* |
|
2 * dt.h -- minimalist C testing library |
|
3 * |
|
4 * Copyright (c) 2022-2023 David Demelier <markand@malikania.fr> |
|
5 * |
|
6 * Permission to use, copy, modify, and/or distribute this software for any |
|
7 * purpose with or without fee is hereby granted, provided that the above |
|
8 * copyright notice and this permission notice appear in all copies. |
|
9 * |
|
10 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES |
|
11 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF |
|
12 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR |
|
13 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES |
|
14 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN |
|
15 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF |
|
16 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. |
|
17 */ |
|
18 |
|
19 #ifndef DT_H |
|
20 #define DT_H |
|
21 |
|
22 #include <inttypes.h> |
|
23 #include <math.h> |
|
24 #include <stddef.h> |
|
25 #include <stdint.h> |
|
26 #include <stdio.h> |
|
27 #include <string.h> |
|
28 |
|
29 static size_t dt_ntests; |
|
30 static size_t dt_nchecks; |
|
31 static size_t dt_nfailures; |
|
32 |
|
33 #ifndef DT_DOUBLE_TOLERANCE |
|
34 #define DT_DOUBLE_TOLERANCE 0.001 |
|
35 #endif |
|
36 |
|
37 #define DT_ASSERT(x) \ |
|
38 do { \ |
|
39 ++ dt_nchecks; \ |
|
40 \ |
|
41 if (!(x)) { \ |
|
42 ++ dt_nfailures; \ |
|
43 \ |
|
44 printf("%s:%d: assertion '" #x "' failed\n", __FILE__, __LINE__); \ |
|
45 } \ |
|
46 } while (0) |
|
47 |
|
48 #define DT_EQ(x, y, type, f) \ |
|
49 do { \ |
|
50 const type tx = x; \ |
|
51 const type ty = y; \ |
|
52 \ |
|
53 ++ dt_nchecks; \ |
|
54 \ |
|
55 if (tx != ty) { \ |
|
56 ++ dt_nfailures; \ |
|
57 \ |
|
58 printf("%s:%d: assertion " #x " == " #y " failed (" f " != " f ")\n", \ |
|
59 __FILE__, __LINE__, tx, ty); \ |
|
60 } \ |
|
61 } while (0) |
|
62 |
|
63 #define DT_EQ_PTR(x, y) \ |
|
64 do { \ |
|
65 const void *tx = x; \ |
|
66 const void *ty = y; \ |
|
67 \ |
|
68 ++ dt_nchecks; \ |
|
69 \ |
|
70 if (tx != ty) { \ |
|
71 ++ dt_nfailures; \ |
|
72 \ |
|
73 printf("%s:%d: assertion " #x " == " #y " failed (%p != %p)\n", \ |
|
74 __FILE__, __LINE__, tx, ty); \ |
|
75 } \ |
|
76 } while (0) |
|
77 |
|
78 #define DT_EQ_STR(x, y) \ |
|
79 do { \ |
|
80 ++ dt_nchecks; \ |
|
81 \ |
|
82 if (strcmp(x, y) != 0) { \ |
|
83 ++ dt_nfailures; \ |
|
84 \ |
|
85 printf("%s:%d: assertion " #x " == " #y " failed (%s != %s)\n", \ |
|
86 __FILE__, __LINE__, (x), (y)); \ |
|
87 } \ |
|
88 } while (0) |
|
89 |
|
90 #define DT_EQ_DOUBLE(x, y) \ |
|
91 do { \ |
|
92 const double tx = x; \ |
|
93 const double ty = y; \ |
|
94 \ |
|
95 ++ dt_nchecks; \ |
|
96 \ |
|
97 if (fabs(tx - ty) > DT_DOUBLE_TOLERANCE) { \ |
|
98 ++ dt_nfailures; \ |
|
99 \ |
|
100 printf("%s:%d: assertion " #x " == " #y " failed (%f != %f)\n", \ |
|
101 __FILE__, __LINE__, tx, ty); \ |
|
102 } \ |
|
103 } while (0) |
|
104 |
|
105 #define DT_RUN(f, ...) \ |
|
106 do { \ |
|
107 const size_t nchecks = dt_nchecks; \ |
|
108 const size_t nfailures = dt_nfailures; \ |
|
109 \ |
|
110 ++ dt_ntests; \ |
|
111 \ |
|
112 printf("== test " #f " ==\n"); \ |
|
113 f(__VA_ARGS__); \ |
|
114 \ |
|
115 printf("\n%zu checks, %zu failures\n\n", \ |
|
116 dt_nchecks - nchecks, dt_nfailures - nfailures); \ |
|
117 } while (0) |
|
118 |
|
119 #define DT_RUN_EX(f, init, fini, ...) \ |
|
120 do { \ |
|
121 const size_t nchecks = dt_nchecks; \ |
|
122 const size_t nfailures = dt_nfailures; \ |
|
123 \ |
|
124 ++ dt_ntests; \ |
|
125 \ |
|
126 printf("== test " #f " ==\n"); \ |
|
127 init(__VA_ARGS__); \ |
|
128 f(__VA_ARGS__); \ |
|
129 fini(__VA_ARGS__); \ |
|
130 \ |
|
131 printf("\n%zu checks, %zu failures\n\n", \ |
|
132 dt_nchecks - nchecks, dt_nfailures - nfailures); \ |
|
133 } while (0) |
|
134 |
|
135 #define DT_SUMMARY() \ |
|
136 do { \ |
|
137 printf("summary: %zu tests, %zu checks, %zu failures\n", \ |
|
138 dt_ntests, dt_nchecks, dt_nfailures); \ |
|
139 } while (0) |
|
140 |
|
141 #define DT_EXIT() (dt_nfailures != 0) |
|
142 |
|
143 /* Aliases for basic types. */ |
|
144 #define DT_EQ_CHAR(x, y) DT_EQ(x, y, char, "%c") |
|
145 #define DT_EQ_SHORT(x, y) DT_EQ(x, y, short, "%hd") |
|
146 #define DT_EQ_USHORT(x, y) DT_EQ(x, y, unsigned short, "%hu") |
|
147 #define DT_EQ_INT(x, y) DT_EQ(x, y, int, "%d") |
|
148 #define DT_EQ_UINT(x, y) DT_EQ(x, y, unsigned int, "%u") |
|
149 #define DT_EQ_LONG(x, y) DT_EQ(x, y, long, "%ld") |
|
150 #define DT_EQ_ULONG(x, y) DT_EQ(x, y, unsigned long, "%lu") |
|
151 #define DT_EQ_LLONG(x, y) DT_EQ(x, y, long long, "%lld") |
|
152 #define DT_EQ_ULLONG(x, y) DT_EQ(x, y, unsigned long long, "%llu") |
|
153 #define DT_EQ_INTMAX(x, y) DT_EQ(x, y, intmax_t, "%jd") |
|
154 #define DT_EQ_UINTMAX(x, y) DT_EQ(x, y, uintmax_t, "%ju") |
|
155 #define DT_EQ_SIZE(x, y) DT_EQ(x, y, size_t, "%zu") |
|
156 #define DT_EQ_PTRDIFF(x, y) DT_EQ(x, y, ptrdiff_t, "%td") |
|
157 |
|
158 /* Aliases for fixed size integers. */ |
|
159 #define DT_EQ_INT8(x, y) DT_EQ(x, y, int8_t, PRId8) |
|
160 #define DT_EQ_UINT8(x, y) DT_EQ(x, y, uint8_t int, PRIu8) |
|
161 #define DT_EQ_INT16(x, y) DT_EQ(x, y, int16_t, PRId16) |
|
162 #define DT_EQ_UINT16(x, y) DT_EQ(x, y, uint16_t int, PRIu16) |
|
163 #define DT_EQ_INT32(x, y) DT_EQ(x, y, int32_t, PRId32) |
|
164 #define DT_EQ_UINT32(x, y) DT_EQ(x, y, uint32_t int, PRIu32) |
|
165 #define DT_EQ_INT64(x, y) DT_EQ(x, y, int64_t, PRId64) |
|
166 #define DT_EQ_UINT64(x, y) DT_EQ(x, y, uint64_t int, PRIu64) |
|
167 |
|
168 #endif /* !DT_H */ |