1 /* Copyright (C) 2019 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
2
3 This program is free software: you can redistribute it and/or modify
4 it under the terms of the GNU General Public License as published by
5 the Free Software Foundation, either version 3 of the License, or
6 (at your option) any later version.
7
8 This program is distributed in the hope that it will be useful,
9 but WITHOUT ANY WARRANTY; without even the implied warranty of
10 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 GNU General Public License for more details.
12
13 You should have received a copy of the GNU General Public License
14 along with this program. If not, see <https://www.gnu.org/licenses/>.
15 */
16
17 #include <stdlib.h>
18 #include <stdint.h>
19 #include <string.h>
20 #include <tap/basic.h>
21
22 #include "libknot/yparser/ypschema.h"
23 #include "libknot/yparser/yptrafo.h"
24 #include "libknot/libknot.h"
25
26 #define C_ID "\x02""id"
27 #define C_INT "\x07""integer"
28 #define C_BOOL "\x04""bool"
29 #define C_OPT "\x06""option"
30 #define C_STR "\x06""string"
31 #define C_ADDR "\x07""address"
32 #define C_DNAME "\x05""dname"
33 #define C_HEX "\x03""hex"
34 #define C_BASE64 "\x06""base64"
35 #define C_DATA "\x04""data"
36 #define C_REF "\x09""reference"
37 #define C_GRP "\x05""group"
38 #define C_MULTIGRP "\x0B""multi-group"
39
40 static const yp_item_t group[] = {
41 { C_INT, YP_TINT, YP_VINT = { 0, 100, YP_NIL } },
42 { C_STR, YP_TSTR, YP_VNONE, YP_FMULTI },
43 { NULL }
44 };
45
46 static const yp_item_t multi_group[] = {
47 { C_ID, YP_TSTR, YP_VNONE },
48 { C_HEX, YP_THEX, YP_VNONE },
49 { C_BASE64, YP_TB64, YP_VNONE },
50 { NULL }
51 };
52
53 static const knot_lookup_t opts[] = {
54 { 1, "one" },
55 { 10, "ten" },
56 { 0, NULL }
57 };
58
59 static const yp_item_t static_schema[] = {
60 { C_OPT, YP_TOPT, YP_VOPT = { opts } },
61 { C_BOOL, YP_TBOOL, YP_VNONE },
62 { C_DNAME, YP_TDNAME, YP_VNONE },
63 { C_GRP, YP_TGRP, YP_VGRP = { group } },
64 { C_MULTIGRP, YP_TGRP, YP_VGRP = { multi_group }, YP_FMULTI },
65 { C_REF, YP_TREF, YP_VREF = { C_MULTIGRP } },
66 { C_DATA, YP_TDATA, YP_VNONE },
67 { NULL }
68 };
69
schema_find_test(void)70 static void schema_find_test(void)
71 {
72 yp_item_t *schema = NULL;
73
74 int ret = yp_schema_copy(&schema, static_schema);
75 is_int(KNOT_EOK, ret, "schema copy");
76
77 const yp_item_t *i = yp_schema_find(C_OPT, NULL, schema);
78 ok(i != NULL, "schema find");
79 if (i == NULL) {
80 goto error_schema;
81 }
82 ok(strcmp(&i->name[1], &C_OPT[1]) == 0, "name check");
83
84 i = yp_schema_find(C_STR, C_GRP, schema);
85 ok(i != NULL, "schema find with parent");
86 if (i == NULL) {
87 goto error_schema;
88 }
89 ok(strcmp(&i->name[1], &C_STR[1]) == 0, "name check");
90
91 i = yp_schema_find(C_ADDR, NULL, schema);
92 ok(i == NULL, "schema not find");
93
94 i = yp_schema_find(C_ADDR, C_GRP, schema);
95 ok(i == NULL, "schema not find with parent");
96
97 error_schema:
98 yp_schema_free(schema);
99 }
100
schema_merge_test(void)101 static void schema_merge_test(void)
102 {
103 static const yp_item_t items1[] = {
104 { "\x01""1", YP_TSTR, YP_VNONE },
105 { "\x01""2", YP_TSTR, YP_VNONE },
106 { NULL }
107 };
108
109 static const yp_item_t items2[] = {
110 { "\x01""3", YP_TSTR, YP_VNONE },
111 { "\x01""4", YP_TSTR, YP_VNONE },
112 { NULL }
113 };
114
115 yp_item_t *schema = NULL;
116 yp_item_t *tmp = NULL;
117
118 int ret = yp_schema_copy(&tmp, items1);
119 is_int(KNOT_EOK, ret, "schema copy");
120
121 ret = yp_schema_merge(&schema, items1, items2);
122 is_int(KNOT_EOK, ret, "schema merge");
123
124 yp_schema_free(tmp);
125
126 for (uint8_t i = 0; i < 4; i++) {
127 yp_name_t name[3] = { '\x01', '1' + i };
128 const yp_item_t *item = yp_schema_find(name, NULL, schema);
129 ok(item != NULL, "schema find");
130 }
131
132 yp_schema_free(schema);
133 }
134
135 #define SET_INPUT_STR(str) \
136 ret = yp_set_input_string(yp, str, strlen(str)); \
137 is_int(KNOT_EOK, ret, "set input string");
138
139 #define PARSER_CHECK(depth) \
140 ret = yp_parse(yp); \
141 is_int(KNOT_EOK, ret, "parse"); \
142 ret = yp_schema_check_parser(ctx, yp); \
143 is_int(KNOT_EOK, ret, "check parser"); \
144 node = &ctx->nodes[ctx->current]; \
145 parent = node->parent; \
146 ok(ctx->current == depth, "depth check");
147
148 #define PARSER_RET_CHECK(code) \
149 ret = yp_parse(yp); \
150 is_int(KNOT_EOK, ret, "parse"); \
151 ret = yp_schema_check_parser(ctx, yp); \
152 ok(ret == code, "return check parser");
153
parser_test(void)154 static void parser_test(void)
155 {
156 yp_parser_t yparser;
157 yp_parser_t *yp = &yparser;
158 yp_item_t *schema = NULL;
159 yp_check_ctx_t *ctx = NULL;
160
161 yp_init(yp);
162
163 int ret = yp_schema_copy(&schema, static_schema);
164 is_int(KNOT_EOK, ret, "schema copy");
165 if (ret != KNOT_EOK) {
166 goto error_parser;
167 }
168
169 ctx = yp_schema_check_init(&schema);
170 ok(ctx != NULL, "create check ctx");
171 if (ctx == NULL) {
172 goto error_parser;
173 }
174
175 yp_node_t *node;
176 yp_node_t *parent;
177 const yp_item_t *id;
178
179 diag("parser key0 test");
180 SET_INPUT_STR("option: one");
181 PARSER_CHECK(0);
182 ok(strcmp(node->item->name + 1, "option") == 0, "name check");
183 ok(node->item->type == YP_TOPT, "type check");
184 ok(yp_opt(node->data) == 1, "value check");
185
186 diag("parser group test");
187 SET_INPUT_STR("group:\n integer: 20\n string: [short, \"long string\"]");
188 PARSER_CHECK(0);
189 ok(strcmp(node->item->name + 1, "group") == 0, "name check");
190 ok(node->item->type == YP_TGRP, "type check");
191 ok(node->data_len == 0, "value length check");
192 PARSER_CHECK(1);
193 ok(strcmp(node->item->name + 1, "integer") == 0, "name check");
194 ok(node->item->type == YP_TINT, "type check");
195 ok(yp_int(node->data) == 20, "value check");
196 PARSER_CHECK(1);
197 ok(strcmp(node->item->name + 1, "string") == 0, "name check");
198 ok(node->item->type == YP_TSTR, "type check");
199 ok(strcmp(yp_str(node->data), "short") == 0, "value check");
200 PARSER_CHECK(1);
201 ok(strcmp(node->item->name + 1, "string") == 0, "name check");
202 ok(node->item->type == YP_TSTR, "type check");
203 ok(strcmp(yp_str(node->data), "long string") == 0, "value check");
204
205 diag("parser multi-group test");
206 SET_INPUT_STR("multi-group:\n - id: foo\n base64: Zm9vYmFy\nreference: foo");
207 PARSER_CHECK(0);
208 ok(strcmp(node->item->name + 1, "multi-group") == 0, "name check");
209 ok(node->item->type == YP_TGRP, "type check");
210 ok(node->data_len == 0, "value length check");
211 PARSER_CHECK(0);
212 ok(node->id_len > 0, "id check");
213 ok(strcmp(node->item->name + 1, "multi-group") == 0, "name check");
214 ok(node->item->type == YP_TGRP, "type check");
215 ok(node->data_len == 0, "value length check");
216 id = node->item->var.g.id;
217 ok(strcmp(id->name + 1, "id") == 0, "name check");
218 ok(id->type == YP_TSTR, "type check");
219 ok(strcmp(yp_str(node->id), "foo") == 0, "value check");
220 PARSER_CHECK(1);
221 id = parent->item->var.g.id;
222 ok(strcmp(parent->item->name + 1, "multi-group") == 0, "name check");
223 ok(parent->item->type == YP_TGRP, "type check");
224 ok(parent->data_len == 0, "value length check");
225 ok(strcmp(yp_str(parent->id), "foo") == 0, "value check");
226 ok(strcmp(id->name + 1, "id") == 0, "name check");
227 ok(id->type == YP_TSTR, "type check");
228 ok(strcmp(node->item->name + 1, "base64") == 0, "name check");
229 ok(node->item->type == YP_TB64, "type check");
230 ok(memcmp(yp_bin(node->data), "foobar", yp_bin_len(node->data)) == 0,
231 "value check");
232 ok(node->id_len == 0, "id length check");
233 PARSER_CHECK(0);
234 ok(strcmp(node->item->name + 1, "reference") == 0, "name check");
235 ok(node->item->type == YP_TREF, "type check");
236 ok(strcmp(yp_str(node->data), "foo") == 0, "value check");
237
238 diag("parser check return");
239 SET_INPUT_STR("unknown:");
240 PARSER_RET_CHECK(KNOT_YP_EINVAL_ITEM);
241
242 SET_INPUT_STR("group:\n unknown:");
243 PARSER_RET_CHECK(KNOT_EOK);
244 PARSER_RET_CHECK(KNOT_YP_EINVAL_ITEM);
245
246 SET_INPUT_STR("group:\n - unknown: data");
247 PARSER_RET_CHECK(KNOT_EOK);
248 PARSER_RET_CHECK(KNOT_YP_EINVAL_ITEM);
249
250 SET_INPUT_STR("group:\n - hex: data");
251 PARSER_RET_CHECK(KNOT_EOK);
252 PARSER_RET_CHECK(KNOT_YP_EINVAL_ITEM);
253
254 SET_INPUT_STR("dname:");
255 PARSER_RET_CHECK(KNOT_EINVAL);
256
257 SET_INPUT_STR("group: data");
258 PARSER_RET_CHECK(KNOT_YP_ENOTSUP_DATA);
259
260 SET_INPUT_STR("group:\n integer:");
261 PARSER_RET_CHECK(KNOT_EOK);
262 PARSER_RET_CHECK(KNOT_EINVAL);
263
264 SET_INPUT_STR("multi-group:\n id:");
265 PARSER_RET_CHECK(KNOT_EOK);
266 PARSER_RET_CHECK(KNOT_YP_ENODATA);
267
268 SET_INPUT_STR("multi-group:\n hex:");
269 PARSER_RET_CHECK(KNOT_EOK);
270 PARSER_RET_CHECK(KNOT_YP_ENOID);
271
272 error_parser:
273 yp_schema_check_deinit(ctx);
274 yp_schema_free(schema);
275 yp_deinit(yp);
276 }
277
278 #define STR_CHECK(depth, key0, key1, id, data) \
279 ret = yp_schema_check_str(ctx, key0, key1, id, data); \
280 is_int(KNOT_EOK, ret, "check str"); \
281 ok(ctx->current == depth, "depth check"); \
282 node = &ctx->nodes[ctx->current]; \
283 parent = node->parent;
284
285 #define STR_RET_CHECK(code, key0, key1, id, data) \
286 ret = yp_schema_check_str(ctx, key0, key1, id, data); \
287 ok(ret == code, "return check str");
288
str_test(void)289 static void str_test(void)
290 {
291 yp_item_t *schema;
292 yp_check_ctx_t *ctx = NULL;
293
294 int ret = yp_schema_copy(&schema, static_schema);
295 is_int(KNOT_EOK, ret, "schema copy");
296 if (ret != KNOT_EOK) {
297 goto error_str;
298 }
299
300 ctx = yp_schema_check_init(&schema);
301 ok(ctx != NULL, "create check ctx");
302 if (ctx == NULL) {
303 goto error_str;
304 }
305
306 yp_node_t *node;
307 yp_node_t *parent;
308 const yp_item_t *id;
309
310 diag("str key0 test");
311 STR_CHECK(0, "option", NULL, NULL, "one");
312 ok(strcmp(node->item->name + 1, "option") == 0, "name check");
313 ok(node->item->type == YP_TOPT, "type check");
314 ok(yp_opt(node->data) == 1, "value check");
315
316 diag("str group test");
317 STR_CHECK(0, "group", NULL, NULL, NULL);
318 ok(strcmp(node->item->name + 1, "group") == 0, "name check");
319 ok(node->item->type == YP_TGRP, "type check");
320 ok(node->data_len == 0, "value length check");
321 STR_CHECK(1, "group", "integer", NULL, "20");
322 ok(strcmp(node->item->name + 1, "integer") == 0, "name check");
323 ok(node->item->type == YP_TINT, "type check");
324 ok(yp_int(node->data) == 20, "value check");
325 STR_CHECK(1, "group", "string", NULL, "short");
326 ok(strcmp(node->item->name + 1, "string") == 0, "name check");
327 ok(node->item->type == YP_TSTR, "type check");
328 ok(strcmp(yp_str(node->data), "short") == 0, "value check");
329 STR_CHECK(1, "group", "string", NULL, "long string");
330 ok(strcmp(node->item->name + 1, "string") == 0, "name check");
331 ok(node->item->type == YP_TSTR, "type check");
332 ok(strcmp(yp_str(node->data), "long string") == 0, "value check");
333
334 diag("str multi-group test");
335 STR_CHECK(0, "multi-group", NULL, NULL, NULL);
336 ok(strcmp(node->item->name + 1, "multi-group") == 0, "name check");
337 ok(node->item->type == YP_TGRP, "type check");
338 ok(node->data_len == 0, "value length check");
339 STR_CHECK(0, "multi-group", NULL, "foo", NULL);
340 ok(node->id_len > 0, "id check");
341 ok(strcmp(node->item->name + 1, "multi-group") == 0, "name check");
342 ok(node->item->type == YP_TGRP, "type check");
343 ok(node->data_len == 0, "value length check");
344 id = node->item->var.g.id;
345 ok(strcmp(id->name + 1, "id") == 0, "name check");
346 ok(id->type == YP_TSTR, "type check");
347 ok(strcmp(yp_str(node->id), "foo") == 0, "value check");
348 STR_CHECK(1, "multi-group", "base64", "foo", "Zm9vYmFy");
349 id = parent->item->var.g.id;
350 ok(strcmp(parent->item->name + 1, "multi-group") == 0, "name check");
351 ok(parent->item->type == YP_TGRP, "type check");
352 ok(parent->data_len == 0, "value length check");
353 ok(strcmp(yp_str(parent->id), "foo") == 0, "value check");
354 ok(strcmp(id->name + 1, "id") == 0, "name check");
355 ok(id->type == YP_TSTR, "type check");
356 ok(strcmp(node->item->name + 1, "base64") == 0, "name check");
357 ok(node->item->type == YP_TB64, "type check");
358 ok(memcmp(yp_bin(node->data), "foobar", yp_bin_len(node->data)) == 0,
359 "value check");
360 ok(node->id_len == 0, "id length check");
361 STR_CHECK(0, "reference", NULL, NULL, "foo");
362 ok(strcmp(node->item->name + 1, "reference") == 0, "name check");
363 ok(node->item->type == YP_TREF, "type check");
364 ok(strcmp(yp_str(node->data), "foo") == 0, "value check");
365
366 diag("str check return");
367 STR_RET_CHECK(KNOT_YP_EINVAL_ITEM, "", "", "", "");
368 STR_RET_CHECK(KNOT_YP_EINVAL_ITEM, NULL, NULL, NULL, NULL);
369 STR_RET_CHECK(KNOT_YP_EINVAL_ITEM, "unknown", NULL, NULL, NULL);
370 STR_RET_CHECK(KNOT_YP_EINVAL_ITEM, NULL, "unknown", NULL, NULL);
371 STR_RET_CHECK(KNOT_EINVAL, "dname", "", "", "");
372 STR_RET_CHECK(KNOT_EOK, "dname", NULL, NULL, NULL);
373 STR_RET_CHECK(KNOT_EOK, "dname", NULL, NULL, ".");
374 STR_RET_CHECK(KNOT_EINVAL, "dname", NULL, NULL, "..");
375 STR_RET_CHECK(KNOT_YP_ENOTSUP_ID, "dname", NULL, "id", NULL);
376 STR_RET_CHECK(KNOT_YP_EINVAL_ITEM, "dname", "unknown", NULL, NULL);
377
378 STR_RET_CHECK(KNOT_EOK, "group", "", "", "");
379 STR_RET_CHECK(KNOT_EOK, "group", NULL, NULL, NULL);
380 STR_RET_CHECK(KNOT_YP_ENOTSUP_DATA, "group", "", "", "data");
381 STR_RET_CHECK(KNOT_YP_EINVAL_ITEM, "group", "unknown", NULL, NULL);
382 STR_RET_CHECK(KNOT_EOK, "group", "string", NULL, NULL);
383 STR_RET_CHECK(KNOT_EOK, "group", "string", NULL, "data");
384 STR_RET_CHECK(KNOT_EOK, "group", "string", NULL, "");
385 STR_RET_CHECK(KNOT_YP_ENOTSUP_ID, "group", "", "id", NULL);
386 STR_RET_CHECK(KNOT_YP_ENOTSUP_ID, "group", "string", "id", NULL);
387
388 STR_RET_CHECK(KNOT_EOK, "multi-group", "", "", "");
389 STR_RET_CHECK(KNOT_EOK, "multi-group", NULL, NULL, NULL);
390 STR_RET_CHECK(KNOT_YP_ENOTSUP_DATA, "multi-group", NULL, NULL, "data");
391 STR_RET_CHECK(KNOT_EOK, "multi-group", NULL, "idval", NULL);
392 STR_RET_CHECK(KNOT_YP_ENOTSUP_DATA, "multi-group", NULL, "idval", "data");
393 STR_RET_CHECK(KNOT_EOK, "multi-group", "hex", "idval", NULL);
394 STR_RET_CHECK(KNOT_EOK, "multi-group", "hex", "idval", "data");
395 STR_RET_CHECK(KNOT_EOK, "multi-group", "hex", NULL, NULL);
396 STR_RET_CHECK(KNOT_EOK, "multi-group", "hex", NULL, "data");
397 STR_RET_CHECK(KNOT_EOK, "multi-group", "id", "", NULL);
398 STR_RET_CHECK(KNOT_EOK, "multi-group", "id", NULL, "idval");
399 STR_RET_CHECK(KNOT_EOK, "multi-group", "id", "idval", NULL);
400 STR_RET_CHECK(KNOT_YP_ENOTSUP_DATA, "multi-group", "id", "idval", "data");
401
402 error_str:
403 yp_schema_check_deinit(ctx);
404 yp_schema_free(schema);
405 }
406
main(int argc,char * argv[])407 int main(int argc, char *argv[])
408 {
409 plan_lazy();
410
411 schema_find_test();
412 schema_merge_test();
413 parser_test();
414 str_test();
415
416 return 0;
417 }
418