Imported Upstream version 0.10.0
[platform/upstream/augeas.git] / tests / test-run.c
1 /*
2  * test-run.c: test the aug_srun API function
3  *
4  * Copyright (C) 2009-2011 Red Hat Inc.
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
39 #define KW_TEST "test"
40 #define KW_PRINTS "prints"
41 #define KW_SOMETHING "something"
42
43 /* This array needs to be kept in sync with aug_errcode_t, and
44  * the entries need to be in the same order as in that enum; used
45  * by errtok
46  */
47 static const char *const errtokens[] = {
48     "NOERROR", "ENOMEM", "EINTERNAL", "EPATHX", "ENOMATCH",
49     "EMMATCH", "ESYNTAX", "ENOLENS", "EMXFM", "ENOSPAN",
50     "EMVDESC", "ECMDRUN"
51 };
52
53 struct test {
54     struct test *next;
55     char *name;
56     int  result;
57     int  errcode;
58     char *cmd;
59     char *out;
60     bool  out_present;
61 };
62
63 #define die(msg)                                                    \
64     do {                                                            \
65         fprintf(stderr, "%d: Fatal error: %s\n", __LINE__, msg);    \
66         exit(EXIT_FAILURE);                                         \
67     } while(0)
68
69 static char *skipws(char *s) {
70     while (isspace(*s)) s++;
71     return s;
72 }
73
74 static char *findws(char *s) {
75     while (*s && ! isspace(*s)) s++;
76     return s;
77 }
78
79 static char *token(char *s, char **tok) {
80     char *t = skipws(s);
81     s = findws(t);
82     *tok = strndup(t, s - t);
83     return s;
84 }
85
86 static char *inttok(char *s, int *tok) {
87     char *t = skipws(s);
88     s = findws(t);
89     *tok = strtol(t, NULL, 10);
90     return s;
91 }
92
93 static char *errtok(char *s, int *err) {
94     char *t = skipws(s);
95     s = findws(t);
96     if (s == t) {
97         *err = AUG_NOERROR;
98         return s;
99     }
100     for (*err = 0; *err < ARRAY_CARDINALITY(errtokens); *err += 1) {
101         const char *e = errtokens[*err];
102         if (strlen(e) == s - t && STREQLEN(e, t, s - t))
103             return s;
104     }
105     fprintf(stderr, "errtok: '%s'\n", t);
106     die("unknown error code");
107 }
108
109 static bool looking_at(const char *s, const char *kw) {
110     return STREQLEN(s, kw, strlen(kw));
111 }
112
113 static struct test *read_tests(void) {
114     char *fname;
115     FILE *fp;
116     char line[BUFSIZ];
117     struct test *result = NULL, *t = NULL;
118     int lc = 0;
119     bool append_cmd = true;
120
121     if (asprintf(&fname, "%s/tests/run.tests", abs_top_srcdir) < 0)
122         die("asprintf fname");
123
124     if ((fp = fopen(fname, "r")) == NULL)
125         die("fopen run.tests");
126
127     while (fgets(line, BUFSIZ, fp) != NULL) {
128         lc += 1;
129         char *s = skipws(line);
130         if (*s == '#' || *s == '\0')
131             continue;
132         if (*s == ':')
133             s += 1;
134         char *eos = s + strlen(s) - 2;
135         if (eos >= s && *eos == ':') {
136             *eos++ = '\n';
137             *eos = '\0';
138         }
139
140         if (looking_at(s, KW_TEST)) {
141             if (ALLOC(t) < 0)
142                 die_oom();
143             list_append(result, t);
144             append_cmd = true;
145             s = token(s + strlen(KW_TEST), &(t->name));
146             s = inttok(s, &t->result);
147             s = errtok(s, &t->errcode);
148         } else if (looking_at(s, KW_PRINTS)) {
149             s = skipws(s + strlen(KW_PRINTS));
150             t->out_present = looking_at(s, KW_SOMETHING);
151             append_cmd = false;
152         } else {
153             char **buf = append_cmd ? &(t->cmd) : &(t->out);
154             if (*buf == NULL) {
155                 *buf = strdup(s);
156                 if (*buf == NULL)
157                     die_oom();
158             } else {
159                 if (REALLOC_N(*buf, strlen(*buf) + strlen(s) + 1) < 0)
160                     die_oom();
161                 strcat(*buf, s);
162             }
163         }
164         if (t->out != NULL)
165             t->out_present = true;
166     }
167     return result;
168 }
169
170 #define fail(cond, msg ...)                     \
171     if (cond) {                                 \
172         printf("FAIL (");                       \
173         fprintf(stdout, ## msg);                \
174         printf(")\n");                          \
175         goto error;                             \
176     }
177
178 static int run_one_test(struct test *test) {
179     int r;
180     struct augeas *aug = NULL;
181     struct memstream ms;
182     int result = 0;
183
184     aug = aug_init("/dev/null", NULL, AUG_NO_STDINC|AUG_NO_LOAD);
185     fail(aug == NULL, "aug_init");
186     fail(aug_error(aug) != AUG_NOERROR, "aug_init: errcode was %d",
187          aug_error(aug));
188
189     printf("%-30s ... ", test->name);
190
191     r = init_memstream(&ms);
192     fail(r < 0, "init_memstream");
193
194     r = aug_srun(aug, ms.stream, test->cmd);
195     fail(r != test->result, "return value: expected %d, actual %d",
196          test->result, r);
197     fail(aug_error(aug) != test->errcode, "errcode: expected %s, actual %s",
198          errtokens[test->errcode], errtokens[aug_error(aug)]);
199
200     r = close_memstream(&ms);
201     fail(r < 0, "close_memstream");
202     fail(ms.buf == NULL, "close_memstream left buf NULL");
203
204     if (test->out != NULL) {
205         fail(STRNEQ(ms.buf, test->out), "output: expected '%s', actual '%s'",
206              test->out, ms.buf);
207     } else if (test->out_present) {
208         fail(strlen(ms.buf) == 0,
209              "output: expected some output");
210     } else {
211         fail(strlen(ms.buf) > 0,
212              "output: expected nothing, actual '%s'", ms.buf);
213     }
214     printf("PASS\n");
215
216  done:
217     free(ms.buf);
218     aug_close(aug);
219     return result;
220  error:
221     result = -1;
222     goto done;
223 }
224
225 static int run_tests(struct test *tests) {
226     int result = EXIT_SUCCESS;
227
228     list_for_each(t, tests) {
229         if (run_one_test(t) < 0)
230             result = EXIT_FAILURE;
231     }
232     return result;
233 }
234
235 int main(void) {
236     struct test *tests;
237
238     abs_top_srcdir = getenv("abs_top_srcdir");
239     if (abs_top_srcdir == NULL)
240         die("env var abs_top_srcdir must be set");
241
242     tests = read_tests();
243     return run_tests(tests);
244 }
245
246 /*
247  * Local variables:
248  *  indent-tabs-mode: nil
249  *  c-indent-level: 4
250  *  c-basic-offset: 4
251  *  tab-width: 4
252  * End:
253  */