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

Reply via email to