From 8185af6a8e8e587f267d901328f7c5d956c06de3 Mon Sep 17 00:00:00 2001 From: Nick Bowler Date: Tue, 24 Oct 2023 21:21:49 -0400 Subject: [PATCH] tests: Add sanity check for truncated output. Nothing really verifies that output truncation of the cdecl_declare and cdecl_explain functions actually works as expected. Add a new test program and a couple invocations to at least cover the basic functionality. --- Makefile.am | 4 ++ t/.gitignore | 1 + t/crossparse.c | 2 - t/rendertest.c | 142 ++++++++++++++++++++++++++++++++++++++++++++++ t/testlib.c | 4 +- tests/internal.at | 38 +++++++++++++ 6 files changed, 187 insertions(+), 4 deletions(-) create mode 100644 t/rendertest.c diff --git a/Makefile.am b/Makefile.am index e7cfb6b..4af8e9a 100644 --- a/Makefile.am +++ b/Makefile.am @@ -100,6 +100,10 @@ t_rng_test_LDADD = $(TEST_LIBS) $(t_rng_test_OBJECTS): $(gnulib_headers) EXTRA_DIST += t/xos256p.c +check_PROGRAMS += t/rendertest +t_rendertest_LDADD = $(TEST_LIBS) +$(t_rendertest_OBJECTS): $(gnulib_headers) + src/error.lo: src/errmsg.h src/keywords.lo: src/parse.h src/output.lo: src/parse.h src/specstr.h diff --git a/t/.gitignore b/t/.gitignore index 9da3294..f6bb37d 100644 --- a/t/.gitignore +++ b/t/.gitignore @@ -2,5 +2,6 @@ /crossparse /normalize /randomdecl +/rendertest /rng-test /typegen.h diff --git a/t/crossparse.c b/t/crossparse.c index 520b08a..630e02e 100644 --- a/t/crossparse.c +++ b/t/crossparse.c @@ -45,8 +45,6 @@ static void print_usage(FILE *f) static void print_help(void) { - const struct option *opt; - print_usage(stdout); puts("Test that libcdecl can parse its own output.\n"); test_print_options(lopts); diff --git a/t/rendertest.c b/t/rendertest.c new file mode 100644 index 0000000..93574e2 --- /dev/null +++ b/t/rendertest.c @@ -0,0 +1,142 @@ +/* + * Helper to verify the output rendering routines. + * Copyright © 2023 Nick Bowler + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#include +#include +#include +#include +#include +#include + +#include +#include "test.h" + +#define PROGNAME "outbuf" +static const char *progname = PROGNAME; +static const char sopts[] = "n:ECVH"; +static const struct option lopts[] = { + { "count", 1, NULL, 'n' }, + { "cdecl", 0, NULL, 'C' }, + { "english", 0, NULL, 'E' }, + { "version", 0, NULL, 'V' }, + { "help", 0, NULL, 'H' }, + { 0 } +}; + +static void print_usage(FILE *f) +{ + fprintf(f, "Usage: %s [options]\n", progname); +} + +static void print_help(void) +{ + print_usage(stdout); + puts("Helper application to test output rendering.\n"); + test_print_options(lopts); +} + +enum { MODE_CDECL, MODE_ENGLISH }; + +static int do_test(char *line, unsigned long n, int mode) +{ + struct cdecl *decl; + size_t rc; + + if (mode) + decl = cdecl_parse_english(line); + else + decl = cdecl_parse_decl(line); + + if (!decl) { + fprintf(stderr, "%s: %s\n", progname, cdecl_get_error()->str); + fprintf(stderr, "%s: the failed input was: %s\n", + progname, line); + return -1; + } + + memset(line, '\a', n+1); + if (mode) + rc = cdecl_explain(line, n, decl); + else + rc = cdecl_declare(line, n, decl); + + if (n && ( rc < n ? line[rc] : line[n-1] ) != '\0') { + fprintf(stderr, "%s: output is not 0-terminated\n", progname); + return -1; + } + + if (line[n] != '\a') { + fprintf(stderr, "%s: output overflow\n", progname); + return -1; + } + + printf("%lu %.*s\n", (unsigned long)rc, -(n>0), line); + cdecl_free(decl); + return 0; +} + +int main(int argc, char **argv) +{ + int opt, mode = MODE_CDECL, ret = EXIT_SUCCESS; + unsigned long n = 60; + char *line; + size_t sz; + + if (argc > 0) + progname = argv[0]; + + while ((opt = getopt_long(argc, argv, sopts, lopts, NULL)) != -1) { + switch (opt) { + case 'C': + mode = MODE_CDECL; + break; + case 'E': + mode = MODE_ENGLISH; + break; + case 'n': + if (!strict_strtoul(&n, optarg, 0) || n > (size_t)-2) { + fprintf(stderr, "%s: invalid count: %s\n", + progname, optarg); + return EXIT_FAILURE; + } + break; + case 'V': + test_print_version(PROGNAME); + return EXIT_SUCCESS; + case 'H': + print_help(); + return EXIT_SUCCESS; + default: + print_usage(stderr); + return EXIT_FAILURE; + } + } + + line = malloc_nofail((sz = n+1)); + while (getline(&line, &sz, stdin) >= 0) { + char *c = strchr(line, '\n'); + if (c) + *c = '\0'; + + if (do_test(line, n, mode) < 0) + ret = EXIT_FAILURE; + } + + free(line); + return ret; +} diff --git a/t/testlib.c b/t/testlib.c index fdb9d3b..8edb423 100644 --- a/t/testlib.c +++ b/t/testlib.c @@ -1,6 +1,6 @@ /* * Miscellaneous functions used by the cdecl99 test suite. - * Copyright © 2011-2012, 2021-2022 Nick Bowler + * Copyright © 2011-2012, 2021-2023 Nick Bowler * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -92,7 +92,7 @@ bool strict_strtoul(unsigned long *val, const char *str, int base) void test_print_version(const char *program) { printf("%s (%s) %s\n", program, PACKAGE_NAME, PACKAGE_VERSION); - puts("Copyright (C) 2022 Nick Bowler."); + puts("Copyright (C) 2023 Nick Bowler."); puts("License GPLv3+: GNU GPL version 3 or later ."); puts("This is free software: you are free to change and redistribute it."); puts("There is NO WARRANTY, to the extent permitted by law."); diff --git a/tests/internal.at b/tests/internal.at index 9012c15..1ae6f99 100644 --- a/tests/internal.at +++ b/tests/internal.at @@ -73,3 +73,41 @@ AT_CLEANUP TEST_TAP_SIMPLE([cdecl__err sanity], [cdeclerr], [TEST_NEED_PROGRAM([cdeclerr])], [libcdecl internal]) + +AT_SETUP([cdecl_declare truncation]) + +AT_DATA([input], +[[int hello_world +int x[1234567890] +]]) + +AT_CHECK([rendertest -n 0