test_ypschema.c 13.9 KB
Newer Older
1
/*  Copyright (C) 2017 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21

    This program is free software: you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation, either version 3 of the License, or
    (at your option) any later version.

    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with this program.  If not, see <http://www.gnu.org/licenses/>.
*/

#include <stdlib.h>
#include <stdint.h>
#include <string.h>
#include <tap/basic.h>

22
#include "libknot/yparser/ypschema.h"
23
#include "libknot/yparser/yptrafo.h"
24
#include "libknot/libknot.h"
25 26 27 28 29 30 31

#define C_ID		"\x02""id"
#define C_INT		"\x07""integer"
#define C_BOOL		"\x04""bool"
#define C_OPT		"\x06""option"
#define C_STR		"\x06""string"
#define C_ADDR		"\x07""address"
32 33
#define C_DNAME		"\x05""dname"
#define C_HEX		"\x03""hex"
34
#define C_BASE64	"\x06""base64"
35
#define C_DATA		"\x04""data"
36 37 38 39 40 41 42 43 44 45 46 47
#define C_REF		"\x09""reference"
#define C_GRP		"\x05""group"
#define C_MULTIGRP	"\x0B""multi-group"

static const yp_item_t group[] = {
	{ C_INT, YP_TINT, YP_VINT = { 0, 100, YP_NIL } },
	{ C_STR, YP_TSTR, YP_VNONE, YP_FMULTI },
	{ NULL }
};

static const yp_item_t multi_group[] = {
	{ C_ID,     YP_TSTR, YP_VNONE },
48
	{ C_HEX,    YP_THEX, YP_VNONE },
49 50 51 52
	{ C_BASE64, YP_TB64, YP_VNONE },
	{ NULL }
};

53
static const knot_lookup_t opts[] = {
54 55 56 57 58
	{ 1,   "one" },
	{ 10,  "ten" },
	{ 0, NULL }
	};

59
static const yp_item_t static_schema[] = {
60 61 62 63 64 65 66
	{ C_OPT,      YP_TOPT,   YP_VOPT = { opts } },
	{ C_BOOL,     YP_TBOOL,  YP_VNONE },
	{ C_DNAME,    YP_TDNAME, YP_VNONE },
	{ C_GRP,      YP_TGRP,   YP_VGRP = { group } },
	{ C_MULTIGRP, YP_TGRP,   YP_VGRP = { multi_group }, YP_FMULTI },
	{ C_REF,      YP_TREF,   YP_VREF = { C_MULTIGRP } },
	{ C_DATA,     YP_TDATA,  YP_VNONE },
67 68 69
	{ NULL }
};

70
static void schema_find_test(void)
71
{
72
	yp_item_t *schema = NULL;
73

74 75
	int ret = yp_schema_copy(&schema, static_schema);
	is_int(KNOT_EOK, ret, "schema copy");
76

77 78
	const yp_item_t *i = yp_schema_find(C_OPT, NULL, schema);
	ok(i != NULL, "schema find");
79
	if (i == NULL) {
80
		goto error_schema;
81 82 83
	}
	ok(strcmp(i->name + 1, C_OPT + 1) == 0, "name check");

84 85
	i = yp_schema_find(C_STR, C_GRP, schema);
	ok(i != NULL, "schema find with parent");
86
	if (i == NULL) {
87
		goto error_schema;
88 89 90
	}
	ok(strcmp(i->name + 1, C_STR + 1) == 0, "name check");

91 92
	i = yp_schema_find(C_ADDR, NULL, schema);
	ok(i == NULL, "schema not find");
93

94 95
	i = yp_schema_find(C_ADDR, C_GRP, schema);
	ok(i == NULL, "schema not find with parent");
96

97 98
error_schema:
	yp_schema_free(schema);
99 100
}

101
static void schema_merge_test(void)
102 103 104 105 106 107 108 109 110 111 112 113 114
{
	static const yp_item_t items1[] = {
		{ "\x01""1", YP_TSTR,  YP_VNONE },
		{ "\x01""2", YP_TSTR,  YP_VNONE },
		{ NULL }
	};

	static const yp_item_t items2[] = {
		{ "\x01""3", YP_TSTR,  YP_VNONE },
		{ "\x01""4", YP_TSTR,  YP_VNONE },
		{ NULL }
	};

115
	yp_item_t *schema = NULL;
116 117
	yp_item_t *tmp = NULL;

118 119
	int ret = yp_schema_copy(&tmp, items1);
	is_int(KNOT_EOK, ret, "schema copy");
120

121 122
	ret = yp_schema_merge(&schema, items1, items2);
	is_int(KNOT_EOK, ret, "schema merge");
123

124
	yp_schema_free(tmp);
125 126 127

	for (uint8_t i = 0; i < 4; i++) {
		yp_name_t name[3] = { '\x01', '1' + i };
128 129
		const yp_item_t *item = yp_schema_find(name, NULL, schema);
		ok(item != NULL, "schema find");
130 131
	}

132
	yp_schema_free(schema);
133 134
}

135 136
#define SET_INPUT_STR(str) \
	ret = yp_set_input_string(yp, str, strlen(str)); \
137
	is_int(KNOT_EOK, ret, "set input string");
138 139 140

#define PARSER_CHECK(depth) \
	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 145 146 147 148 149
	node = &ctx->nodes[ctx->current]; \
	parent = node->parent; \
	ok(ctx->current == depth, "depth check");

#define PARSER_RET_CHECK(code) \
	ret = yp_parse(yp); \
150
	is_int(KNOT_EOK, ret, "parse"); \
151
	ret = yp_schema_check_parser(ctx, yp); \
152 153 154 155
	ok(ret == code, "return check parser");

static void parser_test(void)
{
156 157
	yp_parser_t yparser;
	yp_parser_t *yp = &yparser;
158
	yp_item_t *schema = NULL;
159 160
	yp_check_ctx_t *ctx = NULL;

161
	yp_init(yp);
162

163 164
	int ret = yp_schema_copy(&schema, static_schema);
	is_int(KNOT_EOK, ret, "schema copy");
165 166 167 168
	if (ret != KNOT_EOK) {
		goto error_parser;
	}

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 176 177
	yp_node_t *node;
	yp_node_t *parent;
	const yp_item_t *id;
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
	diag("parser key0 test");
	SET_INPUT_STR("option: one");
	PARSER_CHECK(0);
	ok(strcmp(node->item->name + 1, "option") == 0, "name check");
	ok(node->item->type == YP_TOPT, "type check");
	ok(yp_opt(node->data) == 1, "value check");

	diag("parser group test");
	SET_INPUT_STR("group:\n integer: 20\n string: [short, \"long string\"]");
	PARSER_CHECK(0);
	ok(strcmp(node->item->name + 1, "group") == 0, "name check");
	ok(node->item->type == YP_TGRP, "type check");
	ok(node->data_len == 0, "value length check");
	PARSER_CHECK(1);
	ok(strcmp(node->item->name + 1, "integer") == 0, "name check");
	ok(node->item->type == YP_TINT, "type check");
	ok(yp_int(node->data) == 20, "value check");
	PARSER_CHECK(1);
	ok(strcmp(node->item->name + 1, "string") == 0, "name check");
	ok(node->item->type == YP_TSTR, "type check");
	ok(strcmp(yp_str(node->data), "short") == 0, "value check");
	PARSER_CHECK(1);
	ok(strcmp(node->item->name + 1, "string") == 0, "name check");
	ok(node->item->type == YP_TSTR, "type check");
	ok(strcmp(yp_str(node->data), "long string") == 0, "value check");

	diag("parser multi-group test");
	SET_INPUT_STR("multi-group:\n - id: foo\n   base64: Zm9vYmFy\nreference: foo");
	PARSER_CHECK(0);
	ok(strcmp(node->item->name + 1, "multi-group") == 0, "name check");
	ok(node->item->type == YP_TGRP, "type check");
	ok(node->data_len == 0, "value length check");
	PARSER_CHECK(0);
	ok(node->id_len > 0, "id check");
	ok(strcmp(node->item->name + 1, "multi-group") == 0, "name check");
	ok(node->item->type == YP_TGRP, "type check");
	ok(node->data_len == 0, "value length check");
	id = node->item->var.g.id;
	ok(strcmp(id->name + 1, "id") == 0, "name check");
	ok(id->type == YP_TSTR, "type check");
	ok(strcmp(yp_str(node->id), "foo") == 0, "value check");
	PARSER_CHECK(1);
	id = parent->item->var.g.id;
	ok(strcmp(parent->item->name + 1, "multi-group") == 0, "name check");
	ok(parent->item->type == YP_TGRP, "type check");
	ok(parent->data_len == 0, "value length check");
	ok(strcmp(yp_str(parent->id), "foo") == 0, "value check");
	ok(strcmp(id->name + 1, "id") == 0, "name check");
	ok(id->type == YP_TSTR, "type check");
	ok(strcmp(node->item->name + 1, "base64") == 0, "name check");
	ok(node->item->type == YP_TB64, "type check");
	ok(memcmp(yp_bin(node->data), "foobar", yp_bin_len(node->data)) == 0,
	   "value check");
	ok(node->id_len == 0, "id length check");
	PARSER_CHECK(0);
	ok(strcmp(node->item->name + 1, "reference") == 0, "name check");
	ok(node->item->type == YP_TREF, "type check");
	ok(strcmp(yp_str(node->data), "foo") == 0, "value check");

	diag("parser check return");
	SET_INPUT_STR("unknown:");
	PARSER_RET_CHECK(KNOT_YP_EINVAL_ITEM);

	SET_INPUT_STR("group:\n unknown:");
	PARSER_RET_CHECK(KNOT_EOK);
	PARSER_RET_CHECK(KNOT_YP_EINVAL_ITEM);

	SET_INPUT_STR("group:\n - unknown: data");
	PARSER_RET_CHECK(KNOT_EOK);
	PARSER_RET_CHECK(KNOT_YP_EINVAL_ITEM);

	SET_INPUT_STR("group:\n - hex: data");
	PARSER_RET_CHECK(KNOT_EOK);
	PARSER_RET_CHECK(KNOT_YP_EINVAL_ITEM);

	SET_INPUT_STR("dname:");
	PARSER_RET_CHECK(KNOT_EINVAL);

	SET_INPUT_STR("group: data");
	PARSER_RET_CHECK(KNOT_YP_ENOTSUP_DATA);

	SET_INPUT_STR("group:\n integer:");
	PARSER_RET_CHECK(KNOT_EOK);
	PARSER_RET_CHECK(KNOT_EINVAL);

	SET_INPUT_STR("multi-group:\n id:");
	PARSER_RET_CHECK(KNOT_EOK);
	PARSER_RET_CHECK(KNOT_YP_ENODATA);

	SET_INPUT_STR("multi-group:\n hex:");
	PARSER_RET_CHECK(KNOT_EOK);
	PARSER_RET_CHECK(KNOT_YP_ENOID);

error_parser:
273 274
	yp_schema_check_deinit(ctx);
	yp_schema_free(schema);
275 276 277 278
	yp_deinit(yp);
}

#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 282 283 284 285
	ok(ctx->current == depth, "depth check"); \
	node = &ctx->nodes[ctx->current]; \
	parent = node->parent;

#define STR_RET_CHECK(code, key0, key1, id, data) \
286
	ret = yp_schema_check_str(ctx, key0, key1, id, data); \
287 288 289 290
	ok(ret == code, "return check str");

static void str_test(void)
{
291
	yp_item_t *schema;
292 293
	yp_check_ctx_t *ctx = NULL;

294 295
	int ret = yp_schema_copy(&schema, static_schema);
	is_int(KNOT_EOK, ret, "schema copy");
296 297
	if (ret != KNOT_EOK) {
		goto error_str;
298
	}
299

300
	ctx = yp_schema_check_init(&schema);
301 302 303
	ok(ctx != NULL, "create check ctx");
	if (ctx == NULL) {
		goto error_str;
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 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402
	yp_node_t *node;
	yp_node_t *parent;
	const yp_item_t *id;

	diag("str key0 test");
	STR_CHECK(0, "option", NULL, NULL, "one");
	ok(strcmp(node->item->name + 1, "option") == 0, "name check");
	ok(node->item->type == YP_TOPT, "type check");
	ok(yp_opt(node->data) == 1, "value check");

	diag("str group test");
	STR_CHECK(0, "group", NULL, NULL, NULL);
	ok(strcmp(node->item->name + 1, "group") == 0, "name check");
	ok(node->item->type == YP_TGRP, "type check");
	ok(node->data_len == 0, "value length check");
	STR_CHECK(1, "group", "integer", NULL, "20");
	ok(strcmp(node->item->name + 1, "integer") == 0, "name check");
	ok(node->item->type == YP_TINT, "type check");
	ok(yp_int(node->data) == 20, "value check");
	STR_CHECK(1, "group", "string", NULL, "short");
	ok(strcmp(node->item->name + 1, "string") == 0, "name check");
	ok(node->item->type == YP_TSTR, "type check");
	ok(strcmp(yp_str(node->data), "short") == 0, "value check");
	STR_CHECK(1, "group", "string", NULL, "long string");
	ok(strcmp(node->item->name + 1, "string") == 0, "name check");
	ok(node->item->type == YP_TSTR, "type check");
	ok(strcmp(yp_str(node->data), "long string") == 0, "value check");

	diag("str multi-group test");
	STR_CHECK(0, "multi-group", NULL, NULL, NULL);
	ok(strcmp(node->item->name + 1, "multi-group") == 0, "name check");
	ok(node->item->type == YP_TGRP, "type check");
	ok(node->data_len == 0, "value length check");
	STR_CHECK(0, "multi-group", NULL, "foo", NULL);
	ok(node->id_len > 0, "id check");
	ok(strcmp(node->item->name + 1, "multi-group") == 0, "name check");
	ok(node->item->type == YP_TGRP, "type check");
	ok(node->data_len == 0, "value length check");
	id = node->item->var.g.id;
	ok(strcmp(id->name + 1, "id") == 0, "name check");
	ok(id->type == YP_TSTR, "type check");
	ok(strcmp(yp_str(node->id), "foo") == 0, "value check");
	STR_CHECK(1, "multi-group", "base64", "foo", "Zm9vYmFy");
	id = parent->item->var.g.id;
	ok(strcmp(parent->item->name + 1, "multi-group") == 0, "name check");
	ok(parent->item->type == YP_TGRP, "type check");
	ok(parent->data_len == 0, "value length check");
	ok(strcmp(yp_str(parent->id), "foo") == 0, "value check");
	ok(strcmp(id->name + 1, "id") == 0, "name check");
	ok(id->type == YP_TSTR, "type check");
	ok(strcmp(node->item->name + 1, "base64") == 0, "name check");
	ok(node->item->type == YP_TB64, "type check");
	ok(memcmp(yp_bin(node->data), "foobar", yp_bin_len(node->data)) == 0,
	   "value check");
	ok(node->id_len == 0, "id length check");
	STR_CHECK(0, "reference", NULL, NULL, "foo");
	ok(strcmp(node->item->name + 1, "reference") == 0, "name check");
	ok(node->item->type == YP_TREF, "type check");
	ok(strcmp(yp_str(node->data), "foo") == 0, "value check");

	diag("str check return");
	STR_RET_CHECK(KNOT_YP_EINVAL_ITEM,  "",        "",        "",   "");
	STR_RET_CHECK(KNOT_YP_EINVAL_ITEM,  NULL,      NULL,      NULL, NULL);
	STR_RET_CHECK(KNOT_YP_EINVAL_ITEM,  "unknown", NULL,      NULL, NULL);
	STR_RET_CHECK(KNOT_YP_EINVAL_ITEM,  NULL,      "unknown", NULL, NULL);
	STR_RET_CHECK(KNOT_EINVAL,          "dname",   "",        "",   "");
	STR_RET_CHECK(KNOT_EOK,             "dname",   NULL,      NULL, NULL);
	STR_RET_CHECK(KNOT_EOK,             "dname",   NULL,      NULL, ".");
	STR_RET_CHECK(KNOT_EINVAL,          "dname",   NULL,      NULL, "..");
	STR_RET_CHECK(KNOT_YP_ENOTSUP_ID,   "dname",   NULL,      "id", NULL);
	STR_RET_CHECK(KNOT_YP_EINVAL_ITEM,  "dname",   "unknown", NULL, NULL);

	STR_RET_CHECK(KNOT_EOK,             "group",   "",        "",   "");
	STR_RET_CHECK(KNOT_EOK,             "group",   NULL,      NULL, NULL);
	STR_RET_CHECK(KNOT_YP_ENOTSUP_DATA, "group",   "",        "",   "data");
	STR_RET_CHECK(KNOT_YP_EINVAL_ITEM,  "group",   "unknown", NULL, NULL);
	STR_RET_CHECK(KNOT_EOK,             "group",   "string",  NULL, NULL);
	STR_RET_CHECK(KNOT_EOK,             "group",   "string",  NULL, "data");
	STR_RET_CHECK(KNOT_EOK,             "group",   "string",  NULL, "");
	STR_RET_CHECK(KNOT_YP_ENOTSUP_ID,   "group",   "",        "id", NULL);
	STR_RET_CHECK(KNOT_YP_ENOTSUP_ID,   "group",   "string",  "id", NULL);

	STR_RET_CHECK(KNOT_EOK,             "multi-group", "",    "",      "");
	STR_RET_CHECK(KNOT_EOK,             "multi-group", NULL,  NULL,    NULL);
	STR_RET_CHECK(KNOT_YP_ENOTSUP_DATA, "multi-group", NULL,  NULL,    "data");
	STR_RET_CHECK(KNOT_EOK,             "multi-group", NULL,  "idval", NULL);
	STR_RET_CHECK(KNOT_YP_ENOTSUP_DATA, "multi-group", NULL,  "idval", "data");
	STR_RET_CHECK(KNOT_EOK,             "multi-group", "hex", "idval", NULL);
	STR_RET_CHECK(KNOT_EOK,             "multi-group", "hex", "idval", "data");
	STR_RET_CHECK(KNOT_EOK,             "multi-group", "hex", NULL,    NULL);
	STR_RET_CHECK(KNOT_EOK,             "multi-group", "hex", NULL,    "data");
	STR_RET_CHECK(KNOT_EOK,             "multi-group", "id",  "",      NULL);
	STR_RET_CHECK(KNOT_EOK,             "multi-group", "id",  NULL,    "idval");
	STR_RET_CHECK(KNOT_EOK,             "multi-group", "id",  "idval", NULL);
	STR_RET_CHECK(KNOT_YP_ENOTSUP_DATA, "multi-group", "id",  "idval", "data");

error_str:
403 404
	yp_schema_check_deinit(ctx);
	yp_schema_free(schema);
405 406 407 408 409 410
}

int main(int argc, char *argv[])
{
	plan_lazy();

411 412
	schema_find_test();
	schema_merge_test();
413 414
	parser_test();
	str_test();
415 416 417

	return 0;
}