From 4f3aca579e4b74b6f89e7292e465369e2c425860 Mon Sep 17 00:00:00 2001 From: jsing Date: Sun, 28 Dec 2014 14:01:33 +0000 Subject: [PATCH] Provide initial regress tests for the complex option parsing that is needed for openssl(1), which is also variable in behaviour between applications (and currently inconsistent). --- regress/usr.bin/openssl/Makefile | 4 +- regress/usr.bin/openssl/options/Makefile | 17 ++ regress/usr.bin/openssl/options/optionstest.c | 219 ++++++++++++++++++ 3 files changed, 239 insertions(+), 1 deletion(-) create mode 100644 regress/usr.bin/openssl/options/Makefile create mode 100644 regress/usr.bin/openssl/options/optionstest.c diff --git a/regress/usr.bin/openssl/Makefile b/regress/usr.bin/openssl/Makefile index 800e2fd0611..994e1952d26 100644 --- a/regress/usr.bin/openssl/Makefile +++ b/regress/usr.bin/openssl/Makefile @@ -1,4 +1,6 @@ -# $OpenBSD: Makefile,v 1.1 2014/08/26 17:50:07 jsing Exp $ +# $OpenBSD: Makefile,v 1.2 2014/12/28 14:01:33 jsing Exp $ + +SUBDIR= options CLEANFILES+= testdsa.key testdsa.pem rsakey.pem rsacert.pem dsa512.pem diff --git a/regress/usr.bin/openssl/options/Makefile b/regress/usr.bin/openssl/options/Makefile new file mode 100644 index 00000000000..ba3857ad39a --- /dev/null +++ b/regress/usr.bin/openssl/options/Makefile @@ -0,0 +1,17 @@ +# $OpenBSD: Makefile,v 1.1 2014/12/28 14:01:33 jsing Exp $ + +PROG= optionstest +SRCS= optionstest.c + +LDADD= -lcrypto -lssl +DPADD= ${LIBCRYPTO} ${LIBSSL} + +OSSLSRC= ${.CURDIR}/../../../../usr.bin/openssl/ +CFLAGS+= -I${OSSLSRC} + +.PATH: ${OSSLSRC} +SRCS+= apps.c + +CFLAGS+= -Werror + +.include diff --git a/regress/usr.bin/openssl/options/optionstest.c b/regress/usr.bin/openssl/options/optionstest.c new file mode 100644 index 00000000000..8df208dc844 --- /dev/null +++ b/regress/usr.bin/openssl/options/optionstest.c @@ -0,0 +1,219 @@ +/* $OpenBSD: optionstest.c,v 1.1 2014/12/28 14:01:33 jsing Exp $ */ +/* + * Copyright (c) 2014 Joel Sing + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include +#include +#include + +#include +#include + +#include "apps.h" + +/* Needed to keep apps.c happy... */ +BIO *bio_err; +CONF *config; + +static int argfunc(struct option *opt, char *arg); + +static struct { + char *arg; + int flag; +} test_config; + +static struct option test_options[] = { + { + .name = "arg", + .type = OPTION_ARG, + .opt.arg = &test_config.arg, + }, + { + .name = "argfunc", + .type = OPTION_ARG_FUNC, + .func = argfunc, + }, + { + .name = "flag", + .type = OPTION_FLAG, + .opt.flag = &test_config.flag, + }, + { NULL }, +}; + +char *args1[] = { "opts" }; +char *args2[] = { "opts", "-arg", "arg", "-flag" }; +char *args3[] = { "opts", "-arg", "arg", "-flag", "unnamed" }; +char *args4[] = { "opts", "-arg", "arg", "unnamed", "-flag" }; +char *args5[] = { "opts", "unnamed1", "-arg", "arg", "-flag", "unnamed2" }; +char *args6[] = { "opts", "-argfunc", "arg", "-flag" }; + +struct options_test { + int argc; + char **argv; + enum { + OPTIONS_TEST_NONE, + OPTIONS_TEST_UNNAMED, + } type; + char *unnamed; + int used; + int want; + char *wantarg; + int wantflag; +}; + +struct options_test options_tests[] = { + { + /* No arguments (only program name). */ + .argc = 1, + .argv = args1, + .type = OPTIONS_TEST_NONE, + .want = 0, + .wantarg = NULL, + .wantflag = 0, + }, + { + /* Named arguments (unnamed not permitted). */ + .argc = 4, + .argv = args2, + .type = OPTIONS_TEST_NONE, + .want = 0, + .wantarg = "arg", + .wantflag = 1, + }, + { + /* Named arguments (unnamed permitted). */ + .argc = 4, + .argv = args2, + .type = OPTIONS_TEST_UNNAMED, + .unnamed = NULL, + .want = 0, + .wantarg = "arg", + .wantflag = 1, + }, + { + /* Named and single unnamed (unnamed not permitted). */ + .argc = 5, + .argv = args3, + .type = OPTIONS_TEST_NONE, + .want = 1, + }, + { + /* Named and single unnamed (unnamed permitted). */ + .argc = 5, + .argv = args3, + .type = OPTIONS_TEST_UNNAMED, + .unnamed = "unnamed", + .want = 0, + .wantarg = "arg", + .wantflag = 1, + }, + { + /* Named and single unnamed (different sequence). */ + .argc = 5, + .argv = args4, + .type = OPTIONS_TEST_UNNAMED, + .unnamed = "unnamed", + .want = 0, + .wantarg = "arg", + .wantflag = 1, + }, + { + /* Multiple unnamed arguments (retain last). */ + .argc = 6, + .argv = args5, + .type = OPTIONS_TEST_UNNAMED, + .unnamed = "unnamed2", + .want = 0, + .wantarg = "arg", + .wantflag = 1, + }, + { + /* Function. */ + .argc = 4, + .argv = args6, + .type = OPTIONS_TEST_NONE, + .want = 0, + .wantarg = "arg", + .wantflag = 1, + }, +}; + +#define N_OPTIONS_TESTS \ + (sizeof(options_tests) / sizeof(*options_tests)) + +int +argfunc(struct option *opt, char *arg) +{ + test_config.arg = arg; + return (0); +} + +static int +do_options_test(int test_no, struct options_test *ot) +{ + char *unnamed = NULL; + char **arg = NULL; + int ret; + + if (ot->type == OPTIONS_TEST_UNNAMED) + arg = &unnamed; + + memset(&test_config, 0, sizeof(test_config)); + ret = options_parse(ot->argc, ot->argv, test_options, arg); + if (ret != ot->want) { + fprintf(stderr, "FAIL: test %i options_parse() returned %i, " + "want %i\n", test_no, ret, ot->want); + return (1); + } + if (ret != 0) + return (0); + + if ((test_config.arg != NULL || ot->wantarg != NULL) && + (test_config.arg == NULL || ot->wantarg == NULL || + strcmp(test_config.arg, ot->wantarg) != 0)) { + fprintf(stderr, "FAIL: test %i got arg '%s', want '%s'\n", + test_no, test_config.arg, ot->wantarg); + return (1); + } + if (test_config.flag != ot->wantflag) { + fprintf(stderr, "FAIL: test %i got flag %i, want %i\n", + test_no, test_config.flag, ot->wantflag); + return (1); + } + if (ot->type == OPTIONS_TEST_UNNAMED && + (unnamed != NULL || ot->unnamed != NULL) && + (unnamed == NULL || ot->unnamed == NULL || + strcmp(unnamed, ot->unnamed) != 0)) { + fprintf(stderr, "FAIL: test %i got unnamed '%s', want '%s'\n", + test_no, unnamed, ot->unnamed); + return (1); + } + + return (0); +} + +int +main(int argc, char **argv) +{ + int failed = 0; + size_t i; + + for (i = 0; i < N_OPTIONS_TESTS; i++) + failed += do_options_test(i, &options_tests[i]); + + return (failed); +} -- 2.20.1