From: Todd C. Miller Date: Wed, 27 May 2015 02:25:08 +0000 (-0600) Subject: Add unit tests for strsplit and parse_gid_list. X-Git-Tag: SUDO_1_8_14^2~112 X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=8c3fd195d26c128e1ac49850549785fa30469d01;p=sudo Add unit tests for strsplit and parse_gid_list. --- diff --git a/MANIFEST b/MANIFEST index 6cfcaf351..2ec449fb0 100644 --- a/MANIFEST +++ b/MANIFEST @@ -119,7 +119,9 @@ lib/util/regress/glob/files lib/util/regress/glob/globtest.c lib/util/regress/glob/globtest.in lib/util/regress/mktemp/mktemp_test.c +lib/util/regress/parse_gids/parse_gids_test.c lib/util/regress/progname/progname_test.c +lib/util/regress/strsplit/strsplit_test.c lib/util/regress/sudo_conf/conf_test.c lib/util/regress/sudo_conf/test1.in lib/util/regress/sudo_conf/test1.out.ok diff --git a/lib/util/Makefile.in b/lib/util/Makefile.in index 6c52be61d..bbd8f3791 100644 --- a/lib/util/Makefile.in +++ b/lib/util/Makefile.in @@ -81,7 +81,8 @@ CPPCHECK_OPTS = -q --force --enable=warning,performance,portability --suppress=c SPLINT_OPTS = -D__restrict= -checks # Regression tests -TEST_PROGS = atofoo_test conf_test hltq_test parseln_test progname_test @COMPAT_TEST_PROGS@ +TEST_PROGS = atofoo_test conf_test hltq_test parseln_test progname_test \ + strsplit_test parse_gids_test @COMPAT_TEST_PROGS@ TEST_LIBS = @LIBS@ TEST_LDFLAGS = @LDFLAGS@ @@ -121,6 +122,10 @@ FNM_TEST_OBJS = fnm_test.lo GLOBTEST_OBJS = globtest.lo +STRSPLIT_TEST_OBJS = strsplit_test.lo + +PARSE_GIDS_TEST_OBJS = parse_gids_test.lo + all: libsudo_util.la Makefile: $(srcdir)/Makefile.in @@ -191,6 +196,12 @@ parseln_test: $(PARSELN_TEST_OBJS) libsudo_util.la progname_test: $(PROGNAME_TEST_OBJS) $(LIBTOOL) --mode=link $(CC) -o $@ $(PROGNAME_TEST_OBJS) $(PIE_LDFLAGS) $(SSP_LDFLAGS) $(TEST_LDFLAGS) $(TEST_LIBS) +parse_gids_test: $(PARSE_GIDS_TEST_OBJS) libsudo_util.la + $(LIBTOOL) --mode=link $(CC) -o $@ $(PARSE_GIDS_TEST_OBJS) libsudo_util.la $(PIE_LDFLAGS) $(SSP_LDFLAGS) $(TEST_LDFLAGS) $(TEST_LIBS) + +strsplit_test: $(STRSPLIT_TEST_OBJS) libsudo_util.la + $(LIBTOOL) --mode=link $(CC) -o $@ $(STRSPLIT_TEST_OBJS) libsudo_util.la $(PIE_LDFLAGS) $(SSP_LDFLAGS) $(TEST_LDFLAGS) $(TEST_LIBS) + pre-install: install: install-dirs @@ -225,6 +236,12 @@ cppcheck: check: $(TEST_PROGS) @if test X"$(cross_compiling)" != X"yes"; then \ rval=0; \ + if test -f parse_gids_test; then \ + ./parse_gids_test || rval=`expr $$rval + $$?`; \ + fi; \ + if test -f strsplit_test; then \ + ./strsplit_test || rval=`expr $$rval + $$?`; \ + fi; \ if test -f fnm_test; then \ ./fnm_test $(srcdir)/regress/fnmatch/fnm_test.in || rval=`expr $$rval + $$?`; \ fi; \ @@ -440,6 +457,11 @@ mktemp_test.lo: $(srcdir)/regress/mktemp/mktemp_test.c \ $(incdir)/sudo_fatal.h $(incdir)/sudo_util.h \ $(top_builddir)/config.h $(LIBTOOL) --mode=compile $(CC) -c -o $@ $(CPPFLAGS) $(CFLAGS) $(PIE_CFLAGS) $(SSP_CFLAGS) $(DEFS) $(srcdir)/regress/mktemp/mktemp_test.c +parse_gids_test.lo: $(srcdir)/regress/parse_gids/parse_gids_test.c \ + $(incdir)/compat/stdbool.h $(incdir)/sudo_compat.h \ + $(incdir)/sudo_fatal.h $(incdir)/sudo_util.h \ + $(top_builddir)/config.h + $(LIBTOOL) --mode=compile $(CC) -c -o $@ $(CPPFLAGS) $(CFLAGS) $(PIE_CFLAGS) $(SSP_CFLAGS) $(DEFS) $(srcdir)/regress/parse_gids/parse_gids_test.c parseln.lo: $(srcdir)/parseln.c $(incdir)/compat/stdbool.h \ $(incdir)/sudo_compat.h $(incdir)/sudo_debug.h \ $(incdir)/sudo_queue.h $(incdir)/sudo_util.h \ @@ -497,6 +519,11 @@ strsplit.lo: $(srcdir)/strsplit.c $(incdir)/compat/stdbool.h \ $(incdir)/sudo_queue.h $(incdir)/sudo_util.h \ $(top_builddir)/config.h $(LIBTOOL) --mode=compile $(CC) -c -o $@ $(CPPFLAGS) $(CFLAGS) $(PIE_CFLAGS) $(SSP_CFLAGS) $(DEFS) $(srcdir)/strsplit.c +strsplit_test.lo: $(srcdir)/regress/strsplit/strsplit_test.c \ + $(incdir)/compat/stdbool.h $(incdir)/sudo_compat.h \ + $(incdir)/sudo_fatal.h $(incdir)/sudo_util.h \ + $(top_builddir)/config.h + $(LIBTOOL) --mode=compile $(CC) -c -o $@ $(CPPFLAGS) $(CFLAGS) $(PIE_CFLAGS) $(SSP_CFLAGS) $(DEFS) $(srcdir)/regress/strsplit/strsplit_test.c strtobool.lo: $(srcdir)/strtobool.c $(incdir)/compat/stdbool.h \ $(incdir)/sudo_compat.h $(incdir)/sudo_debug.h \ $(incdir)/sudo_queue.h $(incdir)/sudo_util.h \ diff --git a/lib/util/regress/parse_gids/parse_gids_test.c b/lib/util/regress/parse_gids/parse_gids_test.c new file mode 100644 index 000000000..5a697f01f --- /dev/null +++ b/lib/util/regress/parse_gids/parse_gids_test.c @@ -0,0 +1,123 @@ +/* + * Copyright (c) 2015 Todd C. Miller + * + * 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 +#ifdef STDC_HEADERS +# include +# include +#else +# ifdef HAVE_STDLIB_H +# include +# endif +#endif /* STDC_HEADERS */ +#ifdef HAVE_STRING_H +# if defined(HAVE_MEMORY_H) && !defined(STDC_HEADERS) +# include +# endif +# include +#endif /* HAVE_STRING_H */ +#ifdef HAVE_STRINGS_H +# include +#endif /* HAVE_STRINGS_H */ +#ifdef HAVE_STDBOOL_H +# include +#else +# include "compat/stdbool.h" +#endif + +#include "sudo_compat.h" +#include "sudo_fatal.h" +#include "sudo_util.h" + +__dso_public int main(int argc, char *argv[]); + +/* + * Test that sudo_parse_gids() works as expected. + */ + +struct parse_gids_test { + const char *gids; + gid_t *baseptr; + gid_t basegid; + int ngids; + const GETGROUPS_T *gidlist; +}; + +static const GETGROUPS_T test1_out[] = { 0, 1, 2, 3, 4 }; +static const GETGROUPS_T test2_out[] = { 1, 2, 3, 4 }; +static const GETGROUPS_T test3_out[] = { 0, 1, -2, 3, 4 }; + +/* XXX - test syntax errors too */ +static struct parse_gids_test test_data[] = { + { "1,2,3,4", &test_data[0].basegid, 0, 5, test1_out }, + { "1,2,3,4", NULL, 0, 4, test2_out }, + { "1,-2,3,4", &test_data[2].basegid, 0, 5, test3_out }, + { NULL, false, 0, 0, NULL } +}; + +static void +dump_gids(const char *prefix, int ngids, const GETGROUPS_T *gidlist) +{ + int i; + + fprintf(stderr, "%s: %s: ", getprogname(), prefix); + for (i = 0; i < ngids; i++) { + fprintf(stderr, "%s%d", i ? ", " : "", (int)gidlist[i]); + } + fputc('\n', stderr); +} + +int +main(int argc, char *argv[]) +{ + GETGROUPS_T *gidlist = NULL; + int i, j, errors = 0, ntests = 0; + int ngids; + initprogname(argc > 0 ? argv[0] : "strsplit_test"); + + for (i = 0; test_data[i].gids != NULL; i++) { + free(gidlist); + ngids = sudo_parse_gids(test_data[i].gids, test_data[i].baseptr, &gidlist); + if (ngids == -1) + exit(1); /* out of memory? */ + ntests++; + if (ngids != test_data[i].ngids) { + sudo_warnx_nodebug("test #%d: expected %d gids, got %d", + ntests, test_data[i].ngids, ngids); + dump_gids("expected", test_data[i].ngids, test_data[i].gidlist); + dump_gids("received", ngids, gidlist); + errors++; + continue; + } + ntests++; + for (j = 0; j < ngids; j++) { + if (test_data[i].gidlist[j] != gidlist[j]) { + sudo_warnx_nodebug("test #%d: gid mismatch", ntests); + dump_gids("expected", test_data[i].ngids, test_data[i].gidlist); + dump_gids("received", ngids, gidlist); + errors++; + break; + } + } + } + if (ntests != 0) { + printf("%s: %d tests run, %d errors, %d%% success rate\n", + getprogname(), ntests, errors, (ntests - errors) * 100 / ntests); + } +} diff --git a/lib/util/regress/strsplit/strsplit_test.c b/lib/util/regress/strsplit/strsplit_test.c new file mode 100644 index 000000000..502ba6f6e --- /dev/null +++ b/lib/util/regress/strsplit/strsplit_test.c @@ -0,0 +1,117 @@ +/* + * Copyright (c) 2015 Todd C. Miller + * + * 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 +#ifdef STDC_HEADERS +# include +# include +#else +# ifdef HAVE_STDLIB_H +# include +# endif +#endif /* STDC_HEADERS */ +#ifdef HAVE_STRING_H +# if defined(HAVE_MEMORY_H) && !defined(STDC_HEADERS) +# include +# endif +# include +#endif /* HAVE_STRING_H */ +#ifdef HAVE_STRINGS_H +# include +#endif /* HAVE_STRINGS_H */ +#ifdef HAVE_STDBOOL_H +# include +#else +# include "compat/stdbool.h" +#endif + +#include "sudo_compat.h" +#include "sudo_fatal.h" +#include "sudo_util.h" + +__dso_public int main(int argc, char *argv[]); + +/* + * Test that sudo_strsplit() works as expected. + */ + +struct strsplit_test { + const char *input; + size_t input_len; + const char **output; +}; + +static const char test1_in[] = " vi "; +static const char *test1_out[] = { "vi", NULL }; +static const char test2_in[] = "vi -r "; +static const char *test2_out[] = { "vi", "-r", NULL }; +static const char test3_in[] = "vi -r -R abc\tdef "; +static const char *test3_out[] = { "vi", "-r", "-R", "abc", "def", NULL }; +static const char test4_in[] = "vi -r -R abc\tdef "; +static const char *test4_out[] = { "vi", "-r", "-R", "abc", NULL }; + +static struct strsplit_test test_data[] = { + { test1_in, sizeof(test1_in) - 1, test1_out }, + { test2_in, sizeof(test2_in) - 1, test2_out }, + { test3_in, sizeof(test3_in) - 1, test3_out }, + { test4_in, sizeof(test4_in) - 5, test4_out }, + { NULL, 0, NULL } +}; + +int +main(int argc, char *argv[]) +{ + const char *cp, *ep, *input_end; + int i, j, errors = 0, ntests = 0; + size_t len; + initprogname(argc > 0 ? argv[0] : "strsplit_test"); + + for (i = 0; test_data[i].input != NULL; i++) { + input_end = test_data[i].input + test_data[i].input_len; + cp = sudo_strsplit(test_data[i].input, input_end, " \t", &ep); + for (j = 0; test_data[i].output[j] != NULL; j++) { + ntests++; + len = strlen(test_data[i].output[j]); + if ((size_t)(ep - cp) != len) { + sudo_warnx_nodebug("failed test #%d: bad length, expected " + "%zu, got %zu", ntests, len, (size_t)(ep - cp)); + errors++; + continue; + } + ntests++; + if (strncmp(cp, test_data[i].output[j], len) != 0) { + sudo_warnx_nodebug("failed test #%d: expected %s, got %.*s", + ntests, test_data[i].output[j], (int)(ep - cp), cp); + errors++; + continue; + } + cp = sudo_strsplit(NULL, input_end, " \t", &ep); + } + ntests++; + if (cp != NULL) { + sudo_warnx_nodebug("failed test #%d: extra tokens \"%.*s\"", + ntests, (int)(input_end - cp), cp); + errors++; + } + } + if (ntests != 0) { + printf("%s: %d tests run, %d errors, %d%% success rate\n", + getprogname(), ntests, errors, (ntests - errors) * 100 / ntests); + } +}