blob: a22c70751ca19c3be3033f184723f8592b5e869a [file] [log] [blame]
Radek Krejcidd4e8d42018-10-16 14:55:43 +02001/*
2 * @file test_parser_yang.c
3 * @author: Radek Krejci <rkrejci@cesnet.cz>
4 * @brief unit tests for functions from parser_yang.c
5 *
6 * Copyright (c) 2018 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
Radek Krejci86d106e2018-10-18 09:53:19 +020015#include "../../src/tree_schema.c"
16#include "../../src/parser_yang.c"
17
Radek Krejcidd4e8d42018-10-16 14:55:43 +020018#include <stdarg.h>
19#include <stddef.h>
20#include <setjmp.h>
21#include <cmocka.h>
22
23#include <stdio.h>
24#include <string.h>
25
26#include "libyang.h"
Radek Krejcidd4e8d42018-10-16 14:55:43 +020027
28#define BUFSIZE 1024
29char logbuf[BUFSIZE] = {0};
30
31/* set to 0 to printing error messages to stderr instead of checking them in code */
32#define ENABLE_LOGGER_CHECKING 1
33
34#if ENABLE_LOGGER_CHECKING
35static void
36logger(LY_LOG_LEVEL level, const char *msg, const char *path)
37{
38 (void) level; /* unused */
39
Radek Krejci87616bb2018-10-31 13:30:52 +010040 if (path && path[0]) {
Radek Krejcidd4e8d42018-10-16 14:55:43 +020041 snprintf(logbuf, BUFSIZE - 1, "%s %s", msg, path);
42 } else {
43 strncpy(logbuf, msg, BUFSIZE - 1);
44 }
45}
46#endif
47
48static int
49logger_setup(void **state)
50{
51 (void) state; /* unused */
52#if ENABLE_LOGGER_CHECKING
53 ly_set_log_clb(logger, 1);
54#endif
55 return 0;
56}
57
58void
59logbuf_clean(void)
60{
61 logbuf[0] = '\0';
62}
63
64#if ENABLE_LOGGER_CHECKING
65# define logbuf_assert(str) assert_string_equal(logbuf, str)
66#else
67# define logbuf_assert(str)
68#endif
69
70static void
71test_module(void **state)
72{
73 (void) state; /* unused */
74
75 const char *str;
76 struct ly_ctx *ctx;
77 struct lys_module mod = {0};
Radek Krejci151a5b72018-10-19 14:21:44 +020078 struct lysc_feature *f;
79 struct lysc_iffeature *iff;
Radek Krejcidd4e8d42018-10-16 14:55:43 +020080
81 str = "module test {namespace urn:test; prefix t;"
Radek Krejci151a5b72018-10-19 14:21:44 +020082 "feature f1;feature f2 {if-feature f1;}}";
Radek Krejcidd4e8d42018-10-16 14:55:43 +020083 assert_int_equal(LY_SUCCESS, ly_ctx_new(NULL, 0, &ctx));
84
Radek Krejcif8f882a2018-10-31 14:51:15 +010085 assert_int_equal(LY_EINVAL, lys_compile(NULL, 0));
86 logbuf_assert("Invalid argument mod (lys_compile()).");
87 assert_int_equal(LY_EINVAL, lys_compile(&mod, 0));
88 logbuf_assert("Invalid argument mod->parsed (lys_compile()).");
Radek Krejcidd4e8d42018-10-16 14:55:43 +020089 assert_int_equal(LY_SUCCESS, yang_parse(ctx, str, &mod.parsed));
Radek Krejcif8f882a2018-10-31 14:51:15 +010090 assert_int_equal(LY_SUCCESS, lys_compile(&mod, 0));
Radek Krejcidd4e8d42018-10-16 14:55:43 +020091 assert_non_null(mod.compiled);
92 assert_ptr_equal(mod.parsed->name, mod.compiled->name);
93 assert_ptr_equal(mod.parsed->ns, mod.compiled->ns);
Radek Krejci151a5b72018-10-19 14:21:44 +020094 /* features */
95 assert_non_null(mod.compiled->features);
96 assert_int_equal(2, LY_ARRAY_SIZE(mod.compiled->features));
Radek Krejci2c4e7172018-10-19 15:56:26 +020097 f = &mod.compiled->features[1];
Radek Krejci151a5b72018-10-19 14:21:44 +020098 assert_non_null(f->iffeatures);
99 assert_int_equal(1, LY_ARRAY_SIZE(f->iffeatures));
Radek Krejci2c4e7172018-10-19 15:56:26 +0200100 iff = &f->iffeatures[0];
Radek Krejci151a5b72018-10-19 14:21:44 +0200101 assert_non_null(iff->expr);
102 assert_non_null(iff->features);
103 assert_int_equal(1, LY_ARRAY_SIZE(iff->features));
Radek Krejci2c4e7172018-10-19 15:56:26 +0200104 assert_ptr_equal(&mod.compiled->features[0], iff->features[0]);
Radek Krejcidd4e8d42018-10-16 14:55:43 +0200105
Radek Krejci86d106e2018-10-18 09:53:19 +0200106 lysc_module_free(mod.compiled, NULL);
Radek Krejcidd4e8d42018-10-16 14:55:43 +0200107
Radek Krejcif8f882a2018-10-31 14:51:15 +0100108 assert_int_equal(LY_SUCCESS, lys_compile(&mod, LYSC_OPT_FREE_SP));
Radek Krejcidd4e8d42018-10-16 14:55:43 +0200109 assert_non_null(mod.compiled);
110 assert_string_equal("test", mod.compiled->name);
111 assert_string_equal("urn:test", mod.compiled->ns);
112
Radek Krejci86d106e2018-10-18 09:53:19 +0200113 lysc_module_free(mod.compiled, NULL);
114 mod.compiled = NULL;
115
Radek Krejci151a5b72018-10-19 14:21:44 +0200116 /* submodules cannot be compiled directly */
Radek Krejci86d106e2018-10-18 09:53:19 +0200117 str = "submodule test {belongs-to xxx {prefix x;}}";
118 assert_int_equal(LY_SUCCESS, yang_parse(ctx, str, &mod.parsed));
Radek Krejcif8f882a2018-10-31 14:51:15 +0100119 assert_int_equal(LY_EINVAL, lys_compile(&mod, 0));
Radek Krejci86d106e2018-10-18 09:53:19 +0200120 logbuf_assert("Submodules (test) are not supposed to be compiled, compile only the main modules.");
121 assert_null(mod.compiled);
122
123 lysp_module_free(mod.parsed);
Radek Krejcidd4e8d42018-10-16 14:55:43 +0200124 ly_ctx_destroy(ctx, NULL);
125}
126
Radek Krejci151a5b72018-10-19 14:21:44 +0200127static void
128test_feature(void **state)
129{
130 (void) state; /* unused */
131
132 struct ly_ctx *ctx;
133 struct lys_module mod = {0};
134 const char *str;
135 struct lysc_feature *f, *f1;
136
137 str = "module a {namespace urn:a;prefix a;yang-version 1.1;\n"
138 "feature f1 {description test1;reference test2;status current;} feature f2; feature f3;\n"
Radek Krejci87616bb2018-10-31 13:30:52 +0100139 "feature orfeature {if-feature \"f1 or f2\";}\n"
140 "feature andfeature {if-feature \"f1 and f2\";}\n"
Radek Krejci151a5b72018-10-19 14:21:44 +0200141 "feature f6 {if-feature \"not f1\";}\n"
Radek Krejcidde18c52018-10-24 14:43:04 +0200142 "feature f7 {if-feature \"(f2 and f3) or (not f1)\";}\n"
Radek Krejci87616bb2018-10-31 13:30:52 +0100143 "feature f8 {if-feature \"f1 or f2 or f3 or orfeature or andfeature\";}\n"
144 "feature f9 {if-feature \"not not f1\";}}";
Radek Krejci151a5b72018-10-19 14:21:44 +0200145
146 assert_int_equal(LY_SUCCESS, ly_ctx_new(NULL, 0, &ctx));
147 assert_int_equal(LY_SUCCESS, yang_parse(ctx, str, &mod.parsed));
Radek Krejcif8f882a2018-10-31 14:51:15 +0100148 assert_int_equal(LY_SUCCESS, lys_compile(&mod, 0));
Radek Krejci151a5b72018-10-19 14:21:44 +0200149 assert_non_null(mod.compiled);
150 assert_non_null(mod.compiled->features);
Radek Krejci87616bb2018-10-31 13:30:52 +0100151 assert_int_equal(9, LY_ARRAY_SIZE(mod.compiled->features));
Radek Krejci151a5b72018-10-19 14:21:44 +0200152 /* all features are disabled by default */
153 LY_ARRAY_FOR(mod.compiled->features, struct lysc_feature, f) {
154 assert_int_equal(0, lysc_feature_value(f));
155 }
156 /* enable f1 */
157 assert_int_equal(LY_SUCCESS, lys_feature_enable(&mod, "f1"));
Radek Krejci2c4e7172018-10-19 15:56:26 +0200158 f1 = &mod.compiled->features[0];
Radek Krejci151a5b72018-10-19 14:21:44 +0200159 assert_int_equal(1, lysc_feature_value(f1));
160
Radek Krejci87616bb2018-10-31 13:30:52 +0100161 /* enable orfeature */
Radek Krejci2c4e7172018-10-19 15:56:26 +0200162 f = &mod.compiled->features[3];
Radek Krejci151a5b72018-10-19 14:21:44 +0200163 assert_int_equal(0, lysc_feature_value(f));
Radek Krejci87616bb2018-10-31 13:30:52 +0100164 assert_int_equal(LY_SUCCESS, lys_feature_enable(&mod, "orfeature"));
Radek Krejci151a5b72018-10-19 14:21:44 +0200165 assert_int_equal(1, lysc_feature_value(f));
166
Radek Krejci87616bb2018-10-31 13:30:52 +0100167 /* enable andfeature - no possible since f2 is disabled */
Radek Krejci2c4e7172018-10-19 15:56:26 +0200168 f = &mod.compiled->features[4];
Radek Krejci151a5b72018-10-19 14:21:44 +0200169 assert_int_equal(0, lysc_feature_value(f));
Radek Krejci87616bb2018-10-31 13:30:52 +0100170 assert_int_equal(LY_EDENIED, lys_feature_enable(&mod, "andfeature"));
171 logbuf_assert("Feature \"andfeature\" cannot be enabled since it is disabled by its if-feature condition(s).");
Radek Krejci151a5b72018-10-19 14:21:44 +0200172 assert_int_equal(0, lysc_feature_value(f));
173
174 /* first enable f2, so f5 can be enabled then */
175 assert_int_equal(LY_SUCCESS, lys_feature_enable(&mod, "f2"));
Radek Krejci87616bb2018-10-31 13:30:52 +0100176 assert_int_equal(LY_SUCCESS, lys_feature_enable(&mod, "andfeature"));
Radek Krejci151a5b72018-10-19 14:21:44 +0200177 assert_int_equal(1, lysc_feature_value(f));
178
179 /* f1 is enabled, so f6 cannot be enabled */
Radek Krejci2c4e7172018-10-19 15:56:26 +0200180 f = &mod.compiled->features[5];
Radek Krejci151a5b72018-10-19 14:21:44 +0200181 assert_int_equal(0, lysc_feature_value(f));
182 assert_int_equal(LY_EDENIED, lys_feature_enable(&mod, "f6"));
183 logbuf_assert("Feature \"f6\" cannot be enabled since it is disabled by its if-feature condition(s).");
184 assert_int_equal(0, lysc_feature_value(f));
185
Radek Krejci87616bb2018-10-31 13:30:52 +0100186 /* so disable f1 - andfeature will became also disabled */
Radek Krejci151a5b72018-10-19 14:21:44 +0200187 assert_int_equal(1, lysc_feature_value(f1));
Radek Krejci151a5b72018-10-19 14:21:44 +0200188 assert_int_equal(LY_SUCCESS, lys_feature_disable(&mod, "f1"));
189 assert_int_equal(0, lysc_feature_value(f1));
Radek Krejci2c4e7172018-10-19 15:56:26 +0200190 assert_int_equal(0, lysc_feature_value(&mod.compiled->features[4]));
Radek Krejci87616bb2018-10-31 13:30:52 +0100191 /* while orfeature is stille enabled */
Radek Krejci2c4e7172018-10-19 15:56:26 +0200192 assert_int_equal(1, lysc_feature_value(&mod.compiled->features[3]));
Radek Krejci151a5b72018-10-19 14:21:44 +0200193 /* and finally f6 can be enabled */
Radek Krejci151a5b72018-10-19 14:21:44 +0200194 assert_int_equal(LY_SUCCESS, lys_feature_enable(&mod, "f6"));
Radek Krejci2c4e7172018-10-19 15:56:26 +0200195 assert_int_equal(1, lysc_feature_value(&mod.compiled->features[5]));
Radek Krejci151a5b72018-10-19 14:21:44 +0200196
197 /* complex evaluation of f7: f1 and f3 are disabled, while f2 is enabled */
Radek Krejci2c4e7172018-10-19 15:56:26 +0200198 assert_int_equal(1, lysc_iffeature_value(&mod.compiled->features[6].iffeatures[0]));
Radek Krejcidde18c52018-10-24 14:43:04 +0200199 /* long evaluation of f8 to need to reallocate internal stack for operators */
200 assert_int_equal(1, lysc_iffeature_value(&mod.compiled->features[7].iffeatures[0]));
Radek Krejci151a5b72018-10-19 14:21:44 +0200201
Radek Krejci87616bb2018-10-31 13:30:52 +0100202 /* double negation of disabled f1 -> disabled */
203 assert_int_equal(0, lysc_iffeature_value(&mod.compiled->features[8].iffeatures[0]));
204
Radek Krejci151a5b72018-10-19 14:21:44 +0200205 lysc_module_free(mod.compiled, NULL);
206 lysp_module_free(mod.parsed);
Radek Krejci87616bb2018-10-31 13:30:52 +0100207
208 /* some invalid expressions */
209 assert_int_equal(LY_SUCCESS, yang_parse(ctx, "module b{yang-version 1.1;namespace urn:b; prefix b; feature f{if-feature f1;}}", &mod.parsed));
Radek Krejcif8f882a2018-10-31 14:51:15 +0100210 assert_int_equal(LY_EVALID, lys_compile(&mod, 0));
Radek Krejci87616bb2018-10-31 13:30:52 +0100211 logbuf_assert("Invalid value \"f1\" of if-feature - unable to find feature \"f1\".");
212 lysp_module_free(mod.parsed);
213
214 assert_int_equal(LY_SUCCESS, yang_parse(ctx, "module b{yang-version 1.1;namespace urn:b; prefix b; feature f1; feature f2{if-feature 'f and';}}", &mod.parsed));
Radek Krejcif8f882a2018-10-31 14:51:15 +0100215 assert_int_equal(LY_EVALID, lys_compile(&mod, 0));
Radek Krejci87616bb2018-10-31 13:30:52 +0100216 logbuf_assert("Invalid value \"f and\" of if-feature - unexpected end of expression.");
217 lysp_module_free(mod.parsed);
218
219 assert_int_equal(LY_SUCCESS, yang_parse(ctx, "module b{yang-version 1.1;namespace urn:b; prefix b; feature f{if-feature 'or';}}", &mod.parsed));
Radek Krejcif8f882a2018-10-31 14:51:15 +0100220 assert_int_equal(LY_EVALID, lys_compile(&mod, 0));
Radek Krejci87616bb2018-10-31 13:30:52 +0100221 logbuf_assert("Invalid value \"or\" of if-feature - unexpected end of expression.");
222 lysp_module_free(mod.parsed);
223
224 assert_int_equal(LY_SUCCESS, yang_parse(ctx, "module b{yang-version 1.1;namespace urn:b; prefix b; feature f1; feature f2{if-feature '(f1';}}", &mod.parsed));
Radek Krejcif8f882a2018-10-31 14:51:15 +0100225 assert_int_equal(LY_EVALID, lys_compile(&mod, 0));
Radek Krejci87616bb2018-10-31 13:30:52 +0100226 logbuf_assert("Invalid value \"(f1\" of if-feature - non-matching opening and closing parentheses.");
227 lysp_module_free(mod.parsed);
228
229 assert_int_equal(LY_SUCCESS, yang_parse(ctx, "module b{yang-version 1.1;namespace urn:b; prefix b; feature f1; feature f2{if-feature 'f1)';}}", &mod.parsed));
Radek Krejcif8f882a2018-10-31 14:51:15 +0100230 assert_int_equal(LY_EVALID, lys_compile(&mod, 0));
Radek Krejci87616bb2018-10-31 13:30:52 +0100231 logbuf_assert("Invalid value \"f1)\" of if-feature - non-matching opening and closing parentheses.");
232 lysp_module_free(mod.parsed);
233
234 assert_int_equal(LY_SUCCESS, yang_parse(ctx, "module b{yang-version 1.1;namespace urn:b; prefix b; feature f1; feature f2{if-feature ---;}}", &mod.parsed));
Radek Krejcif8f882a2018-10-31 14:51:15 +0100235 assert_int_equal(LY_EVALID, lys_compile(&mod, 0));
Radek Krejci87616bb2018-10-31 13:30:52 +0100236 logbuf_assert("Invalid value \"---\" of if-feature - unable to find feature \"---\".");
237 lysp_module_free(mod.parsed);
238
239 assert_int_equal(LY_SUCCESS, yang_parse(ctx, "module b{namespace urn:b; prefix b; feature f1; feature f2{if-feature 'not f1';}}", &mod.parsed));
Radek Krejcif8f882a2018-10-31 14:51:15 +0100240 assert_int_equal(LY_EVALID, lys_compile(&mod, 0));
Radek Krejci87616bb2018-10-31 13:30:52 +0100241 logbuf_assert("Invalid value \"not f1\" of if-feature - YANG 1.1 expression in YANG 1.0 module.");
242 lysp_module_free(mod.parsed);
243
Radek Krejci151a5b72018-10-19 14:21:44 +0200244 ly_ctx_destroy(ctx, NULL);
245}
Radek Krejcidd4e8d42018-10-16 14:55:43 +0200246
Radek Krejci478020e2018-10-30 16:02:14 +0100247static void
248test_identity(void **state)
249{
250 (void) state; /* unused */
251
252 struct ly_ctx *ctx;
253 const struct lys_module *mod1, *mod2;
254 const char *mod1_str = "module a {namespace urn:a;prefix a; identity a1;}";
255 const char *mod2_str = "module b {namespace urn:b;prefix b; import a {prefix a;}identity b1; identity b2; identity b3 {base b1; base b:b2; base a:a1;} identity b4 {base b:b1; base b3;}}";
256
257 assert_int_equal(LY_SUCCESS, ly_ctx_new(NULL, LY_CTX_DISABLE_SEARCHDIRS, &ctx));
258 assert_non_null(mod1 = lys_parse_mem(ctx, mod1_str, LYS_IN_YANG));
259 assert_non_null(mod2 = lys_parse_mem(ctx, mod2_str, LYS_IN_YANG));
Radek Krejcif8f882a2018-10-31 14:51:15 +0100260 assert_int_equal(LY_SUCCESS, lys_compile(mod2, 0));
Radek Krejci478020e2018-10-30 16:02:14 +0100261
262 assert_non_null(mod1->compiled);
263 assert_non_null(mod1->compiled->identities);
264 assert_non_null(mod2->compiled);
265 assert_non_null(mod2->compiled->identities);
266
267 assert_non_null(mod1->compiled->identities[0].derived);
268 assert_int_equal(1, LY_ARRAY_SIZE(mod1->compiled->identities[0].derived));
269 assert_ptr_equal(mod1->compiled->identities[0].derived[0], &mod2->compiled->identities[2]);
270 assert_non_null(mod2->compiled->identities[0].derived);
271 assert_int_equal(2, LY_ARRAY_SIZE(mod2->compiled->identities[0].derived));
272 assert_ptr_equal(mod2->compiled->identities[0].derived[0], &mod2->compiled->identities[2]);
273 assert_ptr_equal(mod2->compiled->identities[0].derived[1], &mod2->compiled->identities[3]);
274 assert_non_null(mod2->compiled->identities[1].derived);
275 assert_int_equal(1, LY_ARRAY_SIZE(mod2->compiled->identities[1].derived));
276 assert_ptr_equal(mod2->compiled->identities[1].derived[0], &mod2->compiled->identities[2]);
277 assert_non_null(mod2->compiled->identities[2].derived);
278 assert_int_equal(1, LY_ARRAY_SIZE(mod2->compiled->identities[2].derived));
279 assert_ptr_equal(mod2->compiled->identities[2].derived[0], &mod2->compiled->identities[3]);
280
Radek Krejci478020e2018-10-30 16:02:14 +0100281 ly_ctx_destroy(ctx, NULL);
282}
283
Radek Krejcidd4e8d42018-10-16 14:55:43 +0200284int main(void)
285{
286 const struct CMUnitTest tests[] = {
287 cmocka_unit_test_setup(test_module, logger_setup),
Radek Krejci151a5b72018-10-19 14:21:44 +0200288 cmocka_unit_test_setup(test_feature, logger_setup),
Radek Krejci478020e2018-10-30 16:02:14 +0100289 cmocka_unit_test_setup(test_identity, logger_setup),
Radek Krejcidd4e8d42018-10-16 14:55:43 +0200290 };
291
292 return cmocka_run_group_tests(tests, NULL, NULL);
293}