Browse Source

[1324] Changes to allow for command line parser testing
Initial tests added
Some style cleanup

John DuBois 13 years ago
parent
commit
cb1c34cd2f

+ 55 - 73
tests/tools/perfdhcp/cloptions.cc

@@ -28,7 +28,8 @@ static void printHelp(const char *progName, const char *usage);
  * 1 if argument processing was successful and the program should continue.
  */
 int
-procArgs(int argc, char **argv)
+procArgs(int argc, const char *argv[], confdata_t *confdata,
+	const char **server)
 {
     char usage[] =
 "Usage:\n\
@@ -36,9 +37,12 @@ perfdhcp [-hv] [-4|-6] [-r<rate>] [-n<num-request>] [-p<test-period>]\n\
          [-d<drop-time>] [-D<max-drop>] [-l<local-addr|interface>] [-i]\n\
          [-x<diagnostic-selector>] [server]\n";
     int v4 = 0;
+    int v6 = 0;
     char *maxDropOpt;
+    const char *localName;
     double dropTime;
     double testPeriod;
+    const char *msg;
 
     /* Names of configuration variables, for defaults file processor */
     confvar_t optConf[] = {
@@ -46,27 +50,29 @@ perfdhcp [-hv] [-4|-6] [-r<rate>] [-n<num-request>] [-p<test-period>]\n\
 	{ 'v', NULL,		CF_SWITCH,	NULL,		0 },
 	{ '4', NULL,		CF_SWITCH,	&v4,		1 },
 	{ '6', NULL,		CF_SWITCH,	&v6,		1 },
-	{ 'i', NULL,		CF_SWITCH,	&initialOnly,	1 },
+	{ 'i', NULL,		CF_SWITCH,	NULL,		1 },
 	{ 'l', NULL,		CF_NE_STRING,	&localName,	0 },
-	{ 'r', NULL,		CF_POS_INT,	&rate,		0 },
-	{ 'x', NULL,		CF_STRING,	&diagSelector,	0 },
+	{ 'r', NULL,		CF_POS_INT,	NULL,		0 },
+	{ 'x', NULL,		CF_STRING,	NULL,		0 },
 	{ 'd', NULL,		CF_POS_FLOAT,	&dropTime,	0 },
 	{ 'D', NULL,		CF_STRING,	&maxDropOpt,	0 },
-	{ 'n', NULL,		CF_POS_INT,	&numRequest,	0 },
+	{ 'n', NULL,		CF_POS_INT,	NULL,		0 },
 	{ 'p', NULL,		CF_POS_FLOAT,	&testPeriod,	0 },
         { '\0', NULL,           CF_ENDLIST,	NULL,		0 }
     };
 
-    confdata_t confdata;
-
     /* Process command line options and config file */
-    procOpts(&argc, &argv, optConf, &confdata, NULL, progName, usage);
+    msg = procOpts(&argc, &argv, optConf, confdata, NULL, progName, NULL);
+    if (msg != NULL) {
+        fprintf(stderr, "%s\n", msg);
+        return 2;
+    }
 
-    if (confdata.map['h']->num > 0) {
+    if (confdata->map['h']->num > 0) {
         printHelp(progName, usage);
         return 0;
     }
-    if (confdata.map['v']->num > 0) {
+    if (confdata->map['v']->num > 0) {
         printf("dhcpperf v1.0 2011-10-30\n");
         return 0;
     }
@@ -78,17 +84,18 @@ perfdhcp [-hv] [-4|-6] [-r<rate>] [-n<num-request>] [-p<test-period>]\n\
     switch (argc) {
     case 0:
 	if (v6 && localName != NULL)
-	    server = "all";
+	    *server = "all";
 	else {
 	    if (v6)
-		fprintf(stderr, "Use -l to specify an interface name.\n\%s\n", usage);
+		fprintf(stderr, "Use -l to specify an interface name.\n\%s\n",
+			usage);
 	    else
 		fprintf(stderr, "Must specify a DHCP server.\n\%s\n", usage);
 	    return 2;
 	}
 	break;
     case 1:
-	server = argv[0];
+	*server = argv[0];
 	break;
     default:
 	fprintf(stderr, "Too many arguments.\n\%s\n", usage);
@@ -103,19 +110,20 @@ printHelp(const char *progName, const char *usage)
     printf(
 "%s: Execute a performance test against a DHCP server.\n\
 %s\n\
-The [server] argument is the name/address of the DHCP server to contact.  For\n\
-DHCPv4 operation, exchanges are initiated by transmitting a DHCP DISCOVER to\n\
-this address.  For DHCPv6 operation, exchanges are initiated by transmitting a\n\
-DHCP SOLICIT to this address.  In the DHCPv6 case, the special name \"all\" can\n\
-be used to refer to All_DHCP_Relay_Agents_and_Servers (the multicast address\n\
-FF02::1:2), or the special name \"servers\" to refer to All_DHCP_Servers (the\n\
-multicast address FF05::1:3).  The [server] argument is optional only in the\n\
-case that -l is used to specify an interface, in which case [server] defaults\n\
+The [server] argument is the name/address of the DHCP server to contact. \n\
+For DHCPv4 operation, exchanges are initiated by transmitting a DHCP\n\
+DISCOVER to this address.  For DHCPv6 operation, exchanges are initiated\n\
+by transmitting a DHCP SOLICIT to this address.  In the DHCPv6 case, the\n\
+special name \"all\" can be used to refer to\n\
+All_DHCP_Relay_Agents_and_Servers (the multicast address FF02::1:2), or\n\
+the special name \"servers\" to refer to All_DHCP_Servers (the multicast\n\
+address FF05::1:3).  The [server] argument is optional only in the case\n\
+that -l is used to specify an interface, in which case [server] defaults\n\
 to \"all\".\n\
 \n\
 Exchanges are initiated by transmitting a DHCP SOLICIT to\n\
-All_DHCP_Relay_Agents_and_Servers (the multicast address FF02::1:2) via this\n\
-interface.\n\
+All_DHCP_Relay_Agents_and_Servers (the multicast address FF02::1:2) via\n\
+this interface.\n\
 \n\
 The default is to perform a single 4-way exchange, effectively pinging the\n\
 server.  The -r option is used to set up a performance test.\n\
@@ -124,16 +132,16 @@ Options:\n\
 -4: DHCPv4 operation (default). This is incompatible with the -6 option.\n\
 -6: DHCPv6 operation. This is incompatible with the -4 option.\n\
 -h: Print this help.\n\
--i: Do only the initial part of an exchange: DO or SA, depending on whether -6\n\
-    is given.\n\
+-i: Do only the initial part of an exchange: DO or SA, depending on\n\
+    whether -6 is given.\n\
 -l<local-addr|interface>: For DHCPv4 operation, specify the local\n\
-    hostname/address to use when communicating with the server.  By default,\n\
-    the interface address through which traffic would normally be routed to the\n\
-    server is used.\n\
-    For DHCPv6 operation, specify the name of the network interface via which\n\
-    exchanges are initiated.  This must be specified unless a server name is\n\
-    given, in which case the interface through which traffic would normally be\n\
+    hostname/address to use when communicating with the server.  By\n\
+    default, the interface address through which traffic would normally be\n\
     routed to the server is used.\n\
+    For DHCPv6 operation, specify the name of the network interface via\n\
+    which exchanges are initiated.  This must be specified unless a server\n\
+    name is given, in which case the interface through which traffic would\n\
+    normally be routed to the server is used.\n\
 -r<rate>: Initiate <rate> DORA/SARR (or if -i is given, DO/SA) exchanges per\n\
     second.  A periodic report is generated showing the number of exchanges\n\
     which were not completed, as well as the average response latency.  The\n\
@@ -148,55 +156,29 @@ Options:\n\
 \n\
 The remaining options are used only in conjunction with -r:\n\
 \n\
--d<drop-time>: Specify the time after which a request is treated as having been\n\
-    lost.  The value is given in seconds and may contain a fractional\n\
+-d<drop-time>: Specify the time after which a request is treated as having\n\
+    been lost.  The value is given in seconds and may contain a fractional\n\
     component.  The default is 1 second.\n\
 -D<max-drop>: Abort the test if more than <max-drop> requests have been\n\
-    dropped.  Use -D0 to abort if even a single request has been dropped.  If\n\
-    <max-drop> includes the suffix \"%%\", it specifies a maximum percentage of\n\
-    requests that may be dropped before abort.  In this case, testing of the\n\
-    threshold begins after 10 requests have been expected to be received.\n\
--n<num-request>: Initiate <num-request> transactions.  No report is generated\n\
-    until all transactions have been initiated/waited-for, after which a report\n\
-    is generated and the program terminates.\n\
--p<test-period>: Send requests for the given test period, which is specified in\n\
-    the same manner as -d.  This can be used as an alternative to -n, or both\n\
-    options can be given, in which case the testing is completed when either\n\
-    limit is reached.\n\
+    dropped.  Use -D0 to abort if even a single request has been dropped. \n\
+    If <max-drop> includes the suffix \"%%\", it specifies a maximum\n\
+    percentage of requests that may be dropped before abort.  In this\n\
+    case, testing of the threshold begins after 10 requests have been\n\
+    expected to be received.\n\
+-n<num-request>: Initiate <num-request> transactions.  No report is\n\
+    generated until all transactions have been initiated/waited-for, after\n\
+    which a report is generated and the program terminates.\n\
+-p<test-period>: Send requests for the given test period, which is\n\
+    specified in the same manner as -d.  This can be used as an\n\
+    alternative to -n, or both options can be given, in which case the\n\
+    testing is completed when either limit is reached.\n\
 \n\
 Exit status:\n\
 The exit status is:\n\
 0 on complete success.\n\
 1 for a general error.\n\
 2 if an error is found in the command line arguments.\n\
-3 if there are no general failures in operation, but one or more exchanges are\n\
-  not successfully completed.\n",
+3 if there are no general failures in operation, but one or more exchanges\n\
+  are not successfully completed.\n",
 		    progName, usage);
 }
-
-// Null functions to get the tests compiling.
-
-
-int parse(int, char**) {
-    // Argument names not given to prevent compiler warning about unused
-    // variables;
-    return (-1);
-}
-
-const char* getAddress() {
-    return (NULL);
-}
-
-uint16_t getPort() {
-    return (0);
-}
-
-uint32_t getTimeout() {
-    return (0);
-}
-
-const char* getQname() {
-    return (NULL);
-}
-
-

+ 3 - 47
tests/tools/perfdhcp/cloptions.h

@@ -1,49 +1,5 @@
-/*
-#ifdef __cplusplus
-extern "C" {
-#endif 
-*/
-
 #include <stdint.h>
+#include "procconf.h"
 
-extern int v6;
-extern int initialOnly;
-extern const char *localName;
-extern unsigned rate;
-extern unsigned numRequest;
-extern const char *server;
-extern const char *diagSelector;
-
-int procArgs(int argc, char **argv);
-
-// Functions tested in cloptions unit test
-int parse(int argc, char** argv);
-const char* getAddress();
-uint16_t getPort();
-uint32_t getTimeout();
-const char* getQname();
-
-// Also need definitions of these values
-
-namespace OptionInfo {
-    const uint32_t QR = 0x0001;
-    const uint32_t OP = 0x0002;
-    const uint32_t AA = 0x0004;
-    const uint32_t TC = 0x0008;
-    const uint32_t Z  = 0x0010;
-    const uint32_t AD = 0x0020;
-    const uint32_t CD = 0x0040;
-    const uint32_t RC = 0x0080;
-    const uint32_t QC = 0x0100;
-    const uint32_t AC = 0x0200;
-    const uint32_t UC = 0x0400;
-    const uint32_t DC = 0x0800;
-    const uint32_t MS = 0x1000;
-};
-
-
-/*
-#ifdef __cplusplus
-}
-#endif
-*/
+int procArgs(int argc, const char *argv[], confdata_t *confdata,
+	const char **server);

+ 6 - 0
tests/tools/perfdhcp/dkdebug.cc

@@ -54,3 +54,9 @@ vdkprintf(unsigned diag_req, const char format[], va_list ap)
     if (diag_req & dk_diag_mask)
 	vfprintf(stderr, format, ap);
 }
+
+int
+dk_set(unsigned diag_req)
+{
+    return diag_req & dk_diag_mask;
+}

+ 1 - 3
tests/tools/perfdhcp/dkdebug.h

@@ -4,9 +4,6 @@ extern "C" {
 
 #include <stdarg.h>
 
-extern unsigned dk_diag_mask;
-
-#define dk_set(diag_req) ((diag_req) & dk_diag_mask)
 #define DK_ALL (~0)
 
 struct dkdesc {
@@ -17,6 +14,7 @@ struct dkdesc {
 void dkprintf(unsigned diag_req, const char format[], ...);
 void vdkprintf(unsigned diag_req, const char format[], va_list ap);
 int dk_setup(const char *diag_str, const struct dkdesc *diags);
+int dk_set(unsigned diag_req);
 
 #ifdef __cplusplus
 }

+ 17 - 3
tests/tools/perfdhcp/perfdhcp.cc

@@ -67,13 +67,27 @@ static const struct dkdesc diagLetters[] = {
 };
 
 int
-main(int argc, char *argv[])
+main(int argc, const char *argv[])
 {
     int ret;
-
-    if ((ret = procArgs(argc, argv)) != 1)
+    int v6;
+    // int initialOnly;
+    const char *localName = NULL;
+    // unsigned rate;
+    // unsigned numRequest;
+    const char *server;
+    const char *diagSelector = "";
+    confdata_t confdata;
+
+    if ((ret = procArgs(argc, argv, &confdata, &server)) != 1)
 	exit(ret);
 
+    v6 = confdata.map['6']->num > 0;
+    if (confdata.map['l']->num > 0)
+        localName = confdata.map['l']->values[0]->value.string;
+    if (confdata.map['x']->num > 0)
+        diagSelector = confdata.map['x']->values[0]->value.string;
+
     srand(time(NULL));
     if (v6)
 	sarr(server, localName);

+ 81 - 30
tests/tools/perfdhcp/procconf.cc

@@ -60,15 +60,18 @@ pc_malloc(size_t size)
 }
 
 static void
-opterror(const char *expected, const char *value, const confvar_t *varDesc, const char filename[], const char *detail)
+opterror(const char *expected, const char *value, const confvar_t *varDesc,
+	const char filename[], const char *detail)
 {
     if (detail == NULL)
 	detail = "";
     if (filename == NULL)
-	error(USAGE_ERROR, "Invalid value given for option -%c: expected %s, got: %s%s",
+	error(USAGE_ERROR,
+		"Invalid value given for option -%c: expected %s, got: %s%s",
 		varDesc->outind, expected, value, detail);
     else
-	error(USAGE_ERROR, "Invalid value given in configuration file \"%s\" for option %s: expected %s, got: %s%s",
+	error(USAGE_ERROR, "Invalid value given in configuration file \"%s\""
+		" for option %s: expected %s, got: %s%s",
 		filename, varDesc->varname, expected, value, detail);
 }
 
@@ -136,7 +139,8 @@ addOptVal(const cf_source source, const char *value, const confvar_t *varDesc,
 	errno = 0;
 	data.value.intval = strtol(value, &ptr, 0);
 	if (errno == ERANGE) {
-	    opterror("an integer", value, varDesc, filename, " (out of range)");
+	    opterror("an integer", value, varDesc, filename,
+		    " (out of range)");
 	    return -1;
 	}
 	err = *value == '\0' || *ptr != '\0';
@@ -149,7 +153,8 @@ addOptVal(const cf_source source, const char *value, const confvar_t *varDesc,
 	    break;
 	case CF_NON_NEG_INT:
 	    if (err || data.value.intval < 0) {
-		opterror("a non-negative integer", value, varDesc, filename, NULL);
+		opterror("a non-negative integer", value, varDesc, filename,
+			NULL);
 		return -1;
 	    }
 	    data.value.nnint = data.value.intval;
@@ -191,7 +196,8 @@ addOptVal(const cf_source source, const char *value, const confvar_t *varDesc,
 	    break;
 	case CF_NON_NEG_FLOAT:
 	    if (err || data.value.floatval < 0) {
-		opterror("a non-negative number", value, varDesc, filename, NULL);
+		opterror("a non-negative number", value, varDesc, filename,
+			NULL);
 		return -1;
 	    }
 	    break;
@@ -211,7 +217,8 @@ addOptVal(const cf_source source, const char *value, const confvar_t *varDesc,
     case CF_SWITCH:
     case CF_NOCONF:
     case CF_SDEBUG:
-	if (source == CF_FILE && *value != '1')	/* option not turned on; ignore */
+	/* If option not turned on, ignore */
+	if (source == CF_FILE && *value != '1')
 	    return 0;
 	data.value.switchval = varDesc->value;
 	value = "1";	/* for debugging */
@@ -247,15 +254,18 @@ addOptVal(const cf_source source, const char *value, const confvar_t *varDesc,
     *last = ret_data;
     if (debugLevel >= VERBOSE_DEBUG)
 	fprintf(stderr, "Option %c (%s) gets value \"%s\" from %s%s\n",
-		0 < varDesc->outind && varDesc->outind < 256 ? varDesc->outind : '-',
+		0 < varDesc->outind && varDesc->outind < 256 ?
+		varDesc->outind : '-',
 		varDesc->varname == NULL ? "-" : varDesc->varname, value,
-		source == CF_ARGS ? "command line" : "config file", seen ? " (already seen)" : "");
+		source == CF_ARGS ? "command line" : "config file", seen ?
+			" (already seen)" : "");
     return 1;
 }
 
 /*
- * This currently depends on defread().  A CDDL version of the def* library exists:
- * http://www.opensource.apple.com/source/autofs/autofs-207/automountlib/deflt.c
+ * This currently depends on defread().
+ * A CDDL version of the def* library exists:
+ *http://www.opensource.apple.com/source/autofs/autofs-207/automountlib/deflt.c
  * But, this should really be rewritten to not use defread().
  */
 #ifdef DEFREAD
@@ -276,8 +286,8 @@ addOptVal(const cf_source source, const char *value, const confvar_t *varDesc,
  * -1 is returned.
  */
 static int
-procConfFile(const char filename[], const confvar_t optConf[], confval *first[], confval *last[])
-{
+procConfFile(const char filename[], const confvar_t optConf[],
+	confval *first[], confval *last[]) {
     int count;
     char *home;
     int ind;
@@ -321,7 +331,8 @@ procConfFile(const char filename[], const confvar_t optConf[], confval *first[],
 		error(INTERNAL_ERROR, "Out of memory");
 		return -1;
 	    }
-	    switch ((ret = addOptVal(CF_FILE, s, &optConf[ind], &first[ind], &last[ind], filename))) {
+	    switch ((ret = addOptVal(CF_FILE, s, &optConf[ind], &first[ind],
+		    &last[ind], filename))) {
 	    case 1:
 		count++;
 		break;
@@ -352,7 +363,8 @@ procConfFile(const char filename[], const confvar_t optConf[], confval *first[],
  * -1 is returned.
  */
 static int
-procCmdLineArgs(int *argc, char **argv[], const confvar_t optConf[], confval **first, confval **last)
+procCmdLineArgs(int *argc, const char **argv[], const confvar_t optConf[],
+	confval **first, confval **last)
 {
     char *p;
     extern char *optarg;	/* For getopt */
@@ -364,6 +376,7 @@ procCmdLineArgs(int *argc, char **argv[], const confvar_t optConf[], confval **f
     unsigned confNum;
     int count = 0;
 
+    optind = 1;
     p = optstr;
     *(p++) = ':';
     for (confNum = 0; optConf[confNum].type != CF_ENDLIST; confNum++) {
@@ -383,7 +396,7 @@ procCmdLineArgs(int *argc, char **argv[], const confvar_t optConf[], confval **f
 	}
     }
     *p = '\0';
-    while ((optchar = getopt(*argc, *argv, optstr)) != -1) {
+    while ((optchar = getopt(*argc, const_cast<char **>(*argv), optstr)) != -1) {
 	int ind;
 	int ret;
 
@@ -396,7 +409,8 @@ procCmdLineArgs(int *argc, char **argv[], const confvar_t optConf[], confval **f
 	    return -1;
 	}
 	ind = optCharToConf[optchar];
-	switch (ret = addOptVal(CF_ARGS, optarg, &optConf[ind], &first[ind], &last[ind], NULL)) {
+	switch (ret = addOptVal(CF_ARGS, optarg, &optConf[ind], &first[ind],
+		&last[ind], NULL)) {
 	case 1:
 	    count++;
 	    break;
@@ -411,14 +425,42 @@ procCmdLineArgs(int *argc, char **argv[], const confvar_t optConf[], confval **f
     return count;
 }
 
+/*
+ * Input variables:
+ * argc, argv: Command line data.
+ * optConf[]: Option description structures.
+ * confFile[]: Configuration file, or NULL if none provided.
+ * name: Name of program, for messages.
+ * usage: Usage message.  If non-null, on error a message is printed to stderr
+ *    and the program exits.
+ *
+ * Output variables:
+ * The processed option values are stored in confdata.
+ * A pointer to the start of the values for each option is stored in
+ * confdata->optVals[].values at the same offset as the option appears in
+ * confdata[].
+ * For any option for option characters/indexes have been used,
+ * confdata->map[index] is set to the same data.
+ * After processing, argc will have been adjusted to be the number of
+ * non-option arguments and argv will have been adjusted to start with the
+ * first non-option argument.
+ * 
+ * Return value:
+ * On success, NULL.
+ * On error, a message describing the problem.
+ */
 const char *
-procOpts(int *argc, char **argv[], const confvar_t optConf[], confdata_t *confdata,
-	const char confFile[], const char name[], const char usage[])
+procOpts(int *argc, const char **argv[], const confvar_t optConf[],
+	confdata_t *confdata, const char confFile[], const char name[],
+	const char usage[])
 {
+    /* Number of configuration options given in optConf */
     unsigned numConf;
-    confval **first, **last;	/* first & last records in the linked list maintained for each option */
-    unsigned maxOptIndex = 0;
-    int count;		/* number of option instances found */
+    /* First & last records in the linked list maintained for each option */
+    confval **first, **last;
+    unsigned maxOptIndex = 0;	/* The highest option index number seen */
+    /* number of option instances + assignments given */
+    int numOptsFound;
     unsigned optNum;
     unsigned i;
     confval **valuePointers;
@@ -432,12 +474,14 @@ procOpts(int *argc, char **argv[], const confvar_t optConf[], confdata_t *confda
 	    maxOptIndex = outind & ~CF_NOTFLAG;
     }
     if ((first = (confval **)pc_malloc(sizeof(confval *) * numConf)) == NULL ||
-	    (last = (confval **)pc_malloc(sizeof(confval *) * numConf)) == NULL)
+	    (last =
+	    (confval **)pc_malloc(sizeof(confval *) * numConf)) == NULL)
 	return errmsg;
     memset(first, '\0', sizeof(confval *) * numConf);
     memset(last, '\0', sizeof(confval *) * numConf);
 
-    if ((count = procCmdLineArgs(argc, argv, optConf, first, last)) < 0)
+    if ((numOptsFound =
+	    procCmdLineArgs(argc, argv, optConf, first, last)) < 0)
 	return errmsg;
     if (readConf && confFile != NULL) {
 #ifdef DEFREAD
@@ -446,7 +490,7 @@ procOpts(int *argc, char **argv[], const confvar_t optConf[], confdata_t *confda
 	if ((ret = procConfFile(confFile, optConf, first, last)) < 0)
 	    return errmsg;
 	else
-	    count += ret;
+	    nummOptsFound += ret;
 #else
 	error(INTERNAL_ERROR, "Built without defread!");
 	return errmsg;
@@ -459,18 +503,24 @@ procOpts(int *argc, char **argv[], const confvar_t optConf[], confdata_t *confda
      * All options have been read & initial processing done.
      * An array of pointers is now generated for the options.
      */
-    if ((valuePointers = (confval **)pc_malloc(sizeof(confval *) * count)) == NULL ||
-	(confdata->optVals = (cf_option *)pc_malloc(sizeof(cf_option) * numConf)) == NULL)
+    if ((valuePointers =
+	    (confval **)pc_malloc(sizeof(confval *) * numOptsFound)) == NULL ||
+	    (confdata->optVals =
+	    (cf_option *)pc_malloc(sizeof(cf_option) * numConf)) == NULL)
 	return errmsg;
+    /* If option index numbers are used, allocate a map for them */
     if (maxOptIndex != 0) {
-	if ((confdata->map = (cf_option **)pc_malloc(sizeof(cf_option) * (maxOptIndex+1))) == NULL)
+	if ((confdata->map =
+		(cf_option **)pc_malloc(sizeof(cf_option) * (maxOptIndex+1)))
+		== NULL)
 	    return errmsg;
 	memset(confdata->map, '\0', sizeof(confval *) * (maxOptIndex+1));
     }
 
     /*
      * Store the linked lists of option values into arrays.
-     * Pointers to all option instances are stored in valuePointers.
+     * Pointers to all option instances are stored in valuePointers,
+     * with the values for each particular option being contiguous.
      */
     i = 0;
     for (optNum = 0; optNum < numConf; optNum++) {
@@ -488,7 +538,8 @@ procOpts(int *argc, char **argv[], const confvar_t optConf[], confdata_t *confda
 	if (debugLevel > 5)
 	    fprintf(stderr, "Option %c (%s) got %d values\n",
 		    outind == 0 ? '-' : outind,
-		    optConf[optNum].varname == NULL ? "-" : optConf[optNum].varname,         
+		    optConf[optNum].varname == NULL ? "-" :
+		    optConf[optNum].varname,         
 		    confdata->optVals[optNum].num);
     }
     free(first);

+ 11 - 8
tests/tools/perfdhcp/procconf.h

@@ -1,6 +1,5 @@
-#ifdef __cplusplus
-extern "C" {
-#endif 
+#ifndef PROCCONF_H
+#define PROCCONF_H
 
 #include <limits.h>	/* for UINT_MAX */
 
@@ -25,6 +24,11 @@ typedef enum {
     CF_NONE, CF_ARGS, CF_FILE
 } cf_source;
 
+/*
+ * This is to be OR'd into a confvar_t outind to indicate that an index
+ * number that is given is not to be interpreted as a command line option
+ * character.
+ */
 #define CF_NOTFLAG (UINT_MAX & ~(UINT_MAX >> 1))
 
 /*
@@ -35,7 +39,7 @@ typedef enum {
  */
 typedef struct {
     unsigned outind;	/* Single-character option, or option output index */
-    char *varname;	/* Long name, for config file and eventually long option */
+    char *varname;	/* Long name, for config file and long option */
     cf_type type;	/* Option type */
     const void *addr;	/* Address of variable associated with this option */
     int value;		/* Value to assign to switch options */
@@ -68,13 +72,12 @@ typedef struct {
 
 typedef struct {
     cf_option *optVals;	/* All option values */
-    cf_option **map;	/* Option values indexed by option-char / option-index */
+    cf_option **map;	/* Option values indexed by option-char/option-index */
 } confdata_t;
 
 const char *
-procOpts(int *argc, char **argv[], const confvar_t optConf[], confdata_t *confdata, const char confFile[], const char name[],
+procOpts(int *argc, const char **argv[], const confvar_t optConf[],
+	confdata_t *confdata, const char confFile[], const char name[],
 	const char usage[]);
 
-#ifdef __cplusplus
-}
 #endif

+ 1 - 1
tests/tools/perfdhcp/tests/Makefile.am

@@ -16,7 +16,7 @@ TESTS += run_unittests
 run_unittests_SOURCES  = run_unittests.cc
 run_unittests_SOURCES += cloptions_unittest.cc
 run_unittests_SOURCES += $(top_builddir)/tests/tools/perfdhcp/cloptions.cc
-run_unittests_SOURCES += $(top_builddir)/tests/tools/perfdhcp/externals.cc
+run_unittests_SOURCES += $(top_builddir)/tests/tools/perfdhcp/procconf.cc
 
 run_unittests_CPPFLAGS = $(AM_CPPFLAGS) $(GTEST_INCLUDES)
 run_unittests_LDFLAGS  = $(AM_LDFLAGS)  $(GTEST_LDFLAGS)

+ 271 - 253
tests/tools/perfdhcp/tests/cloptions_unittest.cc

@@ -19,275 +19,293 @@
 #include "../cloptions.h"
 
 
-/// \brief Check Non-Limit Options
-///
-/// Checks that the options that are NOT related to the message are set to
-/// their default values.
-void checkDefaultOtherValues() {
-    EXPECT_STREQ("127.0.0.1", getAddress());
-    EXPECT_EQ(53, getPort());
-    EXPECT_EQ(500, getTimeout());
-    EXPECT_STREQ("www.example.com", getQname());
-}
-
-/// \brief Checks the minimum and maximum value specified for an option
-///
-/// Checks the values for one of the options whose values are stored in the
-/// class's options_ array.
-///
-/// \param index Index of the option in the limits_ array
-/// \param minval Expected minimum value
-/// \param maxval Expected maximum value
-void checkValuePair(int, uint32_t, uint32_t) {
-//void checkValuePair(int index, uint32_t minval = 0, uint32_t maxval = 0) {
-    // Argument names commented out as they are not used, so this avoid a
-    // compiler warning (which by default in BIND 10 is promoted to an
-    // error).
-    // maximum and minimum are not yet defined so following lines commented
-    // out.
-    // EXPECT_EQ(minimum(index), minval);
-    // EXPECT_EQ(maximum(index), maxval);
-}
-
-/// \brief Checks that all options are at default values
-///
-/// Checks that all options have both their maximum and minimum set to the
-/// default values.
-///
-/// \param except Index not to check. (This allows options not being tested
-///        to be checked to see that they are at the default value.)  As all
-///        index values are positive, a negative value means check
-///        everything.
-void checkDefaultLimitsValues(int except = -1) {
-    // Dummy use of except to avoid an error
-    EXPECT_EQ(-1, except);
-    // OptionInfo not yet defined!
-    /*
-    for (int i = 0; i < OptionInfo::SIZE; ++i) {
-        if (i != except) {
-            checkValuePair(i, OptionInfo::defval(i), OptionInfo::defval(i));
-        }
-    }
-    */
-}
-
-/// \brief Check valid command option
+///// \brief Check Non-Limit Options
+/////
+///// Checks that the options that are NOT related to the message are set to
+///// their default values.
+//void checkDefaultOtherValues() {
+//    EXPECT_STREQ("127.0.0.1", getAddress());
+//    EXPECT_EQ(53, getPort());
+//    EXPECT_EQ(500, getTimeout());
+//    EXPECT_STREQ("www.example.com", getQname());
+//}
+//
+///// \brief Checks the minimum and maximum value specified for an option
+/////
+///// Checks the values for one of the options whose values are stored in the
+///// class's options_ array.
+/////
+///// \param index Index of the option in the limits_ array
+///// \param minval Expected minimum value
+///// \param maxval Expected maximum value
+//void checkValuePair(int, uint32_t, uint32_t) {
+////void checkValuePair(int index, uint32_t minval = 0, uint32_t maxval = 0) {
+//    // Argument names commented out as they are not used, so this avoid a
+//    // compiler warning (which by default in BIND 10 is promoted to an
+//    // error).
+//    // maximum and minimum are not yet defined so following lines commented
+//    // out.
+//    // EXPECT_EQ(minimum(index), minval);
+//    // EXPECT_EQ(maximum(index), maxval);
+//}
+//
+///// \brief Checks that all options are at default values
+/////
+///// Checks that all options have both their maximum and minimum set to the
+///// default values.
+/////
+///// \param except Index not to check. (This allows options not being tested
+/////        to be checked to see that they are at the default value.)  As all
+/////        index values are positive, a negative value means check
+/////        everything.
+//void checkDefaultLimitsValues(int except = -1) {
+//    // Dummy use of except to avoid an error
+//    EXPECT_EQ(-1, except);
+//    // OptionInfo not yet defined!
+//    /*
+//    for (int i = 0; i < OptionInfo::SIZE; ++i) {
+//        if (i != except) {
+//            checkValuePair(i, OptionInfo::defval(i), OptionInfo::defval(i));
+//        }
+//    }
+//    */
+//}
+//
+///// \brief Check valid command option
+/////
+///// Checks that the command line specification of one of the options taking
+///// a value correctly processes the option.
+/////
+///// \param index Option index
+///// \param optflag Option flag (in the form '--option')
+///// \param optval Value to be passed to the option.
+///// \param minval Expected minimum value
+///// \param maxval Expected maximum value
+//void checkCommandValid(int index, const char* optflag, const char* optval,
+//                       uint32_t minval, uint32_t maxval) {
+//
+//    // Set up the command line and parse it.
+//    const char* argv[] = {"badpacket", NULL, NULL};
+//    argv[1] = optflag;
+//    argv[2] = optval;
+//    int argc = 3;
+//    parse(argc, const_cast<char**>(argv));
+//
+//    // Check the results.  Everything should be at the defaults except for
+//    // the specified option, where the minimum and maximum should be as
+//    // specified.
+//    checkDefaultOtherValues();
+//    checkDefaultLimitsValues(index);
+//    checkValuePair(index, minval, maxval);
+//}
+//
+/// \brief Check invalid command option
 ///
-/// Checks that the command line specification of one of the options taking
-/// a value correctly processes the option.
+/// Passed a command with an invalid value, checks that the parsing indicates
+/// error.
 ///
-/// \param index Option index
-/// \param optflag Option flag (in the form '--option')
+/// \param optflag Option flag (in the form '-c')
 /// \param optval Value to be passed to the option.
-/// \param minval Expected minimum value
-/// \param maxval Expected maximum value
-void checkCommandValid(int index, const char* optflag, const char* optval,
-                       uint32_t minval, uint32_t maxval) {
+void checkOptionInvalid(const char* optflag, const char* optval) {
+    const char* argv[] = { "perfdhcp", NULL, NULL, "foo" };
+    int argc = sizeof(argv) / sizeof(const char* );
+    confdata_t confdata;
+    const char *server;
 
-    // Set up the command line and parse it.
-    const char* argv[] = {"badpacket", NULL, NULL};
     argv[1] = optflag;
     argv[2] = optval;
-    int argc = 3;
-    parse(argc, const_cast<char**>(argv));
-
-    // Check the results.  Everything should be at the defaults except for
-    // the specified option, where the minimum and maximum should be as
-    // specified.
-    checkDefaultOtherValues();
-    checkDefaultLimitsValues(index);
-    checkValuePair(index, minval, maxval);
+    EXPECT_EQ(procArgs(argc, argv, &confdata, &server), 2);
 }
 
-/// \brief Check invalid command option
-///
-/// Passed a command with an invalid value, checks that the parsing throws
-/// a BadValue exception.
-///
-/// \param optflag Option flag (in the form '--option')
-/// \param optval Value to be passed to the option.
-void checkCommandInvalid(const char* optflag, const char* optval) {
+void checkOptionValid(const char* optflag, const char* optval,
+	confdata_t *confdata) {
+    const char* argv[] = { "perfdhcp", NULL, NULL, "foo" };
+    int argc = sizeof(argv) / sizeof(const char* );
+    const char *server;
 
-    // Set up the command line and parse it.
-    const char* argv[] = {"badpacket", NULL, NULL};
     argv[1] = optflag;
     argv[2] = optval;
-    int argc = 3;
-    EXPECT_THROW(parse(argc, const_cast<char**>(argv)), isc::BadValue);
-}
-
-/// \brief Check one-bit field
-///
-/// Explicitly for those fields in the flags word that are one bit wide,
-/// perform a series of tests to check that they accept valid values and
-/// reject invalid ones.
-///
-/// \param index Option index
-/// \param optflag Option flag (in the form '--option')
-void checkOneBitField(int index, const char* optflag) {
-    checkCommandValid(index, optflag, "0", 0, 0);
-    checkCommandValid(index, optflag, "1", 1, 1);
-    checkCommandValid(index, optflag, "0-1", 0, 1);
-    checkCommandValid(index, optflag, "1-0", 0, 1);
-    checkCommandInvalid(optflag, "0-3");
-    checkCommandInvalid(optflag, "4");
-    checkCommandInvalid(optflag, "xyz");
-}
-
-/// \brief Check four-bit field
-///
-/// Explicitly for those fields in the flags word that are four bits wide,
-/// perform a series of tests to check that they accept valid values and
-/// reject invalid ones.
-///
-/// \param index Option index
-/// \param optflag Option flag (in the form '--option')
-void checkFourBitField(int index, const char* optflag) {
-    checkCommandValid(index, optflag, "0", 0, 0);
-    checkCommandValid(index, optflag, "15", 15, 15);
-    checkCommandValid(index, optflag, "0-15", 0, 15);
-    checkCommandValid(index, optflag, "15-0", 0, 15);
-    checkCommandInvalid(optflag, "0-17");
-    checkCommandInvalid(optflag, "24");
-    checkCommandInvalid(optflag, "xyz");
-}
-
-/// \brief Check sixteen-bit field
-///
-/// Explicitly test the parsing of the fields that can take a 16-bit
-/// value ranging from 0 to 65535.
-///
-/// \param index Option index
-/// \param optflag Option flag (in the form '--option')
-void checkSixteenBitField(int index, const char* optflag) {
-    checkCommandValid(index, optflag, "0", 0, 0);
-    checkCommandValid(index, optflag, "65535", 65535, 65535);
-    checkCommandValid(index, optflag, "0-65535", 0, 65535);
-    checkCommandValid(index, optflag, "65535-0", 0, 65535);
-    checkCommandInvalid(optflag, "0-65536");
-    checkCommandInvalid(optflag, "65537");
-    checkCommandInvalid(optflag, "xyz");
-}
-
-// Check that each of the non-message options will be recognised
-
-TEST(CommandOptionsTest, address) {
-
-    const char* argv[] = {"badpacket",  "--address", "192.0.2.1"};
-    int argc = sizeof(argv) / sizeof(const char*);
-
-    // The conversion is ugly but it simplifies the process of entering the
-    // string constant.  The cast throws away the "const"ness of the pointed-to
-    // strings in order to conform to the function signature; however, the
-    // called functions all treat the strings as const.
-    parse(argc, const_cast<char**>(argv));
-    EXPECT_STREQ("192.0.2.1", getAddress());
-    EXPECT_EQ(53, getPort());
-    EXPECT_EQ(500, getTimeout());
-    EXPECT_STREQ("www.example.com", getQname());
-    checkDefaultLimitsValues();
-}
-
-TEST(CommandOptionsTest, port) {
-    const char* argv[] = {"badpacket",  "--port", "153"};
-    int argc = sizeof(argv) / sizeof(const char*);
-
-    parse(argc, const_cast<char**>(argv));
-    EXPECT_STREQ("127.0.0.1", getAddress());
-    EXPECT_EQ(153, getPort());
-    EXPECT_EQ(500, getTimeout());
-    EXPECT_STREQ("www.example.com", getQname());
-    checkDefaultLimitsValues();
-}
-
-TEST(CommandOptionsTest, timeout) {
-    const char* argv[] = {"badpacket",  "--timeout", "250"};
-    int argc = sizeof(argv) / sizeof(const char*);
-
-    parse(argc, const_cast<char**>(argv));
-    EXPECT_STREQ("127.0.0.1", getAddress());
-    EXPECT_EQ(53, getPort());
-    EXPECT_EQ(250, getTimeout());
-    EXPECT_STREQ("www.example.com", getQname());
-    checkDefaultLimitsValues();
-}
-
-TEST(CommandOptionsTest, parameter) {
-    const char* argv[] = {"badpacket",  "ftp.example.net"};
-    int argc = sizeof(argv) / sizeof(const char*);
-
-    parse(argc, const_cast<char**>(argv));
-    EXPECT_STREQ("127.0.0.1", getAddress());
-    EXPECT_EQ(53, getPort());
-    EXPECT_EQ(500, getTimeout());
-    EXPECT_STREQ("ftp.example.net", getQname());
-    checkDefaultLimitsValues();
+    EXPECT_EQ(procArgs(argc, argv, confdata, &server), 1);
 }
 
-// Test options representing the flags fields.
-
-TEST(CommandOptionsTest, qr) {
-    checkOneBitField(OptionInfo::QR, "--qr");
-}
-
-TEST(CommandOptionsTest, op) {
-    checkFourBitField(OptionInfo::OP, "--op");
-}
-
-TEST(CommandOptionsTest, aa) {
-    checkOneBitField(OptionInfo::AA, "--aa");
-}
-
-TEST(CommandOptionsTest, tc) {
-    checkOneBitField(OptionInfo::TC, "--tc");
+void checkPosIntOpt(const char *optflag) {
+    confdata_t confdata;
+    checkOptionValid(optflag, "100", &confdata);
+    EXPECT_EQ(100, confdata.map[(unsigned)optflag[1]]->values[0]->value.nnint);
+    checkOptionInvalid(optflag, "0");
+    checkOptionInvalid(optflag, "-1");
+    checkOptionInvalid(optflag, "1.0");
+    checkOptionInvalid(optflag, "x");
 }
 
-TEST(CommandOptionsTest, z) {
-    checkOneBitField(OptionInfo::Z, "--z");
+TEST(CommandOptionsTest, numreq) {
+    checkPosIntOpt("-n");
 }
 
-TEST(CommandOptionsTest, ad) {
-    checkOneBitField(OptionInfo::AD, "--ad");
+TEST(CommandOptionsTest, rate) {
+    checkPosIntOpt("-r");
 }
 
-TEST(CommandOptionsTest, cd) {
-    checkOneBitField(OptionInfo::CD, "--cd");
-}
-
-TEST(CommandOptionsTest, rc) {
-    checkFourBitField(OptionInfo::RC, "--rc");
-}
-
-// Section count options
-
-TEST(CommandOptionsTest, qc) {
-    checkSixteenBitField(OptionInfo::QC, "--qc");
-}
-
-TEST(CommandOptionsTest, ac) {
-    checkSixteenBitField(OptionInfo::AC, "--ac");
-}
-
-TEST(CommandOptionsTest, uc) {
-    checkSixteenBitField(OptionInfo::UC, "--uc");
-}
-
-TEST(CommandOptionsTest, dc) {
-    checkSixteenBitField(OptionInfo::DC, "--dc");
-}
-
-// ... and the message size option
-
-TEST(CommandOptionsTest, ms) {
-    int index = OptionInfo::MS;
-    const char* optflag = "--ms";
-
-    checkCommandValid(index, optflag, "1", 1, 1);
-    checkCommandValid(index, optflag, "65536", 65536, 65536);
-    checkCommandValid(index, optflag, "1-65536", 1, 65536);
-    checkCommandValid(index, optflag, "65536-1", 1, 65536);
-    checkCommandInvalid(optflag, "0");
-    checkCommandInvalid(optflag, "1-65537");
-    checkCommandInvalid(optflag, "65538");
-    checkCommandInvalid(optflag, "xyz");
-}
+///// \brief Check one-bit field
+/////
+///// Explicitly for those fields in the flags word that are one bit wide,
+///// perform a series of tests to check that they accept valid values and
+///// reject invalid ones.
+/////
+///// \param index Option index
+///// \param optflag Option flag (in the form '--option')
+//void checkOneBitField(int index, const char* optflag) {
+//    checkCommandValid(index, optflag, "0", 0, 0);
+//    checkCommandValid(index, optflag, "1", 1, 1);
+//    checkCommandValid(index, optflag, "0-1", 0, 1);
+//    checkCommandValid(index, optflag, "1-0", 0, 1);
+//    checkCommandInvalid(optflag, "0-3");
+//    checkCommandInvalid(optflag, "4");
+//    checkCommandInvalid(optflag, "xyz");
+//}
+//
+///// \brief Check four-bit field
+/////
+///// Explicitly for those fields in the flags word that are four bits wide,
+///// perform a series of tests to check that they accept valid values and
+///// reject invalid ones.
+/////
+///// \param index Option index
+///// \param optflag Option flag (in the form '--option')
+//void checkFourBitField(int index, const char* optflag) {
+//    checkCommandValid(index, optflag, "0", 0, 0);
+//    checkCommandValid(index, optflag, "15", 15, 15);
+//    checkCommandValid(index, optflag, "0-15", 0, 15);
+//    checkCommandValid(index, optflag, "15-0", 0, 15);
+//    checkCommandInvalid(optflag, "0-17");
+//    checkCommandInvalid(optflag, "24");
+//    checkCommandInvalid(optflag, "xyz");
+//}
+//
+///// \brief Check sixteen-bit field
+/////
+///// Explicitly test the parsing of the fields that can take a 16-bit
+///// value ranging from 0 to 65535.
+/////
+///// \param index Option index
+///// \param optflag Option flag (in the form '--option')
+//void checkSixteenBitField(int index, const char* optflag) {
+//    checkCommandValid(index, optflag, "0", 0, 0);
+//    checkCommandValid(index, optflag, "65535", 65535, 65535);
+//    checkCommandValid(index, optflag, "0-65535", 0, 65535);
+//    checkCommandValid(index, optflag, "65535-0", 0, 65535);
+//    checkCommandInvalid(optflag, "0-65536");
+//    checkCommandInvalid(optflag, "65537");
+//    checkCommandInvalid(optflag, "xyz");
+//}
+//
+//// Check that each of the non-message options will be recognised
+//
+//TEST(CommandOptionsTest, address) {
+//
+//    const char* argv[] = {"badpacket",  "--address", "192.0.2.1"};
+//    int argc = sizeof(argv) / sizeof(const char*);
+//
+//    // The conversion is ugly but it simplifies the process of entering the
+//    // string constant.  The cast throws away the "const"ness of the pointed-to
+//    // strings in order to conform to the function signature; however, the
+//    // called functions all treat the strings as const.
+//    parse(argc, const_cast<char**>(argv));
+//    EXPECT_STREQ("192.0.2.1", getAddress());
+//    EXPECT_EQ(53, getPort());
+//    EXPECT_EQ(500, getTimeout());
+//    EXPECT_STREQ("www.example.com", getQname());
+//    checkDefaultLimitsValues();
+//}
+
+//TEST(CommandOptionsTest, timeout) {
+//    const char* argv[] = {"badpacket",  "--timeout", "250"};
+//    int argc = sizeof(argv) / sizeof(const char*);
+//
+//    parse(argc, const_cast<char**>(argv));
+//    EXPECT_STREQ("127.0.0.1", getAddress());
+//    EXPECT_EQ(53, getPort());
+//    EXPECT_EQ(250, getTimeout());
+//    EXPECT_STREQ("www.example.com", getQname());
+//    checkDefaultLimitsValues();
+//}
+//
+//TEST(CommandOptionsTest, parameter) {
+//    const char* argv[] = {"badpacket",  "ftp.example.net"};
+//    int argc = sizeof(argv) / sizeof(const char*);
+//
+//    parse(argc, const_cast<char**>(argv));
+//    EXPECT_STREQ("127.0.0.1", getAddress());
+//    EXPECT_EQ(53, getPort());
+//    EXPECT_EQ(500, getTimeout());
+//    EXPECT_STREQ("ftp.example.net", getQname());
+//    checkDefaultLimitsValues();
+//}
+//
+//// Test options representing the flags fields.
+//
+//TEST(CommandOptionsTest, qr) {
+//    checkOneBitField(OptionInfo::QR, "--qr");
+//}
+//
+//TEST(CommandOptionsTest, op) {
+//    checkFourBitField(OptionInfo::OP, "--op");
+//}
+//
+//TEST(CommandOptionsTest, aa) {
+//    checkOneBitField(OptionInfo::AA, "--aa");
+//}
+//
+//TEST(CommandOptionsTest, tc) {
+//    checkOneBitField(OptionInfo::TC, "--tc");
+//}
+//
+//TEST(CommandOptionsTest, z) {
+//    checkOneBitField(OptionInfo::Z, "--z");
+//}
+//
+//TEST(CommandOptionsTest, ad) {
+//    checkOneBitField(OptionInfo::AD, "--ad");
+//}
+//
+//TEST(CommandOptionsTest, cd) {
+//    checkOneBitField(OptionInfo::CD, "--cd");
+//}
+//
+//TEST(CommandOptionsTest, rc) {
+//    checkFourBitField(OptionInfo::RC, "--rc");
+//}
+//
+//// Section count options
+//
+//TEST(CommandOptionsTest, qc) {
+//    checkSixteenBitField(OptionInfo::QC, "--qc");
+//}
+//
+//TEST(CommandOptionsTest, ac) {
+//    checkSixteenBitField(OptionInfo::AC, "--ac");
+//}
+//
+//TEST(CommandOptionsTest, uc) {
+//    checkSixteenBitField(OptionInfo::UC, "--uc");
+//}
+//
+//TEST(CommandOptionsTest, dc) {
+//    checkSixteenBitField(OptionInfo::DC, "--dc");
+//}
+//
+//// ... and the message size option
+//
+//TEST(CommandOptionsTest, ms) {
+//    int index = OptionInfo::MS;
+//    const char* optflag = "--ms";
+//
+//    checkCommandValid(index, optflag, "1", 1, 1);
+//    checkCommandValid(index, optflag, "65536", 65536, 65536);
+//    checkCommandValid(index, optflag, "1-65536", 1, 65536);
+//    checkCommandValid(index, optflag, "65536-1", 1, 65536);
+//    checkCommandInvalid(optflag, "0");
+//    checkCommandInvalid(optflag, "1-65537");
+//    checkCommandInvalid(optflag, "65538");
+//    checkCommandInvalid(optflag, "xyz");
+//}