blob: cc8ed71849bf546f4d65a555c0ebaa76704ab0d6 [file] [log] [blame]
Michal Vaskoedb0fa52022-10-04 10:36:00 +02001/**
2 * @file test_structure.c
3 * @author Michal Vasko <mvasko@cesnet.cz>
4 * @brief unit tests for structure extensions support
5 *
6 * Copyright (c) 2022 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#define _UTEST_MAIN_
15#include "utests.h"
16
17#include "libyang.h"
18
19static void
20test_schema(void **state)
21{
22 struct lys_module *mod;
23 struct lysc_ext_instance *e;
24 char *printed = NULL;
Michal Vasko0b50f6b2022-10-05 15:07:55 +020025 const char *data, *info;
26
27 /* valid data */
28 data = "module a {yang-version 1.1; namespace urn:tests:extensions:structure:a; prefix a;"
Michal Vaskoedb0fa52022-10-04 10:36:00 +020029 "import ietf-yang-structure-ext {prefix sx;}"
30 "sx:structure struct {"
31 " must \"/n2/l\";"
32 " status deprecated;"
33 " description desc;"
34 " reference no-ref;"
35 " typedef my-type {type string;}"
36 " grouping my-grp {leaf gl {type my-type;}}"
Michal Vaskoedb0fa52022-10-04 10:36:00 +020037 " container n1 {leaf l {config false; type uint32;}}"
38 " list n2 {leaf l {type leafref {path /n1/l;}}}"
39 " uses my-grp;"
Michal Vaskoedb0fa52022-10-04 10:36:00 +020040 "}}";
Michal Vasko0b50f6b2022-10-05 15:07:55 +020041
Michal Vasko193dacd2022-10-13 08:43:05 +020042 UTEST_ADD_MODULE(data, LYS_IN_YANG, NULL, &mod);
Michal Vasko0b50f6b2022-10-05 15:07:55 +020043 assert_non_null(e = mod->compiled->exts);
44 assert_int_equal(LY_ARRAY_COUNT(mod->compiled->exts), 1);
45
46 /* valid augment data */
47 data = "module b {yang-version 1.1; namespace urn:tests:extensions:structure:b; prefix b;"
48 "import ietf-yang-structure-ext {prefix sx;}"
49 "import a {prefix a;}"
50 "sx:augment-structure \"/a:struct/a:n1\" {"
51 " status obsolete;"
52 " reference none;"
53 " leaf aug-leaf {type string;}"
54 "}}";
55
Michal Vasko193dacd2022-10-13 08:43:05 +020056 UTEST_ADD_MODULE(data, LYS_IN_YANG, NULL, &mod);
Michal Vasko0b50f6b2022-10-05 15:07:55 +020057 assert_non_null(e = mod->compiled->exts);
58 assert_int_equal(LY_ARRAY_COUNT(mod->compiled->exts), 1);
59
60 /* yang compiled print */
61 info = "module a {\n"
Michal Vaskoedb0fa52022-10-04 10:36:00 +020062 " namespace \"urn:tests:extensions:structure:a\";\n"
Michal Vasko0b50f6b2022-10-05 15:07:55 +020063 " prefix a;\n"
Michal Vaskoedb0fa52022-10-04 10:36:00 +020064 "\n"
65 " ietf-yang-structure-ext:structure \"struct\" {\n"
66 " must \"/n2/l\";\n"
67 " status deprecated;\n"
68 " description\n"
69 " \"desc\";\n"
70 " reference\n"
71 " \"no-ref\";\n"
72 " container n1 {\n"
73 " status deprecated;\n"
74 " leaf l {\n"
75 " type uint32;\n"
76 " status deprecated;\n"
77 " }\n"
Michal Vaskoa0ba01e2022-10-19 13:26:57 +020078 " leaf aug-leaf {\n"
79 " type string;\n"
80 " status obsolete;\n"
81 " }\n"
Michal Vaskoedb0fa52022-10-04 10:36:00 +020082 " }\n"
83 " list n2 {\n"
84 " min-elements 0;\n"
85 " max-elements 4294967295;\n"
86 " ordered-by user;\n"
87 " status deprecated;\n"
88 " leaf l {\n"
89 " type leafref {\n"
90 " path \"/n1/l\";\n"
91 " require-instance true;\n"
92 " type uint32;\n"
93 " }\n"
94 " status deprecated;\n"
95 " }\n"
96 " }\n"
97 " leaf gl {\n"
98 " type string;\n"
99 " status deprecated;\n"
100 " }\n"
Michal Vaskoedb0fa52022-10-04 10:36:00 +0200101 " }\n"
102 "}\n";
103
Michal Vasko0b50f6b2022-10-05 15:07:55 +0200104 assert_non_null(mod = ly_ctx_get_module_implemented(UTEST_LYCTX, "a"));
105 assert_int_equal(LY_SUCCESS, lys_print_mem(&printed, mod, LYS_OUT_YANG_COMPILED, 0));
106 assert_string_equal(printed, info);
107 free(printed);
108
109 info = "module b {\n"
110 " namespace \"urn:tests:extensions:structure:b\";\n"
111 " prefix b;\n"
112 "\n"
Michal Vaskoa0ba01e2022-10-19 13:26:57 +0200113 " ietf-yang-structure-ext:augment-structure \"/a:struct/a:n1\";\n"
Michal Vasko0b50f6b2022-10-05 15:07:55 +0200114 "}\n";
115
116 assert_non_null(mod = ly_ctx_get_module_implemented(UTEST_LYCTX, "b"));
Michal Vaskoedb0fa52022-10-04 10:36:00 +0200117 assert_int_equal(LY_SUCCESS, lys_print_mem(&printed, mod, LYS_OUT_YANG_COMPILED, 0));
118 assert_string_equal(printed, info);
119 free(printed);
120
121 /* no substatements */
Michal Vasko0b50f6b2022-10-05 15:07:55 +0200122 data = "module c {yang-version 1.1; namespace urn:tests:extensions:structure:c; prefix c;"
Michal Vaskoedb0fa52022-10-04 10:36:00 +0200123 "import ietf-yang-structure-ext {prefix sx;}"
124 "sx:structure struct;}";
Michal Vasko0b50f6b2022-10-05 15:07:55 +0200125 info = "module c {\n"
126 " namespace \"urn:tests:extensions:structure:c\";\n"
127 " prefix c;\n"
Michal Vaskoedb0fa52022-10-04 10:36:00 +0200128 "\n"
129 " ietf-yang-structure-ext:structure \"struct\";\n"
130 "}\n";
Michal Vasko193dacd2022-10-13 08:43:05 +0200131
132 UTEST_ADD_MODULE(data, LYS_IN_YANG, NULL, &mod);
Michal Vaskoedb0fa52022-10-04 10:36:00 +0200133 assert_non_null(e = mod->compiled->exts);
134 assert_int_equal(LY_ARRAY_COUNT(mod->compiled->exts), 1);
135 assert_int_equal(LY_SUCCESS, lys_print_mem(&printed, mod, LYS_OUT_YANG_COMPILED, 0));
136 assert_string_equal(printed, info);
137 free(printed);
138}
139
140static void
141test_schema_invalid(void **state)
142{
143 const char *data;
144
Michal Vaskoa0ba01e2022-10-19 13:26:57 +0200145 /* structure */
Michal Vaskoedb0fa52022-10-04 10:36:00 +0200146 data = "module a {yang-version 1.1; namespace urn:tests:extensions:structure:a; prefix self;"
147 "import ietf-yang-structure-ext {prefix sx;}"
148 "sx:structure struct {import yang;}}";
Michal Vasko193dacd2022-10-13 08:43:05 +0200149 UTEST_INVALID_MODULE(data, LYS_IN_YANG, NULL, LY_EVALID);
Michal Vaskoedb0fa52022-10-04 10:36:00 +0200150 CHECK_LOG_CTX("Invalid keyword \"import\" as a child of \"sx:structure struct\" extension instance.",
Michal Vasko7a266772024-01-23 11:02:38 +0100151 "/a:{extension='sx:structure'}/struct", 0);
Michal Vaskoedb0fa52022-10-04 10:36:00 +0200152
153 data = "module a {yang-version 1.1; namespace urn:tests:extensions:structure:a; prefix self;"
154 "import ietf-yang-structure-ext {prefix sx;}"
155 "container b { sx:structure struct { container x { leaf x {type string;}}}}}";
Michal Vasko193dacd2022-10-13 08:43:05 +0200156 UTEST_INVALID_MODULE(data, LYS_IN_YANG, NULL, LY_EVALID);
157 CHECK_LOG_CTX("Ext plugin \"ly2 structure v1\": "
Michal Vaskoedb0fa52022-10-04 10:36:00 +0200158 "Extension sx:structure must not be used as a non top-level statement in \"container\" statement.",
Michal Vasko7a266772024-01-23 11:02:38 +0100159 "/a:b/{extension='sx:structure'}/struct", 0);
Michal Vaskoedb0fa52022-10-04 10:36:00 +0200160
161 data = "module a {yang-version 1.1; namespace urn:tests:extensions:structure:a; prefix self;"
162 "import ietf-yang-structure-ext {prefix sx;}"
163 "sx:structure { container x { leaf x {type string;}}}}";
Michal Vasko193dacd2022-10-13 08:43:05 +0200164 UTEST_INVALID_MODULE(data, LYS_IN_YANG, NULL, LY_EVALID);
Michal Vasko7a266772024-01-23 11:02:38 +0100165 CHECK_LOG_CTX("Parsing module \"a\" failed.", NULL, 0);
166 CHECK_LOG_CTX("Extension instance \"sx:structure\" missing argument element \"name\".", NULL, 0);
Michal Vaskoedb0fa52022-10-04 10:36:00 +0200167
168 data = "module a {yang-version 1.1; namespace urn:tests:extensions:structure:a; prefix self;"
169 "import ietf-yang-structure-ext {prefix sx;}"
170 "sx:structure struct { container x { leaf x {type string;}}}"
171 "sx:structure struct { container y { leaf y {type string;}}}}";
Michal Vasko193dacd2022-10-13 08:43:05 +0200172 UTEST_INVALID_MODULE(data, LYS_IN_YANG, NULL, LY_EVALID);
173 CHECK_LOG_CTX("Ext plugin \"ly2 structure v1\": Extension sx:structure is instantiated multiple times.",
Michal Vasko7a266772024-01-23 11:02:38 +0100174 "/a:{extension='sx:structure'}/struct", 0);
Michal Vaskoedb0fa52022-10-04 10:36:00 +0200175
176 data = "module a {yang-version 1.1; namespace urn:tests:extensions:structure:a; prefix self;"
177 "import ietf-yang-structure-ext {prefix sx;}"
178 "sx:structure struct { container x { leaf x {type string;}}}"
179 "choice struct { container y { leaf y {type string;}}}}";
Michal Vasko193dacd2022-10-13 08:43:05 +0200180 UTEST_INVALID_MODULE(data, LYS_IN_YANG, NULL, LY_EVALID);
181 CHECK_LOG_CTX("Ext plugin \"ly2 structure v1\": Extension sx:structure collides with a choice with the same identifier.",
Michal Vasko7a266772024-01-23 11:02:38 +0100182 "/a:{extension='sx:structure'}/struct", 0);
Michal Vaskoa0ba01e2022-10-19 13:26:57 +0200183
184 /* augment-structure */
185 data = "module a {yang-version 1.1; namespace urn:tests:extensions:structure:a; prefix a;"
186 "import ietf-yang-structure-ext {prefix sx;}"
187 "sx:structure struct {"
188 " container n1 {leaf l {config false; type uint32;}}"
189 " list n2 {leaf l {type string;}}"
190 "}"
191 "container n1 {leaf l2 {type uint8;}}}";
192 UTEST_ADD_MODULE(data, LYS_IN_YANG, NULL, NULL);
193
194 data = "module b {yang-version 1.1; namespace urn:tests:extensions:structure:b; prefix b;"
195 "import ietf-yang-structure-ext {prefix sx;}"
196 "import a {prefix a;}"
197 "sx:augment-structure \"/a:n1\" {"
198 " leaf aug-leaf {type string;}"
199 "}}";
200 UTEST_INVALID_MODULE(data, LYS_IN_YANG, NULL, LY_ENOTFOUND);
201 CHECK_LOG_CTX("Augment extension target node \"/a:n1\" from module \"b\" was not found.",
Michal Vasko7a266772024-01-23 11:02:38 +0100202 "/b:{extension='sx:augment-structure'}/{augment='/a:n1'}", 0);
Michal Vaskoedb0fa52022-10-04 10:36:00 +0200203}
204
205static void
206test_parse(void **state)
207{
208 struct lys_module *mod;
209 struct lysc_ext_instance *e;
210 struct lyd_node *tree = NULL;
Michal Vaskoa0ba01e2022-10-19 13:26:57 +0200211 const char *yang;
212 const char *xml = "<x xmlns=\"urn:tests:extensions:structure:a\">"
213 "<x>test</x>"
214 "<x2 xmlns=\"urn:tests:extensions:structure:b\">25</x2>"
215 "</x>";
216 const char *json = "{\"a:x\":{\"x\":\"test\",\"b:x2\":25}}";
217
218 yang = "module a {yang-version 1.1; namespace urn:tests:extensions:structure:a; prefix a;"
Michal Vaskoedb0fa52022-10-04 10:36:00 +0200219 "import ietf-yang-structure-ext {prefix sx;}"
220 "sx:structure struct { container x { leaf x { type string;}}}}";
Michal Vaskoa0ba01e2022-10-19 13:26:57 +0200221 UTEST_ADD_MODULE(yang, LYS_IN_YANG, NULL, &mod);
Michal Vaskoedb0fa52022-10-04 10:36:00 +0200222
Michal Vaskoa0ba01e2022-10-19 13:26:57 +0200223 yang = "module b {yang-version 1.1; namespace urn:tests:extensions:structure:b; prefix b;"
224 "import ietf-yang-structure-ext {prefix sx;}"
225 "import a {prefix a;}"
226 "sx:augment-structure \"/a:struct/a:x\" {"
227 " leaf x2 {type uint32;}"
228 "}}";
229 UTEST_ADD_MODULE(yang, LYS_IN_YANG, NULL, NULL);
230
231 /* get extension after recompilation */
Michal Vaskoedb0fa52022-10-04 10:36:00 +0200232 assert_non_null(e = mod->compiled->exts);
233
234 assert_int_equal(LY_SUCCESS, ly_in_new_memory(xml, &UTEST_IN));
Michal Vaskoa0ba01e2022-10-19 13:26:57 +0200235 assert_int_equal(LY_SUCCESS, lyd_parse_ext_data(e, NULL, UTEST_IN, LYD_XML, LYD_PARSE_STRICT, LYD_VALIDATE_PRESENT, &tree));
Michal Vaskoedb0fa52022-10-04 10:36:00 +0200236 CHECK_LYD_STRING_PARAM(tree, xml, LYD_XML, LYD_PRINT_SHRINK | LYD_PRINT_WITHSIBLINGS);
237 lyd_free_all(tree);
238
239 ly_in_memory(UTEST_IN, json);
Michal Vaskoa0ba01e2022-10-19 13:26:57 +0200240 assert_int_equal(LY_SUCCESS, lyd_parse_ext_data(e, NULL, UTEST_IN, LYD_JSON, LYD_PARSE_STRICT, LYD_VALIDATE_PRESENT, &tree));
Michal Vaskoedb0fa52022-10-04 10:36:00 +0200241 CHECK_LYD_STRING_PARAM(tree, json, LYD_JSON, LYD_PRINT_SHRINK | LYD_PRINT_WITHSIBLINGS);
Michal Vaskoedb0fa52022-10-04 10:36:00 +0200242 lyd_free_all(tree);
243}
244
245int
246main(void)
247{
248 const struct CMUnitTest tests[] = {
249 UTEST(test_schema),
250 UTEST(test_schema_invalid),
251 UTEST(test_parse),
252 };
253
254 return cmocka_run_group_tests(tests, NULL, NULL);
255}