Imported Upstream version 0.10.0
[platform/upstream/augeas.git] / tests / test-api.c
1 /*
2  * test-api.c: test public API functions for conformance
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 "augeas.h"
26
27 #include "cutest.h"
28 #include "internal.h"
29
30 #include <unistd.h>
31
32 #include <libxml/tree.h>
33
34 static const char *abs_top_srcdir;
35 static char *root;
36 static char *loadpath;
37
38 #define die(msg)                                                    \
39     do {                                                            \
40         fprintf(stderr, "%d: Fatal error: %s\n", __LINE__, msg);    \
41         exit(EXIT_FAILURE);                                         \
42     } while(0)
43
44 static void testGet(CuTest *tc) {
45     int r;
46     const char *value;
47     struct augeas *aug;
48
49     aug = aug_init(root, loadpath, AUG_NO_STDINC|AUG_NO_LOAD);
50     CuAssertPtrNotNull(tc, aug);
51     CuAssertIntEquals(tc, AUG_NOERROR, aug_error(aug));
52
53     /* Make sure we're looking at the right thing */
54     r = aug_match(aug, "/augeas/version/save/*", NULL);
55     CuAssertTrue(tc, r > 1);
56     CuAssertIntEquals(tc, AUG_NOERROR, aug_error(aug));
57
58     /* aug_get returns 1 and the value if exactly one node matches */
59     r = aug_get(aug, "/augeas/version/save/*[1]", &value);
60     CuAssertIntEquals(tc, 1, r);
61     CuAssertPtrNotNull(tc, value);
62     CuAssertIntEquals(tc, AUG_NOERROR, aug_error(aug));
63
64     /* aug_get returns 0 and no value when no node matches */
65     r = aug_get(aug, "/augeas/version/save/*[ last() + 1 ]", &value);
66     CuAssertIntEquals(tc, 0, r);
67     CuAssertPtrEquals(tc, NULL, value);
68     CuAssertIntEquals(tc, AUG_NOERROR, aug_error(aug));
69
70     /* aug_get should return an error when multiple nodes match */
71     r = aug_get(aug, "/augeas/version/save/*", &value);
72     CuAssertIntEquals(tc, -1, r);
73     CuAssertPtrEquals(tc, NULL, value);
74     CuAssertIntEquals(tc, AUG_EMMATCH, aug_error(aug));
75
76     /* augeas should prepend context if relative path given */
77     r = aug_set(aug, "/augeas/context", "/augeas/version");
78     r = aug_get(aug, "save/*[1]", &value);
79     CuAssertIntEquals(tc, 1, r);
80     CuAssertPtrNotNull(tc, value);
81     CuAssertIntEquals(tc, AUG_NOERROR, aug_error(aug));
82
83     /* augeas should still work with an empty context */
84     r = aug_set(aug, "/augeas/context", "");
85     r = aug_get(aug, "/augeas/version", &value);
86     CuAssertIntEquals(tc, 1, r);
87     CuAssertPtrNotNull(tc, value);
88     CuAssertIntEquals(tc, AUG_NOERROR, aug_error(aug));
89
90     /* augeas should ignore trailing slashes in context */
91     r = aug_set(aug, "/augeas/context", "/augeas/version/");
92     r = aug_get(aug, "save/*[1]", &value);
93     CuAssertIntEquals(tc, 1, r);
94     CuAssertPtrNotNull(tc, value);
95     CuAssertIntEquals(tc, AUG_NOERROR, aug_error(aug));
96
97     aug_close(aug);
98 }
99
100 static void testSet(CuTest *tc) {
101     int r;
102     const char *value;
103     struct augeas *aug;
104
105     aug = aug_init(root, loadpath, AUG_NO_STDINC|AUG_NO_LOAD);
106     CuAssertPtrNotNull(tc, aug);
107     CuAssertIntEquals(tc, AUG_NOERROR, aug_error(aug));
108
109     /* aug_set returns 0 for a simple set */
110     r = aug_set(aug, "/augeas/testSet", "foo");
111     CuAssertIntEquals(tc, 0, r);
112     CuAssertIntEquals(tc, AUG_NOERROR, aug_error(aug));
113
114     /* aug_set returns -1 when cannot set due to multiple nodes */
115     r = aug_set(aug, "/augeas/version/save/*", "foo");
116     CuAssertIntEquals(tc, -1, r);
117     CuAssertIntEquals(tc, AUG_EMMATCH, aug_error(aug));
118
119     /* aug_set is able to set the context, even when currently invalid */
120     r = aug_set(aug, "/augeas/context", "( /files | /augeas )");
121     CuAssertIntEquals(tc, 0, r);
122     CuAssertIntEquals(tc, AUG_NOERROR, aug_error(aug));
123     r = aug_get(aug, "/augeas/version", &value);
124     CuAssertIntEquals(tc, -1, r);
125     CuAssertIntEquals(tc, AUG_EMMATCH, aug_error(aug));
126     r = aug_set(aug, "/augeas/context", "/files");
127     CuAssertIntEquals(tc, 0, r);
128     CuAssertIntEquals(tc, AUG_NOERROR, aug_error(aug));
129
130     aug_close(aug);
131 }
132
133 static void testSetM(CuTest *tc) {
134     int r;
135     struct augeas *aug;
136
137     aug = aug_init(root, loadpath, AUG_NO_STDINC|AUG_NO_LOAD);
138     CuAssertPtrNotNull(tc, aug);
139     CuAssertIntEquals(tc, AUG_NOERROR, aug_error(aug));
140
141     /* Change base nodes when SUB is NULL */
142     r = aug_setm(aug, "/augeas/version/save/*", NULL, "changed");
143     CuAssertIntEquals(tc, 4, r);
144
145     r = aug_match(aug, "/augeas/version/save/*[. = 'changed']", NULL);
146     CuAssertIntEquals(tc, 4, r);
147
148     /* Only change existing nodes */
149     r = aug_setm(aug, "/augeas/version/save", "mode", "again");
150     CuAssertIntEquals(tc, 4, r);
151
152     r = aug_match(aug, "/augeas/version/save/*", NULL);
153     CuAssertIntEquals(tc, 4, r);
154
155     r = aug_match(aug, "/augeas/version/save/*[. = 'again']", NULL);
156     CuAssertIntEquals(tc, 4, r);
157
158     /* Create a new node */
159     r = aug_setm(aug, "/augeas/version/save", "mode[last() + 1]", "newmode");
160     CuAssertIntEquals(tc, 1, r);
161
162     r = aug_match(aug, "/augeas/version/save/*", NULL);
163     CuAssertIntEquals(tc, 5, r);
164
165     r = aug_match(aug, "/augeas/version/save/*[. = 'again']", NULL);
166     CuAssertIntEquals(tc, 4, r);
167
168     r = aug_match(aug, "/augeas/version/save/*[last()][. = 'newmode']", NULL);
169     CuAssertIntEquals(tc, 1, r);
170
171     /* Noexistent base */
172     r = aug_setm(aug, "/augeas/version/save[last()+1]", "mode", "newmode");
173     CuAssertIntEquals(tc, 0, r);
174
175     /* Invalid path expressions */
176     r = aug_setm(aug, "/augeas/version/save[]", "mode", "invalid");
177     CuAssertIntEquals(tc, -1, r);
178
179     r = aug_setm(aug, "/augeas/version/save/*", "mode[]", "invalid");
180     CuAssertIntEquals(tc, -1, r);
181
182     aug_close(aug);
183 }
184
185 /* Check that defining a variable leads to a corresponding entry in
186  * /augeas/variables and that that entry disappears when the variable is
187  * undefined */
188 static void testDefVarMeta(CuTest *tc) {
189     int r;
190     struct augeas *aug;
191     static const char *const expr = "/augeas/version/save/mode";
192     const char *value;
193
194     aug = aug_init(root, loadpath, AUG_NO_STDINC|AUG_NO_LOAD);
195     CuAssertPtrNotNull(tc, aug);
196     CuAssertIntEquals(tc, AUG_NOERROR, aug_error(aug));
197
198     r = aug_defvar(aug, "var", expr);
199     CuAssertIntEquals(tc, 4, r);
200
201     r = aug_match(aug, "/augeas/variables/*", NULL);
202     CuAssertIntEquals(tc, 1, r);
203
204     r = aug_get(aug, "/augeas/variables/var", &value);
205     CuAssertStrEquals(tc, expr, value);
206
207     r = aug_defvar(aug, "var", NULL);
208     CuAssertIntEquals(tc, 0, r);
209
210     r = aug_match(aug, "/augeas/variables/*", NULL);
211     CuAssertIntEquals(tc, 0, r);
212
213     aug_close(aug);
214 }
215
216 /* Check that defining a variable with defnode leads to a corresponding
217  * entry in /augeas/variables and that that entry disappears when the
218  * variable is undefined
219  */
220 static void testDefNodeExistingMeta(CuTest *tc) {
221     int r, created;
222     struct augeas *aug;
223     static const char *const expr = "/augeas/version/save/mode";
224     const char *value;
225
226     aug = aug_init(root, loadpath, AUG_NO_STDINC|AUG_NO_LOAD);
227     CuAssertPtrNotNull(tc, aug);
228     CuAssertIntEquals(tc, AUG_NOERROR, aug_error(aug));
229
230     r = aug_defnode(aug, "var", expr, "other", &created);
231     CuAssertIntEquals(tc, 4, r);
232     CuAssertIntEquals(tc, 0, created);
233
234     r = aug_match(aug, "/augeas/variables/*", NULL);
235     CuAssertIntEquals(tc, 1, r);
236
237     r = aug_get(aug, "/augeas/variables/var", &value);
238     CuAssertStrEquals(tc, expr, value);
239
240     r = aug_defvar(aug, "var", NULL);
241     CuAssertIntEquals(tc, 0, r);
242
243     r = aug_match(aug, "/augeas/variables/*", NULL);
244     CuAssertIntEquals(tc, 0, r);
245
246     aug_close(aug);
247 }
248
249 /* Check that defining a variable with defnode leads to a corresponding
250  * entry in /augeas/variables and that that entry disappears when the
251  * variable is undefined
252  */
253 static void testDefNodeCreateMeta(CuTest *tc) {
254     int r, created;
255     struct augeas *aug;
256     static const char *const expr = "/augeas/version/save/mode[last()+1]";
257     static const char *const expr_can = "/augeas/version/save/mode[5]";
258     const char *value;
259
260     aug = aug_init(root, loadpath, AUG_NO_STDINC|AUG_NO_LOAD);
261     CuAssertPtrNotNull(tc, aug);
262     CuAssertIntEquals(tc, AUG_NOERROR, aug_error(aug));
263
264     r = aug_defnode(aug, "var", expr, "other", &created);
265     CuAssertIntEquals(tc, 1, r);
266     CuAssertIntEquals(tc, 1, created);
267
268     r = aug_match(aug, "/augeas/variables/*", NULL);
269     CuAssertIntEquals(tc, 1, r);
270
271     r = aug_get(aug, "/augeas/variables/var", &value);
272     CuAssertStrEquals(tc, expr_can, value);
273
274     r = aug_defvar(aug, "var", NULL);
275     CuAssertIntEquals(tc, 0, r);
276
277     r = aug_match(aug, "/augeas/variables/*", NULL);
278     CuAssertIntEquals(tc, 0, r);
279
280     aug_close(aug);
281 }
282
283 static void reset_indexes(uint *a, uint *b, uint *c, uint *d, uint *e, uint *f) {
284     *a = 0; *b = 0; *c = 0; *d = 0; *e = 0; *f = 0;
285 }
286
287 #define SPAN_TEST_DEF_LAST { .expr = NULL, .ls = 0, .le = 0, \
288         .vs = 0, .ve = 0, .ss = 0, .se = 0 }
289
290 struct span_test_def {
291     const char *expr;
292     const char *f;
293     int ret;
294     int ls;
295     int le;
296     int vs;
297     int ve;
298     int ss;
299     int se;
300 };
301
302 static const struct span_test_def span_test[] = {
303     { .expr = "/files/etc/hosts/1/ipaddr", .f = "hosts", .ret = 0, .ls = 0, .le = 0, .vs = 104, .ve = 113, .ss = 104, .se = 113 },
304     { .expr = "/files/etc/hosts/1", .f = "hosts", .ret = 0, .ls = 0, .le = 0, .vs = 0, .ve = 0, .ss = 104, .se = 171 },
305     { .expr = "/files/etc/hosts/*[last()]", .f = "hosts", .ret = 0, .ls = 0, .le = 0, .vs = 0, .ve = 0, .ss = 266, .se = 309 },
306     { .expr = "/files/etc/hosts/#comment[2]", .f = "hosts", .ret = 0, .ls = 0, .le = 0, .vs = 58, .ve = 103, .ss = 56, .se = 104 },
307     { .expr = "/files/etc/hosts", .f = "hosts", .ret = 0, .ls = 0, .le = 0, .vs = 0, .ve = 0, .ss = 0, .se = 309 },
308     { .expr = "/files", .f = NULL, .ret = -1, .ls = 0, .le = 0, .vs = 0, .ve = 0, .ss = 0, .se = 0 },
309     { .expr = "/random", .f = NULL, .ret = -1, .ls = 0, .le = 0, .vs = 0, .ve = 0, .ss = 0, .se = 0 },
310     SPAN_TEST_DEF_LAST
311 };
312
313 static void testNodeInfo(CuTest *tc) {
314     int ret;
315     int i = 0;
316     struct augeas *aug;
317     struct span_test_def test;
318     char *fbase;
319     char msg[1024];
320     static const char *const expr = "/files/etc/hosts/1/ipaddr";
321
322     char *filename_ac;
323     uint label_start, label_end, value_start, value_end, span_start, span_end;
324
325     aug = aug_init(root, loadpath, AUG_NO_STDINC|AUG_NO_LOAD|AUG_ENABLE_SPAN);
326     ret = aug_load(aug);
327     CuAssertRetSuccess(tc, ret);
328
329     while(span_test[i].expr != NULL) {
330         test = span_test[i];
331         i++;
332         ret = aug_span(aug, test.expr, &filename_ac, &label_start, &label_end,
333                      &value_start, &value_end, &span_start, &span_end);
334         sprintf(msg, "span_test %d ret\n", i);
335         CuAssertIntEquals_Msg(tc, msg, test.ret, ret);
336         sprintf(msg, "span_test %d label_start\n", i);
337         CuAssertIntEquals_Msg(tc, msg, test.ls, label_start);
338         sprintf(msg, "span_test %d label_end\n", i);
339         CuAssertIntEquals_Msg(tc, msg, test.le, label_end);
340         sprintf(msg, "span_test %d value_start\n", i);
341         CuAssertIntEquals_Msg(tc, msg, test.vs, value_start);
342         sprintf(msg, "span_test %d value_end\n", i);
343         CuAssertIntEquals_Msg(tc, msg, test.ve, value_end);
344         sprintf(msg, "span_test %d span_start\n", i);
345         CuAssertIntEquals_Msg(tc, msg, test.ss, span_start);
346         sprintf(msg, "span_test %d span_end\n", i);
347         CuAssertIntEquals_Msg(tc, msg, test.se, span_end);
348         if (filename_ac != NULL) {
349             fbase = basename(filename_ac);
350         } else {
351             fbase = NULL;
352         }
353         sprintf(msg, "span_test %d filename\n", i);
354         CuAssertStrEquals_Msg(tc, msg, test.f, fbase);
355         free(filename_ac);
356         filename_ac = NULL;
357         reset_indexes(&label_start, &label_end, &value_start, &value_end,
358                       &span_start, &span_end);
359     }
360
361     /* aug_span returns -1 and when no node matches */
362     ret = aug_span(aug, "/files/etc/hosts/*[ last() + 1 ]", &filename_ac,
363             &label_start, &label_end, &value_start, &value_end,
364             &span_start, &span_end);
365     CuAssertIntEquals(tc, -1, ret);
366     CuAssertPtrEquals(tc, NULL, filename_ac);
367     CuAssertIntEquals(tc, AUG_ENOMATCH, aug_error(aug));
368
369     /* aug_span should return an error when multiple nodes match */
370     ret = aug_span(aug, "/files/etc/hosts/*", &filename_ac,
371             &label_start, &label_end, &value_start, &value_end,
372             &span_start, &span_end);
373     CuAssertIntEquals(tc, -1, ret);
374     CuAssertPtrEquals(tc, NULL, filename_ac);
375     CuAssertIntEquals(tc, AUG_EMMATCH, aug_error(aug));
376
377     /* aug_span returns -1 if nodes span are not loaded */
378     aug_close(aug);
379     aug = aug_init(root, loadpath, AUG_NO_STDINC|AUG_NO_LOAD);
380     ret = aug_load(aug);
381     CuAssertRetSuccess(tc, ret);
382     ret = aug_span(aug, expr, &filename_ac, &label_start, &label_end,
383                  &value_start, &value_end, &span_start, &span_end);
384     CuAssertIntEquals(tc, -1, ret);
385     CuAssertPtrEquals(tc, NULL, filename_ac);
386     CuAssertIntEquals(tc, AUG_ENOSPAN, aug_error(aug));
387     reset_indexes(&label_start, &label_end, &value_start, &value_end,
388                   &span_start, &span_end);
389
390     aug_close(aug);
391 }
392
393 static void testMv(CuTest *tc) {
394     struct augeas *aug;
395     int r;
396
397     aug = aug_init(root, loadpath, AUG_NO_STDINC|AUG_NO_LOAD);
398     CuAssertPtrNotNull(tc, aug);
399
400     r = aug_set(aug, "/a/b/c", "value");
401     CuAssertRetSuccess(tc, r);
402
403     r = aug_mv(aug, "/a/b/c", "/a/b/c/d");
404     CuAssertIntEquals(tc, -1, r);
405     CuAssertIntEquals(tc, AUG_EMVDESC, aug_error(aug));
406
407     aug_close(aug);
408 }
409
410
411 static void testToXml(CuTest *tc) {
412     struct augeas *aug;
413     int r;
414     xmlNodePtr xmldoc;
415     const xmlChar *value;
416
417     aug = aug_init(root, loadpath, AUG_NO_STDINC|AUG_NO_LOAD);
418     r = aug_load(aug);
419     CuAssertRetSuccess(tc, r);
420
421     r = aug_to_xml(aug, "/files/etc/passwd", &xmldoc, 0);
422     CuAssertRetSuccess(tc, r);
423
424     value = xmlGetProp(xmldoc, BAD_CAST "match");
425     CuAssertStrEquals(tc, "/files/etc/passwd", (const char*)value);
426
427     xmldoc = xmlFirstElementChild(xmldoc);
428     value = xmlGetProp(xmldoc, BAD_CAST "label");
429     CuAssertStrEquals(tc, "passwd", (const char*)value);
430
431     value = xmlGetProp(xmldoc, BAD_CAST "path");
432     CuAssertStrEquals(tc, "/files/etc/passwd", (const char*)value);
433
434     xmldoc = xmlFirstElementChild(xmldoc);
435     value = xmlGetProp(xmldoc, BAD_CAST "label");
436     CuAssertStrEquals(tc, "root", (const char*)value);
437
438     aug_close(aug);
439 }
440
441 int main(void) {
442     char *output = NULL;
443     CuSuite* suite = CuSuiteNew();
444     CuSuiteSetup(suite, NULL, NULL);
445
446     SUITE_ADD_TEST(suite, testGet);
447     SUITE_ADD_TEST(suite, testSet);
448     SUITE_ADD_TEST(suite, testSetM);
449     SUITE_ADD_TEST(suite, testDefVarMeta);
450     SUITE_ADD_TEST(suite, testDefNodeExistingMeta);
451     SUITE_ADD_TEST(suite, testDefNodeCreateMeta);
452     SUITE_ADD_TEST(suite, testNodeInfo);
453     SUITE_ADD_TEST(suite, testMv);
454     SUITE_ADD_TEST(suite, testToXml);
455
456     abs_top_srcdir = getenv("abs_top_srcdir");
457     if (abs_top_srcdir == NULL)
458         die("env var abs_top_srcdir must be set");
459
460     if (asprintf(&root, "%s/tests/root", abs_top_srcdir) < 0) {
461         die("failed to set root");
462     }
463
464     if (asprintf(&loadpath, "%s/lenses", abs_top_srcdir) < 0) {
465         die("failed to set loadpath");
466     }
467
468     CuSuiteRun(suite);
469     CuSuiteSummary(suite, &output);
470     CuSuiteDetails(suite, &output);
471     printf("%s\n", output);
472     free(output);
473     return suite->failCount;
474 }
475
476 /*
477  * Local variables:
478  *  indent-tabs-mode: nil
479  *  c-indent-level: 4
480  *  c-basic-offset: 4
481  *  tab-width: 4
482  * End:
483  */