1 /* $NetBSD: testsuite.c,v 1.3 2014/12/10 04:37:56 christos Exp $ */
2
3 #ifndef lint
4 static char *rcsid = "$Id";
5 #endif
6
7 /*
8 * Copyright (c) 2002 Japan Network Information Center.
9 * All rights reserved.
10 *
11 * By using this file, you agree to the terms and conditions set forth bellow.
12 *
13 * LICENSE TERMS AND CONDITIONS
14 *
15 * The following License Terms and Conditions apply, unless a different
16 * license is obtained from Japan Network Information Center ("JPNIC"),
17 * a Japanese association, Kokusai-Kougyou-Kanda Bldg 6F, 2-3-4 Uchi-Kanda,
18 * Chiyoda-ku, Tokyo 101-0047, Japan.
19 *
20 * 1. Use, Modification and Redistribution (including distribution of any
21 * modified or derived work) in source and/or binary forms is permitted
22 * under this License Terms and Conditions.
23 *
24 * 2. Redistribution of source code must retain the copyright notices as they
25 * appear in each source code file, this License Terms and Conditions.
26 *
27 * 3. Redistribution in binary form must reproduce the Copyright Notice,
28 * this License Terms and Conditions, in the documentation and/or other
29 * materials provided with the distribution. For the purposes of binary
30 * distribution the "Copyright Notice" refers to the following language:
31 * "Copyright (c) 2000-2002 Japan Network Information Center. All rights reserved."
32 *
33 * 4. The name of JPNIC may not be used to endorse or promote products
34 * derived from this Software without specific prior written approval of
35 * JPNIC.
36 *
37 * 5. Disclaimer/Limitation of Liability: THIS SOFTWARE IS PROVIDED BY JPNIC
38 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
39 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
40 * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL JPNIC BE LIABLE
41 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
42 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
43 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
44 * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
45 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
46 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
47 * ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.
48 */
49
50 #include <stddef.h>
51 #include <stdio.h>
52 #include <stdlib.h>
53 #include <string.h>
54 #include <assert.h>
55
56 #include <idn/result.h>
57 #include <idn/ucs4.h>
58 #include <testsuite.h>
59
60 typedef struct idn_testcase *idn_testcase_t;
61
62 struct idn_testcase {
63 char *title;
64 idn_testsuite_testproc_t proc;
65 };
66
67 struct idn_testsuite {
68 idn_testcase_t testcases;
69 int ntestcases;
70 int testcase_size;
71
72 int npassed;
73 int nfailed;
74 int nskipped;
75 idn_testcase_t current_testcase;
76 idn_teststatus_t current_status;
77
78 idn_testsuite_msgproc_t msgproc;
79 int verbose;
80 };
81
82 #define INITIAL_TESTCASE_SIZE 16
83 #define INITIAL_SETUP_SIZE 4
84 #define INITIAL_TEARDOWN_SIZE 4
85
86 static void run_internal(idn_testsuite_t ctx, char *titles[]);
87 static char *make_hex_string(const char *string);
88 static char *make_hex_ucs4string(const unsigned long *string);
89 static void put_failure_message(idn_testsuite_t ctx, const char *msg,
90 const char *file, int lineno);
91 static void idn_testsuite_msgtostderr(const char *msg);
92
93 int
idn_testsuite_create(idn_testsuite_t * ctxp)94 idn_testsuite_create(idn_testsuite_t *ctxp) {
95 idn_testsuite_t ctx = NULL;
96
97 assert(ctxp != NULL);
98
99 ctx = (idn_testsuite_t) malloc(sizeof(struct idn_testsuite));
100 if (ctx == NULL)
101 goto error;
102
103 ctx->testcases = NULL;
104 ctx->ntestcases = 0;
105 ctx->testcase_size = 0;
106 ctx->npassed = 0;
107 ctx->nfailed = 0;
108 ctx->nskipped = 0;
109 ctx->current_testcase = NULL;
110 ctx->current_status = idn_teststatus_pass;
111 ctx->msgproc = NULL;
112 ctx->verbose = 0;
113
114 ctx->testcases = (idn_testcase_t) malloc(sizeof(struct idn_testcase)
115 * INITIAL_TESTCASE_SIZE);
116 if (ctx->testcases == NULL)
117 goto error;
118 ctx->testcase_size = INITIAL_TESTCASE_SIZE;
119
120 *ctxp = ctx;
121 return (1);
122
123 error:
124 if (ctx != NULL)
125 free(ctx->testcases);
126 free(ctx);
127 return (0);
128 }
129
130 void
idn_testsuite_destroy(idn_testsuite_t ctx)131 idn_testsuite_destroy(idn_testsuite_t ctx) {
132 int i;
133
134 assert(ctx != NULL);
135
136 for (i = 0; i < ctx->ntestcases; i++)
137 free(ctx->testcases[i].title);
138
139 free(ctx->testcases);
140 free(ctx);
141 }
142
143 int
idn_testsuite_addtestcase(idn_testsuite_t ctx,const char * title,idn_testsuite_testproc_t proc)144 idn_testsuite_addtestcase(idn_testsuite_t ctx, const char *title,
145 idn_testsuite_testproc_t proc) {
146 char *dup_title = NULL;
147 idn_testcase_t new_buffer = NULL;
148 idn_testcase_t new_testcase;
149 int new_size;
150
151 assert(ctx != NULL && title != NULL && proc != NULL);
152
153 dup_title = (char *)malloc(strlen(title) + 1);
154 if (dup_title == NULL)
155 goto error;
156 strcpy(dup_title, title);
157
158 if (ctx->ntestcases == ctx->testcase_size) {
159 new_size = ctx->testcase_size + INITIAL_TESTCASE_SIZE;
160 new_buffer = (idn_testcase_t)
161 realloc(ctx->testcases,
162 sizeof(struct idn_testcase) * new_size);
163 if (new_buffer == NULL)
164 goto error;
165 ctx->testcases = new_buffer;
166 ctx->testcase_size = new_size;
167 }
168
169 new_testcase = ctx->testcases + ctx->ntestcases;
170 new_testcase->title = dup_title;
171 new_testcase->proc = proc;
172 ctx->ntestcases++;
173 return (1);
174
175 error:
176 free(dup_title);
177 free(new_buffer);
178 return (0);
179 }
180
181 int
idn_testsuite_ntestcases(idn_testsuite_t ctx)182 idn_testsuite_ntestcases(idn_testsuite_t ctx) {
183 assert(ctx != NULL);
184 return (ctx->ntestcases);
185 }
186
187 void
idn_testsuite_setverbose(idn_testsuite_t ctx)188 idn_testsuite_setverbose(idn_testsuite_t ctx) {
189 assert(ctx != NULL);
190 ctx->verbose = 1;
191 }
192
193 void
idn_testsuite_unsetverbose(idn_testsuite_t ctx)194 idn_testsuite_unsetverbose(idn_testsuite_t ctx) {
195 assert(ctx != NULL);
196 ctx->verbose = 0;
197 }
198
199 static void
run_internal(idn_testsuite_t ctx,char * titles[])200 run_internal(idn_testsuite_t ctx, char *titles[]) {
201 int i, j;
202 int run_testcase;
203 const char *status;
204
205 assert(ctx != NULL);
206
207 ctx->npassed = 0;
208 ctx->nfailed = 0;
209 ctx->nskipped = 0;
210
211 for (i = 0; i < ctx->ntestcases; i++) {
212 ctx->current_testcase = ctx->testcases + i;
213 ctx->current_status = idn_teststatus_pass;
214
215 if (titles == NULL)
216 run_testcase = 1;
217 else {
218 run_testcase = 0;
219 for (j = 0; titles[j] != NULL; j++) {
220 if (strcmp(ctx->current_testcase->title,
221 titles[j]) == 0) {
222 run_testcase = 1;
223 break;
224 }
225 }
226 }
227
228 if (!run_testcase) {
229 ctx->nskipped++;
230 continue;
231 }
232 if (ctx->verbose) {
233 fprintf(stderr, "start testcase %d: %s\n", i + 1,
234 ctx->testcases[i].title);
235 }
236 (ctx->testcases[i].proc)(ctx);
237 status = idn_teststatus_tostring(ctx->current_status);
238 if (ctx->verbose) {
239 fprintf(stderr, "end testcase %d: %s\n", i + 1,
240 status);
241 }
242
243 switch (ctx->current_status) {
244 case idn_teststatus_pass:
245 ctx->npassed++;
246 break;
247 case idn_teststatus_fail:
248 ctx->nfailed++;
249 break;
250 case idn_teststatus_skip:
251 ctx->nskipped++;
252 break;
253 }
254 }
255 }
256
257 void
idn_testsuite_runall(idn_testsuite_t ctx)258 idn_testsuite_runall(idn_testsuite_t ctx) {
259 assert(ctx != NULL);
260 run_internal(ctx, NULL);
261 }
262
263 void
idn_testsuite_run(idn_testsuite_t ctx,char * titles[])264 idn_testsuite_run(idn_testsuite_t ctx, char *titles[]) {
265 assert(ctx != NULL && titles != NULL);
266 run_internal(ctx, titles);
267 }
268
269 int
idn_testsuite_npassed(idn_testsuite_t ctx)270 idn_testsuite_npassed(idn_testsuite_t ctx) {
271 assert(ctx != NULL);
272 return (ctx->npassed);
273 }
274
275 int
idn_testsuite_nfailed(idn_testsuite_t ctx)276 idn_testsuite_nfailed(idn_testsuite_t ctx) {
277 assert(ctx != NULL);
278 return (ctx->nfailed);
279 }
280
281 int
idn_testsuite_nskipped(idn_testsuite_t ctx)282 idn_testsuite_nskipped(idn_testsuite_t ctx) {
283 assert(ctx != NULL);
284 return (ctx->nskipped);
285 }
286
287 idn_teststatus_t
idn_testsuite_getstatus(idn_testsuite_t ctx)288 idn_testsuite_getstatus(idn_testsuite_t ctx) {
289 assert(ctx != NULL);
290 return (ctx->current_status);
291 }
292
293 void
idn_testsuite_setstatus(idn_testsuite_t ctx,idn_teststatus_t status)294 idn_testsuite_setstatus(idn_testsuite_t ctx, idn_teststatus_t status) {
295 assert(ctx != NULL);
296 assert(status == idn_teststatus_pass ||
297 status == idn_teststatus_fail ||
298 status == idn_teststatus_skip);
299
300 ctx->current_status = status;
301 }
302
303 const char *
idn_teststatus_tostring(idn_teststatus_t status)304 idn_teststatus_tostring(idn_teststatus_t status) {
305 assert(status == idn_teststatus_pass ||
306 status == idn_teststatus_fail ||
307 status == idn_teststatus_skip);
308
309 switch (status) {
310 case idn_teststatus_pass:
311 return "pass";
312 break;
313 case idn_teststatus_fail:
314 return "failed";
315 break;
316 case idn_teststatus_skip:
317 return "skipped";
318 break;
319 }
320
321 return "unknown";
322 }
323
324 void
idn_testsuite_assert(idn_testsuite_t ctx,const char * msg,const char * file,int lineno)325 idn_testsuite_assert(idn_testsuite_t ctx, const char *msg,
326 const char *file, int lineno) {
327 assert(ctx != NULL && msg != NULL && file != NULL);
328
329 if (idn_testsuite_getstatus(ctx) != idn_teststatus_pass)
330 return;
331 idn_testsuite_setstatus(ctx, idn_teststatus_fail);
332 put_failure_message(ctx, msg, file, lineno);
333 }
334
335 void
idn_testsuite_assertint(idn_testsuite_t ctx,int gotten,int expected,const char * file,int lineno)336 idn_testsuite_assertint(idn_testsuite_t ctx, int gotten, int expected,
337 const char *file, int lineno) {
338 char msg[256]; /* large enough */
339
340 assert(ctx != NULL && file != NULL);
341
342 if (idn_testsuite_getstatus(ctx) != idn_teststatus_pass)
343 return;
344 if (expected == gotten)
345 return;
346 idn_testsuite_setstatus(ctx, idn_teststatus_fail);
347
348 sprintf(msg, "`%d' expected, but got `%d'", expected, gotten);
349 put_failure_message(ctx, msg, file, lineno);
350 }
351
352 void
idn_testsuite_assertstring(idn_testsuite_t ctx,const char * gotten,const char * expected,const char * file,int lineno)353 idn_testsuite_assertstring(idn_testsuite_t ctx,
354 const char *gotten, const char *expected,
355 const char *file, int lineno) {
356 char *expected_hex = NULL;
357 char *gotten_hex = NULL;
358 char *msg;
359
360 assert(ctx != NULL && gotten != NULL && expected != NULL &&
361 file != NULL);
362
363 if (idn_testsuite_getstatus(ctx) != idn_teststatus_pass)
364 return;
365 if (strcmp(expected, gotten) == 0)
366 return;
367 idn_testsuite_setstatus(ctx, idn_teststatus_fail);
368
369 msg = (char *)malloc(strlen(expected) * 4 + strlen(gotten) * 4 + 32);
370 expected_hex = make_hex_string(expected);
371 gotten_hex = make_hex_string(gotten);
372 if (msg == NULL || expected_hex == NULL || gotten_hex == NULL) {
373 msg = "";
374 } else {
375 sprintf(msg, "`%s' expected, but got `%s'",
376 expected_hex, gotten_hex);
377 }
378
379 put_failure_message(ctx, msg, file, lineno);
380
381 free(msg);
382 free(expected_hex);
383 free(gotten_hex);
384 }
385
386 void
idn_testsuite_assertptr(idn_testsuite_t ctx,const void * gotten,const void * expected,const char * file,int lineno)387 idn_testsuite_assertptr(idn_testsuite_t ctx, const void *gotten,
388 const void *expected, const char *file, int lineno) {
389 char *msg;
390
391 assert(ctx != NULL && file != NULL);
392
393 if (idn_testsuite_getstatus(ctx) != idn_teststatus_pass)
394 return;
395 if (expected == gotten)
396 return;
397 idn_testsuite_setstatus(ctx, idn_teststatus_fail);
398
399 if (expected == NULL)
400 msg = "NULL expected, but got non-NULL";
401 else if (gotten == NULL)
402 msg = "non-NULL expected, but got NULL";
403 else
404 msg = "expected pointer != gotten pointer";
405 put_failure_message(ctx, msg, file, lineno);
406 }
407
408 void
idn_testsuite_assertptrne(idn_testsuite_t ctx,const void * gotten,const void * unexpected,const char * file,int lineno)409 idn_testsuite_assertptrne(idn_testsuite_t ctx,
410 const void *gotten, const void *unexpected,
411 const char *file, int lineno) {
412 char *msg;
413
414 assert(ctx != NULL && file != NULL);
415
416 if (idn_testsuite_getstatus(ctx) != idn_teststatus_pass)
417 return;
418 if (unexpected != gotten)
419 return;
420 idn_testsuite_setstatus(ctx, idn_teststatus_fail);
421
422 if (unexpected == NULL)
423 msg = "non-NULL unexpected, but got NULL";
424 else if (gotten == NULL)
425 msg = "non-NULL expected, but got NULL";
426 else
427 msg = "expected pointer == gotten pointer";
428 put_failure_message(ctx, msg, file, lineno);
429 }
430
431 void
idn_testsuite_assertresult(idn_testsuite_t ctx,idn_result_t gotten,idn_result_t expected,const char * file,int lineno)432 idn_testsuite_assertresult(idn_testsuite_t ctx,
433 idn_result_t gotten, idn_result_t expected,
434 const char *file, int lineno) {
435 char msg[256]; /* large enough */
436
437 assert(ctx != NULL && file != NULL);
438
439 if (idn_testsuite_getstatus(ctx) != idn_teststatus_pass)
440 return;
441 if (expected == gotten)
442 return;
443 idn_testsuite_setstatus(ctx, idn_teststatus_fail);
444
445 sprintf(msg, "`%s' expected, but got `%s'",
446 idn_result_tostring(expected), idn_result_tostring(gotten));
447 put_failure_message(ctx, msg, file, lineno);
448 }
449
450 void
idn_testsuite_assertucs4string(idn_testsuite_t ctx,const unsigned long * gotten,const unsigned long * expected,const char * file,int lineno)451 idn_testsuite_assertucs4string(idn_testsuite_t ctx,
452 const unsigned long *gotten,
453 const unsigned long *expected,
454 const char *file, int lineno) {
455 char *expected_hex = NULL;
456 char *gotten_hex = NULL;
457 char *msg;
458
459 assert(ctx != NULL && gotten != NULL && expected != NULL &&
460 file != NULL);
461
462 if (idn_testsuite_getstatus(ctx) != idn_teststatus_pass)
463 return;
464 if (idn_ucs4_strcmp(expected, gotten) == 0)
465 return;
466 idn_testsuite_setstatus(ctx, idn_teststatus_fail);
467
468 msg = (char *)malloc(idn_ucs4_strlen(expected) * 8 +
469 idn_ucs4_strlen(gotten) * 8 + 32);
470 expected_hex = make_hex_ucs4string(expected);
471 gotten_hex = make_hex_ucs4string(gotten);
472 if (msg == NULL || expected_hex == NULL || gotten_hex == NULL) {
473 msg = "";
474 } else {
475 sprintf(msg, "`%s' expected, but got `%s'",
476 expected_hex, gotten_hex);
477 }
478
479 put_failure_message(ctx, msg, file, lineno);
480
481 free(msg);
482 free(expected_hex);
483 free(gotten_hex);
484 }
485
486 static char *
make_hex_string(const char * string)487 make_hex_string(const char *string) {
488 static const char hex[] = {"0123456789abcdef"};
489 char *hex_string;
490 const char *src;
491 char *dst;
492
493 hex_string = (char *)malloc((strlen(string)) * 4 + 1);
494 if (hex_string == NULL)
495 return NULL;
496
497 for (src = string, dst = hex_string; *src != '\0'; src++) {
498 if (0x20 <= *src && *src <= 0x7e && *src != '\\') {
499 *dst++ = *src;
500 } else {
501 *dst++ = '\\';
502 *dst++ = 'x';
503 *dst++ = hex[*(const unsigned char *)src >> 4];
504 *dst++ = hex[*src & 0x0f];
505 }
506 }
507 *dst = '\0';
508
509 return hex_string;
510 }
511
512 #define UCS4_MAX 0x10fffffUL
513
514 static char *
make_hex_ucs4string(const unsigned long * string)515 make_hex_ucs4string(const unsigned long *string) {
516 static const char hex[] = {"0123456789abcdef"};
517 char *hex_string;
518 const unsigned long *src;
519 char *dst;
520
521 hex_string = (char *)malloc((idn_ucs4_strlen(string)) * 8 + 1);
522 if (hex_string == NULL)
523 return NULL;
524
525 for (src = string, dst = hex_string; *src != '\0'; src++) {
526 if (0x20 <= *src && *src <= 0x7e && *src != '\\') {
527 *dst++ = *src;
528 } else if (*src <= UCS4_MAX) {
529 *dst++ = '\\';
530 *dst++ = 'u';
531 if (*src >= 0x100000) {
532 *dst++ = hex[(*src >> 20) & 0x0f];
533 }
534 if (*src >= 0x10000) {
535 *dst++ = hex[(*src >> 16) & 0x0f];
536 }
537 *dst++ = hex[(*src >> 12) & 0x0f];
538 *dst++ = hex[(*src >> 8) & 0x0f];
539 *dst++ = hex[(*src >> 4) & 0x0f];
540 *dst++ = hex[*src & 0x0f];
541 } else {
542 *dst++ = '\\';
543 *dst++ = 'u';
544 *dst++ = '?';
545 *dst++ = '?';
546 *dst++ = '?';
547 *dst++ = '?';
548 }
549 }
550 *dst = '\0';
551
552 return hex_string;
553 }
554
555 static void
put_failure_message(idn_testsuite_t ctx,const char * msg,const char * file,int lineno)556 put_failure_message(idn_testsuite_t ctx, const char *msg, const char *file,
557 int lineno) {
558 idn_testsuite_msgproc_t proc;
559 char buffer[256];
560 const char *title;
561
562 proc = (ctx->msgproc == NULL) ?
563 idn_testsuite_msgtostderr : ctx->msgproc;
564 title = (ctx->current_testcase != NULL &&
565 ctx->current_testcase->title != NULL) ?
566 ctx->current_testcase->title : "anonymous";
567
568 sprintf(buffer, "%.100s: In test `%.100s':", file, title);
569 (*proc)(buffer);
570
571 sprintf(buffer, "%.100s:%d: failed (%.100s)", file, lineno, msg);
572 (*proc)(buffer);
573 }
574
575
576 static void
idn_testsuite_msgtostderr(const char * msg)577 idn_testsuite_msgtostderr(const char *msg) {
578 fputs(msg, stderr);
579 fputc('\n', stderr);
580 }
581