blob: eb595f1c9bd294e7f72923b92052ce14abbf061d [file] [log] [blame]
Michal Vasko14795a42020-05-22 16:44:44 +02001/*
2 * @file test_xpath.c
3 * @author: Michal Vasko <mvasko@cesnet.cz>
4 * @brief unit tests for XPath evaluation
5 *
6 * Copyright (c) 2020 CESNET, z.s.p.o.
7 *
8 * This source code is licensed under BSD 3-Clause License (the "License").
9 * You may not use this file except in compliance with the License.
10 * You may obtain a copy of the License at
11 *
12 * https://opensource.org/licenses/BSD-3-Clause
13 */
14
Michal Vasko14795a42020-05-22 16:44:44 +020015#include <stdarg.h>
16#include <stddef.h>
17#include <setjmp.h>
18#include <cmocka.h>
19
20#include <stdio.h>
21#include <string.h>
22
Radek Krejci70593c12020-06-13 20:48:09 +020023#include "context.h"
Radek Krejci7931b192020-06-25 17:05:03 +020024#include "parser_data.h"
Radek Krejci70593c12020-06-13 20:48:09 +020025#include "set.h"
26#include "tests/config.h"
27#include "tree_data.h"
28#include "tree_schema.h"
Michal Vasko14795a42020-05-22 16:44:44 +020029
30#define BUFSIZE 1024
31char logbuf[BUFSIZE] = {0};
32int store = -1; /* negative for infinite logging, positive for limited logging */
33
34struct ly_ctx *ctx; /* context for tests */
35
36/* set to 0 to printing error messages to stderr instead of checking them in code */
37#define ENABLE_LOGGER_CHECKING 1
38
39#if ENABLE_LOGGER_CHECKING
40static void
41logger(LY_LOG_LEVEL level, const char *msg, const char *path)
42{
43 (void) level; /* unused */
44 if (store) {
45 if (path && path[0]) {
46 snprintf(logbuf, BUFSIZE - 1, "%s %s", msg, path);
47 } else {
48 strncpy(logbuf, msg, BUFSIZE - 1);
49 }
50 if (store > 0) {
51 --store;
52 }
53 }
54}
55#endif
56
57static int
58setup(void **state)
59{
60 (void) state; /* unused */
61
62 const char *schema_a =
63 "module a {"
64 "namespace urn:tests:a;"
65 "prefix a;"
66 "yang-version 1.1;"
67
68 "list l1 {"
69 "key \"a b\";"
70 "leaf a {"
71 "type string;"
72 "}"
73 "leaf b {"
74 "type string;"
75 "}"
76 "leaf c {"
77 "type string;"
78 "}"
79 "}"
80 "leaf foo {"
81 "type string;"
82 "}"
Michal Vasko4c7763f2020-07-27 17:40:37 +020083 "leaf foo2 {"
84 "type uint8;"
85 "}"
Michal Vasko14795a42020-05-22 16:44:44 +020086 "container c {"
87 "leaf x {"
88 "type string;"
89 "}"
90 "list ll {"
91 "key \"a\";"
92 "leaf a {"
93 "type string;"
94 "}"
95 "list ll {"
96 "key \"a\";"
97 "leaf a {"
98 "type string;"
99 "}"
100 "leaf b {"
101 "type string;"
102 "}"
103 "}"
104 "}"
Michal Vasko660cc8f2020-05-25 10:33:19 +0200105 "leaf-list ll2 {"
106 "type string;"
107 "}"
Michal Vasko14795a42020-05-22 16:44:44 +0200108 "}"
109 "}";
Michal Vasko61ac2f62020-05-25 12:39:51 +0200110 const char *schema_b =
111 "module b {"
112 "namespace urn:tests:b;"
113 "prefix b;"
114 "yang-version 1.1;"
115
116 "list l2 {"
117 "key \"a\";"
118 "leaf a {"
119 "type uint16;"
120 "}"
121 "leaf b {"
122 "type uint16;"
123 "}"
124 "}"
125 "}";
Michal Vasko14795a42020-05-22 16:44:44 +0200126
127#if ENABLE_LOGGER_CHECKING
128 ly_set_log_clb(logger, 1);
129#endif
130
131 assert_int_equal(LY_SUCCESS, ly_ctx_new(TESTS_DIR_MODULES_YANG, 0, &ctx));
Michal Vasko3a41dff2020-07-15 14:30:28 +0200132 assert_int_equal(lys_parse_mem(ctx, schema_a, LYS_IN_YANG, NULL), LY_SUCCESS);
133 assert_int_equal(lys_parse_mem(ctx, schema_b, LYS_IN_YANG, NULL), LY_SUCCESS);
Michal Vasko14795a42020-05-22 16:44:44 +0200134
135 return 0;
136}
137
138static int
139teardown(void **state)
140{
141#if ENABLE_LOGGER_CHECKING
142 if (*state) {
143 fprintf(stderr, "%s\n", logbuf);
144 }
145#else
146 (void) state; /* unused */
147#endif
148
149 ly_ctx_destroy(ctx, NULL);
150 ctx = NULL;
151
152 return 0;
153}
154
155void
156logbuf_clean(void)
157{
158 logbuf[0] = '\0';
159}
160
161#if ENABLE_LOGGER_CHECKING
162# define logbuf_assert(str) assert_string_equal(logbuf, str)
163#else
164# define logbuf_assert(str)
165#endif
166
167static void
168test_hash(void **state)
169{
170 *state = test_hash;
171
172 const char *data =
173 "<l1 xmlns=\"urn:tests:a\">"
174 "<a>a1</a>"
175 "<b>b1</b>"
176 "<c>c1</c>"
177 "</l1>"
178 "<l1 xmlns=\"urn:tests:a\">"
179 "<a>a2</a>"
180 "<b>b2</b>"
181 "</l1>"
182 "<l1 xmlns=\"urn:tests:a\">"
183 "<a>a3</a>"
184 "<b>b3</b>"
185 "<c>c3</c>"
186 "</l1>"
187 "<foo xmlns=\"urn:tests:a\">foo value</foo>"
188 "<c xmlns=\"urn:tests:a\">"
189 "<x>val</x>"
190 "<ll>"
191 "<a>val_a</a>"
192 "<ll>"
193 "<a>val_a</a>"
194 "<b>val</b>"
195 "</ll>"
196 "<ll>"
197 "<a>val_b</a>"
198 "</ll>"
199 "</ll>"
200 "<ll>"
201 "<a>val_b</a>"
202 "<ll>"
203 "<a>val_a</a>"
204 "</ll>"
205 "<ll>"
206 "<a>val_b</a>"
207 "<b>val</b>"
208 "</ll>"
209 "</ll>"
210 "<ll>"
211 "<a>val_c</a>"
212 "<ll>"
213 "<a>val_a</a>"
214 "</ll>"
215 "<ll>"
216 "<a>val_b</a>"
217 "</ll>"
218 "</ll>"
Michal Vasko660cc8f2020-05-25 10:33:19 +0200219 "<ll2>one</ll2>"
220 "<ll2>two</ll2>"
221 "<ll2>three</ll2>"
222 "<ll2>four</ll2>"
Michal Vasko14795a42020-05-22 16:44:44 +0200223 "</c>";
224 struct lyd_node *tree, *node;
225 struct ly_set *set;
226 int dynamic;
227 const char *val_str;
228
Radek Krejci7931b192020-06-25 17:05:03 +0200229 assert_int_equal(LY_SUCCESS, lyd_parse_data_mem(ctx, data, LYD_XML, LYD_PARSE_STRICT, LYD_VALIDATE_PRESENT, &tree));
Michal Vasko14795a42020-05-22 16:44:44 +0200230 assert_non_null(tree);
231
232 /* top-level, so hash table is not ultimately used but instances can be compared based on hashes */
233 assert_int_equal(LY_SUCCESS, lyd_find_xpath(tree, "/a:l1[a='a3'][b='b3']", &set));
234 assert_int_equal(1, set->count);
235
236 node = set->objs[0];
237 assert_string_equal(node->schema->name, "l1");
Michal Vasko5bfd4be2020-06-23 13:26:19 +0200238 node = lyd_node_children(node, 0);
Michal Vasko14795a42020-05-22 16:44:44 +0200239 assert_string_equal(node->schema->name, "a");
240 val_str = lyd_value2str((struct lyd_node_term *)node, &dynamic);
241 assert_int_equal(0, dynamic);
242 assert_string_equal(val_str, "a3");
243
244 ly_set_free(set, NULL);
245
246 /* hashes should be used for both searches (well, there are not enough nested ll instances, so technically not true) */
247 assert_int_equal(LY_SUCCESS, lyd_find_xpath(tree, "/a:c/ll[a='val_b']/ll[a='val_b']", &set));
248 assert_int_equal(1, set->count);
249
250 node = set->objs[0];
251 assert_string_equal(node->schema->name, "ll");
Michal Vasko5bfd4be2020-06-23 13:26:19 +0200252 node = lyd_node_children(node, 0);
Michal Vasko14795a42020-05-22 16:44:44 +0200253 assert_string_equal(node->schema->name, "a");
254 val_str = lyd_value2str((struct lyd_node_term *)node, &dynamic);
255 assert_int_equal(0, dynamic);
256 assert_string_equal(val_str, "val_b");
257 node = node->next;
258 assert_string_equal(node->schema->name, "b");
259 assert_null(node->next);
260
261 ly_set_free(set, NULL);
262
263 /* hashes are not used */
264 assert_int_equal(LY_SUCCESS, lyd_find_xpath(tree, "/a:c//ll[a='val_b']", &set));
265 assert_int_equal(4, set->count);
266
267 ly_set_free(set, NULL);
268
Michal Vasko660cc8f2020-05-25 10:33:19 +0200269 /* hashes used even for leaf-lists */
270 assert_int_equal(LY_SUCCESS, lyd_find_xpath(tree, "/a:c/ll2[. = 'three']", &set));
271 assert_int_equal(1, set->count);
272
273 node = set->objs[0];
274 assert_string_equal(node->schema->name, "ll2");
275 val_str = lyd_value2str((struct lyd_node_term *)node, &dynamic);
276 assert_int_equal(0, dynamic);
277 assert_string_equal(val_str, "three");
278
279 ly_set_free(set, NULL);
280
Michal Vasko14795a42020-05-22 16:44:44 +0200281 /* not found using hashes */
282 assert_int_equal(LY_SUCCESS, lyd_find_xpath(tree, "/a:c/ll[a='val_d']", &set));
283 assert_int_equal(0, set->count);
284
285 ly_set_free(set, NULL);
286
287 /* white-spaces are also ok */
288 assert_int_equal(LY_SUCCESS, lyd_find_xpath(tree, "/a:c/ll[ \na = 'val_c' ]", &set));
289 assert_int_equal(1, set->count);
290
291 ly_set_free(set, NULL);
292
293 lyd_free_all(tree);
294 *state = NULL;
295}
296
Michal Vasko61ac2f62020-05-25 12:39:51 +0200297static void
298test_toplevel(void **state)
299{
300 *state = test_toplevel;
301
302 const char *data =
303 "<l1 xmlns=\"urn:tests:a\">"
304 "<a>a1</a>"
305 "<b>b1</b>"
306 "<c>c1</c>"
307 "</l1>"
308 "<l1 xmlns=\"urn:tests:a\">"
309 "<a>a2</a>"
310 "<b>b2</b>"
311 "</l1>"
312 "<l1 xmlns=\"urn:tests:a\">"
313 "<a>a3</a>"
314 "<b>b3</b>"
315 "<c>c3</c>"
316 "</l1>"
317 "<foo xmlns=\"urn:tests:a\">foo value</foo>"
318 "<l2 xmlns=\"urn:tests:b\">"
319 "<a>1</a>"
320 "<b>1</b>"
321 "</l2>"
322 "<l2 xmlns=\"urn:tests:b\">"
323 "<a>2</a>"
324 "<b>1</b>"
325 "</l2>"
326 "<l2 xmlns=\"urn:tests:b\">"
327 "<a>3</a>"
328 "<b>1</b>"
329 "</l2>";
Michal Vaskof60e7102020-05-26 10:48:59 +0200330 struct lyd_node *tree;
Michal Vasko61ac2f62020-05-25 12:39:51 +0200331 struct ly_set *set;
Michal Vasko61ac2f62020-05-25 12:39:51 +0200332
Radek Krejci7931b192020-06-25 17:05:03 +0200333 assert_int_equal(LY_SUCCESS, lyd_parse_data_mem(ctx, data, LYD_XML, LYD_PARSE_STRICT , LYD_VALIDATE_PRESENT, &tree));
Michal Vasko61ac2f62020-05-25 12:39:51 +0200334 assert_non_null(tree);
335
336 /* all top-level nodes from one module (default container as well) */
337 assert_int_equal(LY_SUCCESS, lyd_find_xpath(tree, "/a:*", &set));
338 assert_int_equal(5, set->count);
339
340 ly_set_free(set, NULL);
341
342 /* all top-level nodes from all modules */
343 assert_int_equal(LY_SUCCESS, lyd_find_xpath(tree, "/*", &set));
344 assert_int_equal(8, set->count);
345
346 ly_set_free(set, NULL);
347
348 /* all nodes from one module */
349 assert_int_equal(LY_SUCCESS, lyd_find_xpath(tree, "//a:*", &set));
350 assert_int_equal(13, set->count);
351
352 ly_set_free(set, NULL);
353
354 /* all nodes from all modules */
355 assert_int_equal(LY_SUCCESS, lyd_find_xpath(tree, "//*", &set));
356 assert_int_equal(22, set->count);
357
358 ly_set_free(set, NULL);
359
360 /* all nodes from all modules #2 */
361 assert_int_equal(LY_SUCCESS, lyd_find_xpath(tree, "//.", &set));
362 assert_int_equal(22, set->count);
363
364 ly_set_free(set, NULL);
365
366 lyd_free_all(tree);
367 *state = NULL;
368}
369
Michal Vasko519fd602020-05-26 12:17:39 +0200370static void
371test_atomize(void **state)
372{
373 *state = test_atomize;
374
375 struct ly_set *set;
376 const struct lys_module *mod;
377
378 mod = ly_ctx_get_module_latest(ctx, "a");
379
380 /* some random paths just making sure the API function works */
381 assert_int_equal(LY_SUCCESS, lys_atomize_xpath(mod->compiled->data, "/a:*", 0, &set));
Michal Vasko4c7763f2020-07-27 17:40:37 +0200382 assert_int_equal(4, set->count);
Michal Vasko519fd602020-05-26 12:17:39 +0200383
384 ly_set_free(set, NULL);
385
386 /* all nodes from all modules (including internal, which can change easily, so check just the test modules) */
387 assert_int_equal(LY_SUCCESS, lys_atomize_xpath(mod->compiled->data, "//.", 0, &set));
388 assert_in_range(set->count, 16, UINT32_MAX);
389
390 ly_set_free(set, NULL);
391
Michal Vasko4c7763f2020-07-27 17:40:37 +0200392 assert_int_equal(LY_SUCCESS, lys_atomize_xpath(mod->compiled->data->next->next, "/a:c/ll[a='val1']/ll[a='val2']/b",
393 0, &set));
394 assert_int_equal(7, set->count);
Michal Vasko519fd602020-05-26 12:17:39 +0200395
396 ly_set_free(set, NULL);
397}
398
Michal Vasko4c7763f2020-07-27 17:40:37 +0200399static void
400test_canonize(void **state)
401{
402 *state = test_canonize;
403
404 const char *data =
405 "<foo2 xmlns=\"urn:tests:a\">50</foo2>";
406 struct lyd_node *tree;
407 struct ly_set *set;
408
409 assert_int_equal(LY_SUCCESS, lyd_parse_data_mem(ctx, data, LYD_XML, LYD_PARSE_STRICT, LYD_VALIDATE_PRESENT, &tree));
410 assert_non_null(tree);
411
412 assert_int_equal(LY_SUCCESS, lyd_find_xpath(tree, "/a:foo2[.='050']", &set));
413 assert_int_equal(1, set->count);
414 ly_set_free(set, NULL);
415
416 /* TODO more use-cases once there are some type plugins that have canonical values */
417
418 lyd_free_all(tree);
419 *state = NULL;
420}
421
Michal Vasko14795a42020-05-22 16:44:44 +0200422int main(void)
423{
424 const struct CMUnitTest tests[] = {
425 cmocka_unit_test_setup_teardown(test_hash, setup, teardown),
Michal Vasko61ac2f62020-05-25 12:39:51 +0200426 cmocka_unit_test_setup_teardown(test_toplevel, setup, teardown),
Michal Vasko519fd602020-05-26 12:17:39 +0200427 cmocka_unit_test_setup_teardown(test_atomize, setup, teardown),
Michal Vasko4c7763f2020-07-27 17:40:37 +0200428 cmocka_unit_test_setup_teardown(test_canonize, setup, teardown),
Michal Vasko14795a42020-05-22 16:44:44 +0200429 };
430
431 return cmocka_run_group_tests(tests, NULL, NULL);
432}