summaryrefslogtreecommitdiffstats
path: root/tests/utests/data/test_printer_xml.c
blob: d533c41c7a9f097dd48a6ec77fdf1fe6716b063a (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
/*
 * @file test_printer_xml.c
 * @author: Radek Krejci <rkrejci@cesnet.cz>
 * @brief unit tests for functions from printer_yang.c
 *
 * Copyright (c) 2019-2020 CESNET, z.s.p.o.
 *
 * This source code is licensed under BSD 3-Clause License (the "License").
 * You may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     https://opensource.org/licenses/BSD-3-Clause
 */
#define _UTEST_MAIN_
#include "utests.h"

#include <string.h>

#include "context.h"
#include "out.h"
#include "parser_data.h"
#include "printer_data.h"
#include "tests_config.h"
#include "tree_schema.h"

static int
setup(void **state)
{
    const char *schema_defs = "module defs {namespace urn:tests:defs;prefix d;yang-version 1.1;"
            "identity crypto-alg; identity interface-type; identity ethernet {base interface-type;} identity fast-ethernet {base ethernet;}}";
    const char *schema_types = "module types {namespace urn:tests:types;prefix t;yang-version 1.1; import defs {prefix defs;}"
            "feature f; identity gigabit-ethernet { base defs:ethernet;}"
            "container cont {leaf leaftarget {type empty;}"
            "    list listtarget {key id; max-elements 5;leaf id {type uint8;} leaf value {type string;}"
            "        action test {input {leaf a {type string;}} output {leaf b {type string;}}}}"
            "    leaf-list leaflisttarget {type uint8; max-elements 5;}}"
            "list list {key id; leaf id {type string;} leaf value {type string;} leaf-list targets {type string;}}"
            "list list2 {key \"id value\"; leaf id {type string;} leaf value {type string;}}"
            "list list_inst {key id; leaf id {type instance-identifier {require-instance true;}} leaf value {type string;}}"
            "list list_ident {key id; leaf id {type identityref {base defs:interface-type;}} leaf value {type string;}}"
            "leaf-list leaflisttarget {type string;}"
            "leaf binary {type binary {length 5 {error-message \"This base64 value must be of length 5.\";}}}"
            "leaf binary-norestr {type binary;}"
            "leaf int8 {type int8 {range 10..20;}}"
            "leaf uint8 {type uint8 {range 150..200;}}"
            "leaf int16 {type int16 {range -20..-10;}}"
            "leaf uint16 {type uint16 {range 150..200;}}"
            "leaf int32 {type int32;}"
            "leaf uint32 {type uint32;}"
            "leaf int64 {type int64;}"
            "leaf uint64 {type uint64;}"
            "leaf bits {type bits {bit zero; bit one {if-feature f;} bit two;}}"
            "leaf enums {type enumeration {enum white; enum yellow {if-feature f;}}}"
            "leaf dec64 {type decimal64 {fraction-digits 1; range 1.5..10;}}"
            "leaf dec64-norestr {type decimal64 {fraction-digits 18;}}"
            "leaf str {type string {length 8..10; pattern '[a-z ]*';}}"
            "leaf str-norestr {type string;}"
            "leaf bool {type boolean;}"
            "leaf empty {type empty;}"
            "leaf ident {type identityref {base defs:interface-type;}}"
            "leaf inst {type instance-identifier {require-instance true;}}"
            "leaf inst-noreq {type instance-identifier {require-instance false;}}"
            "leaf lref {type leafref {path /leaflisttarget; require-instance true;}}"
            "leaf lref2 {type leafref {path \"../list[id = current()/../str-norestr]/targets\"; require-instance true;}}"
            "leaf un1 {type union {"
            "    type leafref {path /int8; require-instance true;}"
            "    type union { type identityref {base defs:interface-type;} type instance-identifier {require-instance true;} }"
            "    type string {length 1..20;}}}"
            "anydata any;"
            "rpc sum {input {leaf x {type uint8;} leaf y {type uint8;}} output {leaf result {type uint16;}}}}";
    const char *schema_defaults =
            "module defaults {\n"
            "    namespace \"urn:defaults\";\n"
            "    prefix d;\n"
            "    leaf a {\n"
            "        type union {\n"
            "            type instance-identifier;\n"
            "            type string;\n"
            "        }\n"
            "        default \"/d:b\";\n"
            "    }\n"
            "    leaf b {\n"
            "        type string;\n"
            "    }\n"
            "    leaf c {\n"
            "        type string;\n"
            "    }\n"
            "}";

    UTEST_SETUP;

    UTEST_ADD_MODULE(schema_defs, LYS_IN_YANG, NULL, NULL);
    UTEST_ADD_MODULE(schema_types, LYS_IN_YANG, NULL, NULL);
    UTEST_ADD_MODULE(schema_defaults, LYS_IN_YANG, NULL, NULL);

    return 0;
}

#define CHECK_PARSE_LYD(INPUT, PARSE_OPTION, VALIDATE_OPTION, TREE) \
    CHECK_PARSE_LYD_PARAM(INPUT, LYD_XML, PARSE_OPTION, VALIDATE_OPTION, LY_SUCCESS, TREE)

#define CHECK_LYD_STRING(IN_MODEL, PRINT_OPTION, TEXT) \
    CHECK_LYD_STRING_PARAM(IN_MODEL, TEXT, LYD_XML, PRINT_OPTION)

static void
test_anydata(void **state)
{
    struct lyd_node *tree;
    const char *data;

    data = "<any xmlns=\"urn:tests:types\"><somexml xmlns:x=\"url:x\" xmlns=\"example.com\"><x:x/></somexml></any>";
    CHECK_PARSE_LYD(data, 0, LYD_VALIDATE_PRESENT, tree);
    /* canonized */
    data = "<any xmlns=\"urn:tests:types\"><somexml xmlns=\"example.com\"><x xmlns=\"url:x\"/></somexml></any>";
    CHECK_LYD_STRING(tree, LYD_PRINT_SHRINK | LYD_PRINT_WITHSIBLINGS, data);
    lyd_free_all(tree);

    data = "<any xmlns=\"urn:tests:types\"/>";
    CHECK_PARSE_LYD(data, 0, LYD_VALIDATE_PRESENT, tree);
    CHECK_LYD_STRING(tree, LYD_PRINT_SHRINK | LYD_PRINT_WITHSIBLINGS, data);
    lyd_free_all(tree);

    data = "<any xmlns=\"urn:tests:types\">\n"
            "  <cont>\n"
            "    <defs:elem1 xmlns:defs=\"urn:tests:defs\">\n"
            "      <elem2 xmlns:defaults=\"urn:defaults\" defs:attr1=\"defaults:val\" attr2=\"/defaults:node/defs:node2\">\n"
            "      </elem2>\n"
            "    </defs:elem1>\n"
            "  </cont>\n"
            "</any>\n";
    CHECK_PARSE_LYD(data, 0, LYD_VALIDATE_PRESENT, tree);
    assert_non_null(tree);
    tree = tree->next;
    /* cont should be normally parsed */
    CHECK_LYSC_NODE(tree->schema, NULL, 0, LYS_CONFIG_W | LYS_STATUS_CURR, 1, "any", 0, LYS_ANYDATA, 0, 0, NULL, 0);
    CHECK_LYD_NODE_ANY((struct lyd_node_any *)tree, 0, 0, 0, LYD_ANYDATA_DATATREE);
    struct lyd_node *tree_tmp = ((struct lyd_node_any *)tree)->value.tree;

    CHECK_LYSC_NODE(tree_tmp->schema, NULL, 0, LYS_CONFIG_W | LYS_STATUS_CURR, 1, "cont", 1, LYS_CONTAINER, 0, 0, NULL, 0);
    /* but its children not */
    assert_null(((struct lyd_node_inner *)tree_tmp)->child->schema);
    /* canonized */
    data =
            "<any xmlns=\"urn:tests:types\">\n"
            "  <cont>\n"
            "    <elem1 xmlns=\"urn:tests:defs\">\n"
            "      <elem2 xmlns=\"urn:tests:types\" xmlns:defs=\"urn:tests:defs\" xmlns:defaults=\"urn:defaults\" "
            "defs:attr1=\"defaults:val\" attr2=\"/defaults:node/defs:node2\"/>\n"
            "    </elem1>\n"
            "  </cont>\n"
            "</any>\n";
    CHECK_LYD_STRING(tree, LYD_PRINT_WITHSIBLINGS, data);
    lyd_free_all(tree);

    data = "<any xmlns=\"urn:tests:types\">\n"
            "  <ahoj attr=\"&lt;test\">\n"
            "       ahoj jak se vede &lt; how are you"
            "  </ahoj>\n"
            "</any>\n";
    CHECK_PARSE_LYD(data, 0, LYD_VALIDATE_PRESENT, tree);
    CHECK_LYD_STRING(tree, LYD_PRINT_WITHSIBLINGS, data);
    lyd_free_all(tree);

    data = "<any xmlns=\"urn:tests:types\">\n"
            "  <leaflisttarget> ahoj   </leaflisttarget>\n"
            "  <leaflisttarget> nazdar </leaflisttarget>\n"
            "  <leaflisttarget> Čau    </leaflisttarget>\n"
            "</any>\n";
    CHECK_PARSE_LYD(data, 0, LYD_VALIDATE_PRESENT, tree);
    CHECK_LYD_STRING(tree, LYD_PRINT_WITHSIBLINGS, data);
    lyd_free_all(tree);

    data = "<any xmlns=\"urn:tests:types\">\n"
            "  <cont2/>\n"
            "</any>\n";
    CHECK_PARSE_LYD(data, 0, LYD_VALIDATE_PRESENT, tree);
    CHECK_LYD_STRING(tree, LYD_PRINT_WITHSIBLINGS, data);
    lyd_free_all(tree);

    data = "<any xmlns=\"urn:tests:types\">\n"
            "  <cont>\n"
            "        &lt; how are you"
            "  </cont>\n"
            "</any>\n";
    CHECK_PARSE_LYD(data, 0, LYD_VALIDATE_PRESENT, tree);
    CHECK_LYD_STRING(tree, LYD_PRINT_WITHSIBLINGS, data);
    lyd_free_all(tree);
}

static void
test_defaults(void **state)
{
    struct lyd_node *tree;
    const char *data;
    const char *data_trim;
    const char *data_all;
    const char *data_all_tag;
    const char *data_impl_tag;

    assert_int_equal(LY_SUCCESS, ly_ctx_set_searchdir(UTEST_LYCTX, TESTS_DIR_MODULES_YANG));
    assert_non_null(ly_ctx_load_module(UTEST_LYCTX, "ietf-netconf-with-defaults", "2011-06-01", NULL));

    /* standard default value */
    data = "<c xmlns=\"urn:defaults\">aa</c>";
    CHECK_PARSE_LYD(data, 0, LYD_VALIDATE_PRESENT, tree);
    CHECK_LYD_STRING(tree, LYD_PRINT_WD_TRIM | LYD_PRINT_SHRINK | LYD_PRINT_WITHSIBLINGS, data);

    data = "<a xmlns=\"urn:defaults\" xmlns:d=\"urn:defaults\">/d:b</a><c xmlns=\"urn:defaults\">aa</c>";
    CHECK_LYD_STRING(tree, LYD_PRINT_WD_ALL | LYD_PRINT_SHRINK | LYD_PRINT_WITHSIBLINGS, data);

    data = "<a xmlns=\"urn:defaults\" xmlns:ncwd=\"urn:ietf:params:xml:ns:yang:ietf-netconf-with-defaults\""
            " ncwd:default=\"true\" xmlns:d=\"urn:defaults\">/d:b</a>"
            "<c xmlns=\"urn:defaults\">aa</c>";
    CHECK_LYD_STRING(tree, LYD_PRINT_WD_ALL_TAG | LYD_PRINT_SHRINK | LYD_PRINT_WITHSIBLINGS, data);

    data = "<a xmlns=\"urn:defaults\" xmlns:ncwd=\"urn:ietf:params:xml:ns:yang:ietf-netconf-with-defaults\""
            " ncwd:default=\"true\" xmlns:d=\"urn:defaults\">/d:b</a>"
            "<c xmlns=\"urn:defaults\">aa</c>";
    CHECK_LYD_STRING(tree, LYD_PRINT_WD_IMPL_TAG | LYD_PRINT_SHRINK | LYD_PRINT_WITHSIBLINGS, data);
    lyd_free_all(tree);

    /* string value equal to the default but default is an unresolved instance-identifier, so they are not considered equal */
    data = "<a xmlns=\"urn:defaults\">/d:b</a><c xmlns=\"urn:defaults\">aa</c>";
    CHECK_PARSE_LYD(data, 0, LYD_VALIDATE_PRESENT, tree);
    CHECK_LYD_STRING(tree, LYD_PRINT_WD_TRIM | LYD_PRINT_SHRINK | LYD_PRINT_WITHSIBLINGS, data);
    CHECK_LYD_STRING(tree, LYD_PRINT_WD_ALL | LYD_PRINT_SHRINK | LYD_PRINT_WITHSIBLINGS, data);
    CHECK_LYD_STRING(tree, LYD_PRINT_WD_ALL_TAG | LYD_PRINT_SHRINK | LYD_PRINT_WITHSIBLINGS, data);
    CHECK_LYD_STRING(tree, LYD_PRINT_WD_IMPL_TAG | LYD_PRINT_SHRINK | LYD_PRINT_WITHSIBLINGS, data);
    lyd_free_all(tree);

    /* instance-identifier value equal to the default, should be considered equal */
    data = "<a xmlns=\"urn:defaults\" xmlns:d=\"urn:defaults\">/d:b</a><b xmlns=\"urn:defaults\">val</b><c xmlns=\"urn:defaults\">aa</c>";
    data_trim = "<b xmlns=\"urn:defaults\">val</b><c xmlns=\"urn:defaults\">aa</c>";
    data_all = "<a xmlns=\"urn:defaults\" xmlns:d=\"urn:defaults\">/d:b</a><b xmlns=\"urn:defaults\">val</b><c xmlns=\"urn:defaults\">aa</c>";
    data_all_tag = "<a xmlns=\"urn:defaults\" xmlns:ncwd=\"urn:ietf:params:xml:ns:yang:ietf-netconf-with-defaults\""
            " ncwd:default=\"true\" xmlns:d=\"urn:defaults\">/d:b</a>"
            "<b xmlns=\"urn:defaults\">val</b>"
            "<c xmlns=\"urn:defaults\">aa</c>";
    data_impl_tag = "<a xmlns=\"urn:defaults\" xmlns:d=\"urn:defaults\">/d:b</a><b xmlns=\"urn:defaults\">val</b><c xmlns=\"urn:defaults\">aa</c>";

    CHECK_PARSE_LYD(data, 0, LYD_VALIDATE_PRESENT, tree);
    CHECK_LYD_STRING(tree, LYD_PRINT_WD_TRIM | LYD_PRINT_SHRINK | LYD_PRINT_WITHSIBLINGS, data_trim);
    CHECK_LYD_STRING(tree, LYD_PRINT_WD_ALL | LYD_PRINT_SHRINK | LYD_PRINT_WITHSIBLINGS, data_all);
    CHECK_LYD_STRING(tree, LYD_PRINT_WD_ALL_TAG | LYD_PRINT_SHRINK | LYD_PRINT_WITHSIBLINGS, data_all_tag);
    CHECK_LYD_STRING(tree, LYD_PRINT_WD_IMPL_TAG | LYD_PRINT_SHRINK | LYD_PRINT_WITHSIBLINGS, data_impl_tag);
    lyd_free_all(tree);
}

#if 0

static void
test_rpc(void **state)
{
    struct state_s *s = (struct state_s *)(*state);
    struct lyd_node *tree1;
    struct lyd_node *tree2;
    const struct lyd_node **trees;
    const char *request;
    const char *reply, *result;
    char *printed;
    ssize_t len;
    struct ly_out *out;

    s->func = test_rpc;
    assert_non_null(out = ly_out_new_memory(&printed, 0));

    request = "<sum xmlns=\"urn:tests:types\"><x>10</x><y>20</y></sum>";
    reply = "<result xmlns=\"urn:tests:types\">30</result>";
    result = "<sum xmlns=\"urn:tests:types\"><result>30</result></sum>";
    assert_non_null(tree1 = lyd_parse_mem(s->ctx, request, LYD_XML, LYD_OPT_RPC, NULL));
    assert_true((len = lyd_print_tree(out, tree1, LYD_XML, LYD_PRINT_SHRINK)) >= 0);
    assert_int_equal(len, strlen(printed));
    assert_string_equal(printed, request);
    ly_out_reset(out);
    assert_non_null(trees = lyd_trees_new(1, tree1));
    assert_non_null(tree2 = lyd_parse_mem(s->ctx, reply, LYD_XML, LYD_OPT_RPCREPLY, trees));
    assert_true((len = lyd_print_tree(out, tree2, LYD_XML, LYD_PRINT_SHRINK)) >= 0);
    assert_int_equal(len, strlen(printed));
    assert_string_equal(printed, result);
    ly_out_reset(out);
    lyd_trees_free(trees, 0);
    lyd_free_all(tree1);
    lyd_free_all(tree2);

    /* no arguments */
    request = "<sum xmlns=\"urn:tests:types\"/>";
    reply = "";
    result = "<sum xmlns=\"urn:tests:types\"/>";
    assert_non_null(tree1 = lyd_parse_mem(s->ctx, request, LYD_XML, LYD_OPT_RPC, NULL));
    assert_true((len = lyd_print_tree(out, tree1, LYD_XML, LYD_PRINT_SHRINK)) >= 0);
    assert_int_equal(len, strlen(printed));
    assert_string_equal(printed, request);
    ly_out_reset(out);
    assert_non_null(trees = lyd_trees_new(1, tree1));
    assert_non_null(tree2 = lyd_parse_mem(s->ctx, reply, LYD_XML, LYD_OPT_RPCREPLY, trees));
    assert_true((len = lyd_print_tree(out, tree2, LYD_XML, LYD_PRINT_SHRINK)) >= 0);
    assert_int_equal(len, strlen(printed));
    assert_string_equal(printed, result);
    ly_out_reset(out);
    lyd_trees_free(trees, 0);
    lyd_free_all(tree1);
    lyd_free_all(tree2);

    /* action
     * "container cont {leaf leaftarget {type empty;}"
                            "list listtarget {key id; max-elements 5;leaf id {type uint8;} leaf value {type string;}"
                                             "action test {input {leaf a {type string;}} output {leaf b {type string;}}}}"
                            "leaf-list leaflisttarget {type uint8; max-elements 5;}}"
                            */
    request = "<cont xmlns=\"urn:tests:types\"><listtarget><id>10</id><test><a>test</a></test></listtarget></cont>";
    reply = "<b xmlns=\"urn:tests:types\">test-reply</b>";
    result = "<cont xmlns=\"urn:tests:types\"><listtarget><id>10</id><test><b>test-reply</b></test></listtarget></cont>";
    assert_non_null(tree1 = lyd_parse_mem(s->ctx, request, LYD_XML, LYD_OPT_RPC, NULL));
    assert_true((len = lyd_print_tree(out, tree1, LYD_XML, LYD_PRINT_SHRINK)) >= 0);
    assert_int_equal(len, strlen(printed));
    assert_string_equal(printed, request);
    ly_out_reset(out);
    assert_non_null(trees = lyd_trees_new(1, tree1));
    assert_non_null(tree2 = lyd_parse_mem(s->ctx, reply, LYD_XML, LYD_OPT_RPCREPLY, trees));
    assert_true((len = lyd_print_tree(out, tree2, LYD_XML, LYD_PRINT_SHRINK)) >= 0);
    assert_int_equal(len, strlen(printed));
    assert_string_equal(printed, result);
    ly_out_reset(out);
    lyd_trees_free(trees, 0);
    lyd_free_all(tree1);
    lyd_free_all(tree2);

    ly_out_free(out, NULL, 1);
    s->func = NULL;
}

#endif

int
main(void)
{
    const struct CMUnitTest tests[] = {
        UTEST(test_anydata, setup),
        UTEST(test_defaults, setup),
    };

    return cmocka_run_group_tests(tests, NULL, NULL);
}