blob: dc31cc3076123d92271ebb3821d9ccbf55503ffa [file] [log] [blame]
Michal Vasko93923692021-05-07 15:28:02 +02001/**
Michal Vasko14795a42020-05-22 16:44:44 +02002 * @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 */
Radek Iša56ca9e42020-09-08 18:42:00 +020014#define _UTEST_MAIN_
15#include "utests.h"
Michal Vasko14795a42020-05-22 16:44:44 +020016
Michal Vasko14795a42020-05-22 16:44:44 +020017#include <string.h>
18
Radek Krejci70593c12020-06-13 20:48:09 +020019#include "context.h"
Radek Krejci7931b192020-06-25 17:05:03 +020020#include "parser_data.h"
Radek Krejci70593c12020-06-13 20:48:09 +020021#include "set.h"
Radek Krejcief5f7672021-04-01 17:04:12 +020022#include "tests_config.h"
Radek Krejci70593c12020-06-13 20:48:09 +020023#include "tree_data.h"
24#include "tree_schema.h"
Michal Vasko14795a42020-05-22 16:44:44 +020025
Radek Iša56ca9e42020-09-08 18:42:00 +020026const char *schema_a =
27 "module a {\n"
28 " namespace urn:tests:a;\n"
29 " prefix a;\n"
30 " yang-version 1.1;\n"
31 "\n"
Michal Vasko93923692021-05-07 15:28:02 +020032 " identity id_a;\n"
33 " identity id_b {\n"
34 " base id_a;\n"
35 " }\n"
36 " identity id_c {\n"
37 " base id_b;\n"
38 " }\n"
39 "\n"
Radek Iša56ca9e42020-09-08 18:42:00 +020040 " list l1 {\n"
41 " key \"a b\";\n"
42 " leaf a {\n"
43 " type string;\n"
44 " }\n"
45 " leaf b {\n"
46 " type string;\n"
47 " }\n"
48 " leaf c {\n"
49 " type string;\n"
50 " }\n"
51 " }\n"
52 " leaf foo {\n"
53 " type string;\n"
54 " }\n"
55 " leaf foo2 {\n"
56 " type uint8;\n"
57 " }\n"
Michal Vasko93923692021-05-07 15:28:02 +020058 " leaf foo3 {\n"
59 " type identityref {\n"
60 " base id_a;\n"
61 " }\n"
62 " }\n"
Radek Iša56ca9e42020-09-08 18:42:00 +020063 " container c {\n"
64 " leaf x {\n"
65 " type string;\n"
66 " }\n"
67 " list ll {\n"
68 " key \"a\";\n"
69 " leaf a {\n"
70 " type string;\n"
71 " }\n"
72 " list ll {\n"
73 " key \"a\";\n"
74 " leaf a {\n"
75 " type string;\n"
76 " }\n"
77 " leaf b {\n"
78 " type string;\n"
79 " }\n"
80 " }\n"
81 " }\n"
82 " leaf-list ll2 {\n"
83 " type string;\n"
84 " }\n"
85 " }\n"
86 "}";
Michal Vasko14795a42020-05-22 16:44:44 +020087
88static int
89setup(void **state)
90{
Radek Iša56ca9e42020-09-08 18:42:00 +020091 UTEST_SETUP;
Michal Vasko14795a42020-05-22 16:44:44 +020092
Radek Iša56ca9e42020-09-08 18:42:00 +020093 UTEST_ADD_MODULE(schema_a, LYS_IN_YANG, NULL, NULL);
Michal Vasko14795a42020-05-22 16:44:44 +020094
95 return 0;
96}
97
Michal Vasko14795a42020-05-22 16:44:44 +020098static void
aPiecekfff4dca2021-10-07 10:59:53 +020099test_predicate(void **state)
100{
101 const char *data;
102 struct lyd_node *tree;
103 struct ly_set *set;
104
105 data =
106 "<foo2 xmlns=\"urn:tests:a\">50</foo2>";
107 assert_int_equal(LY_SUCCESS, lyd_parse_data_mem(UTEST_LYCTX, data, LYD_XML, LYD_PARSE_STRICT, LYD_VALIDATE_PRESENT, &tree));
108 assert_non_null(tree);
109
110 /* Predicate after number. */
111 assert_int_equal(LY_SUCCESS, lyd_find_xpath(tree, "/foo2[4[3 = 3]]", &set));
112 ly_set_free(set, NULL);
113
114 lyd_free_all(tree);
115}
116
117static void
Michal Vaskoe2be5462021-08-04 10:49:42 +0200118test_invalid(void **state)
119{
120 const char *data =
121 "<foo2 xmlns=\"urn:tests:a\">50</foo2>";
122 struct lyd_node *tree;
123 struct ly_set *set;
124
125 assert_int_equal(LY_SUCCESS, lyd_parse_data_mem(UTEST_LYCTX, data, LYD_XML, LYD_PARSE_STRICT, LYD_VALIDATE_PRESENT, &tree));
126 assert_non_null(tree);
127
128 assert_int_equal(LY_EVALID, lyd_find_xpath(tree, "/a:foo2[.=]", &set));
129 assert_null(set);
130
131 assert_int_equal(LY_EVALID, lyd_find_xpath(tree, "/a:", &set));
132 assert_null(set);
133
134 lyd_free_all(tree);
135}
136
137static void
Michal Vasko14795a42020-05-22 16:44:44 +0200138test_hash(void **state)
139{
Michal Vasko14795a42020-05-22 16:44:44 +0200140 const char *data =
Radek Krejcib4ac5a92020-11-23 17:54:33 +0100141 "<l1 xmlns=\"urn:tests:a\">\n"
142 " <a>a1</a>\n"
143 " <b>b1</b>\n"
144 " <c>c1</c>\n"
145 "</l1>\n"
146 "<l1 xmlns=\"urn:tests:a\">\n"
147 " <a>a2</a>\n"
148 " <b>b2</b>\n"
149 "</l1>\n"
150 "<l1 xmlns=\"urn:tests:a\">\n"
151 " <a>a3</a>\n"
152 " <b>b3</b>\n"
153 " <c>c3</c>\n"
154 "</l1>\n"
155 "<foo xmlns=\"urn:tests:a\">foo value</foo>\n"
156 "<c xmlns=\"urn:tests:a\">\n"
157 " <x>val</x>\n"
158 " <ll>\n"
159 " <a>val_a</a>\n"
160 " <ll>\n"
161 " <a>val_a</a>\n"
162 " <b>val</b>\n"
163 " </ll>\n"
164 " <ll>\n"
165 " <a>val_b</a>\n"
166 " </ll>\n"
167 " </ll>\n"
168 " <ll>\n"
169 " <a>val_b</a>\n"
170 " <ll>\n"
171 " <a>val_a</a>\n"
172 " </ll>\n"
173 " <ll>\n"
174 " <a>val_b</a>\n"
175 " <b>val</b>\n"
176 " </ll>\n"
177 " </ll>\n"
178 " <ll>\n"
179 " <a>val_c</a>\n"
180 " <ll>\n"
181 " <a>val_a</a>\n"
182 " </ll>\n"
183 " <ll>\n"
184 " <a>val_b</a>\n"
185 " </ll>\n"
186 " </ll>\n"
187 " <ll2>one</ll2>\n"
188 " <ll2>two</ll2>\n"
189 " <ll2>three</ll2>\n"
190 " <ll2>four</ll2>\n"
191 "</c>";
Michal Vasko14795a42020-05-22 16:44:44 +0200192 struct lyd_node *tree, *node;
193 struct ly_set *set;
Michal Vasko14795a42020-05-22 16:44:44 +0200194
Radek Iša56ca9e42020-09-08 18:42:00 +0200195 assert_int_equal(LY_SUCCESS, lyd_parse_data_mem(UTEST_LYCTX, data, LYD_XML, LYD_PARSE_STRICT, LYD_VALIDATE_PRESENT, &tree));
Michal Vasko14795a42020-05-22 16:44:44 +0200196 assert_non_null(tree);
197
198 /* top-level, so hash table is not ultimately used but instances can be compared based on hashes */
199 assert_int_equal(LY_SUCCESS, lyd_find_xpath(tree, "/a:l1[a='a3'][b='b3']", &set));
200 assert_int_equal(1, set->count);
201
202 node = set->objs[0];
203 assert_string_equal(node->schema->name, "l1");
Radek Krejcia1c1e542020-09-29 16:06:52 +0200204 node = lyd_child(node);
Michal Vasko14795a42020-05-22 16:44:44 +0200205 assert_string_equal(node->schema->name, "a");
Radek Krejci6d5ba0c2021-04-26 07:49:59 +0200206 assert_string_equal(lyd_get_value(node), "a3");
Michal Vasko14795a42020-05-22 16:44:44 +0200207
208 ly_set_free(set, NULL);
209
210 /* hashes should be used for both searches (well, there are not enough nested ll instances, so technically not true) */
211 assert_int_equal(LY_SUCCESS, lyd_find_xpath(tree, "/a:c/ll[a='val_b']/ll[a='val_b']", &set));
212 assert_int_equal(1, set->count);
213
214 node = set->objs[0];
215 assert_string_equal(node->schema->name, "ll");
Radek Krejcia1c1e542020-09-29 16:06:52 +0200216 node = lyd_child(node);
Michal Vasko14795a42020-05-22 16:44:44 +0200217 assert_string_equal(node->schema->name, "a");
Radek Krejci6d5ba0c2021-04-26 07:49:59 +0200218 assert_string_equal(lyd_get_value(node), "val_b");
Michal Vasko14795a42020-05-22 16:44:44 +0200219 node = node->next;
220 assert_string_equal(node->schema->name, "b");
221 assert_null(node->next);
222
223 ly_set_free(set, NULL);
224
225 /* hashes are not used */
226 assert_int_equal(LY_SUCCESS, lyd_find_xpath(tree, "/a:c//ll[a='val_b']", &set));
227 assert_int_equal(4, set->count);
228
229 ly_set_free(set, NULL);
230
Michal Vasko660cc8f2020-05-25 10:33:19 +0200231 /* hashes used even for leaf-lists */
232 assert_int_equal(LY_SUCCESS, lyd_find_xpath(tree, "/a:c/ll2[. = 'three']", &set));
233 assert_int_equal(1, set->count);
234
235 node = set->objs[0];
236 assert_string_equal(node->schema->name, "ll2");
Radek Krejci6d5ba0c2021-04-26 07:49:59 +0200237 assert_string_equal(lyd_get_value(node), "three");
Michal Vasko660cc8f2020-05-25 10:33:19 +0200238
239 ly_set_free(set, NULL);
240
Michal Vasko14795a42020-05-22 16:44:44 +0200241 /* not found using hashes */
242 assert_int_equal(LY_SUCCESS, lyd_find_xpath(tree, "/a:c/ll[a='val_d']", &set));
243 assert_int_equal(0, set->count);
244
245 ly_set_free(set, NULL);
246
247 /* white-spaces are also ok */
248 assert_int_equal(LY_SUCCESS, lyd_find_xpath(tree, "/a:c/ll[ \na = 'val_c' ]", &set));
249 assert_int_equal(1, set->count);
250
251 ly_set_free(set, NULL);
252
253 lyd_free_all(tree);
Michal Vasko14795a42020-05-22 16:44:44 +0200254}
255
Michal Vasko61ac2f62020-05-25 12:39:51 +0200256static void
257test_toplevel(void **state)
258{
Radek Iša56ca9e42020-09-08 18:42:00 +0200259 const char *schema_b =
260 "module b {\n"
261 " namespace urn:tests:b;\n"
262 " prefix b;\n"
263 " yang-version 1.1;\n"
264 "\n"
265 " list l2 {\n"
266 " key \"a\";\n"
267 " leaf a {\n"
268 " type uint16;\n"
269 " }\n"
270 " leaf b {\n"
271 " type uint16;\n"
272 " }\n"
273 " }\n"
274 "}";
Michal Vasko61ac2f62020-05-25 12:39:51 +0200275 const char *data =
Radek Krejcib4ac5a92020-11-23 17:54:33 +0100276 "<l1 xmlns=\"urn:tests:a\">\n"
277 " <a>a1</a>\n"
278 " <b>b1</b>\n"
279 " <c>c1</c>\n"
280 "</l1>\n"
281 "<l1 xmlns=\"urn:tests:a\">\n"
282 " <a>a2</a>\n"
283 " <b>b2</b>\n"
284 "</l1>\n"
285 "<l1 xmlns=\"urn:tests:a\">\n"
286 " <a>a3</a>\n"
287 " <b>b3</b>\n"
288 " <c>c3</c>\n"
289 "</l1>\n"
290 "<foo xmlns=\"urn:tests:a\">foo value</foo>\n"
291 "<l2 xmlns=\"urn:tests:b\">\n"
292 " <a>1</a>\n"
293 " <b>1</b>\n"
294 "</l2>\n"
295 "<l2 xmlns=\"urn:tests:b\">\n"
296 " <a>2</a>\n"
297 " <b>1</b>\n"
298 "</l2>\n"
299 "<l2 xmlns=\"urn:tests:b\">\n"
300 " <a>3</a>\n"
301 " <b>1</b>\n"
302 "</l2>";
Michal Vaskof60e7102020-05-26 10:48:59 +0200303 struct lyd_node *tree;
Michal Vasko61ac2f62020-05-25 12:39:51 +0200304 struct ly_set *set;
Michal Vasko61ac2f62020-05-25 12:39:51 +0200305
Radek Iša56ca9e42020-09-08 18:42:00 +0200306 UTEST_ADD_MODULE(schema_b, LYS_IN_YANG, NULL, NULL);
307
308 assert_int_equal(LY_SUCCESS, lyd_parse_data_mem(UTEST_LYCTX, data, LYD_XML, LYD_PARSE_STRICT, LYD_VALIDATE_PRESENT, &tree));
Michal Vasko61ac2f62020-05-25 12:39:51 +0200309 assert_non_null(tree);
310
311 /* all top-level nodes from one module (default container as well) */
312 assert_int_equal(LY_SUCCESS, lyd_find_xpath(tree, "/a:*", &set));
313 assert_int_equal(5, set->count);
314
315 ly_set_free(set, NULL);
316
317 /* all top-level nodes from all modules */
318 assert_int_equal(LY_SUCCESS, lyd_find_xpath(tree, "/*", &set));
319 assert_int_equal(8, set->count);
320
321 ly_set_free(set, NULL);
322
323 /* all nodes from one module */
324 assert_int_equal(LY_SUCCESS, lyd_find_xpath(tree, "//a:*", &set));
325 assert_int_equal(13, set->count);
326
327 ly_set_free(set, NULL);
328
329 /* all nodes from all modules */
330 assert_int_equal(LY_SUCCESS, lyd_find_xpath(tree, "//*", &set));
331 assert_int_equal(22, set->count);
332
333 ly_set_free(set, NULL);
334
335 /* all nodes from all modules #2 */
336 assert_int_equal(LY_SUCCESS, lyd_find_xpath(tree, "//.", &set));
337 assert_int_equal(22, set->count);
338
339 ly_set_free(set, NULL);
340
341 lyd_free_all(tree);
Michal Vasko61ac2f62020-05-25 12:39:51 +0200342}
343
Michal Vasko519fd602020-05-26 12:17:39 +0200344static void
345test_atomize(void **state)
346{
Michal Vasko519fd602020-05-26 12:17:39 +0200347 struct ly_set *set;
348 const struct lys_module *mod;
349
Radek Iša56ca9e42020-09-08 18:42:00 +0200350 mod = ly_ctx_get_module_latest(UTEST_LYCTX, "a");
351 assert_non_null(mod);
Michal Vasko519fd602020-05-26 12:17:39 +0200352
353 /* some random paths just making sure the API function works */
Michal Vasko400e9672021-01-11 13:39:17 +0100354 assert_int_equal(LY_SUCCESS, lys_find_xpath_atoms(UTEST_LYCTX, NULL, "/a:*", 0, &set));
Michal Vasko93923692021-05-07 15:28:02 +0200355 assert_int_equal(5, set->count);
Michal Vasko519fd602020-05-26 12:17:39 +0200356
357 ly_set_free(set, NULL);
358
359 /* all nodes from all modules (including internal, which can change easily, so check just the test modules) */
Michal Vasko400e9672021-01-11 13:39:17 +0100360 assert_int_equal(LY_SUCCESS, lys_find_xpath_atoms(UTEST_LYCTX, NULL, "//.", 0, &set));
Michal Vasko93923692021-05-07 15:28:02 +0200361 assert_in_range(set->count, 17, UINT32_MAX);
Michal Vasko519fd602020-05-26 12:17:39 +0200362
363 ly_set_free(set, NULL);
364
Michal Vasko400e9672021-01-11 13:39:17 +0100365 assert_int_equal(LY_SUCCESS, lys_find_xpath_atoms(UTEST_LYCTX, NULL, "/a:c/ll[a='val1']/ll[a='val2']/b", 0, &set));
366 assert_int_equal(6, set->count);
Michal Vasko519fd602020-05-26 12:17:39 +0200367
368 ly_set_free(set, NULL);
369}
370
Michal Vasko4c7763f2020-07-27 17:40:37 +0200371static void
372test_canonize(void **state)
373{
Michal Vasko4c7763f2020-07-27 17:40:37 +0200374 const char *data =
Radek Krejcib4ac5a92020-11-23 17:54:33 +0100375 "<foo2 xmlns=\"urn:tests:a\">50</foo2>";
Michal Vasko4c7763f2020-07-27 17:40:37 +0200376 struct lyd_node *tree;
377 struct ly_set *set;
378
Radek Iša56ca9e42020-09-08 18:42:00 +0200379 assert_int_equal(LY_SUCCESS, lyd_parse_data_mem(UTEST_LYCTX, data, LYD_XML, LYD_PARSE_STRICT, LYD_VALIDATE_PRESENT, &tree));
Michal Vasko4c7763f2020-07-27 17:40:37 +0200380 assert_non_null(tree);
381
382 assert_int_equal(LY_SUCCESS, lyd_find_xpath(tree, "/a:foo2[.='050']", &set));
383 assert_int_equal(1, set->count);
384 ly_set_free(set, NULL);
385
386 /* TODO more use-cases once there are some type plugins that have canonical values */
387
388 lyd_free_all(tree);
Michal Vasko4c7763f2020-07-27 17:40:37 +0200389}
390
Michal Vasko93923692021-05-07 15:28:02 +0200391static void
392test_derived_from(void **state)
393{
394 const char *data =
395 "<foo3 xmlns=\"urn:tests:a\">id_c</foo3>";
396 struct lyd_node *tree;
397 struct ly_set *set;
398
399 assert_int_equal(LY_SUCCESS, lyd_parse_data_mem(UTEST_LYCTX, data, LYD_XML, LYD_PARSE_STRICT, LYD_VALIDATE_PRESENT, &tree));
400 assert_non_null(tree);
401
402 assert_int_equal(LY_SUCCESS, lyd_find_xpath(tree, "/a:foo3[derived-from(., 'a:id_b')]", &set));
403 assert_int_equal(1, set->count);
404 ly_set_free(set, NULL);
405
406 assert_int_equal(LY_SUCCESS, lyd_find_xpath(tree, "/a:foo3[derived-from(., 'a:id_a')]", &set));
407 assert_int_equal(1, set->count);
408 ly_set_free(set, NULL);
409
410 lyd_free_all(tree);
411}
412
Michal Vaskodb08ce52021-10-06 08:57:49 +0200413static void
414test_augment(void **state)
415{
416 const char *schema_b =
417 "module b {\n"
418 " namespace urn:tests:b;\n"
419 " prefix b;\n"
420 " yang-version 1.1;\n"
421 "\n"
422 " import a {\n"
423 " prefix a;\n"
424 " }\n"
425 "\n"
426 " augment /a:c {\n"
427 " leaf a {\n"
428 " type uint16;\n"
429 " }\n"
430 " }\n"
431 "}";
432 const char *data =
433 "<c xmlns=\"urn:tests:a\">\n"
434 " <x>value</x>\n"
435 " <ll>\n"
436 " <a>key</a>\n"
437 " </ll>\n"
438 " <a xmlns=\"urn:tests:b\">25</a>\n"
439 " <ll2>c1</ll2>\n"
440 "</c>";
441 struct lyd_node *tree;
442 struct ly_set *set;
443
444 UTEST_ADD_MODULE(schema_b, LYS_IN_YANG, NULL, NULL);
445
446 assert_int_equal(LY_SUCCESS, lyd_parse_data_mem(UTEST_LYCTX, data, LYD_XML, LYD_PARSE_STRICT, LYD_VALIDATE_PRESENT, &tree));
447 assert_non_null(tree);
448
449 /* get all children ignoring their module */
450 assert_int_equal(LY_SUCCESS, lyd_find_xpath(tree, "/a:c/*", &set));
451 assert_int_equal(4, set->count);
452
453 ly_set_free(set, NULL);
454
455 lyd_free_all(tree);
456}
457
Radek Krejcib4ac5a92020-11-23 17:54:33 +0100458int
459main(void)
Michal Vasko14795a42020-05-22 16:44:44 +0200460{
461 const struct CMUnitTest tests[] = {
aPiecekfff4dca2021-10-07 10:59:53 +0200462 UTEST(test_predicate, setup),
Michal Vaskoe2be5462021-08-04 10:49:42 +0200463 UTEST(test_invalid, setup),
Radek Iša56ca9e42020-09-08 18:42:00 +0200464 UTEST(test_hash, setup),
465 UTEST(test_toplevel, setup),
466 UTEST(test_atomize, setup),
467 UTEST(test_canonize, setup),
Michal Vasko93923692021-05-07 15:28:02 +0200468 UTEST(test_derived_from, setup),
Michal Vaskodb08ce52021-10-06 08:57:49 +0200469 UTEST(test_augment, setup),
Michal Vasko14795a42020-05-22 16:44:44 +0200470 };
471
472 return cmocka_run_group_tests(tests, NULL, NULL);
473}