blob: 9c60e37074bfd9ea87f08f6917f1ba5d93bad1ec [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
179int main(void)
180{
181 const struct CMUnitTest tests[] = {
182 cmocka_unit_test_setup_teardown(test_yang, setup, teardown),
183 };
184
185 return cmocka_run_group_tests(tests, NULL, NULL);
186}