blob: 8be1fbf80e0f04467d4f40b0a6da88bf2a3e8526 [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 */
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"
22#include "tests/config.h"
23#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"
32 " list l1 {\n"
33 " key \"a b\";\n"
34 " leaf a {\n"
35 " type string;\n"
36 " }\n"
37 " leaf b {\n"
38 " type string;\n"
39 " }\n"
40 " leaf c {\n"
41 " type string;\n"
42 " }\n"
43 " }\n"
44 " leaf foo {\n"
45 " type string;\n"
46 " }\n"
47 " leaf foo2 {\n"
48 " type uint8;\n"
49 " }\n"
50 " container c {\n"
51 " leaf x {\n"
52 " type string;\n"
53 " }\n"
54 " list ll {\n"
55 " key \"a\";\n"
56 " leaf a {\n"
57 " type string;\n"
58 " }\n"
59 " list ll {\n"
60 " key \"a\";\n"
61 " leaf a {\n"
62 " type string;\n"
63 " }\n"
64 " leaf b {\n"
65 " type string;\n"
66 " }\n"
67 " }\n"
68 " }\n"
69 " leaf-list ll2 {\n"
70 " type string;\n"
71 " }\n"
72 " }\n"
73 "}";
Michal Vasko14795a42020-05-22 16:44:44 +020074
75static int
76setup(void **state)
77{
Radek Iša56ca9e42020-09-08 18:42:00 +020078 UTEST_SETUP;
Michal Vasko14795a42020-05-22 16:44:44 +020079
Radek Iša56ca9e42020-09-08 18:42:00 +020080 UTEST_ADD_MODULE(schema_a, LYS_IN_YANG, NULL, NULL);
Michal Vasko14795a42020-05-22 16:44:44 +020081
82 return 0;
83}
84
Michal Vasko14795a42020-05-22 16:44:44 +020085static void
86test_hash(void **state)
87{
Michal Vasko14795a42020-05-22 16:44:44 +020088 const char *data =
Radek Krejcib4ac5a92020-11-23 17:54:33 +010089 "<l1 xmlns=\"urn:tests:a\">\n"
90 " <a>a1</a>\n"
91 " <b>b1</b>\n"
92 " <c>c1</c>\n"
93 "</l1>\n"
94 "<l1 xmlns=\"urn:tests:a\">\n"
95 " <a>a2</a>\n"
96 " <b>b2</b>\n"
97 "</l1>\n"
98 "<l1 xmlns=\"urn:tests:a\">\n"
99 " <a>a3</a>\n"
100 " <b>b3</b>\n"
101 " <c>c3</c>\n"
102 "</l1>\n"
103 "<foo xmlns=\"urn:tests:a\">foo value</foo>\n"
104 "<c xmlns=\"urn:tests:a\">\n"
105 " <x>val</x>\n"
106 " <ll>\n"
107 " <a>val_a</a>\n"
108 " <ll>\n"
109 " <a>val_a</a>\n"
110 " <b>val</b>\n"
111 " </ll>\n"
112 " <ll>\n"
113 " <a>val_b</a>\n"
114 " </ll>\n"
115 " </ll>\n"
116 " <ll>\n"
117 " <a>val_b</a>\n"
118 " <ll>\n"
119 " <a>val_a</a>\n"
120 " </ll>\n"
121 " <ll>\n"
122 " <a>val_b</a>\n"
123 " <b>val</b>\n"
124 " </ll>\n"
125 " </ll>\n"
126 " <ll>\n"
127 " <a>val_c</a>\n"
128 " <ll>\n"
129 " <a>val_a</a>\n"
130 " </ll>\n"
131 " <ll>\n"
132 " <a>val_b</a>\n"
133 " </ll>\n"
134 " </ll>\n"
135 " <ll2>one</ll2>\n"
136 " <ll2>two</ll2>\n"
137 " <ll2>three</ll2>\n"
138 " <ll2>four</ll2>\n"
139 "</c>";
Michal Vasko14795a42020-05-22 16:44:44 +0200140 struct lyd_node *tree, *node;
141 struct ly_set *set;
Michal Vasko14795a42020-05-22 16:44:44 +0200142
Radek Iša56ca9e42020-09-08 18:42:00 +0200143 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 +0200144 assert_non_null(tree);
145
146 /* top-level, so hash table is not ultimately used but instances can be compared based on hashes */
147 assert_int_equal(LY_SUCCESS, lyd_find_xpath(tree, "/a:l1[a='a3'][b='b3']", &set));
148 assert_int_equal(1, set->count);
149
150 node = set->objs[0];
151 assert_string_equal(node->schema->name, "l1");
Radek Krejcia1c1e542020-09-29 16:06:52 +0200152 node = lyd_child(node);
Michal Vasko14795a42020-05-22 16:44:44 +0200153 assert_string_equal(node->schema->name, "a");
Michal Vaskob7be7a82020-08-20 09:09:04 +0200154 assert_string_equal(LYD_CANON_VALUE(node), "a3");
Michal Vasko14795a42020-05-22 16:44:44 +0200155
156 ly_set_free(set, NULL);
157
158 /* hashes should be used for both searches (well, there are not enough nested ll instances, so technically not true) */
159 assert_int_equal(LY_SUCCESS, lyd_find_xpath(tree, "/a:c/ll[a='val_b']/ll[a='val_b']", &set));
160 assert_int_equal(1, set->count);
161
162 node = set->objs[0];
163 assert_string_equal(node->schema->name, "ll");
Radek Krejcia1c1e542020-09-29 16:06:52 +0200164 node = lyd_child(node);
Michal Vasko14795a42020-05-22 16:44:44 +0200165 assert_string_equal(node->schema->name, "a");
Michal Vaskob7be7a82020-08-20 09:09:04 +0200166 assert_string_equal(LYD_CANON_VALUE(node), "val_b");
Michal Vasko14795a42020-05-22 16:44:44 +0200167 node = node->next;
168 assert_string_equal(node->schema->name, "b");
169 assert_null(node->next);
170
171 ly_set_free(set, NULL);
172
173 /* hashes are not used */
174 assert_int_equal(LY_SUCCESS, lyd_find_xpath(tree, "/a:c//ll[a='val_b']", &set));
175 assert_int_equal(4, set->count);
176
177 ly_set_free(set, NULL);
178
Michal Vasko660cc8f2020-05-25 10:33:19 +0200179 /* hashes used even for leaf-lists */
180 assert_int_equal(LY_SUCCESS, lyd_find_xpath(tree, "/a:c/ll2[. = 'three']", &set));
181 assert_int_equal(1, set->count);
182
183 node = set->objs[0];
184 assert_string_equal(node->schema->name, "ll2");
Michal Vaskob7be7a82020-08-20 09:09:04 +0200185 assert_string_equal(LYD_CANON_VALUE(node), "three");
Michal Vasko660cc8f2020-05-25 10:33:19 +0200186
187 ly_set_free(set, NULL);
188
Michal Vasko14795a42020-05-22 16:44:44 +0200189 /* not found using hashes */
190 assert_int_equal(LY_SUCCESS, lyd_find_xpath(tree, "/a:c/ll[a='val_d']", &set));
191 assert_int_equal(0, set->count);
192
193 ly_set_free(set, NULL);
194
195 /* white-spaces are also ok */
196 assert_int_equal(LY_SUCCESS, lyd_find_xpath(tree, "/a:c/ll[ \na = 'val_c' ]", &set));
197 assert_int_equal(1, set->count);
198
199 ly_set_free(set, NULL);
200
201 lyd_free_all(tree);
Michal Vasko14795a42020-05-22 16:44:44 +0200202}
203
Michal Vasko61ac2f62020-05-25 12:39:51 +0200204static void
205test_toplevel(void **state)
206{
Radek Iša56ca9e42020-09-08 18:42:00 +0200207 const char *schema_b =
208 "module b {\n"
209 " namespace urn:tests:b;\n"
210 " prefix b;\n"
211 " yang-version 1.1;\n"
212 "\n"
213 " list l2 {\n"
214 " key \"a\";\n"
215 " leaf a {\n"
216 " type uint16;\n"
217 " }\n"
218 " leaf b {\n"
219 " type uint16;\n"
220 " }\n"
221 " }\n"
222 "}";
Michal Vasko61ac2f62020-05-25 12:39:51 +0200223 const char *data =
Radek Krejcib4ac5a92020-11-23 17:54:33 +0100224 "<l1 xmlns=\"urn:tests:a\">\n"
225 " <a>a1</a>\n"
226 " <b>b1</b>\n"
227 " <c>c1</c>\n"
228 "</l1>\n"
229 "<l1 xmlns=\"urn:tests:a\">\n"
230 " <a>a2</a>\n"
231 " <b>b2</b>\n"
232 "</l1>\n"
233 "<l1 xmlns=\"urn:tests:a\">\n"
234 " <a>a3</a>\n"
235 " <b>b3</b>\n"
236 " <c>c3</c>\n"
237 "</l1>\n"
238 "<foo xmlns=\"urn:tests:a\">foo value</foo>\n"
239 "<l2 xmlns=\"urn:tests:b\">\n"
240 " <a>1</a>\n"
241 " <b>1</b>\n"
242 "</l2>\n"
243 "<l2 xmlns=\"urn:tests:b\">\n"
244 " <a>2</a>\n"
245 " <b>1</b>\n"
246 "</l2>\n"
247 "<l2 xmlns=\"urn:tests:b\">\n"
248 " <a>3</a>\n"
249 " <b>1</b>\n"
250 "</l2>";
Michal Vaskof60e7102020-05-26 10:48:59 +0200251 struct lyd_node *tree;
Michal Vasko61ac2f62020-05-25 12:39:51 +0200252 struct ly_set *set;
Michal Vasko61ac2f62020-05-25 12:39:51 +0200253
Radek Iša56ca9e42020-09-08 18:42:00 +0200254 UTEST_ADD_MODULE(schema_b, LYS_IN_YANG, NULL, NULL);
255
256 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 +0200257 assert_non_null(tree);
258
259 /* all top-level nodes from one module (default container as well) */
260 assert_int_equal(LY_SUCCESS, lyd_find_xpath(tree, "/a:*", &set));
261 assert_int_equal(5, set->count);
262
263 ly_set_free(set, NULL);
264
265 /* all top-level nodes from all modules */
266 assert_int_equal(LY_SUCCESS, lyd_find_xpath(tree, "/*", &set));
267 assert_int_equal(8, set->count);
268
269 ly_set_free(set, NULL);
270
271 /* all nodes from one module */
272 assert_int_equal(LY_SUCCESS, lyd_find_xpath(tree, "//a:*", &set));
273 assert_int_equal(13, set->count);
274
275 ly_set_free(set, NULL);
276
277 /* all nodes from all modules */
278 assert_int_equal(LY_SUCCESS, lyd_find_xpath(tree, "//*", &set));
279 assert_int_equal(22, set->count);
280
281 ly_set_free(set, NULL);
282
283 /* all nodes from all modules #2 */
284 assert_int_equal(LY_SUCCESS, lyd_find_xpath(tree, "//.", &set));
285 assert_int_equal(22, set->count);
286
287 ly_set_free(set, NULL);
288
289 lyd_free_all(tree);
Michal Vasko61ac2f62020-05-25 12:39:51 +0200290}
291
Michal Vasko519fd602020-05-26 12:17:39 +0200292static void
293test_atomize(void **state)
294{
Michal Vasko519fd602020-05-26 12:17:39 +0200295 struct ly_set *set;
296 const struct lys_module *mod;
297
Radek Iša56ca9e42020-09-08 18:42:00 +0200298 mod = ly_ctx_get_module_latest(UTEST_LYCTX, "a");
299 assert_non_null(mod);
Michal Vasko519fd602020-05-26 12:17:39 +0200300
301 /* some random paths just making sure the API function works */
Michal Vasko400e9672021-01-11 13:39:17 +0100302 assert_int_equal(LY_SUCCESS, lys_find_xpath_atoms(UTEST_LYCTX, NULL, "/a:*", 0, &set));
Michal Vasko4c7763f2020-07-27 17:40:37 +0200303 assert_int_equal(4, set->count);
Michal Vasko519fd602020-05-26 12:17:39 +0200304
305 ly_set_free(set, NULL);
306
307 /* all nodes from all modules (including internal, which can change easily, so check just the test modules) */
Michal Vasko400e9672021-01-11 13:39:17 +0100308 assert_int_equal(LY_SUCCESS, lys_find_xpath_atoms(UTEST_LYCTX, NULL, "//.", 0, &set));
Michal Vasko519fd602020-05-26 12:17:39 +0200309 assert_in_range(set->count, 16, UINT32_MAX);
310
311 ly_set_free(set, NULL);
312
Michal Vasko400e9672021-01-11 13:39:17 +0100313 assert_int_equal(LY_SUCCESS, lys_find_xpath_atoms(UTEST_LYCTX, NULL, "/a:c/ll[a='val1']/ll[a='val2']/b", 0, &set));
314 assert_int_equal(6, set->count);
Michal Vasko519fd602020-05-26 12:17:39 +0200315
316 ly_set_free(set, NULL);
317}
318
Michal Vasko4c7763f2020-07-27 17:40:37 +0200319static void
320test_canonize(void **state)
321{
Michal Vasko4c7763f2020-07-27 17:40:37 +0200322 const char *data =
Radek Krejcib4ac5a92020-11-23 17:54:33 +0100323 "<foo2 xmlns=\"urn:tests:a\">50</foo2>";
Michal Vasko4c7763f2020-07-27 17:40:37 +0200324 struct lyd_node *tree;
325 struct ly_set *set;
326
Radek Iša56ca9e42020-09-08 18:42:00 +0200327 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 +0200328 assert_non_null(tree);
329
330 assert_int_equal(LY_SUCCESS, lyd_find_xpath(tree, "/a:foo2[.='050']", &set));
331 assert_int_equal(1, set->count);
332 ly_set_free(set, NULL);
333
334 /* TODO more use-cases once there are some type plugins that have canonical values */
335
336 lyd_free_all(tree);
Michal Vasko4c7763f2020-07-27 17:40:37 +0200337}
338
Radek Krejcib4ac5a92020-11-23 17:54:33 +0100339int
340main(void)
Michal Vasko14795a42020-05-22 16:44:44 +0200341{
342 const struct CMUnitTest tests[] = {
Radek Iša56ca9e42020-09-08 18:42:00 +0200343 UTEST(test_hash, setup),
344 UTEST(test_toplevel, setup),
345 UTEST(test_atomize, setup),
346 UTEST(test_canonize, setup),
Michal Vasko14795a42020-05-22 16:44:44 +0200347 };
348
349 return cmocka_run_group_tests(tests, NULL, NULL);
350}