Bump to 1.14.1
[platform/upstream/augeas.git] / tests / test-api.c
1 /*
2  * test-api.c: test public API functions for conformance
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 "augeas.h"
26
27 #include "cutest.h"
28 #include "internal.h"
29
30 #include <unistd.h>
31 #include <libgen.h>
32
33 #include <libxml/tree.h>
34
35 static const char *abs_top_srcdir;
36 static char *root;
37 static char *loadpath;
38
39 #define die(msg)                                                    \
40     do {                                                            \
41         fprintf(stderr, "%d: Fatal error: %s\n", __LINE__, msg);    \
42         exit(EXIT_FAILURE);                                         \
43     } while(0)
44
45 static void testGet(CuTest *tc) {
46     int r;
47     const char *value;
48     const char *label;
49     struct augeas *aug;
50
51     aug = aug_init(root, loadpath, AUG_NO_STDINC|AUG_NO_LOAD);
52     CuAssertPtrNotNull(tc, aug);
53     CuAssertIntEquals(tc, AUG_NOERROR, aug_error(aug));
54
55     /* Make sure we're looking at the right thing */
56     r = aug_match(aug, "/augeas/version/save/*", NULL);
57     CuAssertTrue(tc, r > 1);
58     CuAssertIntEquals(tc, AUG_NOERROR, aug_error(aug));
59
60     /* aug_get returns 1 and the value if exactly one node matches */
61     r = aug_get(aug, "/augeas/version/save/*[1]", &value);
62     CuAssertIntEquals(tc, 1, r);
63     CuAssertPtrNotNull(tc, value);
64     CuAssertIntEquals(tc, AUG_NOERROR, aug_error(aug));
65
66     /* aug_get returns 0 and no value when no node matches */
67     r = aug_get(aug, "/augeas/version/save/*[ last() + 1 ]", &value);
68     CuAssertIntEquals(tc, 0, r);
69     CuAssertPtrEquals(tc, NULL, value);
70     CuAssertIntEquals(tc, AUG_NOERROR, aug_error(aug));
71
72     /* aug_get should return an error when multiple nodes match */
73     r = aug_get(aug, "/augeas/version/save/*", &value);
74     CuAssertIntEquals(tc, -1, r);
75     CuAssertPtrEquals(tc, NULL, value);
76     CuAssertIntEquals(tc, AUG_EMMATCH, aug_error(aug));
77
78     /* aug_label returns 1 and the label if exactly one node matches */
79     r = aug_label(aug, "/augeas/version/save/*[1]", &label);
80     CuAssertIntEquals(tc, 1, r);
81     CuAssertPtrNotNull(tc, label);
82     CuAssertIntEquals(tc, AUG_NOERROR, aug_error(aug));
83
84     /* aug_label returns 0 and no label when no node matches */
85     r = aug_label(aug, "/augeas/version/save/*[ last() + 1 ]", &label);
86     CuAssertIntEquals(tc, 0, r);
87     CuAssertPtrEquals(tc, NULL, label);
88     CuAssertIntEquals(tc, AUG_NOERROR, aug_error(aug));
89
90     /* aug_label should return an error when multiple nodes match */
91     r = aug_label(aug, "/augeas/version/save/*", &label);
92     CuAssertIntEquals(tc, -1, r);
93     CuAssertPtrEquals(tc, NULL, label);
94     CuAssertIntEquals(tc, AUG_EMMATCH, aug_error(aug));
95
96     /* augeas should prepend context if relative path given */
97     r = aug_set(aug, "/augeas/context", "/augeas/version");
98     r = aug_get(aug, "save/*[1]", &value);
99     CuAssertIntEquals(tc, 1, r);
100     CuAssertPtrNotNull(tc, value);
101     CuAssertIntEquals(tc, AUG_NOERROR, aug_error(aug));
102
103     /* augeas should still work with an empty context */
104     r = aug_set(aug, "/augeas/context", "");
105     r = aug_get(aug, "/augeas/version", &value);
106     CuAssertIntEquals(tc, 1, r);
107     CuAssertPtrNotNull(tc, value);
108     CuAssertIntEquals(tc, AUG_NOERROR, aug_error(aug));
109
110     /* augeas should ignore trailing slashes in context */
111     r = aug_set(aug, "/augeas/context", "/augeas/version/");
112     r = aug_get(aug, "save/*[1]", &value);
113     CuAssertIntEquals(tc, 1, r);
114     CuAssertPtrNotNull(tc, value);
115     CuAssertIntEquals(tc, AUG_NOERROR, aug_error(aug));
116
117     /* augeas should create non-existent context path */
118     r = aug_set(aug, "/augeas/context", "/context/foo");
119     r = aug_set(aug, "bar", "value");
120     r = aug_get(aug, "/context/foo/bar", &value);
121     CuAssertIntEquals(tc, 1, r);
122     CuAssertPtrNotNull(tc, value);
123     CuAssertIntEquals(tc, AUG_NOERROR, aug_error(aug));
124
125     /* aug_get should set VALUE to NULL even if the path expression is invalid
126        Issue #372 */
127     value = (const char *) 7;
128     r = aug_get(aug, "[invalid path]", &value);
129     CuAssertIntEquals(tc, -1, r);
130     CuAssertPtrEquals(tc, NULL, value);
131
132     aug_close(aug);
133 }
134
135 static void testSet(CuTest *tc) {
136     int r;
137     const char *value;
138     struct augeas *aug;
139
140     aug = aug_init(root, loadpath, AUG_NO_STDINC|AUG_NO_LOAD);
141     CuAssertPtrNotNull(tc, aug);
142     CuAssertIntEquals(tc, AUG_NOERROR, aug_error(aug));
143
144     /* aug_set returns 0 for a simple set */
145     r = aug_set(aug, "/augeas/testSet", "foo");
146     CuAssertIntEquals(tc, 0, r);
147     CuAssertIntEquals(tc, AUG_NOERROR, aug_error(aug));
148
149     /* aug_set returns -1 when cannot set due to multiple nodes */
150     r = aug_set(aug, "/augeas/version/save/*", "foo");
151     CuAssertIntEquals(tc, -1, r);
152     CuAssertIntEquals(tc, AUG_EMMATCH, aug_error(aug));
153
154     /* aug_set is able to set the context, even when currently invalid */
155     r = aug_set(aug, "/augeas/context", "( /files | /augeas )");
156     CuAssertIntEquals(tc, 0, r);
157     CuAssertIntEquals(tc, AUG_NOERROR, aug_error(aug));
158     r = aug_get(aug, "/augeas/version", &value);
159     CuAssertIntEquals(tc, -1, r);
160     CuAssertIntEquals(tc, AUG_EMMATCH, aug_error(aug));
161     r = aug_set(aug, "/augeas/context", "/files");
162     CuAssertIntEquals(tc, 0, r);
163     CuAssertIntEquals(tc, AUG_NOERROR, aug_error(aug));
164
165     aug_close(aug);
166 }
167
168 static void testSetM(CuTest *tc) {
169     int r;
170     struct augeas *aug;
171
172     aug = aug_init(root, loadpath, AUG_NO_STDINC|AUG_NO_LOAD);
173     CuAssertPtrNotNull(tc, aug);
174     CuAssertIntEquals(tc, AUG_NOERROR, aug_error(aug));
175
176     /* Change base nodes when SUB is NULL */
177     r = aug_setm(aug, "/augeas/version/save/*", NULL, "changed");
178     CuAssertIntEquals(tc, 4, r);
179
180     r = aug_match(aug, "/augeas/version/save/*[. = 'changed']", NULL);
181     CuAssertIntEquals(tc, 4, r);
182
183     /* Only change existing nodes */
184     r = aug_setm(aug, "/augeas/version/save", "mode", "again");
185     CuAssertIntEquals(tc, 4, r);
186
187     r = aug_match(aug, "/augeas/version/save/*", NULL);
188     CuAssertIntEquals(tc, 4, r);
189
190     r = aug_match(aug, "/augeas/version/save/*[. = 'again']", NULL);
191     CuAssertIntEquals(tc, 4, r);
192
193     /* Create a new node */
194     r = aug_setm(aug, "/augeas/version/save", "mode[last() + 1]", "newmode");
195     CuAssertIntEquals(tc, 1, r);
196
197     r = aug_match(aug, "/augeas/version/save/*", NULL);
198     CuAssertIntEquals(tc, 5, r);
199
200     r = aug_match(aug, "/augeas/version/save/*[. = 'again']", NULL);
201     CuAssertIntEquals(tc, 4, r);
202
203     r = aug_match(aug, "/augeas/version/save/*[last()][. = 'newmode']", NULL);
204     CuAssertIntEquals(tc, 1, r);
205
206     /* Noexistent base */
207     r = aug_setm(aug, "/augeas/version/save[last()+1]", "mode", "newmode");
208     CuAssertIntEquals(tc, 0, r);
209
210     /* Invalid path expressions */
211     r = aug_setm(aug, "/augeas/version/save[]", "mode", "invalid");
212     CuAssertIntEquals(tc, -1, r);
213
214     r = aug_setm(aug, "/augeas/version/save/*", "mode[]", "invalid");
215     CuAssertIntEquals(tc, -1, r);
216
217     aug_close(aug);
218 }
219
220 /* Check that defining a variable leads to a corresponding entry in
221  * /augeas/variables and that that entry disappears when the variable is
222  * undefined */
223 static void testDefVarMeta(CuTest *tc) {
224     int r;
225     struct augeas *aug;
226     static const char *const expr = "/augeas/version/save/mode";
227     const char *value;
228
229     aug = aug_init(root, loadpath, AUG_NO_STDINC|AUG_NO_LOAD);
230     CuAssertPtrNotNull(tc, aug);
231     CuAssertIntEquals(tc, AUG_NOERROR, aug_error(aug));
232
233     r = aug_defvar(aug, "var", expr);
234     CuAssertIntEquals(tc, 4, r);
235
236     r = aug_match(aug, "/augeas/variables/*", NULL);
237     CuAssertIntEquals(tc, 1, r);
238
239     r = aug_get(aug, "/augeas/variables/var", &value);
240     CuAssertStrEquals(tc, expr, value);
241
242     r = aug_defvar(aug, "var", NULL);
243     CuAssertIntEquals(tc, 0, r);
244
245     r = aug_match(aug, "/augeas/variables/*", NULL);
246     CuAssertIntEquals(tc, 0, r);
247
248     aug_close(aug);
249 }
250
251 /* Check that defining a variable with defnode leads to a corresponding
252  * entry in /augeas/variables and that that entry disappears when the
253  * variable is undefined
254  */
255 static void testDefNodeExistingMeta(CuTest *tc) {
256     int r, created;
257     struct augeas *aug;
258     static const char *const expr = "/augeas/version/save/mode";
259     const char *value;
260
261     aug = aug_init(root, loadpath, AUG_NO_STDINC|AUG_NO_LOAD);
262     CuAssertPtrNotNull(tc, aug);
263     CuAssertIntEquals(tc, AUG_NOERROR, aug_error(aug));
264
265     r = aug_defnode(aug, "var", expr, "other", &created);
266     CuAssertIntEquals(tc, 4, r);
267     CuAssertIntEquals(tc, 0, created);
268
269     r = aug_match(aug, "/augeas/variables/*", NULL);
270     CuAssertIntEquals(tc, 1, r);
271
272     r = aug_get(aug, "/augeas/variables/var", &value);
273     CuAssertStrEquals(tc, expr, value);
274
275     r = aug_defvar(aug, "var", NULL);
276     CuAssertIntEquals(tc, 0, r);
277
278     r = aug_match(aug, "/augeas/variables/*", NULL);
279     CuAssertIntEquals(tc, 0, r);
280
281     aug_close(aug);
282 }
283
284 /* Check that defining a variable with defnode leads to a corresponding
285  * entry in /augeas/variables and that that entry disappears when the
286  * variable is undefined
287  */
288 static void testDefNodeCreateMeta(CuTest *tc) {
289     int r, created;
290     struct augeas *aug;
291     static const char *const expr = "/augeas/version/save/mode[last()+1]";
292     static const char *const expr_can = "/augeas/version/save/mode[5]";
293     const char *value;
294
295     aug = aug_init(root, loadpath, AUG_NO_STDINC|AUG_NO_LOAD);
296     CuAssertPtrNotNull(tc, aug);
297     CuAssertIntEquals(tc, AUG_NOERROR, aug_error(aug));
298
299     r = aug_defnode(aug, "var", expr, "other", &created);
300     CuAssertIntEquals(tc, 1, r);
301     CuAssertIntEquals(tc, 1, created);
302
303     r = aug_match(aug, "/augeas/variables/*", NULL);
304     CuAssertIntEquals(tc, 1, r);
305
306     r = aug_get(aug, "/augeas/variables/var", &value);
307     CuAssertStrEquals(tc, expr_can, value);
308
309     r = aug_defvar(aug, "var", NULL);
310     CuAssertIntEquals(tc, 0, r);
311
312     r = aug_match(aug, "/augeas/variables/*", NULL);
313     CuAssertIntEquals(tc, 0, r);
314
315     aug_close(aug);
316 }
317
318 static void reset_indexes(uint *a, uint *b, uint *c, uint *d, uint *e, uint *f) {
319     *a = 0; *b = 0; *c = 0; *d = 0; *e = 0; *f = 0;
320 }
321
322 #define SPAN_TEST_DEF_LAST { .expr = NULL, .ls = 0, .le = 0, \
323         .vs = 0, .ve = 0, .ss = 0, .se = 0 }
324
325 struct span_test_def {
326     const char *expr;
327     const char *f;
328     int ret;
329     int ls;
330     int le;
331     int vs;
332     int ve;
333     int ss;
334     int se;
335 };
336
337 static const struct span_test_def span_test[] = {
338     { .expr = "/files/etc/hosts/1/ipaddr", .f = "hosts", .ret = 0, .ls = 0, .le = 0, .vs = 104, .ve = 113, .ss = 104, .se = 113 },
339     { .expr = "/files/etc/hosts/1", .f = "hosts", .ret = 0, .ls = 0, .le = 0, .vs = 0, .ve = 0, .ss = 104, .se = 171 },
340     { .expr = "/files/etc/hosts/*[last()]", .f = "hosts", .ret = 0, .ls = 0, .le = 0, .vs = 0, .ve = 0, .ss = 266, .se = 309 },
341     { .expr = "/files/etc/hosts/#comment[2]", .f = "hosts", .ret = 0, .ls = 0, .le = 0, .vs = 58, .ve = 103, .ss = 56, .se = 104 },
342     { .expr = "/files/etc/hosts", .f = "hosts", .ret = 0, .ls = 0, .le = 0, .vs = 0, .ve = 0, .ss = 0, .se = 309 },
343     { .expr = "/files", .f = NULL, .ret = -1, .ls = 0, .le = 0, .vs = 0, .ve = 0, .ss = 0, .se = 0 },
344     { .expr = "/random", .f = NULL, .ret = -1, .ls = 0, .le = 0, .vs = 0, .ve = 0, .ss = 0, .se = 0 },
345     SPAN_TEST_DEF_LAST
346 };
347
348 static void testNodeInfo(CuTest *tc) {
349     int ret;
350     int i = 0;
351     struct augeas *aug;
352     struct span_test_def test;
353     char *fbase;
354     char msg[1024];
355     static const char *const expr = "/files/etc/hosts/1/ipaddr";
356
357     char *filename_ac;
358     uint label_start, label_end, value_start, value_end, span_start, span_end;
359
360     aug = aug_init(root, loadpath, AUG_NO_STDINC|AUG_NO_LOAD|AUG_ENABLE_SPAN);
361     ret = aug_load(aug);
362     CuAssertRetSuccess(tc, ret);
363
364     while(span_test[i].expr != NULL) {
365         test = span_test[i];
366         i++;
367         ret = aug_span(aug, test.expr, &filename_ac, &label_start, &label_end,
368                      &value_start, &value_end, &span_start, &span_end);
369         sprintf(msg, "span_test %d ret\n", i);
370         CuAssertIntEquals_Msg(tc, msg, test.ret, ret);
371         sprintf(msg, "span_test %d label_start\n", i);
372         CuAssertIntEquals_Msg(tc, msg, test.ls, label_start);
373         sprintf(msg, "span_test %d label_end\n", i);
374         CuAssertIntEquals_Msg(tc, msg, test.le, label_end);
375         sprintf(msg, "span_test %d value_start\n", i);
376         CuAssertIntEquals_Msg(tc, msg, test.vs, value_start);
377         sprintf(msg, "span_test %d value_end\n", i);
378         CuAssertIntEquals_Msg(tc, msg, test.ve, value_end);
379         sprintf(msg, "span_test %d span_start\n", i);
380         CuAssertIntEquals_Msg(tc, msg, test.ss, span_start);
381         sprintf(msg, "span_test %d span_end\n", i);
382         CuAssertIntEquals_Msg(tc, msg, test.se, span_end);
383         if (filename_ac != NULL) {
384             fbase = basename(filename_ac);
385         } else {
386             fbase = NULL;
387         }
388         sprintf(msg, "span_test %d filename\n", i);
389         CuAssertStrEquals_Msg(tc, msg, test.f, fbase);
390         free(filename_ac);
391         filename_ac = NULL;
392         reset_indexes(&label_start, &label_end, &value_start, &value_end,
393                       &span_start, &span_end);
394     }
395
396     /* aug_span returns -1 and when no node matches */
397     ret = aug_span(aug, "/files/etc/hosts/*[ last() + 1 ]", &filename_ac,
398             &label_start, &label_end, &value_start, &value_end,
399             &span_start, &span_end);
400     CuAssertIntEquals(tc, -1, ret);
401     CuAssertPtrEquals(tc, NULL, filename_ac);
402     CuAssertIntEquals(tc, AUG_ENOMATCH, aug_error(aug));
403
404     /* aug_span should return an error when multiple nodes match */
405     ret = aug_span(aug, "/files/etc/hosts/*", &filename_ac,
406             &label_start, &label_end, &value_start, &value_end,
407             &span_start, &span_end);
408     CuAssertIntEquals(tc, -1, ret);
409     CuAssertPtrEquals(tc, NULL, filename_ac);
410     CuAssertIntEquals(tc, AUG_EMMATCH, aug_error(aug));
411
412     /* aug_span returns -1 if nodes span are not loaded */
413     aug_close(aug);
414     aug = aug_init(root, loadpath, AUG_NO_STDINC|AUG_NO_LOAD);
415     ret = aug_load(aug);
416     CuAssertRetSuccess(tc, ret);
417     ret = aug_span(aug, expr, &filename_ac, &label_start, &label_end,
418                  &value_start, &value_end, &span_start, &span_end);
419     CuAssertIntEquals(tc, -1, ret);
420     CuAssertPtrEquals(tc, NULL, filename_ac);
421     CuAssertIntEquals(tc, AUG_ENOSPAN, aug_error(aug));
422     reset_indexes(&label_start, &label_end, &value_start, &value_end,
423                   &span_start, &span_end);
424
425     aug_close(aug);
426 }
427
428 static void testMv(CuTest *tc) {
429     struct augeas *aug;
430     int r;
431
432     aug = aug_init(root, loadpath, AUG_NO_STDINC|AUG_NO_LOAD);
433     CuAssertPtrNotNull(tc, aug);
434
435     r = aug_set(aug, "/a/b/c", "value");
436     CuAssertRetSuccess(tc, r);
437
438     r = aug_mv(aug, "/a/b/c", "/a/b/c/d");
439     CuAssertIntEquals(tc, -1, r);
440     CuAssertIntEquals(tc, AUG_EMVDESC, aug_error(aug));
441
442     aug_close(aug);
443 }
444
445 static void testCp(CuTest *tc) {
446     struct augeas *aug;
447     int r;
448     const char *value;
449
450     aug = aug_init(root, loadpath, AUG_NO_STDINC|AUG_NO_LOAD);
451     CuAssertPtrNotNull(tc, aug);
452     r = aug_load(aug);
453     CuAssertRetSuccess(tc, r);
454
455     r = aug_set(aug, "/a/b/c", "value");
456     CuAssertRetSuccess(tc, r);
457
458     r = aug_cp(aug, "/a/b/c", "/a/b/c/d");
459     CuAssertIntEquals(tc, -1, r);
460     CuAssertIntEquals(tc, AUG_ECPDESC, aug_error(aug));
461
462     // Copy recursive tree with empty label
463     r = aug_cp(aug, "/files/etc/logrotate.d/rpm/rule/create", "/files/etc/logrotate.d/acpid/rule/create");
464     CuAssertRetSuccess(tc, r);
465
466     // Check empty label
467     r = aug_get(aug, "/files/etc/logrotate.d/rpm/rule/create", &value);
468     CuAssertIntEquals(tc, 1, r);
469     CuAssertStrEquals(tc, NULL, value);
470
471     // Check that copies are well separated
472     r = aug_set(aug, "/files/etc/logrotate.d/rpm/rule/create/mode", "1234");
473     CuAssertRetSuccess(tc, r);
474     r = aug_set(aug, "/files/etc/logrotate.d/acpid/rule/create/mode", "5678");
475     CuAssertRetSuccess(tc, r);
476     r = aug_get(aug, "/files/etc/logrotate.d/rpm/rule/create/mode", &value);
477     CuAssertIntEquals(tc, 1, r);
478     CuAssertStrEquals(tc, "1234", value);
479     r = aug_get(aug, "/files/etc/logrotate.d/acpid/rule/create/mode", &value);
480     CuAssertIntEquals(tc, 1, r);
481     CuAssertStrEquals(tc, "5678", value);
482
483     aug_close(aug);
484 }
485
486
487 static void testRename(CuTest *tc) {
488     struct augeas *aug;
489     int r;
490
491     aug = aug_init(root, loadpath, AUG_NO_STDINC|AUG_NO_LOAD);
492     CuAssertPtrNotNull(tc, aug);
493
494     r = aug_set(aug, "/a/b/c", "value");
495     CuAssertRetSuccess(tc, r);
496
497     r = aug_rename(aug, "/a/b/c", "d");
498     CuAssertIntEquals(tc, 1, r);
499
500     r = aug_set(aug, "/a/e/d", "value2");
501     CuAssertRetSuccess(tc, r);
502
503     // Multiple rename
504     r = aug_rename(aug, "/a//d", "x");
505     CuAssertIntEquals(tc, 2, r);
506
507     // Label with a /
508     r = aug_rename(aug, "/a/e/x", "a/b");
509     CuAssertIntEquals(tc, -1, r);
510     CuAssertIntEquals(tc, AUG_ELABEL, aug_error(aug));
511
512     aug_close(aug);
513 }
514
515 static void testToXml(CuTest *tc) {
516     struct augeas *aug;
517     int r;
518     xmlNodePtr xmldoc, xmlnode;
519     xmlChar *value;
520
521     aug = aug_init(root, loadpath, AUG_NO_STDINC|AUG_NO_LOAD);
522     r = aug_load(aug);
523     CuAssertRetSuccess(tc, r);
524
525     r = aug_to_xml(aug, "/files/etc/passwd", &xmldoc, 0);
526     CuAssertRetSuccess(tc, r);
527
528     value = xmlGetProp(xmldoc, BAD_CAST "match");
529     CuAssertStrEquals(tc, "/files/etc/passwd", (const char *) value);
530     xmlFree(value);
531
532     xmlnode = xmlFirstElementChild(xmldoc);
533     value = xmlGetProp(xmlnode, BAD_CAST "label");
534     CuAssertStrEquals(tc, "passwd", (const char *) value);
535     xmlFree(value);
536
537     value = xmlGetProp(xmlnode, BAD_CAST "path");
538     CuAssertStrEquals(tc, "/files/etc/passwd", (const char *) value);
539     xmlFree(value);
540
541     xmlnode = xmlFirstElementChild(xmlnode);
542     value = xmlGetProp(xmlnode, BAD_CAST "label");
543     CuAssertStrEquals(tc, "root", (const char *) value);
544     xmlFree(value);
545     xmlFreeNode(xmldoc);
546
547     /* Bug #239 */
548     r = aug_set(aug, "/augeas/context", "/files/etc/passwd");
549     CuAssertRetSuccess(tc, r);
550     r = aug_to_xml(aug, ".", &xmldoc, 0);
551     CuAssertRetSuccess(tc, r);
552     xmlnode = xmlFirstElementChild(xmldoc);
553     value = xmlGetProp(xmlnode, BAD_CAST "label");
554     CuAssertStrEquals(tc, "passwd", (const char *) value);
555     xmlFree(value);
556
557     xmlFreeNode(xmldoc);
558     aug_close(aug);
559 }
560
561 static void testTextStore(CuTest *tc) {
562     static const char *const hosts = "192.168.0.1 rtr.example.com router\n";
563     /* Not acceptable for Hosts.lns - missing canonical and \n */
564     static const char *const hosts_bad = "192.168.0.1";
565     const char *v;
566
567     struct augeas *aug;
568     int r;
569
570     aug = aug_init(root, loadpath, AUG_NO_STDINC|AUG_NO_LOAD);
571     CuAssertPtrNotNull(tc, aug);
572
573     r = aug_set(aug, "/raw/hosts", hosts);
574     CuAssertRetSuccess(tc, r);
575
576     r = aug_text_store(aug, "Hosts.lns", "/raw/hosts", "/t1");
577     CuAssertRetSuccess(tc, r);
578
579     r = aug_match(aug, "/t1/*", NULL);
580     CuAssertIntEquals(tc, 1, r);
581
582     /* Test bad lens name */
583     r = aug_text_store(aug, "Notthere.lns", "/raw/hosts", "/t2");
584     CuAssertIntEquals(tc, -1, r);
585     CuAssertIntEquals(tc, AUG_ENOLENS, aug_error(aug));
586
587     r = aug_match(aug, "/t2", NULL);
588     CuAssertIntEquals(tc, 0, r);
589
590     /* Test parse error */
591     r = aug_set(aug, "/raw/hosts_bad", hosts_bad);
592     CuAssertRetSuccess(tc, r);
593
594     r = aug_text_store(aug, "Hosts.lns", "/raw/hosts_bad", "/t3");
595     CuAssertIntEquals(tc, -1, r);
596
597     r = aug_match(aug, "/t3", NULL);
598     CuAssertIntEquals(tc, 0, r);
599
600     r = aug_get(aug, "/augeas/text/t3/error", &v);
601     CuAssertIntEquals(tc, 1, r);
602     CuAssertStrEquals(tc, "parse_failed", v);
603
604     r = aug_text_store(aug, "Hosts.lns", "/raw/hosts", "/t3");
605     CuAssertRetSuccess(tc, r);
606
607     r = aug_match(aug, "/augeas/text/t3/error", NULL);
608     CuAssertIntEquals(tc, 0, r);
609
610     /* Test invalid PATH */
611     r = aug_text_store(aug, "Hosts.lns", "/raw/hosts", "[garbage]");
612     CuAssertIntEquals(tc, -1, r);
613     CuAssertIntEquals(tc, AUG_EPATHX, aug_error(aug));
614
615     r = aug_match(aug, "/t2", NULL);
616     CuAssertIntEquals(tc, 0, r);
617
618     aug_close(aug);
619 }
620
621 static void testTextRetrieve(CuTest *tc) {
622     static const char *const hosts = "192.168.0.1 rtr.example.com router\n";
623     const char *hosts_out;
624     struct augeas *aug;
625     int r;
626
627     aug = aug_init(root, loadpath, AUG_NO_STDINC|AUG_NO_LOAD);
628     CuAssertPtrNotNull(tc, aug);
629
630     r = aug_set(aug, "/raw/hosts", hosts);
631     CuAssertRetSuccess(tc, r);
632
633     r = aug_text_store(aug, "Hosts.lns", "/raw/hosts", "/t1");
634     CuAssertRetSuccess(tc, r);
635
636     r = aug_text_retrieve(aug, "Hosts.lns", "/raw/hosts", "/t1", "/out/hosts");
637     CuAssertRetSuccess(tc, r);
638
639     r = aug_get(aug, "/out/hosts", &hosts_out);
640     CuAssertIntEquals(tc, 1, r);
641
642     CuAssertStrEquals(tc, hosts, hosts_out);
643
644     aug_close(aug);
645 }
646
647 static void testAugEscape(CuTest *tc) {
648     static const char *const in  = "a/[]b|=c()!, \td";
649     static const char *const exp = "a\\/\\[\\]b\\|\\=c\\(\\)\\!\\,\\ \\\td";
650     char *out;
651     struct augeas *aug;
652     int r;
653
654     aug = aug_init(root, loadpath, AUG_NO_STDINC|AUG_NO_LOAD);
655     CuAssertPtrNotNull(tc, aug);
656
657     r = aug_escape_name(aug, in, &out);
658     CuAssertRetSuccess(tc, r);
659
660     CuAssertStrEquals(tc, out, exp);
661     free(out);
662
663     aug_close(aug);
664 }
665
666 static void testRm(CuTest *tc) {
667     struct augeas *aug;
668     int r;
669
670     aug = aug_init(root, loadpath, AUG_NO_STDINC|AUG_NO_MODL_AUTOLOAD);
671     CuAssertPtrNotNull(tc, aug);
672
673     r = aug_set(aug, "/files/1/2/3/4/5", "1");
674     CuAssertRetSuccess(tc, r);
675
676     r = aug_rm(aug, "/files//*");
677     CuAssertIntEquals(tc, 5, r);
678
679     aug_close(aug);
680 }
681
682 static void testLoadFile(CuTest *tc) {
683     struct augeas *aug;
684     const char *value;
685     int r;
686
687     aug = aug_init(root, loadpath, AUG_NO_STDINC|AUG_NO_LOAD);
688     CuAssertPtrNotNull(tc, aug);
689     CuAssertIntEquals(tc, AUG_NOERROR, aug_error(aug));
690
691     /* augeas should load a single file */
692     r = aug_load_file(aug, "/etc/fstab");
693     CuAssertRetSuccess(tc, r);
694     r = aug_get(aug, "/files/etc/fstab/1/vfstype", &value);
695     CuAssertIntEquals(tc, 1, r);
696     CuAssertPtrNotNull(tc, value);
697
698     /* Only one file should be loaded */
699     r = aug_match(aug, "/files/etc/*", NULL);
700     CuAssertIntEquals(tc, 1, r);
701
702     /* augeas should return an error when no lens can be found for a file */
703     r = aug_load_file(aug, "/etc/unknown.conf");
704     CuAssertIntEquals(tc, -1, r);
705     CuAssertIntEquals(tc, AUG_ENOLENS, aug_error(aug));
706
707     /* augeas should return without an error when trying to load a
708        nonexistent file that would be handled by a lens */
709     r = aug_load_file(aug, "/etc/mtab");
710     CuAssertRetSuccess(tc, r);
711     r = aug_match(aug, "/files/etc/mtab", NULL);
712     CuAssertIntEquals(tc, 0, r);
713
714     aug_close(aug);
715 }
716
717 /* Make sure that if somebody erroneously creates a node
718    /augeas/files/path, we do not corrupt the tree. It used to be that
719    having such a node would free /augeas/files
720 */
721 static void testLoadBadPath(CuTest *tc) {
722     struct augeas *aug;
723     int r;
724
725     aug = aug_init(root, loadpath, AUG_NO_STDINC|AUG_NO_LOAD);
726     CuAssertPtrNotNull(tc, aug);
727     CuAssertIntEquals(tc, AUG_NOERROR, aug_error(aug));
728
729     r = aug_set(aug, "/augeas/files/path", "/files");
730     CuAssertRetSuccess(tc, r);
731
732     r = aug_load(aug);
733     CuAssertRetSuccess(tc, r);
734
735     aug_close(aug);
736 }
737
738 /* If a lens is set to a partial path which happens to actually resolve to
739    a file when appended to the loadpath, we went into an infinite loop of
740    loading a module, but then not realizing that it had actually been
741    loaded, reloading it over and over again.
742    See https://github.com/hercules-team/augeas/issues/522
743 */
744 static void testLoadBadLens(CuTest *tc) {
745     struct augeas *aug;
746     int r;
747     char *lp;
748
749     // This setup depends on the fact that
750     //   loadpath == abs_top_srcdir + "/lenses"
751     r = asprintf(&lp, "%s:%s", loadpath, abs_top_srcdir);
752     CuAssert(tc, "failed to allocate loadpath", (r >= 0));
753
754     aug = aug_init(root, lp, AUG_NO_STDINC|AUG_NO_LOAD);
755     CuAssertPtrNotNull(tc, aug);
756     CuAssertIntEquals(tc, AUG_NOERROR, aug_error(aug));
757
758     r = aug_set(aug, "/augeas/load/Fstab/lens", "lenses/Fstab.lns");
759     CuAssertRetSuccess(tc, r);
760
761     r = aug_load(aug);
762     CuAssertRetSuccess(tc, r);
763
764     // We used to record the error to load the lens above against every
765     // lens that we tried to load after it.
766     r = aug_match(aug, "/augeas//error", NULL);
767     CuAssertIntEquals(tc, 1, r);
768
769     free(lp);
770 }
771
772 /* Test the aug_ns_* functions */
773 static void testAugNs(CuTest *tc) {
774     struct augeas *aug;
775     int r;
776     const char *v, *l;
777     char *s;
778
779     aug = aug_init(root, loadpath, AUG_NO_STDINC|AUG_NO_LOAD);
780     CuAssertPtrNotNull(tc, aug);
781     CuAssertIntEquals(tc, AUG_NOERROR, aug_error(aug));
782
783     r = aug_load_file(aug, "/etc/hosts");
784     CuAssertIntEquals(tc, 0, r);
785
786     r = aug_defvar(aug, "matches",
787                    "/files/etc/hosts/*[label() != '#comment']/ipaddr");
788     CuAssertIntEquals(tc, 2, r);
789
790     r = aug_ns_attr(aug, "matches", 0, &v, &l, &s);
791     CuAssertIntEquals(tc, 1, r);
792     CuAssertStrEquals(tc, "127.0.0.1", v);
793     CuAssertStrEquals(tc, "ipaddr", l);
794     CuAssertStrEquals(tc, "/files/etc/hosts", s);
795     free(s);
796     s = NULL;
797
798     r = aug_ns_attr(aug, "matches", 0, NULL, NULL, NULL);
799     CuAssertIntEquals(tc, 1, r);
800
801     r = aug_ns_attr(aug, "matches", 1, &v, NULL, &s);
802     CuAssertIntEquals(tc, 1, r);
803     CuAssertStrEquals(tc, "172.31.122.14", v);
804     CuAssertStrEquals(tc, "/files/etc/hosts", s);
805     free(s);
806     s = NULL;
807
808     r = aug_ns_attr(aug, "matches", 2, &v, &l, &s);
809     CuAssertIntEquals(tc, -1, r);
810     CuAssertPtrEquals(tc, NULL, v);
811     CuAssertPtrEquals(tc, NULL, l);
812     CuAssertPtrEquals(tc, NULL, s);
813     free(s);
814     s = NULL;
815
816     aug_close(aug);
817 }
818
819 /* Test aug_source */
820 static void testAugSource(CuTest *tc) {
821     struct augeas *aug;
822     int r;
823     char *s;
824
825     aug = aug_init(root, loadpath, AUG_NO_STDINC|AUG_NO_LOAD);
826     CuAssertPtrNotNull(tc, aug);
827     CuAssertIntEquals(tc, AUG_NOERROR, aug_error(aug));
828
829     r = aug_load_file(aug, "/etc/hosts");
830     CuAssertIntEquals(tc, 0, r);
831
832     r = aug_source(aug, "/files/etc/hosts/1", &s);
833     CuAssertIntEquals(tc, 0, r);
834     CuAssertStrEquals(tc, "/files/etc/hosts", s);
835     free(s);
836
837     r = aug_source(aug, "/files/etc/fstab", &s);
838     CuAssertIntEquals(tc, -1, r);
839     CuAssertIntEquals(tc, AUG_ENOMATCH, aug_error(aug));
840     CuAssertPtrEquals(tc, NULL, s);
841
842     r = aug_source(aug, "/files[", &s);
843     CuAssertIntEquals(tc, -1, r);
844     CuAssertIntEquals(tc, AUG_EPATHX, aug_error(aug));
845     CuAssertPtrEquals(tc, NULL, s);
846
847     r = aug_source(aug, "/files/etc/hosts/*", &s);
848     CuAssertIntEquals(tc, -1, r);
849     CuAssertIntEquals(tc, AUG_EMMATCH, aug_error(aug));
850     CuAssertPtrEquals(tc, NULL, s);
851
852 }
853
854 static void testAugPreview(CuTest *tc) {
855     struct augeas *aug;
856     int r;
857     char *s;
858     char *etc_hosts_fn = NULL;
859     FILE *hosts_fp = NULL;
860     char *hosts_txt = NULL;
861     int readsz = 0;
862
863     /* Read the original contents of the etc/hosts file */
864     if (asprintf(&etc_hosts_fn,"%s/etc/hosts",root) >=0 ) {
865         hosts_fp = fopen(etc_hosts_fn,"r");
866         if ( hosts_fp ) {
867             hosts_txt = calloc(sizeof(char),4096);
868             if ( hosts_txt ) {
869                 readsz = fread(hosts_txt,sizeof(char),4096,hosts_fp);
870                 *(hosts_txt+readsz) = '\0';
871             }
872             fclose(hosts_fp);
873         }
874         free(etc_hosts_fn);
875     }
876
877     aug = aug_init(root, loadpath, AUG_NO_STDINC|AUG_NO_LOAD);
878     CuAssertPtrNotNull(tc, aug);
879     CuAssertIntEquals(tc, AUG_NOERROR, aug_error(aug));
880
881     r = aug_load_file(aug, "/etc/hosts");
882     CuAssertIntEquals(tc, 0, r);
883
884     r = aug_preview(aug, "/files/etc/hosts/1", &s);
885     CuAssertIntEquals(tc, 0, r);
886     CuAssertStrEquals(tc, hosts_txt, s);
887
888     free(hosts_txt);
889     free(s);
890     aug_close(aug);
891 }
892
893 int main(void) {
894     char *output = NULL;
895     CuSuite* suite = CuSuiteNew();
896     CuSuiteSetup(suite, NULL, NULL);
897
898     SUITE_ADD_TEST(suite, testGet);
899     SUITE_ADD_TEST(suite, testSet);
900     SUITE_ADD_TEST(suite, testSetM);
901     SUITE_ADD_TEST(suite, testDefVarMeta);
902     SUITE_ADD_TEST(suite, testDefNodeExistingMeta);
903     SUITE_ADD_TEST(suite, testDefNodeCreateMeta);
904     SUITE_ADD_TEST(suite, testNodeInfo);
905     SUITE_ADD_TEST(suite, testMv);
906     SUITE_ADD_TEST(suite, testCp);
907     SUITE_ADD_TEST(suite, testRename);
908     SUITE_ADD_TEST(suite, testToXml);
909     SUITE_ADD_TEST(suite, testTextStore);
910     SUITE_ADD_TEST(suite, testTextRetrieve);
911     SUITE_ADD_TEST(suite, testAugEscape);
912     SUITE_ADD_TEST(suite, testRm);
913     SUITE_ADD_TEST(suite, testLoadFile);
914     SUITE_ADD_TEST(suite, testLoadBadPath);
915     SUITE_ADD_TEST(suite, testLoadBadLens);
916     SUITE_ADD_TEST(suite, testAugNs);
917     SUITE_ADD_TEST(suite, testAugSource);
918     SUITE_ADD_TEST(suite, testAugPreview);
919
920     abs_top_srcdir = getenv("abs_top_srcdir");
921     if (abs_top_srcdir == NULL)
922         die("env var abs_top_srcdir must be set");
923
924     if (asprintf(&root, "%s/tests/root", abs_top_srcdir) < 0) {
925         die("failed to set root");
926     }
927
928     if (asprintf(&loadpath, "%s/lenses", abs_top_srcdir) < 0) {
929         die("failed to set loadpath");
930     }
931
932     CuSuiteRun(suite);
933     CuSuiteSummary(suite, &output);
934     CuSuiteDetails(suite, &output);
935     printf("%s\n", output);
936     free(output);
937     int result = suite->failCount;
938     CuSuiteFree(suite);
939     return result;
940 }
941
942 /*
943  * Local variables:
944  *  indent-tabs-mode: nil
945  *  c-indent-level: 4
946  *  c-basic-offset: 4
947  *  tab-width: 4
948  * End:
949  */