blob: 7be4ccf4cc354ca5571129078264baff58a6cf95 [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
aPiecekadc1e4f2021-10-07 11:15:12 +0200118test_union(void **state)
119{
120 const char *data;
121 struct lyd_node *tree;
122 struct ly_set *set;
123
124 data =
125 "<l1 xmlns=\"urn:tests:a\">\n"
126 " <a>a1</a>\n"
127 " <b>b1</b>\n"
128 " <c>c1</c>\n"
129 "</l1>\n"
130 "<l1 xmlns=\"urn:tests:a\">\n"
131 " <a>a2</a>\n"
132 " <b>b2</b>\n"
133 "</l1>"
134 "<l1 xmlns=\"urn:tests:a\">\n"
135 " <a>a3</a>\n"
136 " <b>b3</b>\n"
137 " <c>c3</c>\n"
138 "</l1>";
139 assert_int_equal(LY_SUCCESS, lyd_parse_data_mem(UTEST_LYCTX, data, LYD_XML, LYD_PARSE_STRICT, LYD_VALIDATE_PRESENT, &tree));
140 assert_non_null(tree);
141
142 /* Predicate for operand. */
143 assert_int_equal(LY_SUCCESS, lyd_find_xpath(tree, "/l1[c[../a = 'a1'] | c]/a", &set));
144 ly_set_free(set, NULL);
145
146 lyd_free_all(tree);
147}
148
149static void
Michal Vaskoe2be5462021-08-04 10:49:42 +0200150test_invalid(void **state)
151{
152 const char *data =
153 "<foo2 xmlns=\"urn:tests:a\">50</foo2>";
154 struct lyd_node *tree;
155 struct ly_set *set;
156
157 assert_int_equal(LY_SUCCESS, lyd_parse_data_mem(UTEST_LYCTX, data, LYD_XML, LYD_PARSE_STRICT, LYD_VALIDATE_PRESENT, &tree));
158 assert_non_null(tree);
159
160 assert_int_equal(LY_EVALID, lyd_find_xpath(tree, "/a:foo2[.=]", &set));
161 assert_null(set);
162
163 assert_int_equal(LY_EVALID, lyd_find_xpath(tree, "/a:", &set));
164 assert_null(set);
165
166 lyd_free_all(tree);
167}
168
169static void
Michal Vasko14795a42020-05-22 16:44:44 +0200170test_hash(void **state)
171{
Michal Vasko14795a42020-05-22 16:44:44 +0200172 const char *data =
Radek Krejcib4ac5a92020-11-23 17:54:33 +0100173 "<l1 xmlns=\"urn:tests:a\">\n"
174 " <a>a1</a>\n"
175 " <b>b1</b>\n"
176 " <c>c1</c>\n"
177 "</l1>\n"
178 "<l1 xmlns=\"urn:tests:a\">\n"
179 " <a>a2</a>\n"
180 " <b>b2</b>\n"
181 "</l1>\n"
182 "<l1 xmlns=\"urn:tests:a\">\n"
183 " <a>a3</a>\n"
184 " <b>b3</b>\n"
185 " <c>c3</c>\n"
186 "</l1>\n"
187 "<foo xmlns=\"urn:tests:a\">foo value</foo>\n"
188 "<c xmlns=\"urn:tests:a\">\n"
189 " <x>val</x>\n"
190 " <ll>\n"
191 " <a>val_a</a>\n"
192 " <ll>\n"
193 " <a>val_a</a>\n"
194 " <b>val</b>\n"
195 " </ll>\n"
196 " <ll>\n"
197 " <a>val_b</a>\n"
198 " </ll>\n"
199 " </ll>\n"
200 " <ll>\n"
201 " <a>val_b</a>\n"
202 " <ll>\n"
203 " <a>val_a</a>\n"
204 " </ll>\n"
205 " <ll>\n"
206 " <a>val_b</a>\n"
207 " <b>val</b>\n"
208 " </ll>\n"
209 " </ll>\n"
210 " <ll>\n"
211 " <a>val_c</a>\n"
212 " <ll>\n"
213 " <a>val_a</a>\n"
214 " </ll>\n"
215 " <ll>\n"
216 " <a>val_b</a>\n"
217 " </ll>\n"
218 " </ll>\n"
219 " <ll2>one</ll2>\n"
220 " <ll2>two</ll2>\n"
221 " <ll2>three</ll2>\n"
222 " <ll2>four</ll2>\n"
223 "</c>";
Michal Vasko14795a42020-05-22 16:44:44 +0200224 struct lyd_node *tree, *node;
225 struct ly_set *set;
Michal Vasko14795a42020-05-22 16:44:44 +0200226
Radek Iša56ca9e42020-09-08 18:42:00 +0200227 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 +0200228 assert_non_null(tree);
229
230 /* top-level, so hash table is not ultimately used but instances can be compared based on hashes */
231 assert_int_equal(LY_SUCCESS, lyd_find_xpath(tree, "/a:l1[a='a3'][b='b3']", &set));
232 assert_int_equal(1, set->count);
233
234 node = set->objs[0];
235 assert_string_equal(node->schema->name, "l1");
Radek Krejcia1c1e542020-09-29 16:06:52 +0200236 node = lyd_child(node);
Michal Vasko14795a42020-05-22 16:44:44 +0200237 assert_string_equal(node->schema->name, "a");
Radek Krejci6d5ba0c2021-04-26 07:49:59 +0200238 assert_string_equal(lyd_get_value(node), "a3");
Michal Vasko14795a42020-05-22 16:44:44 +0200239
240 ly_set_free(set, NULL);
241
242 /* hashes should be used for both searches (well, there are not enough nested ll instances, so technically not true) */
243 assert_int_equal(LY_SUCCESS, lyd_find_xpath(tree, "/a:c/ll[a='val_b']/ll[a='val_b']", &set));
244 assert_int_equal(1, set->count);
245
246 node = set->objs[0];
247 assert_string_equal(node->schema->name, "ll");
Radek Krejcia1c1e542020-09-29 16:06:52 +0200248 node = lyd_child(node);
Michal Vasko14795a42020-05-22 16:44:44 +0200249 assert_string_equal(node->schema->name, "a");
Radek Krejci6d5ba0c2021-04-26 07:49:59 +0200250 assert_string_equal(lyd_get_value(node), "val_b");
Michal Vasko14795a42020-05-22 16:44:44 +0200251 node = node->next;
252 assert_string_equal(node->schema->name, "b");
253 assert_null(node->next);
254
255 ly_set_free(set, NULL);
256
257 /* hashes are not used */
258 assert_int_equal(LY_SUCCESS, lyd_find_xpath(tree, "/a:c//ll[a='val_b']", &set));
259 assert_int_equal(4, set->count);
260
261 ly_set_free(set, NULL);
262
Michal Vasko660cc8f2020-05-25 10:33:19 +0200263 /* hashes used even for leaf-lists */
264 assert_int_equal(LY_SUCCESS, lyd_find_xpath(tree, "/a:c/ll2[. = 'three']", &set));
265 assert_int_equal(1, set->count);
266
267 node = set->objs[0];
268 assert_string_equal(node->schema->name, "ll2");
Radek Krejci6d5ba0c2021-04-26 07:49:59 +0200269 assert_string_equal(lyd_get_value(node), "three");
Michal Vasko660cc8f2020-05-25 10:33:19 +0200270
271 ly_set_free(set, NULL);
272
Michal Vasko14795a42020-05-22 16:44:44 +0200273 /* not found using hashes */
274 assert_int_equal(LY_SUCCESS, lyd_find_xpath(tree, "/a:c/ll[a='val_d']", &set));
275 assert_int_equal(0, set->count);
276
277 ly_set_free(set, NULL);
278
279 /* white-spaces are also ok */
280 assert_int_equal(LY_SUCCESS, lyd_find_xpath(tree, "/a:c/ll[ \na = 'val_c' ]", &set));
281 assert_int_equal(1, set->count);
282
283 ly_set_free(set, NULL);
284
285 lyd_free_all(tree);
Michal Vasko14795a42020-05-22 16:44:44 +0200286}
287
Michal Vasko61ac2f62020-05-25 12:39:51 +0200288static void
289test_toplevel(void **state)
290{
Radek Iša56ca9e42020-09-08 18:42:00 +0200291 const char *schema_b =
292 "module b {\n"
293 " namespace urn:tests:b;\n"
294 " prefix b;\n"
295 " yang-version 1.1;\n"
296 "\n"
297 " list l2 {\n"
298 " key \"a\";\n"
299 " leaf a {\n"
300 " type uint16;\n"
301 " }\n"
302 " leaf b {\n"
303 " type uint16;\n"
304 " }\n"
305 " }\n"
306 "}";
Michal Vasko61ac2f62020-05-25 12:39:51 +0200307 const char *data =
Radek Krejcib4ac5a92020-11-23 17:54:33 +0100308 "<l1 xmlns=\"urn:tests:a\">\n"
309 " <a>a1</a>\n"
310 " <b>b1</b>\n"
311 " <c>c1</c>\n"
312 "</l1>\n"
313 "<l1 xmlns=\"urn:tests:a\">\n"
314 " <a>a2</a>\n"
315 " <b>b2</b>\n"
316 "</l1>\n"
317 "<l1 xmlns=\"urn:tests:a\">\n"
318 " <a>a3</a>\n"
319 " <b>b3</b>\n"
320 " <c>c3</c>\n"
321 "</l1>\n"
322 "<foo xmlns=\"urn:tests:a\">foo value</foo>\n"
323 "<l2 xmlns=\"urn:tests:b\">\n"
324 " <a>1</a>\n"
325 " <b>1</b>\n"
326 "</l2>\n"
327 "<l2 xmlns=\"urn:tests:b\">\n"
328 " <a>2</a>\n"
329 " <b>1</b>\n"
330 "</l2>\n"
331 "<l2 xmlns=\"urn:tests:b\">\n"
332 " <a>3</a>\n"
333 " <b>1</b>\n"
334 "</l2>";
Michal Vaskof60e7102020-05-26 10:48:59 +0200335 struct lyd_node *tree;
Michal Vasko61ac2f62020-05-25 12:39:51 +0200336 struct ly_set *set;
Michal Vasko61ac2f62020-05-25 12:39:51 +0200337
Radek Iša56ca9e42020-09-08 18:42:00 +0200338 UTEST_ADD_MODULE(schema_b, LYS_IN_YANG, NULL, NULL);
339
340 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 +0200341 assert_non_null(tree);
342
343 /* all top-level nodes from one module (default container as well) */
344 assert_int_equal(LY_SUCCESS, lyd_find_xpath(tree, "/a:*", &set));
345 assert_int_equal(5, set->count);
346
347 ly_set_free(set, NULL);
348
349 /* all top-level nodes from all modules */
350 assert_int_equal(LY_SUCCESS, lyd_find_xpath(tree, "/*", &set));
351 assert_int_equal(8, set->count);
352
353 ly_set_free(set, NULL);
354
355 /* all nodes from one module */
356 assert_int_equal(LY_SUCCESS, lyd_find_xpath(tree, "//a:*", &set));
357 assert_int_equal(13, set->count);
358
359 ly_set_free(set, NULL);
360
361 /* all nodes from all modules */
362 assert_int_equal(LY_SUCCESS, lyd_find_xpath(tree, "//*", &set));
363 assert_int_equal(22, set->count);
364
365 ly_set_free(set, NULL);
366
367 /* all nodes from all modules #2 */
368 assert_int_equal(LY_SUCCESS, lyd_find_xpath(tree, "//.", &set));
369 assert_int_equal(22, set->count);
370
371 ly_set_free(set, NULL);
372
373 lyd_free_all(tree);
Michal Vasko61ac2f62020-05-25 12:39:51 +0200374}
375
Michal Vasko519fd602020-05-26 12:17:39 +0200376static void
377test_atomize(void **state)
378{
Michal Vasko519fd602020-05-26 12:17:39 +0200379 struct ly_set *set;
380 const struct lys_module *mod;
381
Radek Iša56ca9e42020-09-08 18:42:00 +0200382 mod = ly_ctx_get_module_latest(UTEST_LYCTX, "a");
383 assert_non_null(mod);
Michal Vasko519fd602020-05-26 12:17:39 +0200384
385 /* some random paths just making sure the API function works */
Michal Vasko400e9672021-01-11 13:39:17 +0100386 assert_int_equal(LY_SUCCESS, lys_find_xpath_atoms(UTEST_LYCTX, NULL, "/a:*", 0, &set));
Michal Vasko93923692021-05-07 15:28:02 +0200387 assert_int_equal(5, set->count);
Michal Vasko519fd602020-05-26 12:17:39 +0200388
389 ly_set_free(set, NULL);
390
391 /* all nodes from all modules (including internal, which can change easily, so check just the test modules) */
Michal Vasko400e9672021-01-11 13:39:17 +0100392 assert_int_equal(LY_SUCCESS, lys_find_xpath_atoms(UTEST_LYCTX, NULL, "//.", 0, &set));
Michal Vasko93923692021-05-07 15:28:02 +0200393 assert_in_range(set->count, 17, UINT32_MAX);
Michal Vasko519fd602020-05-26 12:17:39 +0200394
395 ly_set_free(set, NULL);
396
Michal Vasko400e9672021-01-11 13:39:17 +0100397 assert_int_equal(LY_SUCCESS, lys_find_xpath_atoms(UTEST_LYCTX, NULL, "/a:c/ll[a='val1']/ll[a='val2']/b", 0, &set));
398 assert_int_equal(6, set->count);
Michal Vasko519fd602020-05-26 12:17:39 +0200399
400 ly_set_free(set, NULL);
401}
402
Michal Vasko4c7763f2020-07-27 17:40:37 +0200403static void
404test_canonize(void **state)
405{
Michal Vasko4c7763f2020-07-27 17:40:37 +0200406 const char *data =
Radek Krejcib4ac5a92020-11-23 17:54:33 +0100407 "<foo2 xmlns=\"urn:tests:a\">50</foo2>";
Michal Vasko4c7763f2020-07-27 17:40:37 +0200408 struct lyd_node *tree;
409 struct ly_set *set;
410
Radek Iša56ca9e42020-09-08 18:42:00 +0200411 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 +0200412 assert_non_null(tree);
413
414 assert_int_equal(LY_SUCCESS, lyd_find_xpath(tree, "/a:foo2[.='050']", &set));
415 assert_int_equal(1, set->count);
416 ly_set_free(set, NULL);
417
418 /* TODO more use-cases once there are some type plugins that have canonical values */
419
420 lyd_free_all(tree);
Michal Vasko4c7763f2020-07-27 17:40:37 +0200421}
422
Michal Vasko93923692021-05-07 15:28:02 +0200423static void
424test_derived_from(void **state)
425{
426 const char *data =
427 "<foo3 xmlns=\"urn:tests:a\">id_c</foo3>";
428 struct lyd_node *tree;
429 struct ly_set *set;
430
431 assert_int_equal(LY_SUCCESS, lyd_parse_data_mem(UTEST_LYCTX, data, LYD_XML, LYD_PARSE_STRICT, LYD_VALIDATE_PRESENT, &tree));
432 assert_non_null(tree);
433
434 assert_int_equal(LY_SUCCESS, lyd_find_xpath(tree, "/a:foo3[derived-from(., 'a:id_b')]", &set));
435 assert_int_equal(1, set->count);
436 ly_set_free(set, NULL);
437
438 assert_int_equal(LY_SUCCESS, lyd_find_xpath(tree, "/a:foo3[derived-from(., 'a:id_a')]", &set));
439 assert_int_equal(1, set->count);
440 ly_set_free(set, NULL);
441
442 lyd_free_all(tree);
443}
444
Michal Vaskodb08ce52021-10-06 08:57:49 +0200445static void
446test_augment(void **state)
447{
448 const char *schema_b =
449 "module b {\n"
450 " namespace urn:tests:b;\n"
451 " prefix b;\n"
452 " yang-version 1.1;\n"
453 "\n"
454 " import a {\n"
455 " prefix a;\n"
456 " }\n"
457 "\n"
458 " augment /a:c {\n"
459 " leaf a {\n"
460 " type uint16;\n"
461 " }\n"
462 " }\n"
463 "}";
464 const char *data =
465 "<c xmlns=\"urn:tests:a\">\n"
466 " <x>value</x>\n"
467 " <ll>\n"
468 " <a>key</a>\n"
469 " </ll>\n"
470 " <a xmlns=\"urn:tests:b\">25</a>\n"
471 " <ll2>c1</ll2>\n"
472 "</c>";
473 struct lyd_node *tree;
474 struct ly_set *set;
475
476 UTEST_ADD_MODULE(schema_b, LYS_IN_YANG, NULL, NULL);
477
478 assert_int_equal(LY_SUCCESS, lyd_parse_data_mem(UTEST_LYCTX, data, LYD_XML, LYD_PARSE_STRICT, LYD_VALIDATE_PRESENT, &tree));
479 assert_non_null(tree);
480
481 /* get all children ignoring their module */
482 assert_int_equal(LY_SUCCESS, lyd_find_xpath(tree, "/a:c/*", &set));
483 assert_int_equal(4, set->count);
484
485 ly_set_free(set, NULL);
486
487 lyd_free_all(tree);
488}
489
Radek Krejcib4ac5a92020-11-23 17:54:33 +0100490int
491main(void)
Michal Vasko14795a42020-05-22 16:44:44 +0200492{
493 const struct CMUnitTest tests[] = {
aPiecekfff4dca2021-10-07 10:59:53 +0200494 UTEST(test_predicate, setup),
aPiecekadc1e4f2021-10-07 11:15:12 +0200495 UTEST(test_union, setup),
Michal Vaskoe2be5462021-08-04 10:49:42 +0200496 UTEST(test_invalid, setup),
Radek Iša56ca9e42020-09-08 18:42:00 +0200497 UTEST(test_hash, setup),
498 UTEST(test_toplevel, setup),
499 UTEST(test_atomize, setup),
500 UTEST(test_canonize, setup),
Michal Vasko93923692021-05-07 15:28:02 +0200501 UTEST(test_derived_from, setup),
Michal Vaskodb08ce52021-10-06 08:57:49 +0200502 UTEST(test_augment, setup),
Michal Vasko14795a42020-05-22 16:44:44 +0200503 };
504
505 return cmocka_run_group_tests(tests, NULL, NULL);
506}