xref: /minix3/external/bsd/bind/dist/contrib/idn/idnkit-1.0-src/lib/tests/testsuite.c (revision 00b67f09dd46474d133c95011a48590a8e8f94c7)
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