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 { |
a469422e MW |
164 | int plain(int x) { STEP(x); return (x + 1); } |
165 | ||
b07535d8 MW |
166 | [combination = progn] void aprogn(); |
167 | [combination = sum] int asum(); | |
168 | [combination = and] int aand(); | |
169 | [combination = max] int amax(); | |
30eb3c68 | 170 | [role = around] int base.asum() { return (CALL_NEXT_METHOD); } |
4a83289a MW |
171 | |
172 | [combination = custom, | |
b07535d8 | 173 | empty = { sod_ret = 0; }, |
4a83289a MW |
174 | decls = { struct item **head = &sod_ret; }, |
175 | each = { *head = sod_val; head = &sod_val->next; }, | |
176 | after = { *head = 0; }] | |
b07535d8 | 177 | struct item *alist(); |
4a83289a MW |
178 | |
179 | [combination = custom, | |
180 | decls = { int *v; size_t i = 0; }, methty = <int>, count = n, | |
b07535d8 | 181 | empty = { sod_ret.v = 0; sod_ret.n = 0; }, |
4a83289a MW |
182 | before = { v = xmalloc(n*sizeof(int)); }, |
183 | each = { v[i++] = sod_val; }, | |
184 | after = { sod_ret.v = v; sod_ret.n = n; }] | |
185 | struct vec avec(); | |
b07535d8 MW |
186 | } |
187 | ||
1e99dff0 | 188 | [link = T1Base, nick = mid] |
b07535d8 | 189 | class T1Mid: T1Base { |
a469422e | 190 | int base.plain(int x) { STEP(x - 1); return (CALL_NEXT_METHOD); } |
1e99dff0 MW |
191 | void base.aprogn() { STEP(1); } |
192 | int base.asum() { return 1; } | |
193 | int base.aand() { return 8; } | |
194 | int base.amax() { return 12; } | |
195 | struct item *base.alist() { return make_item("mid"); } | |
196 | int base.avec() { return 19; } | |
4a83289a MW |
197 | } |
198 | ||
1e99dff0 | 199 | [link = T1Mid, nick = sub] |
b07535d8 | 200 | class T1Sub: T1Mid { |
1e99dff0 MW |
201 | void base.aprogn() { STEP(0); } |
202 | int base.asum() { return 2; } | |
203 | int base.aand() { return 6; } | |
204 | int base.amax() { return 17; } | |
205 | struct item *base.alist() { return make_item("sub"); } | |
206 | int base.avec() { return 4; } | |
4a83289a MW |
207 | } |
208 | ||
fd040f06 | 209 | code c: tests { |
4a83289a | 210 | prepare("aggregate, base"); |
a142609c | 211 | { SOD_DECL(T1Base, t1, NO_KWARGS); |
b07535d8 MW |
212 | struct item *l; |
213 | struct vec v; | |
214 | STEP(0); T1Base_aprogn(t1); STEP(1); | |
215 | if (T1Base_asum(t1) == 0) STEP(2); | |
216 | if (T1Base_aand(t1) == 1) STEP(3); | |
1e99dff0 | 217 | if (!t1->_vt->base.amax) STEP(4); |
b07535d8 MW |
218 | l = T1Base_alist(t1); |
219 | if (!l) STEP(5); | |
220 | v = T1Base_avec(t1); | |
221 | if (!v.n) STEP(6); | |
a469422e MW |
222 | STEP(T1Base_plain(t1, 7)); /* 7, 8 */ |
223 | DONE(9); | |
b07535d8 MW |
224 | } |
225 | prepare("aggregate, mid"); | |
226 | { SOD_DECL(T1Mid, t1, NO_KWARGS); | |
4a83289a MW |
227 | struct item *l; |
228 | struct vec v; | |
229 | STEP(0); T1Base_aprogn(t1); /* 1 */ | |
230 | if (T1Base_asum(t1) == 1) STEP(2); | |
231 | if (T1Base_aand(t1) == 8) STEP(3); | |
232 | if (T1Base_amax(t1) == 12) STEP(4); | |
233 | l = T1Base_alist(t1); | |
b07535d8 | 234 | if (!check_list(l, "mid", (const char *)0)) STEP(5); |
4a83289a MW |
235 | free_list(l); |
236 | v = T1Base_avec(t1); | |
237 | if (!check_vec(&v, 19, -1)) STEP(6); | |
238 | free_vec(&v); | |
a469422e MW |
239 | STEP(T1Base_plain(t1, 8)); /* 7, 8, 9 */ |
240 | DONE(10); | |
4a83289a MW |
241 | } |
242 | prepare("aggregate, sub"); | |
a142609c | 243 | { SOD_DECL(T1Sub, t1, NO_KWARGS); |
4a83289a MW |
244 | struct item *l; |
245 | struct vec v; | |
246 | T1Base_aprogn(t1); /* 0, 1 */ | |
247 | if (T1Base_asum(t1) == 3) STEP(2); | |
248 | if (T1Base_aand(t1) == 8) STEP(3); | |
249 | if (T1Base_amax(t1) == 17) STEP(4); | |
250 | l = T1Base_alist(t1); | |
b07535d8 | 251 | if (!check_list(l, "sub", "mid", (const char *)0)) STEP(5); |
4a83289a MW |
252 | free_list(l); |
253 | v = T1Base_avec(t1); | |
254 | if (!check_vec(&v, 4, 19, -1)) STEP(6); | |
255 | free_vec(&v); | |
256 | DONE(7); | |
257 | } | |
258 | } | |
259 | ||
b2983f35 MW |
260 | /*----- Slot and user initargs --------------------------------------------*/ |
261 | ||
262 | [link = SodObject, nick = t2] | |
fd040f06 | 263 | class T2: SodObject { |
b2983f35 | 264 | [initarg = x] int x = 0; |
dea6ee94 | 265 | [initarg = z] t2.x; |
b2983f35 MW |
266 | |
267 | initarg int y = 1; | |
268 | init { if (!y) STEP(0); } | |
269 | } | |
270 | ||
dea6ee94 MW |
271 | [link = T2] |
272 | class T2Sub: T2 { | |
273 | [initarg = a] t2.x; | |
274 | [initarg = b] t2.x; | |
275 | [initarg = x] t2.x; | |
276 | [initarg = c] t2.x; | |
277 | } | |
278 | ||
fd040f06 | 279 | code c: tests { |
b2983f35 MW |
280 | prepare("initargs, defaults"); |
281 | { SOD_DECL(T2, t, NO_KWARGS); | |
282 | if (t->t2.x == 0) STEP(0); | |
283 | DONE(1); | |
284 | } | |
285 | prepare("initargs, explicit"); | |
286 | { SOD_DECL(T2, t, KWARGS(K(x, 42) K(y, 0))); | |
287 | if (t->t2.x == 42) STEP(1); | |
288 | DONE(2); | |
289 | } | |
dea6ee94 MW |
290 | prepare("initargs, inheritance"); |
291 | { SOD_DECL(T2Sub, t, KWARGS(K(c, 1) K(z, 2))); | |
292 | if (t->t2.x == 1) STEP(0); | |
293 | DONE(1); | |
294 | } | |
295 | prepare("initargs, ordering"); | |
296 | { SOD_DECL(T2Sub, t, KWARGS(K(a, 1) K(b, 2))); | |
297 | if (t->t2.x == 1) STEP(0); | |
298 | DONE(1); | |
299 | } | |
300 | prepare("initargs, reprioritizing"); | |
301 | { SOD_DECL(T2Sub, t, KWARGS(K(x, 1) K(c, 2))); | |
302 | if (t->t2.x == 1) STEP(0); | |
303 | DONE(1); | |
304 | } | |
b2983f35 MW |
305 | } |
306 | ||
bce58d37 MW |
307 | /*----- Keyword argument propagation --------------------------------------*/ |
308 | ||
309 | [link = SodObject, nick = base] | |
fd040f06 | 310 | class T3Base: SodObject { |
bce58d37 MW |
311 | void m0(?int x) { STEP(x); } |
312 | void m1(?) { } | |
313 | } | |
314 | ||
12386a26 | 315 | [link = T3Base, nick = mid] |
fd040f06 | 316 | class T3Mid: T3Base { |
12386a26 MW |
317 | void base.m0(?int y) { STEP(y); CALL_NEXT_METHOD; } |
318 | void base.m1(?) { STEP(4); CALL_NEXT_METHOD; } | |
319 | } | |
320 | ||
321 | [link = T3Mid, nick = sub] | |
fd040f06 | 322 | class T3Sub: T3Mid { |
bce58d37 MW |
323 | void base.m0(?int z) { STEP(z); CALL_NEXT_METHOD; } |
324 | void base.m1(?int z) { STEP(z); CALL_NEXT_METHOD; } | |
325 | } | |
326 | ||
fd040f06 | 327 | code c: tests { |
bce58d37 MW |
328 | prepare("kwargs"); |
329 | { SOD_DECL(T3Sub, t, NO_KWARGS); | |
12386a26 MW |
330 | T3Base_m0(t, KWARGS(K(z, 0) K(y, 1) K(x, 2))); |
331 | T3Base_m1(t, KWARGS(K(z, 3))); | |
332 | DONE(5); | |
bce58d37 MW |
333 | } |
334 | } | |
335 | ||
4aea4c60 MW |
336 | /*----- Metaclass initialization ------------------------------------------*/ |
337 | ||
338 | [link = SodClass, nick = mycls] | |
339 | class MyClass: SodClass { | |
340 | int x = -1, y, z = 2; | |
341 | } | |
342 | ||
94fd46f5 | 343 | [nick = myobj, metaclass = MyClass] |
4aea4c60 MW |
344 | class MyObject: SodObject { |
345 | class mycls.x = 0, mycls.y = 1; | |
346 | } | |
347 | ||
348 | code c: tests { | |
349 | prepare("metaclass, init"); | |
350 | STEP(MyObject__cls_obj->mycls.x); | |
351 | STEP(MyObject__cls_obj->mycls.y); | |
352 | STEP(MyObject__cls_obj->mycls.z); | |
353 | DONE(3); | |
354 | } | |
355 | ||
4a83289a | 356 | /*----- That's all, folks -------------------------------------------------*/ |