Revision: 41748
http://brlcad.svn.sourceforge.net/brlcad/?rev=41748&view=rev
Author: r_weiss
Date: 2010-12-21 21:48:44 +0000 (Tue, 21 Dec 2010)
Log Message:
-----------
Updated the 'bntester' tool used to test 'libbn' functions. The basic framework
is complete and has been setup to test the 'bn_distsq_line3_pt3' function (i.e.
function number 1). Additional 'libbn' functions can be added as necessary.
Modified Paths:
--------------
brlcad/trunk/src/libbn/bntester.c
Modified: brlcad/trunk/src/libbn/bntester.c
===================================================================
--- brlcad/trunk/src/libbn/bntester.c 2010-12-21 21:23:20 UTC (rev 41747)
+++ brlcad/trunk/src/libbn/bntester.c 2010-12-21 21:48:44 UTC (rev 41748)
@@ -23,65 +23,111 @@
#include <stdio.h>
#include <math.h>
#include <string.h>
+#include <errno.h>
#include "bu.h"
#include "vmath.h"
#include "bn.h"
+static char *usage="Usage: bntester [-l test_case_line_number] [-f
function_number] -i input_file [-o output_file]\n";
-static char *usage="Usage: bntester [-c test_case_number] [-f function_number]
-i input_file -o output_file\n";
-
int
-parse_case(char *buf_p, long *l, double *d, char *fmt_str, int line_num, int
case_idx)
+parse_case(char *buf_p, int *i, long *l, double *d, unsigned long *u, char
*fmt_str, unsigned long line_num, FILE *stream)
{
- int l_idx;
- int d_idx;
+ int i_idx = 0;
+ int l_idx = 0;
+ int d_idx = 0;
+ int u_idx = 1; /* start index at 1 since function number is stored at 0 */
int idx;
int fmt_str_len;
char *endp;
+ long int l_tmp;
fmt_str_len = strlen(fmt_str);
for (idx = 0 ; idx < fmt_str_len ; idx++) {
buf_p = strtok(NULL, ",");
- if ((buf_p == NULL) && (idx != fmt_str_len-1)) {
- bu_log("missing parameter(s) for test case %d on line %d\n",
case_idx, line_num);
+ /* The variable buf_p should never become NULL since the for loop
+ * will exit just before we run out of data if all the required
+ * data is supplied in the data file.
+ */
+ if (buf_p == NULL) {
+ (void)fprintf(stream, "ERROR: Missing parameter(s) for test case
on line %lu, skipping test case.\n", line_num);
return EXIT_FAILURE;
}
+ errno = 0;
switch (fmt_str[idx]) {
case 'd' : /* double */
d[d_idx] = strtod(buf_p, &endp);
- if (!((buf_p != endp) && (*endp == '\0'))) {
- /* 2 is added to idx since the user numbers the parameters
- * starting with 1 but internally they start at 0, also idx
- * starts a the 2nd parameter in the data file since the
first
- * parameter is always the function number, so we need to
add
- * again to the idx to correspond to the parameter in the
data
- * file
- */
- bu_log("Convert to double failed, line %d test case %d
parameter %d string '%s'\n",
- line_num, case_idx, idx+2, buf_p);
+ if (errno) {
+ (void)fprintf(stream, "Convert to double failed, function
%lu test case on line %lu parameter %d error msg: '%s' string '%s'\n",
+ u[0], line_num, idx+2, strerror(errno), buf_p);
return EXIT_FAILURE;
}
+ if ((*endp != '\0') || (buf_p == endp)) {
+ (void)fprintf(stream, "Convert to double failed, function
%lu test case on line %lu parameter %d string '%s'\n",
+ u[0], line_num, idx+2, buf_p);
+ return EXIT_FAILURE;
+ }
d_idx++;
break;
case 'l' : /* long int */
l[l_idx] = strtol(buf_p, &endp, 10);
- if (!((buf_p != endp) && (*endp == '\0'))) {
- bu_log("Convert to long int failed, line %d test case %d
parameter %d string '%s'\n",
- line_num, case_idx, idx+2, buf_p);
+ if (errno) {
+ (void)fprintf(stream, "Convert to long int failed,
function %lu test case on line %lu parameter %d error msg: '%s' string '%s'\n",
+ u[0], line_num, idx+2, strerror(errno), buf_p);
return EXIT_FAILURE;
}
+ if ((*endp != '\0') || (buf_p == endp)) {
+ (void)fprintf(stream, "Convert to long int failed,
function %lu test case on line %lu parameter %d string '%s'\n",
+ u[0], line_num, idx+2, buf_p);
+ return EXIT_FAILURE;
+ }
l_idx++;
break;
+ case 'i' : /* int */
+ l_tmp = strtol(buf_p, &endp, 10);
+ if (errno) {
+ (void)fprintf(stream, "Convert to int failed, function %lu
test case on line %lu parameter %d error msg: '%s' string '%s'\n",
+ u[0], line_num, idx+2, strerror(errno), buf_p);
+ return EXIT_FAILURE;
+ }
+ if ((*endp != '\0') || (buf_p == endp)) {
+ (void)fprintf(stream, "Convert to int failed, function %lu
test case on line %lu parameter %d string '%s'\n",
+ u[0], line_num, idx+2, buf_p);
+ return EXIT_FAILURE;
+ }
+ if (l_tmp > INT_MAX || l_tmp < INT_MIN) {
+ (void)fprintf(stream, "Convert to int failed (under/over
flow), function %lu test case on line %lu parameter %d string '%s'\n",
+ u[0], line_num, idx+2, buf_p);
+ return EXIT_FAILURE;
+ }
+ i[i_idx] = (int)l_tmp;
+ i_idx++;
+ break;
+ case 'u' : /* unsigned long */
+ u[u_idx] = strtoul(buf_p, &endp, 10);
+ if (errno) {
+ (void)fprintf(stream, "Convert to unsigned long int
failed, function %lu test case on line %lu parameter %d error msg: '%s' string
'%s'\n",
+ u[0], line_num, idx+2, strerror(errno), buf_p);
+ return EXIT_FAILURE;
+ }
+ if ((*endp != '\0') || (buf_p == endp) || (strchr(buf_p, '-')
!= '\0')) {
+ (void)fprintf(stream, "Convert to unsigned long int
failed, function %lu test case on line %lu parameter %d string '%s'\n",
+ u[0], line_num, idx+2, buf_p);
+ return EXIT_FAILURE;
+ }
+ u_idx++;
+ break;
default:
- bu_log("unknown data type '%c'\n", fmt_str[idx]);
+ (void)fprintf(stream, "INTERNAL ERROR: Unknown data type '%c'
for function %lu test case on line %lu, skipping test case.\n",
+ fmt_str[idx], u[0], line_num);
return EXIT_FAILURE;
break;
- } /* end of data format switch */
- } /* end of for loop traversing data format string */
+ } /* End of data format switch */
+ } /* End of for loop traversing data format string */
return 0;
}
@@ -90,32 +136,45 @@
main(int argc, char **argv)
{
char buf[BUFSIZ];
- char input_file_name[BUFSIZ];
- char output_file_name[BUFSIZ];
- int input_file_name_defined = 0;
- int output_file_name_defined = 0;
FILE *fp_in;
- FILE *fp_out;
+ FILE *stream;
char *endp;
- long int case_num;
- int process_single_case = 0;
- int function_num_defined = 0;
- long int function_num;
+ unsigned long line_num = 0;
+ unsigned long failed_cnt = 0;
+ unsigned long bomb_cnt = 0;
+ unsigned long success_cnt = 0;
int string_length;
+ int argv_idx;
char c;
- int early_exit = 0;
- int found_eof = 0;
- long l[50];
- double d[50];
char dt_fmt[50]; /* data type format string */
- int ret = 0;
-
char *buf_p1;
char *buf_p;
- int case_idx = 0;
- int line_num = 0;
struct bn_tol tol;
+ int ret = 0;
+ /* command line parameters */
+ char input_file_name[BUFSIZ];
+ char output_file_name[BUFSIZ];
+ unsigned long test_case_line_num;
+ unsigned long function_num;
+
+ /* function parameter arrays */
+ int i[50];
+ long l[50];
+ double d[50];
+ unsigned long u[50];
+
+ /* boolean variables */
+ int input_file_name_defined = 0;
+ int output_file_name_defined = 0;
+ int process_single_test_case = 0;
+ int process_single_function = 0;
+ int valid_function_number = 0;
+ int process_test_case = 0;
+ int early_exit = 0;
+ int found_eof = 0;
+
+ /* set initial values in tol structure */
tol.magic = BN_TOL_MAGIC;
tol.dist = 0.0005;
tol.dist_sq = tol.dist * tol.dist;
@@ -123,51 +182,57 @@
tol.para = 1.0 - tol.perp;
- if (argc < 3) {
- bu_log("Too few parameters, %d specified, at least 2 required\n", argc
- 1);
+ if (argc < 2) {
+ bu_log("Too few parameters, %d specified, at least 1 required\n", argc
- 1);
bu_exit(EXIT_FAILURE, usage);
}
- while ((c = bu_getopt(argc, argv, "c:f:i:o:")) != EOF) {
+ while ((c = bu_getopt(argc, argv, "l:f:i:o:")) != EOF) {
switch (c) {
- case 'c': /* test case number */
- case_num = strtol(bu_optarg, &endp, 10);
- if ((bu_optarg != endp) && (*endp == '\0')) {
- /* convert to long integer success */
- process_single_case = 1;
- } else {
- /* convert to long integer failed */
+ case 'l': /* test case line number */
+ errno = 0;
+ test_case_line_num = strtoul(bu_optarg, &endp, 10);
+ if (errno) {
+ bu_log("Invalid test case line number '%s' '%s'\n",
bu_optarg, strerror(errno));
bu_exit(EXIT_FAILURE, usage);
}
+ if ((*endp != '\0') || (bu_optarg == endp) ||
(strchr(bu_optarg, '-') != '\0')) {
+ bu_log("Invalid test case line number '%s'\n", bu_optarg);
+ bu_exit(EXIT_FAILURE, usage);
+ }
+ process_single_test_case = 1;
break;
case 'f': /* function number */
- function_num = strtol(bu_optarg, &endp, 10);
- if ((bu_optarg != endp) && (*endp == '\0')) {
- /* convert to long integer success */
- function_num_defined = 1;
- } else {
- /* convert to long integer failed */
+ errno = 0;
+ function_num = strtoul(bu_optarg, &endp, 10);
+ if (errno) {
+ bu_log("Invalid function number '%s' '%s'\n", bu_optarg,
strerror(errno));
bu_exit(EXIT_FAILURE, usage);
}
+ if ((*endp != '\0') || (bu_optarg == endp) ||
(strchr(bu_optarg, '-') != '\0')) {
+ bu_log("Invalid function number '%s'\n", bu_optarg);
+ bu_exit(EXIT_FAILURE, usage);
+ }
+ process_single_function = 1;
break;
case 'i': /* input file name */
- string_length = strlen(bu_optarg);
+ string_length = strlen(bu_optarg);
if (string_length >= BUFSIZ) {
bu_log("Input file name too long, length was %d but must
be less than %d\n",
string_length, BUFSIZ);
bu_exit(EXIT_FAILURE, usage);
}
- strcpy(input_file_name,bu_optarg);
+ (void)strcpy(input_file_name, bu_optarg);
input_file_name_defined = 1;
break;
case 'o': /* output file name */
- string_length = strlen(bu_optarg);
+ string_length = strlen(bu_optarg);
if (string_length >= BUFSIZ) {
bu_log("Output file name too long, length was %d but must
be less than %d\n",
string_length, BUFSIZ);
bu_exit(EXIT_FAILURE, usage);
}
- strcpy(output_file_name,bu_optarg);
+ (void)strcpy(output_file_name, bu_optarg);
output_file_name_defined = 1;
break;
default:
@@ -177,8 +242,8 @@
}
}
- if (process_single_case && function_num_defined) {
- bu_log("Can not specify both test case number and function number.\n");
+ if (process_single_test_case && process_single_function) {
+ bu_log("Can not specify both test case line number and function
number.\n");
early_exit = 1;
}
@@ -186,112 +251,196 @@
bu_log("Input file name is required but was not specified.\n");
early_exit = 1;
}
- if (!output_file_name_defined) {
- bu_log("Output file name is required but was not specified.\n");
- early_exit = 1;
- }
if (early_exit) {
bu_exit(EXIT_FAILURE, usage);
}
- bu_log("Using input path and file name: '%s'\n", input_file_name);
- bu_log("Using output path and file name: '%s'\n", output_file_name);
+ if ((fp_in = fopen(input_file_name, "r")) == NULL) {
+ bu_log("Cannot open input file (%s)\n", input_file_name);
+ return EXIT_FAILURE;
+ }
- if (process_single_case) {
- bu_log("Processing only test case: '%d'\n", case_num);
+
+ if (output_file_name_defined) {
+ if ((stream = fopen(output_file_name, "w")) == NULL) {
+ bu_log("Cannot create output file (%s)\n", output_file_name);
+ if (fclose(fp_in) != 0) {
+ bu_log("Unable to close input file.\n");
+ }
+ return EXIT_FAILURE;
+ }
+ } else {
+ stream = stderr;
}
- if (function_num_defined) {
- bu_log("Processing all test cases for function number: '%ld'\n",
function_num);
+ /* all output after this point is sent to stream */
+
+ (void)fprintf(stream, "Command line parameters: bntester ");
+ for (argv_idx = 1 ; argv_idx < argc ; argv_idx++) {
+ (void)fprintf(stream, "%s ", argv[argv_idx]);
}
+ (void)fprintf(stream, "\n");
- if (!process_single_case && !function_num_defined) {
- bu_log("Processing all test cases.\n");
+ if (process_single_test_case) {
+ (void)fprintf(stream, "Processing only test case on line number:
%lu\n", test_case_line_num);
}
- if ((fp_in = fopen(input_file_name, "r")) == NULL) {
- bu_log("Cannot open input file (%s)\n", input_file_name);
- return EXIT_FAILURE;
+ if (process_single_function) {
+ (void)fprintf(stream, "Processing all test cases for function number:
%lu\n", function_num);
}
- if ((fp_out = fopen(output_file_name, "w")) == NULL) {
- bu_log("Cannot create output file (%s)\n", output_file_name);
- if (fclose(fp_in) != 0) {
- bu_log("Unable to close input file.\n");
- }
- return EXIT_FAILURE;
+ if (!process_single_test_case && !process_single_function) {
+ (void)fprintf(stream, "Processing all test cases.\n");
}
+
while (!found_eof) {
+ if (line_num == ULONG_MAX) {
+ (void)fprintf(stream, "ERROR: Input data file exceeded max %lu
number of lines.\n", ULONG_MAX);
+ if (fclose(fp_in) != 0) {
+ (void)fprintf(stream, "Unable to close input file.\n");
+ }
+ if (output_file_name_defined) {
+ if (fclose(stream) != 0) {
+ bu_log("Unable to close output file.\n");
+ }
+ }
+ return EXIT_FAILURE;
+ }
line_num++;
(void)fgets(buf, BUFSIZ, fp_in);
if (feof(fp_in)) {
if (ferror(fp_in)) {
perror("ERROR: Problem reading file, system error message");
- fclose(fp_in);
+ if (fclose(fp_in) != 0) {
+ (void)fprintf(stream, "Unable to close input file.\n");
+ }
return EXIT_FAILURE;
} else {
found_eof = 1;
}
} else {
+ /* Skip input data file lines which start with a '#' character
+ * or a new line character.
+ */
if ((buf[0] != '#') && (buf[0] != '\n')) {
- case_idx++;
buf_p1 = strtok(buf, "\n");
buf_p = strtok(buf_p1, ",");
- /* the 1st parameter is alway a long int which represents the
function number */
- l[0] = strtol(buf_p, &endp, 10);
- if (!((bu_optarg != endp) && (*endp == '\0'))) {
- /* convert to long integer failed */
- bu_log("read function number failed, line number '%d' case
number '%d' string '%s'\n",
- line_num, case_idx, buf_p);
- if (fclose(fp_in) != 0) {
- bu_log("Unable to close input file.\n");
- }
- return EXIT_FAILURE;
+ /* The 1st parameter of the test case is alway an unsigned
+ * long int which represents the function number. This logic
+ * validates the test case function number to ensure it is
+ * an unsigned long int.
+ */
+ valid_function_number = 1;
+ errno = 0;
+ u[0] = strtoul(buf_p, &endp, 10);
+ if (errno) {
+ (void)fprintf(stream, "Read function number failed, line
%lu error msg: '%s' string '%s'\n",
+ line_num, strerror(errno), buf_p);
+ valid_function_number = 0;
+ } else if ((*endp != '\0') || (buf_p == endp) ||
(strchr(buf_p, '-') != '\0')) {
+ (void)fprintf(stream, "Read function number failed, line
%lu string '%s'\n", line_num, buf_p);
+ valid_function_number = 0;
}
- switch (l[0]) {
+ /* This logic restricts processing of the test case(s) to
+ * only those specified by the bntester input parameters.
+ */
+ process_test_case = 0;
+ if (valid_function_number && process_single_test_case &&
(test_case_line_num == line_num)) {
+ process_test_case = 1;
+ } else if (valid_function_number && process_single_function &&
(function_num == u[0])) {
+ process_test_case = 1;
+ } else if (valid_function_number && !process_single_test_case
&& !process_single_function) {
+ process_test_case = 1;
+ }
+
+ if (process_test_case) {
+ /* Each case within this switch corresponds to each
+ * function to be tested.
+ */
+ switch (u[0]) {
case 1: /* function number 'bn_distsq_line3_pt3' */
-
- /* data type string indicating data type of
- * function parameters
- */
- strcpy(dt_fmt, "dddddddddd");
-
- if (parse_case(buf_p, l, d, dt_fmt, line_num,
case_idx)) {
- bu_log("skipped line %d test case %d\n",
line_num, case_idx);
+ (void)strcpy(dt_fmt, "dddddddddd"); /* defines
parameter data types */
+ if (parse_case(buf_p, i, l, d, u, dt_fmt,
line_num, stream)) {
+ /* Parse failed, skipping test case */
ret = 1;
} else {
double result;
-
- result = bn_distsq_line3_pt3(&d[0], &d[3],
&d[6]);
- if (!NEAR_ZERO(result - d[9], SMALL_FASTF)) {
+ if (!BU_SETJUMP) {
+ /* try */
+ result = bn_distsq_line3_pt3(&d[0], &d[3],
&d[6]);
+ if (!NEAR_ZERO(result - d[9],
VUNITIZE_TOL)) {
+ ret = 1;
+ failed_cnt++;
+ (void)fprintf(stream, "Failed function
%lu test case on line %lu expected = %.15lf result = %.15lf\n",
+ u[0], line_num, d[9], result);
+ } else {
+ success_cnt++;
+ }
+ } else {
+ /* catch */
+ BU_UNSETJUMP;
ret = 1;
- bu_log("failed test case %d on line %d
expected = %.15lf result = %.15lf\n",
- case_idx, line_num, d[9], result);
+ bomb_cnt++;
+ (void)fprintf(stream, "Failed function %lu
test case on line %lu bu_bomb encountered.\n", u[0], line_num);
+ } BU_UNSETJUMP;
+ }
+ break;
+ case 2: /* function number 2 (template) */
+ (void)strcpy(dt_fmt, "uu");
+ if (parse_case(buf_p, i, l, d, u, dt_fmt,
line_num, stream)) {
+ /* Parse failed, skipping test case */
+ ret = 1;
+ } else {
+ if (!BU_SETJUMP) {
+ /* try */
+ (void)fprintf(stream, "Processing function
%lu\n", u[0]);
} else {
- bu_log("success test case %d on line %d
expected = %.15lf result = %.15lf\n",
- case_idx, line_num, d[9], result);
- }
+ /* catch */
+ BU_UNSETJUMP;
+ ret = 1;
+ bomb_cnt++;
+ (void)fprintf(stream, "Failed function %lu
test case on line %lu bu_bomb encountered.\n", u[0], line_num);
+ } BU_UNSETJUMP;
}
-
break;
default:
- bu_log("unknown function number '%ld'\n", l[0]);
+ (void)fprintf(stream, "ERROR: Unknown function
number %lu test case on line %lu, skipping test case.\n", u[0], line_num);
return EXIT_FAILURE;
break;
- } /* end of function number switch */
- } /* end of if statement skipping lines start with '#' */
+ } /* End of function number switch */
+ }
+ } /* End of if statement skipping lines starting with '#' or new
line */
}
- } /* end of while loop reading lines from data file */
+ } /* End of while loop reading lines from data file */
+
+ (void)fprintf(stream, "Summary: %lu total test cases success.\n",
success_cnt);
+ (void)fprintf(stream, "Summary: %lu total test cases failed.\n",
failed_cnt);
+ (void)fprintf(stream, "Summary: %lu total test cases bomb.\n", bomb_cnt);
+ if (output_file_name_defined) {
+ bu_log("Summary: %lu total test cases success.\n", success_cnt);
+ bu_log("Summary: %lu total test cases failed.\n", failed_cnt);
+ bu_log("Summary: %lu total test cases bomb.\n", bomb_cnt);
+ }
+
+ (void)fprintf(stream, "Done.\n");
+
+ if (output_file_name_defined) {
+ bu_log("Done.\n");
+ }
+
if (fclose(fp_in) != 0) {
- bu_log("Unable to close input file.\n");
+ (void)fprintf(stream, "Unable to close input file.\n");
}
- if (fclose(fp_out) != 0) {
- bu_log("Unable to close output file.\n");
+
+ if (output_file_name_defined) {
+ if (fclose(stream) != 0) {
+ bu_log("Unable to close output file.\n");
+ }
}
exit(ret);
This was sent by the SourceForge.net collaborative development platform, the
world's largest Open Source development site.
------------------------------------------------------------------------------
Forrester recently released a report on the Return on Investment (ROI) of
Google Apps. They found a 300% ROI, 38%-56% cost savings, and break-even
within 7 months. Over 3 million businesses have gone Google with Google Apps:
an online email calendar, and document program that's accessible from your
browser. Read the Forrester report: http://p.sf.net/sfu/googleapps-sfnew
_______________________________________________
BRL-CAD Source Commits mailing list
[email protected]
https://lists.sourceforge.net/lists/listinfo/brlcad-commits