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