00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021 #include "common.h"
00022
00023 #include <stdio.h>
00024 #include <math.h>
00025 #include <string.h>
00026 #include <errno.h>
00027
00028 #include "bu.h"
00029 #include "vmath.h"
00030 #include "bn.h"
00031
00032 #define USAGE "Usage: bntester [-l test_case_line_number] [-f function_number] -i input_file [-o output_file]\n"
00033
00034
00035 int
00036 parse_case(char *buf_p, int *i, long *l, double *d, unsigned long *u, char *fmt_str, unsigned long line_num, FILE *stream)
00037 {
00038 int i_idx = 0;
00039 int l_idx = 0;
00040 int d_idx = 0;
00041 int u_idx = 1;
00042 int idx;
00043 int fmt_str_len;
00044 char *endp;
00045 long int l_tmp;
00046
00047 fmt_str_len = strlen(fmt_str);
00048
00049 for (idx = 0 ; idx < fmt_str_len ; idx++) {
00050 buf_p = strtok(NULL, ", ");
00051
00052
00053
00054
00055
00056 if (buf_p == NULL) {
00057 (void)fprintf(stream, "ERROR: Missing parameter(s) for test case on line %lu, skipping test case.\n", line_num);
00058 return EXIT_FAILURE;
00059 }
00060
00061 errno = 0;
00062 switch (fmt_str[idx]) {
00063 case 'd' :
00064 d[d_idx] = strtod(buf_p, &endp);
00065 if (errno) {
00066 (void)fprintf(stream, "Convert to double failed, function %lu test case on line %lu parameter %d error msg: '%s' string '%s'\n",
00067 u[0], line_num, idx+2, strerror(errno), buf_p);
00068 return EXIT_FAILURE;
00069 }
00070 if ((*endp != '\0') || (buf_p == endp)) {
00071 (void)fprintf(stream, "Convert to double failed, function %lu test case on line %lu parameter %d string '%s'\n",
00072 u[0], line_num, idx+2, buf_p);
00073 return EXIT_FAILURE;
00074 }
00075 d_idx++;
00076 break;
00077 case 'l' :
00078 l[l_idx] = strtol(buf_p, &endp, 10);
00079 if (errno) {
00080 (void)fprintf(stream, "Convert to long int failed, function %lu test case on line %lu parameter %d error msg: '%s' string '%s'\n",
00081 u[0], line_num, idx+2, strerror(errno), buf_p);
00082 return EXIT_FAILURE;
00083 }
00084 if ((*endp != '\0') || (buf_p == endp)) {
00085 (void)fprintf(stream, "Convert to long int failed, function %lu test case on line %lu parameter %d string '%s'\n",
00086 u[0], line_num, idx+2, buf_p);
00087 return EXIT_FAILURE;
00088 }
00089 l_idx++;
00090 break;
00091 case 'i' :
00092 l_tmp = strtol(buf_p, &endp, 10);
00093 if (errno) {
00094 (void)fprintf(stream, "Convert to int failed, function %lu test case on line %lu parameter %d error msg: '%s' string '%s'\n",
00095 u[0], line_num, idx+2, strerror(errno), buf_p);
00096 return EXIT_FAILURE;
00097 }
00098 if ((*endp != '\0') || (buf_p == endp)) {
00099 (void)fprintf(stream, "Convert to int failed, function %lu test case on line %lu parameter %d string '%s'\n",
00100 u[0], line_num, idx+2, buf_p);
00101 return EXIT_FAILURE;
00102 }
00103 if (l_tmp > INT_MAX || l_tmp < INT_MIN) {
00104 (void)fprintf(stream, "Convert to int failed (under/over flow), function %lu test case on line %lu parameter %d string '%s'\n",
00105 u[0], line_num, idx+2, buf_p);
00106 return EXIT_FAILURE;
00107 }
00108 i[i_idx] = (int)l_tmp;
00109 i_idx++;
00110 break;
00111 case 'u' :
00112 u[u_idx] = strtoul(buf_p, &endp, 10);
00113 if (errno) {
00114 (void)fprintf(stream, "Convert to unsigned long int failed, function %lu test case on line %lu parameter %d error msg: '%s' string '%s'\n",
00115 u[0], line_num, idx+2, strerror(errno), buf_p);
00116 return EXIT_FAILURE;
00117 }
00118 if ((*endp != '\0') || (buf_p == endp) || (strchr(buf_p, '-') != '\0')) {
00119 (void)fprintf(stream, "Convert to unsigned long int failed, function %lu test case on line %lu parameter %d string '%s'\n",
00120 u[0], line_num, idx+2, buf_p);
00121 return EXIT_FAILURE;
00122 }
00123 u_idx++;
00124 break;
00125 default:
00126 (void)fprintf(stream, "INTERNAL ERROR: Unknown data type '%c' for function %lu test case on line %lu, skipping test case.\n",
00127 fmt_str[idx], u[0], line_num);
00128 return EXIT_FAILURE;
00129 break;
00130 }
00131 }
00132
00133 return 0;
00134 }
00135
00136
00137 int
00138 main(int argc, char **argv)
00139 {
00140
00141 static FILE *stream = NULL;
00142 static unsigned long line_num = 0;
00143 static unsigned long failed_cnt = 0;
00144 static unsigned long bomb_cnt = 0;
00145 static unsigned long success_cnt = 0;
00146 static int ret = 0;
00147
00148 char buf[BUFSIZ];
00149 FILE *fp_in = NULL;
00150 char *endp = NULL;
00151 int string_length;
00152 int argv_idx;
00153 int c;
00154 char dt_fmt[50];
00155 char *buf_p1;
00156 char *buf_p;
00157 struct bn_tol tol;
00158
00159
00160 static unsigned long test_case_line_num = 0;
00161 static unsigned long function_num = 0;
00162 struct bu_vls input_file_name = BU_VLS_INIT_ZERO;
00163 struct bu_vls output_file_name = BU_VLS_INIT_ZERO;
00164
00165
00166 int i[50] = {0};
00167 long l[50] = {0};
00168 double d[50] = {0.0};
00169 unsigned long u[50] = {0};
00170
00171
00172 static int output_file_name_defined = 0;
00173 static int process_single_test_case = 0;
00174 static int process_single_function = 0;
00175 int input_file_name_defined = 0;
00176 int valid_function_number = 0;
00177 int process_test_case = 0;
00178 int early_exit = 0;
00179 int found_eof = 0;
00180
00181
00182 tol.magic = BN_TOL_MAGIC;
00183 tol.dist = 0.0005;
00184 tol.dist_sq = tol.dist * tol.dist;
00185 tol.perp = 1e-6;
00186 tol.para = 1.0 - tol.perp;
00187
00188
00189 if (argc < 2) {
00190 bu_log("Too few parameters, %d specified, at least 1 required\n", argc - 1);
00191 bu_exit(EXIT_FAILURE, USAGE);
00192 }
00193
00194 while ((c = bu_getopt(argc, argv, "l:f:i:o:")) != -1) {
00195 switch (c) {
00196 case 'l':
00197 errno = 0;
00198 test_case_line_num = strtoul(bu_optarg, &endp, 10);
00199 if (errno) {
00200 bu_log("Invalid test case line number '%s' '%s'\n", bu_optarg, strerror(errno));
00201 bu_exit(EXIT_FAILURE, USAGE);
00202 }
00203 if ((*endp != '\0') || (bu_optarg == endp) || (strchr(bu_optarg, '-') != '\0')) {
00204 bu_log("Invalid test case line number '%s'\n", bu_optarg);
00205 bu_exit(EXIT_FAILURE, USAGE);
00206 }
00207 process_single_test_case = 1;
00208 break;
00209 case 'f':
00210 errno = 0;
00211 function_num = strtoul(bu_optarg, &endp, 10);
00212 if (errno) {
00213 bu_log("Invalid function number '%s' '%s'\n", bu_optarg, strerror(errno));
00214 bu_exit(EXIT_FAILURE, USAGE);
00215 }
00216 if ((*endp != '\0') || (bu_optarg == endp) || (strchr(bu_optarg, '-') != '\0')) {
00217 bu_log("Invalid function number '%s'\n", bu_optarg);
00218 bu_exit(EXIT_FAILURE, USAGE);
00219 }
00220 process_single_function = 1;
00221 break;
00222 case 'i':
00223 string_length = strlen(bu_optarg);
00224 if (string_length >= BUFSIZ) {
00225 bu_log("Input file name too long, length was %d but must be less than %d\n",
00226 string_length, BUFSIZ);
00227 bu_exit(EXIT_FAILURE, USAGE);
00228 }
00229 bu_vls_strcpy(&input_file_name, bu_optarg);
00230 input_file_name_defined = 1;
00231 break;
00232 case 'o':
00233 string_length = strlen(bu_optarg);
00234 if (string_length >= BUFSIZ) {
00235 bu_log("Output file name too long, length was %d but must be less than %d\n",
00236 string_length, BUFSIZ);
00237 bu_exit(EXIT_FAILURE, USAGE);
00238 }
00239 bu_vls_strcpy(&output_file_name, bu_optarg);
00240 output_file_name_defined = 1;
00241 break;
00242 default:
00243 bu_log("Invalid option '%c'.\n", c);
00244 bu_exit(EXIT_FAILURE, USAGE);
00245 break;
00246 }
00247 }
00248
00249 if (process_single_test_case && process_single_function) {
00250 bu_log("Can not specify both test case line number and function number.\n");
00251 early_exit = 1;
00252 }
00253
00254 if (!input_file_name_defined) {
00255 bu_log("Input file name is required but was not specified.\n");
00256 early_exit = 1;
00257 }
00258
00259 if (early_exit) {
00260 bu_vls_free(&input_file_name);
00261 bu_vls_free(&output_file_name);
00262 bu_exit(EXIT_FAILURE, USAGE);
00263 }
00264
00265 if ((fp_in = fopen(bu_vls_addr(&input_file_name), "r")) == NULL) {
00266 bu_log("Cannot open input file (%V)\n", &input_file_name);
00267 bu_vls_free(&input_file_name);
00268 bu_vls_free(&output_file_name);
00269 return EXIT_FAILURE;
00270 }
00271
00272
00273 if (output_file_name_defined) {
00274 if ((stream = fopen(bu_vls_addr(&output_file_name), "w")) == NULL) {
00275 bu_log("Cannot create output file (%V)\n", &output_file_name);
00276 if (fclose(fp_in) != 0) {
00277 bu_log("Unable to close input file.\n");
00278 }
00279 bu_vls_free(&input_file_name);
00280 bu_vls_free(&output_file_name);
00281 return EXIT_FAILURE;
00282 }
00283 } else {
00284 stream = stderr;
00285 }
00286
00287
00288
00289 (void)fprintf(stream, "Command line parameters: bntester ");
00290 for (argv_idx = 1 ; argv_idx < argc ; argv_idx++) {
00291 (void)fprintf(stream, "%s ", argv[argv_idx]);
00292 }
00293 (void)fprintf(stream, "\n");
00294
00295 if (process_single_test_case) {
00296 (void)fprintf(stream, "Processing only test case on line number: %lu\n", test_case_line_num);
00297 }
00298
00299 if (process_single_function) {
00300 (void)fprintf(stream, "Processing all test cases for function number: %lu\n", function_num);
00301 }
00302
00303 if (!process_single_test_case && !process_single_function) {
00304 (void)fprintf(stream, "Processing all test cases.\n");
00305 }
00306
00307
00308 while (!found_eof) {
00309 if (line_num == ULONG_MAX) {
00310 (void)fprintf(stream, "ERROR: Input data file exceeded max %lu number of lines.\n", ULONG_MAX);
00311 if (fclose(fp_in) != 0) {
00312 (void)fprintf(stream, "Unable to close input file.\n");
00313 }
00314 if (output_file_name_defined) {
00315 if (fclose(stream) != 0) {
00316 bu_log("Unable to close output file.\n");
00317 }
00318 }
00319 bu_vls_free(&input_file_name);
00320 bu_vls_free(&output_file_name);
00321 return EXIT_FAILURE;
00322 }
00323 line_num++;
00324 if (bu_fgets(buf, BUFSIZ, fp_in) == NULL) {
00325 if (feof(fp_in)) {
00326 found_eof = 1;
00327 continue;
00328 }
00329 if (ferror(fp_in)) {
00330 perror("ERROR: Problem reading file, system error message");
00331 if (fclose(fp_in) != 0) {
00332 (void)fprintf(stream, "Unable to close input file.\n");
00333 }
00334 } else {
00335 perror("Oddness reading input file");
00336 }
00337 bu_vls_free(&input_file_name);
00338 bu_vls_free(&output_file_name);
00339 return EXIT_FAILURE;
00340 } else {
00341
00342
00343
00344 if ((buf[0] != '#') && (buf[0] != '\n')) {
00345 buf_p1 = strtok(buf, "\n");
00346 buf_p = strtok(buf_p1, ", ");
00347
00348
00349
00350
00351
00352
00353 valid_function_number = 1;
00354 errno = 0;
00355 u[0] = strtoul(buf_p, &endp, 10);
00356 if (errno) {
00357 (void)fprintf(stream, "Read function number failed, line %lu error msg: '%s' string '%s'\n",
00358 line_num, strerror(errno), buf_p);
00359 valid_function_number = 0;
00360 } else if ((*endp != '\0') || (buf_p == endp) || (strchr(buf_p, '-') != '\0')) {
00361 (void)fprintf(stream, "Read function number failed, line %lu string '%s'\n", line_num, buf_p);
00362 valid_function_number = 0;
00363 }
00364
00365
00366
00367
00368 process_test_case = 0;
00369 if (valid_function_number && process_single_test_case && (test_case_line_num == line_num)) {
00370 process_test_case = 1;
00371 } else if (valid_function_number && process_single_function && (function_num == u[0])) {
00372 process_test_case = 1;
00373 } else if (valid_function_number && !process_single_test_case && !process_single_function) {
00374 process_test_case = 1;
00375 }
00376
00377 if (process_test_case) {
00378
00379
00380
00381 switch (u[0]) {
00382 case 1:
00383 bu_strlcpy(dt_fmt, "dddddddddd", sizeof(dt_fmt));
00384 if (parse_case(buf_p, i, l, d, u, dt_fmt, line_num, stream)) {
00385
00386 ret = 1;
00387 } else {
00388 double result;
00389 if (!BU_SETJUMP) {
00390
00391 result = bn_distsq_line3_pt3(&d[0], &d[3], &d[6]);
00392 if (!NEAR_EQUAL(result, d[9], VUNITIZE_TOL)) {
00393 ret = 1;
00394 failed_cnt++;
00395 (void)fprintf(stream, "Failed function %lu test case on line %lu expected = %.15f result = %.15f\n",
00396 u[0], line_num, d[9], result);
00397 } else {
00398 success_cnt++;
00399 }
00400 } else {
00401
00402 BU_UNSETJUMP;
00403 ret = 1;
00404 bomb_cnt++;
00405 (void)fprintf(stream, "Failed function %lu test case on line %lu bu_bomb encountered.\n", u[0], line_num);
00406 } BU_UNSETJUMP;
00407 }
00408 break;
00409 case 2:
00410 bu_strlcpy(dt_fmt, "ddddddddddddduddddi", sizeof(dt_fmt));
00411 if (parse_case(buf_p, i, l, d, u, dt_fmt, line_num, stream)) {
00412
00413 ret = 1;
00414 } else {
00415 int result;
00416 if (!BU_SETJUMP) {
00417
00418 tol.magic = u[1];
00419 tol.dist = d[13];
00420 tol.dist_sq = d[14];
00421 tol.perp = d[15];
00422 tol.para = d[16];
00423 result = bn_2line3_colinear(&d[0], &d[3], &d[6], &d[9], d[12], &tol);
00424 if (result != i[0]) {
00425 ret = 1;
00426 failed_cnt++;
00427 (void)fprintf(stream, "Failed function %lu test case on line %lu expected = %d result = %d\n",
00428 u[0], line_num, i[0], result);
00429 } else {
00430 success_cnt++;
00431 }
00432 } else {
00433
00434 BU_UNSETJUMP;
00435 ret = 1;
00436 bomb_cnt++;
00437 (void)fprintf(stream, "Failed function %lu test case on line %lu bu_bomb encountered.\n", u[0], line_num);
00438 } BU_UNSETJUMP;
00439 }
00440 break;
00441 case 3:
00442 bu_strlcpy(dt_fmt, "dddddddddddddduddddi", sizeof(dt_fmt));
00443 if (parse_case(buf_p, i, l, d, u, dt_fmt, line_num, stream)) {
00444
00445 ret = 1;
00446 } else {
00447 int result;
00448 double t_out = 0.0;
00449 double u_out = 0.0;
00450 int t_fail = 0;
00451 int u_fail = 0;
00452
00453 if (!BU_SETJUMP) {
00454
00455 tol.magic = u[1];
00456 tol.dist = d[14];
00457 tol.dist_sq = d[15];
00458 tol.perp = d[16];
00459 tol.para = d[17];
00460 result = bn_isect_line3_line3(&t_out, &u_out, &d[2], &d[5], &d[8], &d[11], &tol);
00461 if (result != i[0]) {
00462 ret = 1;
00463 failed_cnt++;
00464 (void)fprintf(stream, "Failed function %lu test case on line %lu expected = %d result = %d\n",
00465 u[0], line_num, i[0], result);
00466 } else if (result == 0) {
00467 if (!NEAR_EQUAL(t_out, d[0], tol.dist)) {
00468 ret = 1;
00469 failed_cnt++;
00470 (void)fprintf(stream, "Failed function %lu test case on line %lu result = %d expected t = %.15f result t = %.15f\n",
00471 u[0], line_num, result, d[0], t_out);
00472 } else {
00473 success_cnt++;
00474 }
00475 } else if (result == 1) {
00476 t_fail = !NEAR_EQUAL(t_out, d[0], tol.dist);
00477 u_fail = !NEAR_EQUAL(u_out, d[1], tol.dist);
00478 if (t_fail) {
00479 (void)fprintf(stream, "Failed function %lu test case on line %lu result = %d expected t = %.15f result t = %.15f\n",
00480 u[0], line_num, result, d[0], t_out);
00481 }
00482 if (u_fail) {
00483 (void)fprintf(stream, "Failed function %lu test case on line %lu result = %d expected u = %.15f result u = %.15f\n",
00484 u[0], line_num, result, d[1], u_out);
00485 }
00486 if (t_fail || u_fail) {
00487 ret = 1;
00488 failed_cnt++;
00489 } else {
00490
00491
00492
00493 success_cnt++;
00494 }
00495 } else {
00496 success_cnt++;
00497 }
00498 } else {
00499
00500 BU_UNSETJUMP;
00501 ret = 1;
00502 bomb_cnt++;
00503 (void)fprintf(stream, "Failed function %lu test case on line %lu bu_bomb encountered.\n", u[0], line_num);
00504 } BU_UNSETJUMP;
00505 }
00506 break;
00507 case 4:
00508 bu_strlcpy(dt_fmt, "dddddddddddddduddddi", sizeof(dt_fmt));
00509 if (parse_case(buf_p, i, l, d, u, dt_fmt, line_num, stream)) {
00510
00511 ret = 1;
00512 } else {
00513 int result;
00514 double dist[2] = {0.0, 0.0};
00515 int d0_fail = 0;
00516 int d1_fail = 0;
00517
00518 if (!BU_SETJUMP) {
00519
00520 tol.magic = u[1];
00521 tol.dist = d[14];
00522 tol.dist_sq = d[15];
00523 tol.perp = d[16];
00524 tol.para = d[17];
00525 result = bn_isect_lseg3_lseg3(&dist[0], &d[2], &d[5], &d[8], &d[11], &tol);
00526 if (result != i[0]) {
00527 ret = 1;
00528 failed_cnt++;
00529 (void)fprintf(stream, "Failed function %lu test case on line %lu expected = %d result = %d\n",
00530 u[0], line_num, i[0], result);
00531 } else if (result == 0 || result == 1) {
00532 d0_fail = !NEAR_EQUAL(dist[0], d[0], VUNITIZE_TOL);
00533 d1_fail = !NEAR_EQUAL(dist[1], d[1], VUNITIZE_TOL);
00534 if (d0_fail) {
00535 (void)fprintf(stream, "Failed function %lu test case on line %lu result = %d expected dist[0] = %.15f result dist[0] = %.15f\n",
00536 u[0], line_num, result, d[0], dist[0]);
00537 }
00538 if (d1_fail) {
00539 (void)fprintf(stream, "Failed function %lu test case on line %lu result = %d expected dist[1] = %.15f result dist[1] = %.15f\n",
00540 u[0], line_num, result, d[1], dist[1]);
00541 }
00542 if (d0_fail || d1_fail) {
00543 ret = 1;
00544 failed_cnt++;
00545 } else {
00546
00547
00548
00549 success_cnt++;
00550 }
00551 } else {
00552 success_cnt++;
00553 }
00554 } else {
00555
00556 BU_UNSETJUMP;
00557 ret = 1;
00558 bomb_cnt++;
00559 (void)fprintf(stream, "Failed function %lu test case on line %lu bu_bomb encountered.\n", u[0], line_num);
00560 } BU_UNSETJUMP;
00561 }
00562 break;
00563 default:
00564 (void)fprintf(stream, "ERROR: Unknown function number %lu test case on line %lu, skipping test case.\n", u[0], line_num);
00565 bu_vls_free(&input_file_name);
00566 bu_vls_free(&output_file_name);
00567 return EXIT_FAILURE;
00568 break;
00569 }
00570 }
00571 }
00572 }
00573 }
00574
00575 (void)fprintf(stream, "Summary: %lu total test cases success.\n", success_cnt);
00576 (void)fprintf(stream, "Summary: %lu total test cases failed.\n", failed_cnt);
00577 (void)fprintf(stream, "Summary: %lu total test cases bomb.\n", bomb_cnt);
00578
00579 if (output_file_name_defined) {
00580 bu_log("Summary: %lu total test cases success.\n", success_cnt);
00581 bu_log("Summary: %lu total test cases failed.\n", failed_cnt);
00582 bu_log("Summary: %lu total test cases bomb.\n", bomb_cnt);
00583 }
00584
00585 (void)fprintf(stream, "Done.\n");
00586
00587 if (output_file_name_defined) {
00588 bu_log("Done.\n");
00589 }
00590
00591 if (fclose(fp_in) != 0) {
00592 (void)fprintf(stream, "Unable to close input file.\n");
00593 }
00594
00595 if (output_file_name_defined) {
00596 if (fclose(stream) != 0) {
00597 bu_log("Unable to close output file.\n");
00598 }
00599 }
00600
00601 bu_vls_free(&input_file_name);
00602 bu_vls_free(&output_file_name);
00603
00604 return ret;
00605 }
00606
00607
00608
00609
00610
00611
00612
00613
00614
00615
00616
00617