1 /**
2 * @file test_tree_data_dup.c
3 * @author Radek Krejci <rkrejci@cesnet.cz>
4 * @brief Cmocka tests for complex data duplications.
5 *
6 * Copyright (c) 2017 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 <stdarg.h>
16 #include <stdio.h>
17 #include <stdlib.h>
18 #include <setjmp.h>
19 #include <cmocka.h>
20
21 #include "tests/config.h"
22 #include "libyang.h"
23
24 struct state {
25 struct ly_ctx *ctx1;
26 struct ly_ctx *ctx2;
27 struct lyd_node *dt1;
28 struct lyd_node *dt2;
29 struct lyd_node *dt3;
30 };
31 static int
setup_f(void ** state)32 setup_f(void **state)
33 {
34 struct state *st;
35
36 (*state) = st = calloc(1, sizeof *st);
37 if (!st) {
38 fprintf(stderr, "Memory allocation error");
39 return -1;
40 }
41
42 /* libyang context */
43 st->ctx1 = ly_ctx_new(NULL, 0);
44 st->ctx2 = ly_ctx_new(NULL, 0);
45 if (!st->ctx1 || !st->ctx2) {
46 fprintf(stderr, "Failed to create context.\n");
47 return -1;
48 }
49
50 return 0;
51 }
52
53 static int
teardown_f(void ** state)54 teardown_f(void **state)
55 {
56 struct state *st = (*state);
57
58 lyd_free(st->dt1);
59 lyd_free(st->dt2);
60 lyd_free(st->dt3);
61 ly_ctx_destroy(st->ctx1, NULL);
62 ly_ctx_destroy(st->ctx2, NULL);
63
64 free(st);
65 (*state) = NULL;
66
67 return 0;
68 }
69
70 static void
test_dup_to_ctx(void ** state)71 test_dup_to_ctx(void **state)
72 {
73 struct state *st = (*state);
74 const struct lys_module *mod;
75 const char *sch = "module x {"
76 " namespace urn:x;"
77 " prefix x;"
78 " leaf x { type string; }}";
79 const char *data = "<x xmlns=\"urn:x\">hello</x>";
80
81 /* case 1 - schema is only in the first context, duplicating data into the second context is supposed to
82 * fail because of missing schema */
83 mod = lys_parse_mem(st->ctx1, sch, LYS_IN_YANG);
84 assert_ptr_not_equal(mod, NULL);
85
86 st->dt1 = lyd_parse_mem(st->ctx1, data, LYD_XML, LYD_OPT_CONFIG);
87 assert_ptr_not_equal(st->dt1, NULL);
88
89 st->dt2 = lyd_dup_to_ctx(st->dt1, 1, st->ctx2);
90 assert_ptr_equal(st->dt2, NULL);
91 assert_int_equal(ly_errno, LY_EINVAL);
92 assert_string_equal(ly_errmsg(st->ctx2),
93 "Target context does not contain schema node for the data node being duplicated (x:x).");
94
95 /* case 2 - with the schema present in both contexts, duplication should succeed */
96 mod = lys_parse_mem(st->ctx2, sch, LYS_IN_YANG);
97 assert_ptr_not_equal(mod, NULL);
98
99 st->dt2 = lyd_dup_to_ctx(st->dt1, 1, st->ctx2);
100 assert_ptr_not_equal(st->dt2, NULL);
101 /* the values are the same, but they are stored in different contexts */
102 assert_string_equal(((struct lyd_node_leaf_list *)st->dt1)->value_str,
103 ((struct lyd_node_leaf_list *)st->dt2)->value_str);
104 assert_ptr_not_equal(((struct lyd_node_leaf_list *)st->dt1)->value_str,
105 ((struct lyd_node_leaf_list *)st->dt2)->value_str);
106 /* and the schema nodes are the same, but comes from a different contexts */
107 assert_int_equal(st->dt1->schema->nodetype, st->dt2->schema->nodetype);
108 assert_string_equal(st->dt1->schema->name, st->dt2->schema->name);
109 assert_string_equal(st->dt1->schema->module->name, st->dt2->schema->module->name);
110 assert_ptr_equal(st->dt1->schema->module->ctx, st->ctx1);
111 assert_ptr_equal(st->dt2->schema->module->ctx, st->ctx2);
112 }
113
114 static void
test_dup_to_ctx_bits(void ** state)115 test_dup_to_ctx_bits(void **state)
116 {
117 struct state *st = (*state);
118 const struct lys_module *mod;
119 const char *sch = "module x {"
120 " namespace urn:x;"
121 " prefix x;"
122 " typedef mybits { type bits {"
123 " bit disable;"
124 " bit enable; } }"
125 " leaf x { type mybits; }}";
126 const char *data = "<x xmlns=\"urn:x\">enable</x>";
127 char *printed = NULL;
128
129 mod = lys_parse_mem(st->ctx1, sch, LYS_IN_YANG);
130 assert_ptr_not_equal(mod, NULL);
131 mod = lys_parse_mem(st->ctx2, sch, LYS_IN_YANG);
132 assert_ptr_not_equal(mod, NULL);
133
134 st->dt1 = lyd_parse_mem(st->ctx1, data, LYD_XML, LYD_OPT_CONFIG);
135 assert_ptr_not_equal(st->dt1, NULL);
136
137 st->dt2 = lyd_dup_to_ctx(st->dt1, 1, st->ctx2);
138 assert_ptr_not_equal(st->dt2, NULL);
139 /* the values are the same, but they are stored in different contexts */
140 assert_string_equal(((struct lyd_node_leaf_list *)st->dt1)->value_str,
141 ((struct lyd_node_leaf_list *)st->dt2)->value_str);
142 assert_ptr_not_equal(((struct lyd_node_leaf_list *)st->dt1)->value_str,
143 ((struct lyd_node_leaf_list *)st->dt2)->value_str);
144 /* check the value data */
145 assert_ptr_not_equal(((struct lyd_node_leaf_list *)st->dt1)->value.bit,
146 ((struct lyd_node_leaf_list *)st->dt2)->value.bit);
147 assert_ptr_not_equal(((struct lyd_node_leaf_list *)st->dt1)->value.bit[1],
148 ((struct lyd_node_leaf_list *)st->dt2)->value.bit[1]);
149 /* first bit is not set, so the value pointer is NULL in both cases */
150 assert_ptr_equal(((struct lyd_node_leaf_list *)st->dt1)->value.bit[0], NULL);
151 assert_ptr_equal(((struct lyd_node_leaf_list *)st->dt2)->value.bit[0], NULL);
152 /* and the schema nodes are the same, but comes from a different contexts */
153 assert_int_equal(st->dt1->schema->nodetype, st->dt2->schema->nodetype);
154 assert_string_equal(st->dt1->schema->name, st->dt2->schema->name);
155 assert_string_equal(st->dt1->schema->module->name, st->dt2->schema->module->name);
156 assert_ptr_equal(st->dt1->schema->module->ctx, st->ctx1);
157 assert_ptr_equal(st->dt2->schema->module->ctx, st->ctx2);
158
159 /* valgrind test - remove the first context and the access the duplicated data
160 * supposed to be in the second context */
161 lyd_free(st->dt1);
162 ly_ctx_destroy(st->ctx1, NULL);
163 st->dt1 = NULL;
164 st->ctx1 = NULL;
165
166 lyd_print_mem(&printed, st->dt2, LYD_XML, 0);
167 assert_string_equal(printed, data);
168
169 free(printed);
170 }
171
172 static void
test_dup_to_ctx_leafrefs(void ** state)173 test_dup_to_ctx_leafrefs(void **state)
174 {
175 struct state *st = (*state);
176 const struct lys_module *mod;
177 const char *sch = "module x {"
178 " namespace urn:x;"
179 " prefix x;"
180 " container x {"
181 " leaf a { type string; }"
182 " leaf b { type leafref { path ../a; } } } }";
183 const char *data = "<x xmlns=\"urn:x\"><b>hello</b><a>hello</a></x>";
184 char *printed = NULL;
185
186 mod = lys_parse_mem(st->ctx1, sch, LYS_IN_YANG);
187 assert_ptr_not_equal(mod, NULL);
188 mod = lys_parse_mem(st->ctx2, sch, LYS_IN_YANG);
189 assert_ptr_not_equal(mod, NULL);
190
191 st->dt1 = lyd_parse_mem(st->ctx1, data, LYD_XML, LYD_OPT_CONFIG);
192 assert_ptr_not_equal(st->dt1, NULL);
193
194 st->dt2 = lyd_dup_to_ctx(st->dt1, 1, st->ctx2);
195 assert_ptr_not_equal(st->dt2, NULL);
196
197 /* the result is not valid - the leafref is not resolved */
198 assert_int_not_equal(((struct lyd_node_leaf_list *)st->dt2->child)->value_type, LY_TYPE_LEAFREF);
199 assert_int_equal(lyd_validate(&st->dt2, LYD_OPT_CONFIG, st->ctx2), 0);
200 assert_ptr_equal(((struct lyd_node_leaf_list *)st->dt2->child)->value_type, LY_TYPE_LEAFREF);
201
202 /* the values are the same, but they are stored in different contexts */
203 assert_string_equal(((struct lyd_node_leaf_list *)st->dt1->child)->value_str,
204 ((struct lyd_node_leaf_list *)st->dt2->child)->value_str);
205 assert_ptr_not_equal(((struct lyd_node_leaf_list *)st->dt1->child)->value_str,
206 ((struct lyd_node_leaf_list *)st->dt2->child)->value_str);
207 /* check the value data */
208 assert_ptr_not_equal(((struct lyd_node_leaf_list *)st->dt1->child)->value.leafref,
209 ((struct lyd_node_leaf_list *)st->dt2->child)->value.leafref);
210 /* and the schema nodes are the same, but comes from a different contexts */
211 assert_int_equal(st->dt1->child->schema->nodetype, st->dt2->child->schema->nodetype);
212 assert_string_equal(st->dt1->child->schema->name, st->dt2->child->schema->name);
213 assert_string_equal(st->dt1->child->schema->module->name, st->dt2->child->schema->module->name);
214 assert_ptr_equal(st->dt1->child->schema->module->ctx, st->ctx1);
215 assert_ptr_equal(st->dt2->child->schema->module->ctx, st->ctx2);
216
217 /* valgrind test - remove the first context and the access the duplicated data
218 * supposed to be in the second context */
219 lyd_free(st->dt1);
220 ly_ctx_destroy(st->ctx1, NULL);
221 st->dt1 = NULL;
222 st->ctx1 = NULL;
223
224 lyd_print_mem(&printed, st->dt2, LYD_XML, 0);
225 assert_string_equal(printed, data);
226
227 free(printed);
228 }
229
main(void)230 int main(void)
231 {
232 const struct CMUnitTest tests[] = {
233 cmocka_unit_test_setup_teardown(test_dup_to_ctx, setup_f, teardown_f),
234 cmocka_unit_test_setup_teardown(test_dup_to_ctx_bits, setup_f, teardown_f),
235 cmocka_unit_test_setup_teardown(test_dup_to_ctx_leafrefs, setup_f, teardown_f),};
236
237 return cmocka_run_group_tests(tests, NULL, NULL);
238 }
239