blob: 9a6c37c08717e55cd34b1868f8bb6717b93fefc6 [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
Michal Vaskoe2be5462021-08-04 10:49:42 +020099test_invalid(void **state)
100{
101 const char *data =
102 "<foo2 xmlns=\"urn:tests:a\">50</foo2>";
103 struct lyd_node *tree;
104 struct ly_set *set;
105
106 assert_int_equal(LY_SUCCESS, lyd_parse_data_mem(UTEST_LYCTX, data, LYD_XML, LYD_PARSE_STRICT, LYD_VALIDATE_PRESENT, &tree));
107 assert_non_null(tree);
108
109 assert_int_equal(LY_EVALID, lyd_find_xpath(tree, "/a:foo2[.=]", &set));
110 assert_null(set);
111
112 assert_int_equal(LY_EVALID, lyd_find_xpath(tree, "/a:", &set));
113 assert_null(set);
114
115 lyd_free_all(tree);
116}
117
118static void
Michal Vasko14795a42020-05-22 16:44:44 +0200119test_hash(void **state)
120{
Michal Vasko14795a42020-05-22 16:44:44 +0200121 const char *data =
Radek Krejcib4ac5a92020-11-23 17:54:33 +0100122 "<l1 xmlns=\"urn:tests:a\">\n"
123 " <a>a1</a>\n"
124 " <b>b1</b>\n"
125 " <c>c1</c>\n"
126 "</l1>\n"
127 "<l1 xmlns=\"urn:tests:a\">\n"
128 " <a>a2</a>\n"
129 " <b>b2</b>\n"
130 "</l1>\n"
131 "<l1 xmlns=\"urn:tests:a\">\n"
132 " <a>a3</a>\n"
133 " <b>b3</b>\n"
134 " <c>c3</c>\n"
135 "</l1>\n"
136 "<foo xmlns=\"urn:tests:a\">foo value</foo>\n"
137 "<c xmlns=\"urn:tests:a\">\n"
138 " <x>val</x>\n"
139 " <ll>\n"
140 " <a>val_a</a>\n"
141 " <ll>\n"
142 " <a>val_a</a>\n"
143 " <b>val</b>\n"
144 " </ll>\n"
145 " <ll>\n"
146 " <a>val_b</a>\n"
147 " </ll>\n"
148 " </ll>\n"
149 " <ll>\n"
150 " <a>val_b</a>\n"
151 " <ll>\n"
152 " <a>val_a</a>\n"
153 " </ll>\n"
154 " <ll>\n"
155 " <a>val_b</a>\n"
156 " <b>val</b>\n"
157 " </ll>\n"
158 " </ll>\n"
159 " <ll>\n"
160 " <a>val_c</a>\n"
161 " <ll>\n"
162 " <a>val_a</a>\n"
163 " </ll>\n"
164 " <ll>\n"
165 " <a>val_b</a>\n"
166 " </ll>\n"
167 " </ll>\n"
168 " <ll2>one</ll2>\n"
169 " <ll2>two</ll2>\n"
170 " <ll2>three</ll2>\n"
171 " <ll2>four</ll2>\n"
172 "</c>";
Michal Vasko14795a42020-05-22 16:44:44 +0200173 struct lyd_node *tree, *node;
174 struct ly_set *set;
Michal Vasko14795a42020-05-22 16:44:44 +0200175
Radek Iša56ca9e42020-09-08 18:42:00 +0200176 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 +0200177 assert_non_null(tree);
178
179 /* top-level, so hash table is not ultimately used but instances can be compared based on hashes */
180 assert_int_equal(LY_SUCCESS, lyd_find_xpath(tree, "/a:l1[a='a3'][b='b3']", &set));
181 assert_int_equal(1, set->count);
182
183 node = set->objs[0];
184 assert_string_equal(node->schema->name, "l1");
Radek Krejcia1c1e542020-09-29 16:06:52 +0200185 node = lyd_child(node);
Michal Vasko14795a42020-05-22 16:44:44 +0200186 assert_string_equal(node->schema->name, "a");
Radek Krejci6d5ba0c2021-04-26 07:49:59 +0200187 assert_string_equal(lyd_get_value(node), "a3");
Michal Vasko14795a42020-05-22 16:44:44 +0200188
189 ly_set_free(set, NULL);
190
191 /* hashes should be used for both searches (well, there are not enough nested ll instances, so technically not true) */
192 assert_int_equal(LY_SUCCESS, lyd_find_xpath(tree, "/a:c/ll[a='val_b']/ll[a='val_b']", &set));
193 assert_int_equal(1, set->count);
194
195 node = set->objs[0];
196 assert_string_equal(node->schema->name, "ll");
Radek Krejcia1c1e542020-09-29 16:06:52 +0200197 node = lyd_child(node);
Michal Vasko14795a42020-05-22 16:44:44 +0200198 assert_string_equal(node->schema->name, "a");
Radek Krejci6d5ba0c2021-04-26 07:49:59 +0200199 assert_string_equal(lyd_get_value(node), "val_b");
Michal Vasko14795a42020-05-22 16:44:44 +0200200 node = node->next;
201 assert_string_equal(node->schema->name, "b");
202 assert_null(node->next);
203
204 ly_set_free(set, NULL);
205
206 /* hashes are not used */
207 assert_int_equal(LY_SUCCESS, lyd_find_xpath(tree, "/a:c//ll[a='val_b']", &set));
208 assert_int_equal(4, set->count);
209
210 ly_set_free(set, NULL);
211
Michal Vasko660cc8f2020-05-25 10:33:19 +0200212 /* hashes used even for leaf-lists */
213 assert_int_equal(LY_SUCCESS, lyd_find_xpath(tree, "/a:c/ll2[. = 'three']", &set));
214 assert_int_equal(1, set->count);
215
216 node = set->objs[0];
217 assert_string_equal(node->schema->name, "ll2");
Radek Krejci6d5ba0c2021-04-26 07:49:59 +0200218 assert_string_equal(lyd_get_value(node), "three");
Michal Vasko660cc8f2020-05-25 10:33:19 +0200219
220 ly_set_free(set, NULL);
221
Michal Vasko14795a42020-05-22 16:44:44 +0200222 /* not found using hashes */
223 assert_int_equal(LY_SUCCESS, lyd_find_xpath(tree, "/a:c/ll[a='val_d']", &set));
224 assert_int_equal(0, set->count);
225
226 ly_set_free(set, NULL);
227
228 /* white-spaces are also ok */
229 assert_int_equal(LY_SUCCESS, lyd_find_xpath(tree, "/a:c/ll[ \na = 'val_c' ]", &set));
230 assert_int_equal(1, set->count);
231
232 ly_set_free(set, NULL);
233
234 lyd_free_all(tree);
Michal Vasko14795a42020-05-22 16:44:44 +0200235}
236
Michal Vasko61ac2f62020-05-25 12:39:51 +0200237static void
238test_toplevel(void **state)
239{
Radek Iša56ca9e42020-09-08 18:42:00 +0200240 const char *schema_b =
241 "module b {\n"
242 " namespace urn:tests:b;\n"
243 " prefix b;\n"
244 " yang-version 1.1;\n"
245 "\n"
246 " list l2 {\n"
247 " key \"a\";\n"
248 " leaf a {\n"
249 " type uint16;\n"
250 " }\n"
251 " leaf b {\n"
252 " type uint16;\n"
253 " }\n"
254 " }\n"
255 "}";
Michal Vasko61ac2f62020-05-25 12:39:51 +0200256 const char *data =
Radek Krejcib4ac5a92020-11-23 17:54:33 +0100257 "<l1 xmlns=\"urn:tests:a\">\n"
258 " <a>a1</a>\n"
259 " <b>b1</b>\n"
260 " <c>c1</c>\n"
261 "</l1>\n"
262 "<l1 xmlns=\"urn:tests:a\">\n"
263 " <a>a2</a>\n"
264 " <b>b2</b>\n"
265 "</l1>\n"
266 "<l1 xmlns=\"urn:tests:a\">\n"
267 " <a>a3</a>\n"
268 " <b>b3</b>\n"
269 " <c>c3</c>\n"
270 "</l1>\n"
271 "<foo xmlns=\"urn:tests:a\">foo value</foo>\n"
272 "<l2 xmlns=\"urn:tests:b\">\n"
273 " <a>1</a>\n"
274 " <b>1</b>\n"
275 "</l2>\n"
276 "<l2 xmlns=\"urn:tests:b\">\n"
277 " <a>2</a>\n"
278 " <b>1</b>\n"
279 "</l2>\n"
280 "<l2 xmlns=\"urn:tests:b\">\n"
281 " <a>3</a>\n"
282 " <b>1</b>\n"
283 "</l2>";
Michal Vaskof60e7102020-05-26 10:48:59 +0200284 struct lyd_node *tree;
Michal Vasko61ac2f62020-05-25 12:39:51 +0200285 struct ly_set *set;
Michal Vasko61ac2f62020-05-25 12:39:51 +0200286
Radek Iša56ca9e42020-09-08 18:42:00 +0200287 UTEST_ADD_MODULE(schema_b, LYS_IN_YANG, NULL, NULL);
288
289 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 +0200290 assert_non_null(tree);
291
292 /* all top-level nodes from one module (default container as well) */
293 assert_int_equal(LY_SUCCESS, lyd_find_xpath(tree, "/a:*", &set));
294 assert_int_equal(5, set->count);
295
296 ly_set_free(set, NULL);
297
298 /* all top-level nodes from all modules */
299 assert_int_equal(LY_SUCCESS, lyd_find_xpath(tree, "/*", &set));
300 assert_int_equal(8, set->count);
301
302 ly_set_free(set, NULL);
303
304 /* all nodes from one module */
305 assert_int_equal(LY_SUCCESS, lyd_find_xpath(tree, "//a:*", &set));
306 assert_int_equal(13, set->count);
307
308 ly_set_free(set, NULL);
309
310 /* all nodes from all modules */
311 assert_int_equal(LY_SUCCESS, lyd_find_xpath(tree, "//*", &set));
312 assert_int_equal(22, set->count);
313
314 ly_set_free(set, NULL);
315
316 /* all nodes from all modules #2 */
317 assert_int_equal(LY_SUCCESS, lyd_find_xpath(tree, "//.", &set));
318 assert_int_equal(22, set->count);
319
320 ly_set_free(set, NULL);
321
322 lyd_free_all(tree);
Michal Vasko61ac2f62020-05-25 12:39:51 +0200323}
324
Michal Vasko519fd602020-05-26 12:17:39 +0200325static void
326test_atomize(void **state)
327{
Michal Vasko519fd602020-05-26 12:17:39 +0200328 struct ly_set *set;
329 const struct lys_module *mod;
330
Radek Iša56ca9e42020-09-08 18:42:00 +0200331 mod = ly_ctx_get_module_latest(UTEST_LYCTX, "a");
332 assert_non_null(mod);
Michal Vasko519fd602020-05-26 12:17:39 +0200333
334 /* some random paths just making sure the API function works */
Michal Vasko400e9672021-01-11 13:39:17 +0100335 assert_int_equal(LY_SUCCESS, lys_find_xpath_atoms(UTEST_LYCTX, NULL, "/a:*", 0, &set));
Michal Vasko93923692021-05-07 15:28:02 +0200336 assert_int_equal(5, set->count);
Michal Vasko519fd602020-05-26 12:17:39 +0200337
338 ly_set_free(set, NULL);
339
340 /* all nodes from all modules (including internal, which can change easily, so check just the test modules) */
Michal Vasko400e9672021-01-11 13:39:17 +0100341 assert_int_equal(LY_SUCCESS, lys_find_xpath_atoms(UTEST_LYCTX, NULL, "//.", 0, &set));
Michal Vasko93923692021-05-07 15:28:02 +0200342 assert_in_range(set->count, 17, UINT32_MAX);
Michal Vasko519fd602020-05-26 12:17:39 +0200343
344 ly_set_free(set, NULL);
345
Michal Vasko400e9672021-01-11 13:39:17 +0100346 assert_int_equal(LY_SUCCESS, lys_find_xpath_atoms(UTEST_LYCTX, NULL, "/a:c/ll[a='val1']/ll[a='val2']/b", 0, &set));
347 assert_int_equal(6, set->count);
Michal Vasko519fd602020-05-26 12:17:39 +0200348
349 ly_set_free(set, NULL);
350}
351
Michal Vasko4c7763f2020-07-27 17:40:37 +0200352static void
353test_canonize(void **state)
354{
Michal Vasko4c7763f2020-07-27 17:40:37 +0200355 const char *data =
Radek Krejcib4ac5a92020-11-23 17:54:33 +0100356 "<foo2 xmlns=\"urn:tests:a\">50</foo2>";
Michal Vasko4c7763f2020-07-27 17:40:37 +0200357 struct lyd_node *tree;
358 struct ly_set *set;
359
Radek Iša56ca9e42020-09-08 18:42:00 +0200360 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 +0200361 assert_non_null(tree);
362
363 assert_int_equal(LY_SUCCESS, lyd_find_xpath(tree, "/a:foo2[.='050']", &set));
364 assert_int_equal(1, set->count);
365 ly_set_free(set, NULL);
366
367 /* TODO more use-cases once there are some type plugins that have canonical values */
368
369 lyd_free_all(tree);
Michal Vasko4c7763f2020-07-27 17:40:37 +0200370}
371
Michal Vasko93923692021-05-07 15:28:02 +0200372static void
373test_derived_from(void **state)
374{
375 const char *data =
376 "<foo3 xmlns=\"urn:tests:a\">id_c</foo3>";
377 struct lyd_node *tree;
378 struct ly_set *set;
379
380 assert_int_equal(LY_SUCCESS, lyd_parse_data_mem(UTEST_LYCTX, data, LYD_XML, LYD_PARSE_STRICT, LYD_VALIDATE_PRESENT, &tree));
381 assert_non_null(tree);
382
383 assert_int_equal(LY_SUCCESS, lyd_find_xpath(tree, "/a:foo3[derived-from(., 'a:id_b')]", &set));
384 assert_int_equal(1, set->count);
385 ly_set_free(set, NULL);
386
387 assert_int_equal(LY_SUCCESS, lyd_find_xpath(tree, "/a:foo3[derived-from(., 'a:id_a')]", &set));
388 assert_int_equal(1, set->count);
389 ly_set_free(set, NULL);
390
391 lyd_free_all(tree);
392}
393
Radek Krejcib4ac5a92020-11-23 17:54:33 +0100394int
395main(void)
Michal Vasko14795a42020-05-22 16:44:44 +0200396{
397 const struct CMUnitTest tests[] = {
Michal Vaskoe2be5462021-08-04 10:49:42 +0200398 UTEST(test_invalid, setup),
Radek Iša56ca9e42020-09-08 18:42:00 +0200399 UTEST(test_hash, setup),
400 UTEST(test_toplevel, setup),
401 UTEST(test_atomize, setup),
402 UTEST(test_canonize, setup),
Michal Vasko93923692021-05-07 15:28:02 +0200403 UTEST(test_derived_from, setup),
Michal Vasko14795a42020-05-22 16:44:44 +0200404 };
405
406 return cmocka_run_group_tests(tests, NULL, NULL);
407}