From: Nick Bowler Date: Thu, 1 Mar 2012 01:14:49 +0000 (-0500) Subject: Add a test case to check if libcdecl can parse its own output. X-Git-Tag: v1~58 X-Git-Url: https://git.draconx.ca/gitweb/cdecl99.git/commitdiff_plain/e031b4f0220432aef6e1864ea6359353dbd8aed3 Add a test case to check if libcdecl can parse its own output. --- diff --git a/Makefile.am b/Makefile.am index e11d380..e3b45d2 100644 --- a/Makefile.am +++ b/Makefile.am @@ -54,7 +54,7 @@ cdecl99_SOURCES = src/cdecl99.c cdecl99_LDADD = libcdecl.la libgnu.la $(LTLIBINTL) $(LTLIBREADLINE) $(cdecl99_OBJECTS): $(gnulib_headers) -check_PROGRAMS = +check_PROGRAMS = test/crossparse check_LTLIBRARIES = libtest.la libtest_la_LIBADD = $(GSL_LIBS) libtest_la_SOURCES = test/testlib.c @@ -65,14 +65,16 @@ libtest_la_SOURCES += test/declgen.c check_PROGRAMS += test/randomdecl endif +test_crossparse_LDADD = libcdecl.la libtest.la libgnu.la +$(test_crossparse_OBJECTS): $(gnulib_headers) test_randomdecl_LDADD = libcdecl.la libtest.la libgnu.la $(test_randomdecl_OBJECTS): $(gnulib_headers) -TESTS_ENVIRONMENT = SHELL='$(SHELL)' LIBTOOL='$(LIBTOOL)' +TESTS_ENVIRONMENT = SHELL='$(SHELL)' LIBTOOL='$(LIBTOOL)' EXEEXT='$(EXEEXT)' TEST_EXTENSIONS = .sh SH_LOG_COMPILER = $(SHELL) -TESTS = tests/libcdecl-static-symbols.sh +TESTS = tests/libcdecl-static-symbols.sh tests/crossparse-c-random.sh EXTRA_DIST += $(TESTS) src/parse.lo: src/scan.h diff --git a/test/.gitignore b/test/.gitignore index 7a3928c..e8d2dda 100644 --- a/test/.gitignore +++ b/test/.gitignore @@ -1,2 +1,3 @@ typegen.h randomdecl +crossparse diff --git a/test/crossparse.c b/test/crossparse.c new file mode 100644 index 0000000..75344cb --- /dev/null +++ b/test/crossparse.c @@ -0,0 +1,135 @@ +#include +#include +#include +#include +#include +#include +#include "test.h" + +#define PROGNAME "crossparse" +static const char *progname = PROGNAME; +static const char sopts[] = "ECVH"; +static const struct option lopts[] = { + { "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("Detailed help coming soon."); +} + +enum { + MODE_CDECL, + MODE_ENGLISH, +}; + +typedef struct cdecl *parse_func(const char *); +typedef size_t render_func(char *, size_t, struct cdecl *); + +char *rerender(const char *str, const char *parse_name, parse_func *parse, + const char *render_name, render_func *render) +{ + struct cdecl *decl = NULL; + char *buf = NULL; + size_t len; + + decl = parse(str); + if (!decl) { + fprintf(stderr, "%s: %s: failed to parse input: %s\n", + progname, parse_name, cdecl_get_error()->str); + goto err; + } + + len = render(NULL, 0, decl); + buf = malloc_nofail(len+1); + if (render(buf, len+1, decl) != len) { + fprintf(stderr, "%s: %s: inconsistent length returned\n", + progname, render_name); + goto err; + } + + cdecl_free(decl); + return buf; +err: + cdecl_free(decl); + free(buf); + + fprintf(stderr, "%s: the failed input was: %s\n", progname, str); + return NULL; +} +#define rerender(str, p, r) (rerender(str, #p, p, #r, r)) + +int main(int argc, char **argv) +{ + char *buf1 = NULL, *buf2 = NULL, *buf3 = NULL; + int opt, mode = MODE_CDECL; + int ret = EXIT_FAILURE; + + 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 'V': + test_print_version(PROGNAME); + return EXIT_SUCCESS; + case 'H': + print_help(); + return EXIT_SUCCESS; + default: + print_usage(stderr); + return EXIT_FAILURE; + } + } + + if (!argv[optind]) { + print_usage(stderr); + return EXIT_FAILURE; + } + + if (mode == MODE_ENGLISH) { + buf1 = rerender(argv[optind], cdecl_parse_english, cdecl_declare); + if (!buf1) + goto out; + buf2 = rerender(buf1, cdecl_parse_decl, cdecl_explain); + if (!buf2) + goto out; + buf3 = rerender(buf2, cdecl_parse_english, cdecl_declare); + if (!buf3) + goto out; + } else { + buf1 = rerender(argv[optind], cdecl_parse_decl, cdecl_explain); + if (!buf1) + goto out; + buf2 = rerender(buf1, cdecl_parse_english, cdecl_declare); + if (!buf2) + goto out; + buf3 = rerender(buf2, cdecl_parse_decl, cdecl_explain); + if (!buf3) + goto out; + } + + if (!strcmp(buf1, buf3)) + ret = EXIT_SUCCESS; +out: + free(buf1); + free(buf2); + free(buf3); + return ret; +} diff --git a/test/randomdecl.c b/test/randomdecl.c index 12728cc..5e8a4a9 100644 --- a/test/randomdecl.c +++ b/test/randomdecl.c @@ -40,15 +40,6 @@ static const struct option lopts[] = { { 0 } }; -static void print_version() -{ - puts(PROGNAME " (" PACKAGE_NAME ") " PACKAGE_VERSION); - puts("Copyright (C) 2011 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."); -} - static void print_usage(FILE *f) { fprintf(f, "Usage: %s [options]\n", progname); @@ -101,7 +92,7 @@ int main(int argc, char **argv) count_str = optarg; break; case 'V': - print_version(); + test_print_version(PROGNAME); return EXIT_SUCCESS; case 'H': print_help(); diff --git a/test/test.h b/test/test.h index dc661e3..7cf89f1 100644 --- a/test/test.h +++ b/test/test.h @@ -14,4 +14,6 @@ void test_print_decl(struct cdecl *decl); bool strict_strtoul(unsigned long *val, const char *str, int base); +void test_print_version(const char *program); + #endif diff --git a/test/testlib.c b/test/testlib.c index e5143c2..3c8bb8c 100644 --- a/test/testlib.c +++ b/test/testlib.c @@ -69,3 +69,12 @@ bool strict_strtoul(unsigned long *val, const char *str, int base) return true; } + +void test_print_version(const char *program) +{ + printf("%s (%s) %s\n", program, PACKAGE_NAME, PACKAGE_VERSION); + puts("Copyright (C) 2011 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/crossparse-c-random.sh b/tests/crossparse-c-random.sh new file mode 100755 index 0000000..03ec30f --- /dev/null +++ b/tests/crossparse-c-random.sh @@ -0,0 +1,47 @@ +#!/bin/sh +# +# Copyright © 2012 Nick Bowler +# +# Randomized tests that libcdecl can parse its own output. +# +# License WTFPL2: Do What The Fuck You Want To Public License, version 2. +# This is free software: you are free to do what the fuck you want to. +# There is NO WARRANTY, to the extent permitted by law. + +: "${RANDOMSEED=$RANDOM}" "${TESTITER=100}" + +randomdecl=test/randomdecl$EXEEXT +crossparse=test/crossparse$EXEEXT +test -x $randomdecl || exit 77 + +proc() { + result=pass + count=0 + + while read decl + do + count=`expr $count + 1` + $crossparse "$decl" || { result=fail; break; } + done + + echo "result=$result" + echo "count=$count" +} + +printf '%s: randomized test using RANDOMSEED=%d\n' "$0" "$RANDOMSEED" + +eval_cmd=`exec 3>&1 + { $randomdecl -s "$RANDOMSEED" -n "$TESTITER" 3>&- + echo gen_status=$? >&3 + } | proc >&3` +eval "$eval_cmd" + +expected_count=`expr "$TESTITER" + 0` +if test x"$count" != x"$expected_count"; then + printf '%s: failed after %d successful tests (out of %d)\n' \ + "$0" "$count" "$expected_count" 1>&2 + exit 1 +fi + +test x"$result" = x"pass" && test x"$gen_status" = x"0" && exit 0 +exit 1