]> git.draconx.ca Git - cdecl99.git/commitdiff
Add a test case to check if libcdecl can parse its own output.
authorNick Bowler <nbowler@draconx.ca>
Thu, 1 Mar 2012 01:14:49 +0000 (20:14 -0500)
committerNick Bowler <nbowler@draconx.ca>
Sat, 3 Mar 2012 03:33:32 +0000 (22:33 -0500)
Makefile.am
test/.gitignore
test/crossparse.c [new file with mode: 0644]
test/randomdecl.c
test/test.h
test/testlib.c
tests/crossparse-c-random.sh [new file with mode: 0755]

index e11d380e197a56d7fadfd6de70cc456acfd3444c..e3b45d2fb12b84ee21058cc111e9e3e6863957e0 100644 (file)
@@ -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
index 7a3928c8e6a9e11a91418929814cde11ece8e334..e8d2dda7225a0c00743180c9744b1594ffd325a1 100644 (file)
@@ -1,2 +1,3 @@
 typegen.h
 randomdecl
+crossparse
diff --git a/test/crossparse.c b/test/crossparse.c
new file mode 100644 (file)
index 0000000..75344cb
--- /dev/null
@@ -0,0 +1,135 @@
+#include <config.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <getopt.h>
+#include <cdecl.h>
+#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;
+}
index 12728ccb7fa09d0aafe87712bb0b44cf04d2949c..5e8a4a94f59ac54d1653d43dd7e884eb98df9444 100644 (file)
@@ -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 <http://gnu.org/licenses/gpl.html>.");
-       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();
index dc661e3f31a538b29e4ea3c16875fb81c3deae1d..7cf89f1d7d2ec92b95c0cc771c0bc300cd4f71ee 100644 (file)
@@ -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
index e5143c20cc49a69805aa1d516d1b72151250d6a3..3c8bb8c03fc4f06333bbc0dab825e59a47c51891 100644 (file)
@@ -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 <http://gnu.org/licenses/gpl.html>.");
+       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 (executable)
index 0000000..03ec30f
--- /dev/null
@@ -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