Bump to 1.14.1
[platform/upstream/augeas.git] / tests / test-run.c
1 /*
2  * test-run.c: test the aug_srun API function
3  *
4  * Copyright (C) 2009-2016 David Lutterkort
5  *
6  * This library is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU Lesser General Public
8  * License as published by the Free Software Foundation; either
9  * version 2.1 of the License, or (at your option) any later version.
10  *
11  * This library is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14  * Lesser General Public License for more details.
15  *
16  * You should have received a copy of the GNU Lesser General Public
17  * License along with this library; if not, write to the Free Software
18  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307  USA
19  *
20  * Author: David Lutterkort <lutter@redhat.com>
21  */
22
23 #include <config.h>
24
25 #include <stdlib.h>
26 #include <stdio.h>
27 #include <ctype.h>
28
29 #include "augeas.h"
30
31 #include "cutest.h"
32 #include "internal.h"
33 #include <memory.h>
34
35 #include <unistd.h>
36
37 static const char *abs_top_srcdir;
38 static char *lensdir;
39
40 #define KW_TEST "test"
41 #define KW_PRINTS "prints"
42 #define KW_SOMETHING "something"
43 #define KW_USE "use"
44
45 /* This array needs to be kept in sync with aug_errcode_t, and
46  * the entries need to be in the same order as in that enum; used
47  * by errtok
48  */
49 static const char *const errtokens[] = {
50     "NOERROR", "ENOMEM", "EINTERNAL", "EPATHX", "ENOMATCH",
51     "EMMATCH", "ESYNTAX", "ENOLENS", "EMXFM", "ENOSPAN",
52     "EMVDESC", "ECMDRUN", "EBADARG", "ELABEL"
53 };
54
55 struct test {
56     struct test *next;
57     char *name;
58     char *module;
59     int  result;
60     int  errcode;
61     char *cmd;
62     char *out;
63     bool  out_present;
64 };
65
66 static void free_tests(struct test *test) {
67     if (test == NULL)
68         return;
69     free_tests(test->next);
70     free(test->name);
71     free(test->module);
72     free(test->cmd);
73     free(test->out);
74     free(test);
75 }
76
77 #define die(msg)                                                    \
78     do {                                                            \
79         fprintf(stderr, "%d: Fatal error: %s\n", __LINE__, msg);    \
80         exit(EXIT_FAILURE);                                         \
81     } while(0)
82
83 static char *skipws(char *s) {
84     while (isspace(*s)) s++;
85     return s;
86 }
87
88 static char *findws(char *s) {
89     while (*s && ! isspace(*s)) s++;
90     return s;
91 }
92
93 static char *token(char *s, char **tok) {
94     char *t = skipws(s);
95     s = findws(t);
96     *tok = strndup(t, s - t);
97     return s;
98 }
99
100 static char *inttok(char *s, int *tok) {
101     char *t = skipws(s);
102     s = findws(t);
103     *tok = strtol(t, NULL, 10);
104     return s;
105 }
106
107 static char *errtok(char *s, int *err) {
108     char *t = skipws(s);
109     s = findws(t);
110     if (s == t) {
111         *err = AUG_NOERROR;
112         return s;
113     }
114     for (*err = 0; *err < ARRAY_CARDINALITY(errtokens); *err += 1) {
115         const char *e = errtokens[*err];
116         if (strlen(e) == s - t && STREQLEN(e, t, s - t))
117             return s;
118     }
119     fprintf(stderr, "errtok: '%s'\n", t);
120     die("unknown error code");
121 }
122
123 static bool looking_at(const char *s, const char *kw) {
124     return STREQLEN(s, kw, strlen(kw));
125 }
126
127 static struct test *read_tests(void) {
128     char *fname = NULL;
129     FILE *fp;
130     char line[BUFSIZ];
131     struct test *result = NULL, *t = NULL;
132     int lc = 0;
133     bool append_cmd = true;
134
135     if (asprintf(&fname, "%s/tests/run.tests", abs_top_srcdir) < 0)
136         die("asprintf fname");
137
138     if ((fp = fopen(fname, "r")) == NULL)
139         die("fopen run.tests");
140
141     while (fgets(line, BUFSIZ, fp) != NULL) {
142         lc += 1;
143         char *s = skipws(line);
144         if (*s == '#' || *s == '\0')
145             continue;
146         if (*s == ':')
147             s += 1;
148         char *eos = s + strlen(s) - 2;
149         if (eos >= s && *eos == ':') {
150             *eos++ = '\n';
151             *eos = '\0';
152         }
153
154         if (looking_at(s, KW_TEST)) {
155             if (ALLOC(t) < 0)
156                 die_oom();
157             list_append(result, t);
158             append_cmd = true;
159             s = token(s + strlen(KW_TEST), &(t->name));
160             s = inttok(s, &t->result);
161             s = errtok(s, &t->errcode);
162         } else if (looking_at(s, KW_PRINTS)) {
163             s = skipws(s + strlen(KW_PRINTS));
164             t->out_present = looking_at(s, KW_SOMETHING);
165             append_cmd = false;
166         } else if (looking_at(s, KW_USE)) {
167             if (t->module !=NULL)
168                 die("Can use at most one module in a test");
169             s = token(s + strlen(KW_USE), &(t->module));
170         } else {
171             char **buf = append_cmd ? &(t->cmd) : &(t->out);
172             if (*buf == NULL) {
173                 *buf = strdup(s);
174                 if (*buf == NULL)
175                     die_oom();
176             } else {
177                 if (REALLOC_N(*buf, strlen(*buf) + strlen(s) + 1) < 0)
178                     die_oom();
179                 strcat(*buf, s);
180             }
181         }
182         if (t->out != NULL)
183             t->out_present = true;
184     }
185     free(fname);
186     return result;
187 }
188
189 #define fail(cond, msg ...)                     \
190     if (cond) {                                 \
191         printf("FAIL (");                       \
192         fprintf(stdout, ## msg);                \
193         printf(")\n");                          \
194         goto error;                             \
195     }
196
197 static int load_module(struct augeas *aug, struct test *test) {
198     char *fname, *fpath;
199     int r, result = -1;
200
201     if (test->module == NULL)
202         return 0;
203
204     if (asprintf(&fname, "%s.aug", test->module) == -1)
205        fail(true, "asprintf test->module");
206
207     for (int i=0; i < strlen(fname); i++)
208         fname[i] = tolower(fname[i]);
209
210     if (asprintf(&fpath, "%s/%s", lensdir, fname) == -1)
211         fail(true, "asprintf lensdir");
212
213     r = __aug_load_module_file(aug, fpath);
214     fail(r < 0, "Could not load %s", fpath);
215     result = 0;
216  error:
217     free(fname);
218     free(fpath);
219     return result;
220 }
221
222 static int run_one_test(struct test *test) {
223     int r;
224     struct augeas *aug = NULL;
225     struct memstream ms;
226     int result = 0;
227
228     MEMZERO(&ms, 1);
229
230     aug = aug_init("/dev/null", lensdir,
231                    AUG_NO_STDINC|AUG_NO_MODL_AUTOLOAD|AUG_ENABLE_SPAN);
232     fail(aug == NULL, "aug_init");
233     fail(aug_error(aug) != AUG_NOERROR, "aug_init: errcode was %d",
234          aug_error(aug));
235
236     printf("%-30s ... ", test->name);
237
238     r = load_module(aug, test);
239     if (r < 0)
240         goto error;
241
242     r = init_memstream(&ms);
243     fail(r < 0, "init_memstream");
244
245     r = aug_srun(aug, ms.stream, test->cmd);
246     fail(r != test->result, "return value: expected %d, actual %d",
247          test->result, r);
248     fail(aug_error(aug) != test->errcode, "errcode: expected %s, actual %s",
249          errtokens[test->errcode], errtokens[aug_error(aug)]);
250
251     r = close_memstream(&ms);
252     fail(r < 0, "close_memstream");
253     fail(ms.buf == NULL, "close_memstream left buf NULL");
254
255     if (test->out != NULL) {
256         fail(STRNEQ(ms.buf, test->out), "output: expected '%s', actual '%s'",
257              test->out, ms.buf);
258     } else if (test->out_present) {
259         fail(strlen(ms.buf) == 0,
260              "output: expected some output");
261     } else {
262         fail(strlen(ms.buf) > 0,
263              "output: expected nothing, actual '%s'", ms.buf);
264     }
265     printf("PASS\n");
266
267  done:
268     free(ms.buf);
269     aug_close(aug);
270     return result;
271  error:
272     result = -1;
273     goto done;
274 }
275
276 static int run_tests(struct test *tests, int argc, char **argv) {
277     int result = EXIT_SUCCESS;
278
279     list_for_each(t, tests) {
280         if (! should_run(t->name, argc, argv))
281             continue;
282         if (run_one_test(t) < 0)
283             result = EXIT_FAILURE;
284     }
285     return result;
286 }
287
288 int main(int argc, char **argv) {
289     struct test *tests;
290
291     abs_top_srcdir = getenv("abs_top_srcdir");
292     if (abs_top_srcdir == NULL)
293         die("env var abs_top_srcdir must be set");
294
295     if (asprintf(&lensdir, "%s/lenses", abs_top_srcdir) < 0)
296         die("out of memory setting lensdir");
297
298     tests = read_tests();
299     int result = run_tests(tests, argc - 1, argv + 1);
300     free_tests(tests);
301     return result;
302 }
303
304 /*
305  * Local variables:
306  *  indent-tabs-mode: nil
307  *  c-indent-level: 4
308  *  c-basic-offset: 4
309  *  tab-width: 4
310  * End:
311  */