blob: d9e6f76c3b0e1c69c6a0f06e19a68c0af8994fd4 [file] [log] [blame]
Radek Krejci509e2592019-05-15 16:30:48 +02001/*
2 * @file test_parser_xml.c
3 * @author: Radek Krejci <rkrejci@cesnet.cz>
4 * @brief unit tests for functions from parser_xml.c
5 *
6 * Copyright (c) 2019 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 Vasko52927e22020-03-16 17:26:14 +010015#include "tests/config.h"
16
Radek Krejci509e2592019-05-15 16:30:48 +020017#include <stdarg.h>
18#include <stddef.h>
19#include <setjmp.h>
20#include <cmocka.h>
21
22#include <stdio.h>
23#include <string.h>
24
Radek Krejci2d7a47b2019-05-16 13:34:10 +020025#include "../../src/context.h"
26#include "../../src/tree_data_internal.h"
Michal Vasko52927e22020-03-16 17:26:14 +010027#include "../../src/printer_data.h"
Radek Krejci509e2592019-05-15 16:30:48 +020028
29#define BUFSIZE 1024
30char logbuf[BUFSIZE] = {0};
31int store = -1; /* negative for infinite logging, positive for limited logging */
32
33struct ly_ctx *ctx; /* context for tests */
34
35/* set to 0 to printing error messages to stderr instead of checking them in code */
36#define ENABLE_LOGGER_CHECKING 1
37
38#if ENABLE_LOGGER_CHECKING
39static void
40logger(LY_LOG_LEVEL level, const char *msg, const char *path)
41{
42 (void) level; /* unused */
43 if (store) {
44 if (path && path[0]) {
45 snprintf(logbuf, BUFSIZE - 1, "%s %s", msg, path);
46 } else {
47 strncpy(logbuf, msg, BUFSIZE - 1);
48 }
49 if (store > 0) {
50 --store;
51 }
52 }
53}
54#endif
55
56static int
57setup(void **state)
58{
59 (void) state; /* unused */
60
61 const char *schema_a = "module a {namespace urn:tests:a;prefix a;yang-version 1.1;"
Michal Vasko44685da2020-03-17 15:38:06 +010062 "list l1 { key \"a b c\"; leaf a {type string;} leaf b {type string;} leaf c {type int16;} leaf d {type string;}}"
Radek Krejciee4cab22019-07-17 17:07:47 +020063 "leaf foo { type string;}"
Radek Krejcib6f7ae52019-07-19 10:31:42 +020064 "container c { leaf x {type string;}}"
Michal Vaskob36053d2020-03-26 15:49:30 +010065 "container cp {presence \"container switch\"; leaf y {type string;} leaf z {type int8;}}"
Michal Vasko8d544252020-03-02 10:19:52 +010066 "anydata any {config false;}"
Michal Vasko44685da2020-03-17 15:38:06 +010067 "leaf foo2 { type string; default \"default-val\"; }"
68 "leaf foo3 { type uint32; }}";
Michal Vaskob36053d2020-03-26 15:49:30 +010069 const struct lys_module *mod;
Radek Krejci509e2592019-05-15 16:30:48 +020070
71#if ENABLE_LOGGER_CHECKING
72 ly_set_log_clb(logger, 1);
73#endif
74
Michal Vasko8d544252020-03-02 10:19:52 +010075 assert_int_equal(LY_SUCCESS, ly_ctx_new(TESTS_DIR_MODULES_YANG, 0, &ctx));
76 assert_non_null(ly_ctx_load_module(ctx, "ietf-netconf-with-defaults", "2011-06-01"));
Michal Vaskob36053d2020-03-26 15:49:30 +010077 assert_non_null((mod = ly_ctx_load_module(ctx, "ietf-netconf", "2011-06-01")));
78 assert_int_equal(LY_SUCCESS, lys_feature_enable(mod, "writable-running"));
Radek Krejci509e2592019-05-15 16:30:48 +020079 assert_non_null(lys_parse_mem(ctx, schema_a, LYS_IN_YANG));
80
81 return 0;
82}
83
84static int
85teardown(void **state)
86{
87#if ENABLE_LOGGER_CHECKING
88 if (*state) {
89 fprintf(stderr, "%s\n", logbuf);
90 }
91#else
92 (void) state; /* unused */
93#endif
94
95 ly_ctx_destroy(ctx, NULL);
96 ctx = NULL;
97
98 return 0;
99}
100
101void
102logbuf_clean(void)
103{
104 logbuf[0] = '\0';
105}
106
107#if ENABLE_LOGGER_CHECKING
108# define logbuf_assert(str) assert_string_equal(logbuf, str)
109#else
110# define logbuf_assert(str)
111#endif
112
Radek Krejci509e2592019-05-15 16:30:48 +0200113static void
114test_leaf(void **state)
115{
116 *state = test_leaf;
117
118 const char *data = "<foo xmlns=\"urn:tests:a\">foo value</foo>";
119 struct lyd_node *tree;
120 struct lyd_node_term *leaf;
121
Michal Vasko9f96a052020-03-10 09:41:45 +0100122 assert_int_equal(LY_SUCCESS, lyd_parse_xml_data(ctx, data, LYD_VALOPT_DATA_ONLY, &tree));
Radek Krejci509e2592019-05-15 16:30:48 +0200123 assert_non_null(tree);
124 assert_int_equal(LYS_LEAF, tree->schema->nodetype);
125 assert_string_equal("foo", tree->schema->name);
126 leaf = (struct lyd_node_term*)tree;
Radek Krejci950f6a52019-09-12 17:15:32 +0200127 assert_string_equal("foo value", leaf->value.original);
Radek Krejci509e2592019-05-15 16:30:48 +0200128
Michal Vasko8d544252020-03-02 10:19:52 +0100129 assert_int_equal(LYS_LEAF, tree->next->next->schema->nodetype);
130 assert_string_equal("foo2", tree->next->next->schema->name);
131 leaf = (struct lyd_node_term*)tree->next->next;
132 assert_string_equal("default-val", leaf->value.original);
133 assert_true(leaf->flags & LYD_DEFAULT);
134
Radek Krejci509e2592019-05-15 16:30:48 +0200135 lyd_free_all(tree);
Michal Vasko8d544252020-03-02 10:19:52 +0100136
137 /* make foo2 explicit */
138 data = "<foo2 xmlns=\"urn:tests:a\">default-val</foo2>";
Michal Vasko9f96a052020-03-10 09:41:45 +0100139 assert_int_equal(LY_SUCCESS, lyd_parse_xml_data(ctx, data, LYD_VALOPT_DATA_ONLY, &tree));
Michal Vasko8d544252020-03-02 10:19:52 +0100140 assert_non_null(tree);
141 assert_int_equal(LYS_LEAF, tree->schema->nodetype);
142 assert_string_equal("foo2", tree->schema->name);
143 leaf = (struct lyd_node_term*)tree;
144 assert_string_equal("default-val", leaf->value.original);
145 assert_false(leaf->flags & LYD_DEFAULT);
146
147 lyd_free_all(tree);
148
149 /* parse foo2 but make it implicit */
150 data = "<foo2 xmlns=\"urn:tests:a\" xmlns:wd=\"urn:ietf:params:xml:ns:yang:ietf-netconf-with-defaults\" wd:default=\"true\">default-val</foo2>";
Michal Vasko9f96a052020-03-10 09:41:45 +0100151 assert_int_equal(LY_SUCCESS, lyd_parse_xml_data(ctx, data, LYD_VALOPT_DATA_ONLY, &tree));
Michal Vasko8d544252020-03-02 10:19:52 +0100152 assert_non_null(tree);
153 assert_int_equal(LYS_LEAF, tree->schema->nodetype);
154 assert_string_equal("foo2", tree->schema->name);
155 leaf = (struct lyd_node_term*)tree;
156 assert_string_equal("default-val", leaf->value.original);
157 assert_true(leaf->flags & LYD_DEFAULT);
158
159 lyd_free_all(tree);
160
Radek Krejci509e2592019-05-15 16:30:48 +0200161 *state = NULL;
162}
163
Radek Krejciee4cab22019-07-17 17:07:47 +0200164static void
165test_anydata(void **state)
166{
167 *state = test_anydata;
168
Michal Vasko52927e22020-03-16 17:26:14 +0100169 const char *data;
170 char *str;
Radek Krejciee4cab22019-07-17 17:07:47 +0200171 struct lyd_node *tree;
Radek Krejciee4cab22019-07-17 17:07:47 +0200172
Michal Vasko52927e22020-03-16 17:26:14 +0100173 data =
174 "<any xmlns=\"urn:tests:a\">"
175 "<element1>"
176 "<x:element2 x:attr2=\"test\" xmlns:a=\"urn:tests:a\" xmlns:x=\"urn:x\">a:data</x:element2>"
177 "</element1>"
178 "<element1a/>"
179 "</any>";
Michal Vasko9f96a052020-03-10 09:41:45 +0100180 assert_int_equal(LY_SUCCESS, lyd_parse_xml_data(ctx, data, LYD_VALOPT_DATA_ONLY, &tree));
Radek Krejciee4cab22019-07-17 17:07:47 +0200181 assert_non_null(tree);
182 assert_int_equal(LYS_ANYDATA, tree->schema->nodetype);
183 assert_string_equal("any", tree->schema->name);
Michal Vasko52927e22020-03-16 17:26:14 +0100184
185 lyd_print_mem(&str, tree, LYD_XML, 0);
186 assert_string_equal(str,
187 "<any xmlns=\"urn:tests:a\">"
188 "<element1>"
189 "<element2 xmlns=\"urn:x\" xmlns:x=\"urn:x\" x:attr2=\"test\" xmlns:a=\"urn:tests:a\">a:data</element2>"
190 "</element1>"
191 "<element1a/>"
192 "</any>"
193 );
194 free(str);
Radek Krejciee4cab22019-07-17 17:07:47 +0200195
196 lyd_free_all(tree);
197 *state = NULL;
198}
199
Radek Krejci1f05b6a2019-07-18 16:15:06 +0200200static void
201test_list(void **state)
202{
203 *state = test_list;
204
Michal Vasko44685da2020-03-17 15:38:06 +0100205 const char *data = "<l1 xmlns=\"urn:tests:a\"><a>one</a><b>one</b><c>1</c></l1>";
Radek Krejci1f05b6a2019-07-18 16:15:06 +0200206 struct lyd_node *tree, *iter;
207 struct lyd_node_inner *list;
Radek Krejci710226d2019-07-24 17:24:59 +0200208 struct lyd_node_term *leaf;
Radek Krejci1f05b6a2019-07-18 16:15:06 +0200209
Radek Krejci710226d2019-07-24 17:24:59 +0200210 /* check hashes */
Michal Vasko9f96a052020-03-10 09:41:45 +0100211 assert_int_equal(LY_SUCCESS, lyd_parse_xml_data(ctx, data, LYD_VALOPT_DATA_ONLY, &tree));
Radek Krejci1f05b6a2019-07-18 16:15:06 +0200212 assert_non_null(tree);
213 assert_int_equal(LYS_LIST, tree->schema->nodetype);
214 assert_string_equal("l1", tree->schema->name);
215 list = (struct lyd_node_inner*)tree;
216 LY_LIST_FOR(list->child, iter) {
217 assert_int_not_equal(0, iter->hash);
218 }
Radek Krejci1f05b6a2019-07-18 16:15:06 +0200219 lyd_free_all(tree);
Radek Krejci710226d2019-07-24 17:24:59 +0200220
Michal Vasko9f96a052020-03-10 09:41:45 +0100221 /* missing keys */
Michal Vasko44685da2020-03-17 15:38:06 +0100222 data = "<l1 xmlns=\"urn:tests:a\"><c>1</c><b>b</b></l1>";
Michal Vasko9f96a052020-03-10 09:41:45 +0100223 assert_int_equal(LY_EVALID, lyd_parse_xml_data(ctx, data, LYD_VALOPT_DATA_ONLY, &tree));
Michal Vasko44685da2020-03-17 15:38:06 +0100224 logbuf_assert("List instance is missing its key \"a\". /a:l1[b='b'][c='1']");
Michal Vasko9f96a052020-03-10 09:41:45 +0100225
226 data = "<l1 xmlns=\"urn:tests:a\"><a>a</a></l1>";
227 assert_int_equal(LY_EVALID, lyd_parse_xml_data(ctx, data, LYD_VALOPT_DATA_ONLY, &tree));
228 logbuf_assert("List instance is missing its key \"b\". /a:l1[a='a']");
229
230 data = "<l1 xmlns=\"urn:tests:a\"><b>b</b><a>a</a></l1>";
231 assert_int_equal(LY_EVALID, lyd_parse_xml_data(ctx, data, LYD_VALOPT_DATA_ONLY, &tree));
232 logbuf_assert("List instance is missing its key \"c\". /a:l1[a='a'][b='b']");
233
234 /* key duplicate */
Michal Vasko44685da2020-03-17 15:38:06 +0100235 data = "<l1 xmlns=\"urn:tests:a\"><c>1</c><b>b</b><a>a</a><c>1</c></l1>";
Michal Vasko9f96a052020-03-10 09:41:45 +0100236 assert_int_equal(LY_EVALID, lyd_parse_xml_data(ctx, data, LYD_VALOPT_DATA_ONLY, &tree));
Michal Vasko44685da2020-03-17 15:38:06 +0100237 logbuf_assert("Duplicate instance of \"c\". /a:l1[a='a'][b='b'][c='1'][c='1']/c");
Michal Vasko9f96a052020-03-10 09:41:45 +0100238
Radek Krejci710226d2019-07-24 17:24:59 +0200239 /* keys order */
Michal Vasko44685da2020-03-17 15:38:06 +0100240 data = "<l1 xmlns=\"urn:tests:a\"><d>d</d><a>a</a><c>1</c><b>b</b></l1>";
Michal Vasko9f96a052020-03-10 09:41:45 +0100241 assert_int_equal(LY_SUCCESS, lyd_parse_xml_data(ctx, data, LYD_VALOPT_DATA_ONLY, &tree));
Radek Krejci710226d2019-07-24 17:24:59 +0200242 assert_non_null(tree);
243 assert_int_equal(LYS_LIST, tree->schema->nodetype);
244 assert_string_equal("l1", tree->schema->name);
245 list = (struct lyd_node_inner*)tree;
246 assert_non_null(leaf = (struct lyd_node_term*)list->child);
247 assert_string_equal("a", leaf->schema->name);
248 assert_non_null(leaf = (struct lyd_node_term*)leaf->next);
249 assert_string_equal("b", leaf->schema->name);
250 assert_non_null(leaf = (struct lyd_node_term*)leaf->next);
251 assert_string_equal("c", leaf->schema->name);
252 assert_non_null(leaf = (struct lyd_node_term*)leaf->next);
253 assert_string_equal("d", leaf->schema->name);
254 logbuf_assert("Invalid position of the key \"b\" in a list.");
255 lyd_free_all(tree);
256
Michal Vasko44685da2020-03-17 15:38:06 +0100257 data = "<l1 xmlns=\"urn:tests:a\"><c>1</c><b>b</b><a>a</a></l1>";
Michal Vasko9f96a052020-03-10 09:41:45 +0100258 assert_int_equal(LY_SUCCESS, lyd_parse_xml_data(ctx, data, LYD_VALOPT_DATA_ONLY, &tree));
Radek Krejci710226d2019-07-24 17:24:59 +0200259 assert_non_null(tree);
260 assert_int_equal(LYS_LIST, tree->schema->nodetype);
261 assert_string_equal("l1", tree->schema->name);
262 list = (struct lyd_node_inner*)tree;
263 assert_non_null(leaf = (struct lyd_node_term*)list->child);
264 assert_string_equal("a", leaf->schema->name);
265 assert_non_null(leaf = (struct lyd_node_term*)leaf->next);
266 assert_string_equal("b", leaf->schema->name);
267 assert_non_null(leaf = (struct lyd_node_term*)leaf->next);
268 assert_string_equal("c", leaf->schema->name);
269 logbuf_assert("Invalid position of the key \"a\" in a list.");
270 logbuf_clean();
271 lyd_free_all(tree);
272
Michal Vasko9f96a052020-03-10 09:41:45 +0100273 assert_int_equal(LY_EVALID, lyd_parse_xml_data(ctx, data, LYD_OPT_STRICT, &tree));
Radek Krejci710226d2019-07-24 17:24:59 +0200274 logbuf_assert("Invalid position of the key \"b\" in a list. Line number 1.");
275
Radek Krejci1f05b6a2019-07-18 16:15:06 +0200276 *state = NULL;
277}
278
Radek Krejcib6f7ae52019-07-19 10:31:42 +0200279static void
280test_container(void **state)
281{
282 *state = test_container;
283
284 const char *data = "<c xmlns=\"urn:tests:a\"/>";
285 struct lyd_node *tree;
286 struct lyd_node_inner *cont;
287
Michal Vasko9f96a052020-03-10 09:41:45 +0100288 assert_int_equal(LY_SUCCESS, lyd_parse_xml_data(ctx, data, LYD_VALOPT_DATA_ONLY, &tree));
Radek Krejcib6f7ae52019-07-19 10:31:42 +0200289 assert_non_null(tree);
290 assert_int_equal(LYS_CONTAINER, tree->schema->nodetype);
291 assert_string_equal("c", tree->schema->name);
292 cont = (struct lyd_node_inner*)tree;
293 assert_true(cont->flags & LYD_DEFAULT);
294 lyd_free_all(tree);
295
296 data = "<cp xmlns=\"urn:tests:a\"/>";
Michal Vasko9f96a052020-03-10 09:41:45 +0100297 assert_int_equal(LY_SUCCESS, lyd_parse_xml_data(ctx, data, LYD_VALOPT_DATA_ONLY, &tree));
Radek Krejcib6f7ae52019-07-19 10:31:42 +0200298 assert_non_null(tree);
299 assert_int_equal(LYS_CONTAINER, tree->schema->nodetype);
300 assert_string_equal("cp", tree->schema->name);
301 cont = (struct lyd_node_inner*)tree;
302 assert_false(cont->flags & LYD_DEFAULT);
303 lyd_free_all(tree);
304
305 *state = NULL;
306}
307
Michal Vasko44685da2020-03-17 15:38:06 +0100308static void
309test_opaq(void **state)
310{
311 *state = test_opaq;
312
313 const char *data;
314 char *str;
315 struct lyd_node *tree;
316
317 /* invalid value, no flags */
318 data = "<foo3 xmlns=\"urn:tests:a\"/>";
319 assert_int_equal(LY_EVALID, lyd_parse_xml_data(ctx, data, LYD_VALOPT_DATA_ONLY, &tree));
320 logbuf_assert("Invalid empty uint32 value. /");
321 assert_null(tree);
322
323 /* opaq flag */
324 assert_int_equal(LY_SUCCESS, lyd_parse_xml_data(ctx, data, LYD_OPT_OPAQ | LYD_VALOPT_DATA_ONLY, &tree));
325 assert_non_null(tree);
326 assert_null(tree->schema);
327 assert_string_equal(((struct lyd_node_opaq *)tree)->name, "foo3");
328 assert_string_equal(((struct lyd_node_opaq *)tree)->value, "");
329
330 lyd_print_mem(&str, tree, LYD_XML, 0);
331 assert_string_equal(str, "<foo3 xmlns=\"urn:tests:a\"/>");
332 free(str);
333 lyd_free_all(tree);
334
335 /* missing key, no flags */
336 data = "<l1 xmlns=\"urn:tests:a\"><a>val_a</a><b>val_b</b><d>val_d</d></l1>";
337 assert_int_equal(LY_EVALID, lyd_parse_xml_data(ctx, data, LYD_VALOPT_DATA_ONLY, &tree));
338 logbuf_assert("List instance is missing its key \"c\". /a:l1[a='val_a'][b='val_b']");
339 assert_null(tree);
340
341 /* opaq flag */
342 assert_int_equal(LY_SUCCESS, lyd_parse_xml_data(ctx, data, LYD_OPT_OPAQ | LYD_VALOPT_DATA_ONLY, &tree));
343 assert_non_null(tree);
344 assert_null(tree->schema);
345 assert_string_equal(((struct lyd_node_opaq *)tree)->name, "l1");
346 assert_string_equal(((struct lyd_node_opaq *)tree)->value, "");
347
348 lyd_print_mem(&str, tree, LYD_XML, 0);
349 assert_string_equal(str, data);
350 free(str);
351 lyd_free_all(tree);
352
353 /* invalid key, no flags */
354 data = "<l1 xmlns=\"urn:tests:a\"><a>val_a</a><b>val_b</b><c>val_c</c></l1>";
355 assert_int_equal(LY_EVALID, lyd_parse_xml_data(ctx, data, LYD_VALOPT_DATA_ONLY, &tree));
356 logbuf_assert("Invalid int16 value \"val_c\". /");
357 assert_null(tree);
358
359 /* opaq flag */
360 assert_int_equal(LY_SUCCESS, lyd_parse_xml_data(ctx, data, LYD_OPT_OPAQ | LYD_VALOPT_DATA_ONLY, &tree));
361 assert_non_null(tree);
362 assert_null(tree->schema);
363 assert_string_equal(((struct lyd_node_opaq *)tree)->name, "l1");
364 assert_string_equal(((struct lyd_node_opaq *)tree)->value, "");
365
366 lyd_print_mem(&str, tree, LYD_XML, 0);
367 assert_string_equal(str, data);
368 free(str);
369 lyd_free_all(tree);
370
371 *state = NULL;
372}
373
Michal Vaskob36053d2020-03-26 15:49:30 +0100374static void
375test_rpc(void **state)
376{
377 *state = test_rpc;
378
379 const char *data;
380 char *str;
381 struct lyd_node *tree, *op;
382
383 data =
384 "<rpc xmlns=\"urn:ietf:params:xml:ns:netconf:base:1.0\" msgid=\"25\" custom-attr=\"val\">"
385 "<edit-config>"
386 "<target>"
387 "<running/>"
388 "<config xmlns:nc=\"urn:ietf:params:xml:ns:netconf:base:1.0\">"
389 "<l1 xmlns=\"urn:tests:a\" nc:operation=\"replace\">"
390 "<a>val_a</a>"
391 "<b>val_b</b>"
392 "<c>val_c</c>"
393 "</l1>"
394 "<cp xmlns=\"urn:tests:a\">"
395 "<z nc:operation=\"delete\"/>"
396 "</cp>"
397 "</config>"
398 "</target>"
399 "</edit-config>"
400 "</rpc>";
401 //assert_int_equal(LY_SUCCESS, lyd_parse_xml_rpc(ctx, data, &tree, &op));
402 assert_non_null(tree);
403 assert_null(tree->schema);
404 assert_string_equal(((struct lyd_node_opaq *)tree)->name, "foo3");
405 assert_string_equal(((struct lyd_node_opaq *)tree)->value, "");
406
407 lyd_print_mem(&str, tree, LYD_XML, 0);
408 assert_string_equal(str, "<foo3 xmlns=\"urn:tests:a\"/>");
409 free(str);
410 lyd_free_all(tree);
411
412 /* wrong namespace, element name, whatever... */
413
414 *state = NULL;
415}
416
Radek Krejci509e2592019-05-15 16:30:48 +0200417int main(void)
418{
419 const struct CMUnitTest tests[] = {
420 cmocka_unit_test_setup_teardown(test_leaf, setup, teardown),
Radek Krejciee4cab22019-07-17 17:07:47 +0200421 cmocka_unit_test_setup_teardown(test_anydata, setup, teardown),
Radek Krejci1f05b6a2019-07-18 16:15:06 +0200422 cmocka_unit_test_setup_teardown(test_list, setup, teardown),
Radek Krejcib6f7ae52019-07-19 10:31:42 +0200423 cmocka_unit_test_setup_teardown(test_container, setup, teardown),
Michal Vasko44685da2020-03-17 15:38:06 +0100424 cmocka_unit_test_setup_teardown(test_opaq, setup, teardown),
Michal Vaskob36053d2020-03-26 15:49:30 +0100425 //cmocka_unit_test_setup_teardown(test_rpc, setup, teardown),
Radek Krejci509e2592019-05-15 16:30:48 +0200426 };
427
428 return cmocka_run_group_tests(tests, NULL, NULL);
429}