Commit | Line | Data |
---|---|---|
5de79fa0 MW |
1 | /* -*-sod-*- * |
2 | * | |
3 | * Test program for Sod functionality | |
4 | * | |
5 | * (c) 2016 Straylight/Edgeware | |
6 | */ | |
7 | ||
8 | /*----- Licensing notice --------------------------------------------------* | |
9 | * | |
10 | * This file is part of the Sensible Object Design, an object system for C. | |
11 | * | |
12 | * SOD is free software; you can redistribute it and/or modify | |
13 | * it under the terms of the GNU General Public License as published by | |
14 | * the Free Software Foundation; either version 2 of the License, or | |
15 | * (at your option) any later version. | |
16 | * | |
17 | * SOD is distributed in the hope that it will be useful, | |
18 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
19 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
20 | * GNU General Public License for more details. | |
21 | * | |
22 | * You should have received a copy of the GNU General Public License | |
23 | * along with SOD; if not, write to the Free Software Foundation, | |
24 | * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. | |
25 | */ | |
4a83289a | 26 | |
fd040f06 | 27 | code h: includes { |
4a83289a MW |
28 | #include "sod.h" |
29 | } | |
30 | ||
fd040f06 | 31 | code c: includes { |
4a83289a MW |
32 | #include <stdio.h> |
33 | #include <stdlib.h> | |
34 | #include <string.h> | |
35 | ||
36 | #include "test.h" | |
37 | } | |
38 | ||
fd040f06 | 39 | code c: early_user { |
4a83289a MW |
40 | /*----- Preliminary definitions -------------------------------------------*/ |
41 | ||
42 | /* Confuse the fragment scanner... */ | |
43 | #define LBRACE { | |
44 | #define RBRACE } | |
45 | ||
46 | static const char *test_name; | |
47 | static int test_seq; | |
48 | ||
49 | static void prepare(const char *name) { test_name = name; test_seq = 0; } | |
50 | ||
51 | static void step(int q, const char *where) | |
52 | { | |
53 | if (test_seq != q) { | |
54 | fprintf(stderr, "test %s (%s): step %d instead of %d\n", | |
55 | test_name, where, q, test_seq); | |
56 | abort(); | |
57 | } | |
58 | test_seq++; | |
59 | } | |
60 | ||
61 | static void done(int q, const char *where) { step(q, where); } | |
62 | ||
63 | #define STRINGIFY_(x) #x | |
64 | #define STRINGIFY(x) STRINGIFY_(x) | |
65 | #define WHERE __FILE__ ":" STRINGIFY(__LINE__) | |
66 | #define STEP(q) step((q), WHERE) | |
67 | #define DONE(q) done((q), WHERE) | |
68 | ||
69 | } | |
70 | ||
fd040f06 | 71 | code c: (tests head) |
4a83289a MW |
72 | [user (tests head) tests (tests tail) main (user end)] |
73 | { | |
74 | /*----- Test machinery ----------------------------------------------------*/ | |
75 | ||
76 | static void tests(void) | |
77 | LBRACE | |
78 | } | |
fd040f06 | 79 | code c: (tests tail) { |
4a83289a MW |
80 | RBRACE |
81 | ||
82 | } | |
83 | ||
fd040f06 | 84 | code c: main { |
4a83289a MW |
85 | /*----- Main program ------------------------------------------------------*/ |
86 | ||
87 | int main(void) | |
88 | { | |
89 | tests(); | |
90 | return (0); | |
91 | } | |
92 | ||
93 | } | |
94 | ||
95 | /*----- Various kinds of method combinations ------------------------------*/ | |
96 | ||
fd040f06 | 97 | code h: early_user { |
4a83289a MW |
98 | struct item { |
99 | struct item *next; | |
100 | const char *p; | |
101 | }; | |
102 | ||
103 | } | |
104 | ||
fd040f06 | 105 | code c: early_user { |
4a83289a MW |
106 | static void *xmalloc(size_t n) |
107 | { | |
108 | void *p = malloc(n); | |
109 | if (!p) { perror("malloc"); exit(EXIT_FAILURE); } | |
110 | return (p); | |
111 | } | |
112 | ||
113 | static struct item *make_item(const char *p) | |
114 | { struct item *q = xmalloc(sizeof(*q)); q->p = p; return (q); } | |
115 | ||
116 | static void free_list(struct item *i) | |
117 | { struct item *ii; while (i) { ii = i->next; free(i); i = ii; } } | |
118 | ||
119 | static int check_list(struct item *i, ...) | |
120 | { | |
121 | va_list ap; | |
122 | const char *p; | |
123 | int rc = -1; | |
124 | ||
125 | va_start(ap, i); | |
126 | for (;;) { | |
127 | p = va_arg(ap, const char *); | |
128 | if (!p) break; | |
129 | if (!i || strcmp(i->p, p) != 0) break; | |
130 | i = i->next; | |
131 | } | |
132 | if (!i) rc = 0; | |
133 | va_end(ap); | |
134 | return (rc); | |
135 | } | |
136 | ||
137 | struct vec { int *v; size_t n; }; | |
138 | ||
139 | static void free_vec(struct vec *v) { free(v->v); } | |
140 | ||
141 | static int check_vec(struct vec *v, ...) | |
142 | { | |
143 | va_list ap; | |
144 | int j; | |
145 | size_t i = 0; | |
146 | int rc = -1; | |
147 | ||
148 | va_start(ap, v); | |
149 | for (;;) { | |
150 | j = va_arg(ap, int); | |
151 | if (j < 0) break; | |
152 | if (i == v->n || j != v->v[i]) break; | |
153 | i++; | |
154 | } | |
155 | if (i == v->n) rc = 0; | |
156 | va_end(ap); | |
157 | return (rc); | |
158 | } | |
159 | ||
160 | } | |
161 | ||
1e99dff0 | 162 | [link = SodObject, nick = base] |
fd040f06 | 163 | class T1Base: SodObject { |
b07535d8 MW |
164 | [combination = progn] void aprogn(); |
165 | [combination = sum] int asum(); | |
166 | [combination = and] int aand(); | |
167 | [combination = max] int amax(); | |
4a83289a MW |
168 | |
169 | [combination = custom, | |
b07535d8 | 170 | empty = { sod_ret = 0; }, |
4a83289a MW |
171 | decls = { struct item **head = &sod_ret; }, |
172 | each = { *head = sod_val; head = &sod_val->next; }, | |
173 | after = { *head = 0; }] | |
b07535d8 | 174 | struct item *alist(); |
4a83289a MW |
175 | |
176 | [combination = custom, | |
177 | decls = { int *v; size_t i = 0; }, methty = <int>, count = n, | |
b07535d8 | 178 | empty = { sod_ret.v = 0; sod_ret.n = 0; }, |
4a83289a MW |
179 | before = { v = xmalloc(n*sizeof(int)); }, |
180 | each = { v[i++] = sod_val; }, | |
181 | after = { sod_ret.v = v; sod_ret.n = n; }] | |
182 | struct vec avec(); | |
b07535d8 MW |
183 | } |
184 | ||
1e99dff0 | 185 | [link = T1Base, nick = mid] |
b07535d8 | 186 | class T1Mid: T1Base { |
1e99dff0 MW |
187 | void base.aprogn() { STEP(1); } |
188 | int base.asum() { return 1; } | |
189 | int base.aand() { return 8; } | |
190 | int base.amax() { return 12; } | |
191 | struct item *base.alist() { return make_item("mid"); } | |
192 | int base.avec() { return 19; } | |
4a83289a MW |
193 | } |
194 | ||
1e99dff0 | 195 | [link = T1Mid, nick = sub] |
b07535d8 | 196 | class T1Sub: T1Mid { |
1e99dff0 MW |
197 | void base.aprogn() { STEP(0); } |
198 | int base.asum() { return 2; } | |
199 | int base.aand() { return 6; } | |
200 | int base.amax() { return 17; } | |
201 | struct item *base.alist() { return make_item("sub"); } | |
202 | int base.avec() { return 4; } | |
4a83289a MW |
203 | } |
204 | ||
fd040f06 | 205 | code c: tests { |
4a83289a | 206 | prepare("aggregate, base"); |
a142609c | 207 | { SOD_DECL(T1Base, t1, NO_KWARGS); |
b07535d8 MW |
208 | struct item *l; |
209 | struct vec v; | |
210 | STEP(0); T1Base_aprogn(t1); STEP(1); | |
211 | if (T1Base_asum(t1) == 0) STEP(2); | |
212 | if (T1Base_aand(t1) == 1) STEP(3); | |
1e99dff0 | 213 | if (!t1->_vt->base.amax) STEP(4); |
b07535d8 MW |
214 | l = T1Base_alist(t1); |
215 | if (!l) STEP(5); | |
216 | v = T1Base_avec(t1); | |
217 | if (!v.n) STEP(6); | |
218 | DONE(7); | |
219 | } | |
220 | prepare("aggregate, mid"); | |
221 | { SOD_DECL(T1Mid, t1, NO_KWARGS); | |
4a83289a MW |
222 | struct item *l; |
223 | struct vec v; | |
224 | STEP(0); T1Base_aprogn(t1); /* 1 */ | |
225 | if (T1Base_asum(t1) == 1) STEP(2); | |
226 | if (T1Base_aand(t1) == 8) STEP(3); | |
227 | if (T1Base_amax(t1) == 12) STEP(4); | |
228 | l = T1Base_alist(t1); | |
b07535d8 | 229 | if (!check_list(l, "mid", (const char *)0)) STEP(5); |
4a83289a MW |
230 | free_list(l); |
231 | v = T1Base_avec(t1); | |
232 | if (!check_vec(&v, 19, -1)) STEP(6); | |
233 | free_vec(&v); | |
234 | DONE(7); | |
235 | } | |
236 | prepare("aggregate, sub"); | |
a142609c | 237 | { SOD_DECL(T1Sub, t1, NO_KWARGS); |
4a83289a MW |
238 | struct item *l; |
239 | struct vec v; | |
240 | T1Base_aprogn(t1); /* 0, 1 */ | |
241 | if (T1Base_asum(t1) == 3) STEP(2); | |
242 | if (T1Base_aand(t1) == 8) STEP(3); | |
243 | if (T1Base_amax(t1) == 17) STEP(4); | |
244 | l = T1Base_alist(t1); | |
b07535d8 | 245 | if (!check_list(l, "sub", "mid", (const char *)0)) STEP(5); |
4a83289a MW |
246 | free_list(l); |
247 | v = T1Base_avec(t1); | |
248 | if (!check_vec(&v, 4, 19, -1)) STEP(6); | |
249 | free_vec(&v); | |
250 | DONE(7); | |
251 | } | |
252 | } | |
253 | ||
b2983f35 MW |
254 | /*----- Slot and user initargs --------------------------------------------*/ |
255 | ||
256 | [link = SodObject, nick = t2] | |
fd040f06 | 257 | class T2: SodObject { |
b2983f35 | 258 | [initarg = x] int x = 0; |
dea6ee94 | 259 | [initarg = z] t2.x; |
b2983f35 MW |
260 | |
261 | initarg int y = 1; | |
262 | init { if (!y) STEP(0); } | |
263 | } | |
264 | ||
dea6ee94 MW |
265 | [link = T2] |
266 | class T2Sub: T2 { | |
267 | [initarg = a] t2.x; | |
268 | [initarg = b] t2.x; | |
269 | [initarg = x] t2.x; | |
270 | [initarg = c] t2.x; | |
271 | } | |
272 | ||
fd040f06 | 273 | code c: tests { |
b2983f35 MW |
274 | prepare("initargs, defaults"); |
275 | { SOD_DECL(T2, t, NO_KWARGS); | |
276 | if (t->t2.x == 0) STEP(0); | |
277 | DONE(1); | |
278 | } | |
279 | prepare("initargs, explicit"); | |
280 | { SOD_DECL(T2, t, KWARGS(K(x, 42) K(y, 0))); | |
281 | if (t->t2.x == 42) STEP(1); | |
282 | DONE(2); | |
283 | } | |
dea6ee94 MW |
284 | prepare("initargs, inheritance"); |
285 | { SOD_DECL(T2Sub, t, KWARGS(K(c, 1) K(z, 2))); | |
286 | if (t->t2.x == 1) STEP(0); | |
287 | DONE(1); | |
288 | } | |
289 | prepare("initargs, ordering"); | |
290 | { SOD_DECL(T2Sub, t, KWARGS(K(a, 1) K(b, 2))); | |
291 | if (t->t2.x == 1) STEP(0); | |
292 | DONE(1); | |
293 | } | |
294 | prepare("initargs, reprioritizing"); | |
295 | { SOD_DECL(T2Sub, t, KWARGS(K(x, 1) K(c, 2))); | |
296 | if (t->t2.x == 1) STEP(0); | |
297 | DONE(1); | |
298 | } | |
b2983f35 MW |
299 | } |
300 | ||
bce58d37 MW |
301 | /*----- Keyword argument propagation --------------------------------------*/ |
302 | ||
303 | [link = SodObject, nick = base] | |
fd040f06 | 304 | class T3Base: SodObject { |
bce58d37 MW |
305 | void m0(?int x) { STEP(x); } |
306 | void m1(?) { } | |
307 | } | |
308 | ||
12386a26 | 309 | [link = T3Base, nick = mid] |
fd040f06 | 310 | class T3Mid: T3Base { |
12386a26 MW |
311 | void base.m0(?int y) { STEP(y); CALL_NEXT_METHOD; } |
312 | void base.m1(?) { STEP(4); CALL_NEXT_METHOD; } | |
313 | } | |
314 | ||
315 | [link = T3Mid, nick = sub] | |
fd040f06 | 316 | class T3Sub: T3Mid { |
bce58d37 MW |
317 | void base.m0(?int z) { STEP(z); CALL_NEXT_METHOD; } |
318 | void base.m1(?int z) { STEP(z); CALL_NEXT_METHOD; } | |
319 | } | |
320 | ||
fd040f06 | 321 | code c: tests { |
bce58d37 MW |
322 | prepare("kwargs"); |
323 | { SOD_DECL(T3Sub, t, NO_KWARGS); | |
12386a26 MW |
324 | T3Base_m0(t, KWARGS(K(z, 0) K(y, 1) K(x, 2))); |
325 | T3Base_m1(t, KWARGS(K(z, 3))); | |
326 | DONE(5); | |
bce58d37 MW |
327 | } |
328 | } | |
329 | ||
4aea4c60 MW |
330 | /*----- Metaclass initialization ------------------------------------------*/ |
331 | ||
332 | [link = SodClass, nick = mycls] | |
333 | class MyClass: SodClass { | |
334 | int x = -1, y, z = 2; | |
335 | } | |
336 | ||
337 | [link = SodObject, nick = myobj, metaclass = MyClass] | |
338 | class MyObject: SodObject { | |
339 | class mycls.x = 0, mycls.y = 1; | |
340 | } | |
341 | ||
342 | code c: tests { | |
343 | prepare("metaclass, init"); | |
344 | STEP(MyObject__cls_obj->mycls.x); | |
345 | STEP(MyObject__cls_obj->mycls.y); | |
346 | STEP(MyObject__cls_obj->mycls.z); | |
347 | DONE(3); | |
348 | } | |
349 | ||
4a83289a | 350 | /*----- That's all, folks -------------------------------------------------*/ |