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