blob: a97db00cb9b9a8be9bb86c139e96ca4369fc1124 [file] [log] [blame]
Radek Krejciad5963b2019-09-06 16:03:05 +02001/*
2 * @file test_metadata.c
3 * @author: Radek Krejci <rkrejci@cesnet.cz>
4 * @brief unit tests for Metadata extension (annotation) support
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
15#include "tests/config.h"
16
17#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
25#include "../../src/libyang.h"
26#include "../../src/plugins_exts_metadata.h"
27
28#define BUFSIZE 1024
29char logbuf[BUFSIZE] = {0};
30int store = -1; /* negative for infinite logging, positive for limited logging */
31
32struct state_s {
33 void *func;
34 struct ly_ctx *ctx;
35};
36
37/* set to 0 to printing error messages to stderr instead of checking them in code */
38#define ENABLE_LOGGER_CHECKING 1
39
40#if ENABLE_LOGGER_CHECKING
41static void
42logger(LY_LOG_LEVEL level, const char *msg, const char *path)
43{
44 (void) level; /* unused */
45 if (store) {
46 if (path && path[0]) {
47 snprintf(logbuf, BUFSIZE - 1, "%s %s", msg, path);
48 } else {
49 strncpy(logbuf, msg, BUFSIZE - 1);
50 }
51 if (store > 0) {
52 --store;
53 }
54 }
55}
56#endif
57
58static int
59setup(void **state)
60{
61 struct state_s *s;
62
63 s = calloc(1, sizeof *s);
64 assert_non_null(s);
65
66#if ENABLE_LOGGER_CHECKING
67 ly_set_log_clb(logger, 1);
68#endif
69
70 assert_int_equal(LY_SUCCESS, ly_ctx_new(NULL, 0, &s->ctx));
71 *state = s;
72
73 return 0;
74}
75
76static int
77teardown(void **state)
78{
79 struct state_s *s = (struct state_s*)(*state);
80
81#if ENABLE_LOGGER_CHECKING
82 if (s->func) {
83 fprintf(stderr, "%s\n", logbuf);
84 }
85#endif
86
87 ly_ctx_destroy(s->ctx, NULL);
88 free(s);
89
90 return 0;
91}
92
93void
94logbuf_clean(void)
95{
96 logbuf[0] = '\0';
97}
98
99#if ENABLE_LOGGER_CHECKING
100# define logbuf_assert(str) assert_string_equal(logbuf, str)
101#else
102# define logbuf_assert(str)
103#endif
104
105static void
106test_yang(void **state)
107{
108 struct state_s *s = (struct state_s*)(*state);
109 s->func = test_yang;
110
111 struct lys_module *mod;
112 struct lysc_ext_instance *e;
113 struct lyext_metadata *ant;
114
115 const char *data = "module a {yang-version 1.1; namespace urn:tests:extensions:metadata:a; prefix a;"
116 "import ietf-yang-metadata {prefix md;}"
117 "feature f;"
118 "md:annotation x {"
119 " description \"test\";"
120 " if-feature f;"
121 " reference \"test\";"
122 " status \"current\";"
123 " type uint8;"
124 " units meters;"
125 "}}";
126 assert_non_null(mod = lys_parse_mem(s->ctx, data, LYS_IN_YANG));
127 assert_int_equal(1, LY_ARRAY_SIZE(mod->compiled->exts));
128 e = &mod->compiled->exts[0];
129 assert_non_null(ant = (struct lyext_metadata*)e->data);
130 assert_string_equal("meters", ant->units);
131
132 /* invalid */
133 /* missing mandatory type substatement */
134 data = "module aa {yang-version 1.1; namespace urn:tests:extensions:metadata:aa; prefix aa;"
135 "import ietf-yang-metadata {prefix md;}"
136 "md:annotation aa;}";
137 assert_null(lys_parse_mem(s->ctx, data, LYS_IN_YANG));
138 logbuf_assert("Missing mandatory keyword \"type\" as a child of \"md:annotation aa\". /aa:{extension='md:annotation'}/aa");
139
140 /* not allowed substatement */
141 data = "module aa {yang-version 1.1; namespace urn:tests:extensions:metadata:aa; prefix aa;"
142 "import ietf-yang-metadata {prefix md;}"
143 "md:annotation aa {default x;}}";
144 assert_null(lys_parse_mem(s->ctx, data, LYS_IN_YANG));
145 logbuf_assert("Invalid keyword \"default\" as a child of \"md:annotation aa\" extension instance. /aa:{extension='md:annotation'}/aa");
146
147 /* invalid cardinality of units substatement */
148 data = "module aa {yang-version 1.1; namespace urn:tests:extensions:metadata:aa; prefix aa;"
149 "import ietf-yang-metadata {prefix md;}"
150 "md:annotation aa {type string; units x; units y;}}";
151 assert_null(lys_parse_mem(s->ctx, data, LYS_IN_YANG));
152 logbuf_assert("Duplicate keyword \"units\". /aa:{extension='md:annotation'}/aa");
153
154 /* invalid cardinality of status substatement */
155 data = "module aa {yang-version 1.1; namespace urn:tests:extensions:metadata:aa; prefix aa;"
156 "import ietf-yang-metadata {prefix md;}"
157 "md:annotation aa {type string; status current; status obsolete;}}";
158 assert_null(lys_parse_mem(s->ctx, data, LYS_IN_YANG));
159 logbuf_assert("Duplicate keyword \"status\". /aa:{extension='md:annotation'}/aa");
160
161 /* invalid cardinality of status substatement */
162 data = "module aa {yang-version 1.1; namespace urn:tests:extensions:metadata:aa; prefix aa;"
163 "import ietf-yang-metadata {prefix md;}"
164 "md:annotation aa {type string; type uint8;}}";
165 assert_null(lys_parse_mem(s->ctx, data, LYS_IN_YANG));
166 logbuf_assert("Duplicate keyword \"type\". /aa:{extension='md:annotation'}/aa");
167
168 /* duplication of the same annotation */
169 data = "module aa {yang-version 1.1; namespace urn:tests:extensions:metadata:aa; prefix aa;"
170 "import ietf-yang-metadata {prefix md;}"
171 "md:annotation aa {type string;} md:annotation aa {type uint8;}}";
172 assert_null(lys_parse_mem(s->ctx, data, LYS_IN_YANG));
173 logbuf_assert("Extension plugin \"libyang 2 - metadata, version 1\": "
174 "Extension md:annotation is instantiated multiple times.) /aa:{extension='md:annotation'}/aa");
175
176 s->func = NULL;
177}
178
Radek Krejci7c960162019-09-18 14:16:12 +0200179static void
180test_yin(void **state)
181{
182 struct state_s *s = (struct state_s*)(*state);
183 s->func = test_yin;
184
185 struct lys_module *mod;
186 struct lysc_ext_instance *e;
187 struct lyext_metadata *ant;
188
189 const char *data = "<module xmlns=\"urn:ietf:params:xml:ns:yang:yin:1\" xmlns:md=\"urn:ietf:params:xml:ns:yang:ietf-yang-metadata\" name=\"a\">\n"
190 "<yang-version value=\"1.1\"/><namespace uri=\"urn:tests:extensions:metadata:a\"/><prefix value=\"a\"/>\n"
191 "<import module=\"ietf-yang-metadata\"><prefix value=\"md\"/></import>\n"
192 "<feature name=\"f\"/>\n"
193 "<md:annotation name=\"x\">\n"
194 " <description><text>test</text></description>\n"
195 " <reference><text>test</text></reference>\n"
196 " <if-feature name=\"f\"/>\n"
197 " <status value=\"current\"/>\n"
198 " <type name=\"uint8\"/>\n"
199 " <units name=\"meters\"/>\n"
200 "</md:annotation></module>";
201 assert_non_null(mod = lys_parse_mem(s->ctx, data, LYS_IN_YIN));
202 assert_int_equal(1, LY_ARRAY_SIZE(mod->compiled->exts));
203 e = &mod->compiled->exts[0];
204 assert_non_null(ant = (struct lyext_metadata*)e->data);
205 assert_string_equal("meters", ant->units);
206
207 /* invalid */
208 /* missing mandatory type substatement */
209 data = "<module xmlns=\"urn:ietf:params:xml:ns:yang:yin:1\" xmlns:md=\"urn:ietf:params:xml:ns:yang:ietf-yang-metadata\" name=\"aa\">\n"
210 "<yang-version value=\"1.1\"/><namespace uri=\"urn:tests:extensions:metadata:aa\"/><prefix value=\"aa\"/>\n"
211 "<import module=\"ietf-yang-metadata\"><prefix value=\"md\"/></import>\n"
212 "<md:annotation name=\"aa\"/>\n"
213 "</module>";
214 assert_null(lys_parse_mem(s->ctx, data, LYS_IN_YIN));
215 logbuf_assert("Missing mandatory keyword \"type\" as a child of \"md:annotation aa\". /aa:{extension='md:annotation'}/aa");
216
217 /* not allowed substatement */
218 data = "<module xmlns=\"urn:ietf:params:xml:ns:yang:yin:1\" xmlns:md=\"urn:ietf:params:xml:ns:yang:ietf-yang-metadata\" name=\"aa\">\n"
219 "<yang-version value=\"1.1\"/><namespace uri=\"urn:tests:extensions:metadata:aa\"/><prefix value=\"aa\"/>\n"
220 "<import module=\"ietf-yang-metadata\"><prefix value=\"md\"/></import>\n"
221 "<md:annotation name=\"aa\">\n"
222 " <default value=\"x\"/>\n"
223 "</md:annotation></module>";
224 assert_null(lys_parse_mem(s->ctx, data, LYS_IN_YIN));
225 logbuf_assert("Invalid keyword \"default\" as a child of \"md:annotation aa\" extension instance. /aa:{extension='md:annotation'}/aa");
226
227 /* invalid cardinality of units substatement */
228 data = "<module xmlns=\"urn:ietf:params:xml:ns:yang:yin:1\" xmlns:md=\"urn:ietf:params:xml:ns:yang:ietf-yang-metadata\" name=\"aa\">\n"
229 "<yang-version value=\"1.1\"/><namespace uri=\"urn:tests:extensions:metadata:aa\"/><prefix value=\"aa\"/>\n"
230 "<import module=\"ietf-yang-metadata\"><prefix value=\"md\"/></import>\n"
231 "<md:annotation name=\"aa\">\n"
232 " <type name=\"string\"/>\n"
233 " <units name=\"x\"/>\n"
234 " <units name=\"y\"/>\n"
235 "</md:annotation></module>";
236 assert_null(lys_parse_mem(s->ctx, data, LYS_IN_YIN));
237 logbuf_assert("Duplicate keyword \"units\". /aa:{extension='md:annotation'}/aa");
238
239 /* invalid cardinality of status substatement */
240 data = "<module xmlns=\"urn:ietf:params:xml:ns:yang:yin:1\" xmlns:md=\"urn:ietf:params:xml:ns:yang:ietf-yang-metadata\" name=\"aa\">\n"
241 "<yang-version value=\"1.1\"/><namespace uri=\"urn:tests:extensions:metadata:aa\"/><prefix value=\"aa\"/>\n"
242 "<import module=\"ietf-yang-metadata\"><prefix value=\"md\"/></import>\n"
243 "<md:annotation name=\"aa\">\n"
244 " <type name=\"string\"/>\n"
245 " <status value=\"current\"/>\n"
246 " <status value=\"obsolete\"/>\n"
247 "</md:annotation></module>";
248 assert_null(lys_parse_mem(s->ctx, data, LYS_IN_YIN));
249 logbuf_assert("Duplicate keyword \"status\". /aa:{extension='md:annotation'}/aa");
250
251 /* invalid cardinality of status substatement */
252 data = "<module xmlns=\"urn:ietf:params:xml:ns:yang:yin:1\" xmlns:md=\"urn:ietf:params:xml:ns:yang:ietf-yang-metadata\" name=\"aa\">\n"
253 "<yang-version value=\"1.1\"/><namespace uri=\"urn:tests:extensions:metadata:aa\"/><prefix value=\"aa\"/>\n"
254 "<import module=\"ietf-yang-metadata\"><prefix value=\"md\"/></import>\n"
255 "<md:annotation name=\"aa\">\n"
256 " <type name=\"string\"/>\n"
257 " <type name=\"uint8\"/>\n"
258 "</md:annotation></module>";
259 assert_null(lys_parse_mem(s->ctx, data, LYS_IN_YIN));
260 logbuf_assert("Duplicate keyword \"type\". /aa:{extension='md:annotation'}/aa");
261
262 /* duplication of the same annotation */
263 data = "<module xmlns=\"urn:ietf:params:xml:ns:yang:yin:1\" xmlns:md=\"urn:ietf:params:xml:ns:yang:ietf-yang-metadata\" name=\"aa\">\n"
264 "<yang-version value=\"1.1\"/><namespace uri=\"urn:tests:extensions:metadata:aa\"/><prefix value=\"aa\"/>\n"
265 "<import module=\"ietf-yang-metadata\"><prefix value=\"md\"/></import>\n"
266 "<md:annotation name=\"aa\">\n"
267 " <type name=\"string\"/>\n"
268 "</md:annotation><md:annotation name=\"aa\">\n"
269 " <type name=\"uint8\"/>\n"
270 "</md:annotation></module>";
271 assert_null(lys_parse_mem(s->ctx, data, LYS_IN_YIN));
272 logbuf_assert("Extension plugin \"libyang 2 - metadata, version 1\": "
273 "Extension md:annotation is instantiated multiple times.) /aa:{extension='md:annotation'}/aa");
274 s->func = NULL;
275}
276
Radek Krejciad5963b2019-09-06 16:03:05 +0200277int main(void)
278{
279 const struct CMUnitTest tests[] = {
280 cmocka_unit_test_setup_teardown(test_yang, setup, teardown),
Radek Krejci7c960162019-09-18 14:16:12 +0200281 cmocka_unit_test_setup_teardown(test_yin, setup, teardown),
Radek Krejciad5963b2019-09-06 16:03:05 +0200282 };
283
284 return cmocka_run_group_tests(tests, NULL, NULL);
285}