]> git.draconx.ca Git - cdecl99.git/blob - test/crossparse.c
Batch up crossparse tests to improve performance.
[cdecl99.git] / test / crossparse.c
1 #include <config.h>
2 #include <stdio.h>
3 #include <stdlib.h>
4 #include <string.h>
5 #include <stdbool.h>
6 #include <getopt.h>
7 #include <cdecl.h>
8 #include "test.h"
9
10 #define PROGNAME "crossparse"
11 static const char *progname = PROGNAME;
12 static const char sopts[] = "ECVH";
13 static const struct option lopts[] = {
14         { "cdecl",   0, NULL, 'C' },
15         { "english", 0, NULL, 'E' },
16         { "version", 0, NULL, 'V' },
17         { "help",    0, NULL, 'H' },
18         { 0 }
19 };
20
21 static void print_usage(FILE *f)
22 {
23         fprintf(f, "Usage: %s [options]\n", progname);
24 }
25
26 static void print_help(void)
27 {
28         print_usage(stdout);
29         puts("Detailed help coming soon.");
30 }
31
32 enum {
33         MODE_CDECL,
34         MODE_ENGLISH,
35 };
36
37 typedef struct cdecl *parse_func(const char *);
38 typedef size_t render_func(char *, size_t, struct cdecl *);
39
40 char *rerender(const char *str, const char *parse_name,  parse_func *parse,
41                                 const char *render_name, render_func *render)
42 {
43         struct cdecl *decl = NULL;
44         char *buf = NULL;
45         size_t len;
46
47         decl = parse(str);
48         if (!decl) {
49                 fprintf(stderr, "%s: %s: failed to parse input: %s\n",
50                                 progname, parse_name, cdecl_get_error()->str);
51                 goto err;
52         }
53
54         len = render(NULL, 0, decl);
55         buf = malloc_nofail(len+1);
56         if (render(buf, len+1, decl) != len) {
57                 fprintf(stderr, "%s: %s: inconsistent length returned\n",
58                                 progname, render_name);
59                 goto err;
60         }
61
62         cdecl_free(decl);
63         return buf;
64 err:
65         cdecl_free(decl);
66         free(buf);
67
68         fprintf(stderr, "%s: the failed input was: %s\n", progname, str);
69         return NULL;
70 }
71 #define rerender(str, p, r) (rerender(str, #p, p, #r, r))
72
73 static bool test_crossparse(const char *str, int mode)
74 {
75         char *buf1 = NULL, *buf2 = NULL, *buf3 = NULL;
76         bool ret = false;
77
78         if (mode == MODE_ENGLISH) {
79                 buf1 = rerender(str, cdecl_parse_english, cdecl_declare);
80                 if (!buf1)
81                         goto out;
82                 buf2 = rerender(buf1, cdecl_parse_decl, cdecl_explain);
83                 if (!buf2)
84                         goto out;
85                 buf3 = rerender(buf2, cdecl_parse_english, cdecl_declare);
86                 if (!buf3)
87                         goto out;
88         } else {
89                 buf1 = rerender(str, cdecl_parse_decl, cdecl_explain);
90                 if (!buf1)
91                         goto out;
92                 buf2 = rerender(buf1, cdecl_parse_english, cdecl_declare);
93                 if (!buf2)
94                         goto out;
95                 buf3 = rerender(buf2, cdecl_parse_decl, cdecl_explain);
96                 if (!buf3)
97                         goto out;
98         }
99
100         if (!strcmp(buf1, buf3))
101                 ret = true;
102 out:
103         free(buf1);
104         free(buf2);
105         free(buf3);
106         return ret;
107 }
108
109 int main(int argc, char **argv)
110 {
111         int opt, mode = MODE_CDECL;
112         int ret = EXIT_FAILURE;
113
114         if (argc > 0)
115                 progname = argv[0];
116
117         while ((opt = getopt_long(argc, argv, sopts, lopts, NULL)) != -1) {
118                 switch (opt) {
119                 case 'C':
120                         mode = MODE_CDECL;
121                         break;
122                 case 'E':
123                         mode = MODE_ENGLISH;
124                         break;
125                 case 'V':
126                         test_print_version(PROGNAME);
127                         return EXIT_SUCCESS;
128                 case 'H':
129                         print_help();
130                         return EXIT_SUCCESS;
131                 default:
132                         print_usage(stderr);
133                         return EXIT_FAILURE;
134                 }
135         }
136
137         if (!argv[optind]) {
138                 print_usage(stderr);
139                 return EXIT_FAILURE;
140         }
141
142         for (int i = optind; i < argc; i++) {
143                 if (!test_crossparse(argv[i], mode)) {
144                         fprintf(stderr, "%s: failed cross-parse check of: %s\n",
145                                         progname, argv[i]);
146                         return EXIT_FAILURE;
147                 }
148         }
149
150         return EXIT_SUCCESS;
151 }