1 /**
2  * @file test_sec9_10.c
3  * @author Pavol Vican
4  * @brief Cmocka test for RFC 6020 section 9.10 conformance.
5  *
6  * Copyright (c) 2016 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 <stdio.h>
16 #include <stdlib.h>
17 #include <setjmp.h>
18 #include <errno.h>
19 #include <unistd.h>
20 #include <stdarg.h>
21 #include <cmocka.h>
22 #include <string.h>
23 #include <sys/wait.h>
24 
25 #include "tests/config.h"
26 #include "libyang.h"
27 
28 #define TEST_DIR "sec9_10"
29 #define TEST_NAME test_sec9_10
30 #define TEST_SCHEMA_COUNT 3
31 #define TEST_SCHEMA_LOAD_FAIL 1,1,0
32 #define TEST_DATA_FILE_COUNT 6
33 #define TEST_DATA_FILE_LOAD_FAIL 1,1,0,1,0,1
34 
35 struct state {
36     struct ly_ctx *ctx;
37     struct lyd_node *node;
38 };
39 
40 static int
setup_f(void ** state)41 setup_f(void **state)
42 {
43     struct state *st;
44 
45     (*state) = st = calloc(1, sizeof *st);
46     if (!st) {
47         fprintf(stderr, "Memory allocation error");
48         return -1;
49     }
50 
51     /* libyang context */
52     st->ctx = ly_ctx_new(TESTS_DIR "/conformance/" TEST_DIR, 0);
53     if (!st->ctx) {
54         fprintf(stderr, "Failed to create context.\n");
55         return -1;
56     }
57 
58     return 0;
59 }
60 
61 static int
teardown_f(void ** state)62 teardown_f(void **state)
63 {
64     struct state *st = (*state);
65 
66     lyd_free_withsiblings(st->node);
67     ly_ctx_destroy(st->ctx, NULL);
68     free(st);
69     (*state) = NULL;
70 
71     return 0;
72 }
73 
74 static void
TEST_IDENTITYREF(void ** state)75 TEST_IDENTITYREF(void **state)
76 {
77     struct state *st = (*state);
78     const int schemas_fail[] = {TEST_SCHEMA_LOAD_FAIL};
79     const int data_files_fail[] = {TEST_DATA_FILE_LOAD_FAIL};
80     char buf[1024];
81     LYS_INFORMAT schema_format = LYS_IN_YANG;
82     const struct lys_module *mod;
83     int i, j, ret;
84 
85     for (i = 0; i < 2; ++i) {
86         for (j = 0; j < TEST_SCHEMA_COUNT; ++j) {
87             sprintf(buf, TESTS_DIR "/conformance/" TEST_DIR "/mod%d.%s", j + 1, (schema_format == LYS_IN_YANG ? "yang" : "yin"));
88             mod = lys_parse_path(st->ctx, buf, schema_format);
89             if (schemas_fail[j]) {
90                 assert_ptr_equal(mod, NULL);
91             } else {
92                 assert_ptr_not_equal(mod, NULL);
93             }
94         }
95 
96         for (j = 0; j < TEST_DATA_FILE_COUNT; ++j) {
97             sprintf(buf, TESTS_DIR "/conformance/" TEST_DIR "/data%d.xml", j + 1);
98             st->node = lyd_parse_path(st->ctx, buf, LYD_XML, LYD_OPT_CONFIG);
99             if (data_files_fail[j]) {
100                 assert_ptr_equal(st->node, NULL);
101             } else {
102                 assert_ptr_not_equal(st->node, NULL);
103             }
104             lyd_free_withsiblings(st->node);
105             st->node = NULL;
106         }
107 
108         if (schema_format == LYS_IN_YANG) {
109             /* convert the modules */
110             for (j = 0; j < TEST_SCHEMA_COUNT; ++j) {
111                 sprintf(buf, BUILD_DIR "/yang2yin "
112                              TESTS_DIR "/conformance/" TEST_DIR "/mod%d.yang "
113                              TESTS_DIR "/conformance/" TEST_DIR "/mod%d.yin", j + 1, j + 1);
114                 ret = system(buf);
115                 if (ret == -1) {
116                     fprintf(stderr, "system() failed (%s).\n", strerror(errno));
117                     fail();
118                 } else if (WEXITSTATUS(ret) != 0) {
119                     fprintf(stderr, "Executing command \"%s\" finished with %d.\n", buf, WEXITSTATUS(ret));
120                     fail();
121                 }
122             }
123 
124             schema_format = LYS_IN_YIN;
125             ly_ctx_destroy(st->ctx, NULL);
126             st->ctx = ly_ctx_new(TESTS_DIR "/conformance/" TEST_DIR, 0);
127             if (!st->ctx) {
128                 fprintf(stderr, "Failed to create context.\n");
129                 fail();
130             }
131         } else {
132             /* remove the modules */
133             for (j = 0; j < TEST_SCHEMA_COUNT; ++j) {
134                 sprintf(buf, TESTS_DIR "/conformance/" TEST_DIR "/mod%d.yin", j + 1);
135                 if (unlink(buf)) {
136                     fprintf(stderr, "unlink() on \"%s\" failed (%s).\n", buf, strerror(errno));
137                 }
138             }
139         }
140     }
141 }
142 
143 /* in data6.xml we have value defined in mod.yang which is just imported in previous test and
144  * the data are not valid. Here, mod.yang is loaded as import by mod-dflt.yang and then explicitly
145  * changed to implemented.
146  */
147 static void
TEST_IDENTITYREF2(void ** state)148 TEST_IDENTITYREF2(void **state)
149 {
150     struct state *st = (*state);
151     const struct lys_module *mod;
152     const char *middle_data = "<test xmlns=\"urn:cesnet:mod3\" xmlns:mm=\"urn:cesnet:mod-middle\">mm:j4</test>";
153 
154     /* mod is imported */
155     mod = lys_parse_path(st->ctx, TESTS_DIR "/conformance/" TEST_DIR "/mod3.yang", LYS_IN_YANG);
156     assert_ptr_not_equal(mod, NULL);
157 
158     /* invalid identityref value from not-implemented schema */
159     st->node = lyd_parse_path(st->ctx, TESTS_DIR "/conformance/" TEST_DIR "/data6.xml", LYD_XML, LYD_OPT_CONFIG);
160     assert_ptr_equal(st->node, NULL);
161 
162     mod = lys_parse_path(st->ctx, TESTS_DIR "/conformance/" TEST_DIR "/mod-dflt-invalid.yang", LYS_IN_YANG);
163     assert_ptr_equal(mod, NULL);
164 
165     mod = lys_parse_path(st->ctx, TESTS_DIR "/conformance/" TEST_DIR "/mod-dflt.yang", LYS_IN_YANG);
166     assert_ptr_not_equal(mod, NULL);
167 
168     /* set mod to be implemented */
169     mod = ly_ctx_get_module(st->ctx, "mod", NULL, 0);
170     assert_int_equal(lys_set_implemented(mod), 0);
171 
172     /* mod is implemented so the identityref value is valid here */
173     st->node = lyd_parse_path(st->ctx, TESTS_DIR "/conformance/" TEST_DIR "/data6.xml", LYD_XML, LYD_OPT_CONFIG);
174     assert_ptr_not_equal(st->node, NULL);
175     lyd_free_withsiblings(st->node);
176 
177     /* but mod-middle is still not implemented, so mod-middle:j1 value is invalid */
178     st->node = lyd_parse_mem(st->ctx, middle_data, LYD_XML, LYD_OPT_CONFIG);
179     assert_ptr_equal(st->node, NULL);
180 
181     /* but making it implemented the data can be loaded */
182     assert_int_equal(lys_set_implemented(ly_ctx_get_module(st->ctx, "mod-middle", NULL, 0)), 0);
183     st->node = lyd_parse_mem(st->ctx, middle_data, LYD_XML, LYD_OPT_CONFIG);
184     assert_ptr_not_equal(st->node, NULL);
185 }
186 
187 int
main(void)188 main(void)
189 {
190     const struct CMUnitTest tests[] = {
191         cmocka_unit_test_setup_teardown(TEST_IDENTITYREF, setup_f, teardown_f),
192         cmocka_unit_test_setup_teardown(TEST_IDENTITYREF2, setup_f, teardown_f),
193     };
194 
195     return cmocka_run_group_tests(tests, NULL, NULL);
196 }
197