knot-dns/tests/libknot/test_ypschema.c
2019-11-05 20:27:33 +01:00

417 lines
14 KiB
C

/* Copyright (C) 2019 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
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 <https://www.gnu.org/licenses/>.
*/
#include <stdlib.h>
#include <stdint.h>
#include <string.h>
#include <tap/basic.h>
#include "libknot/yparser/ypschema.h"
#include "libknot/yparser/yptrafo.h"
#include "libknot/libknot.h"
#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"
#define C_DNAME "\x05""dname"
#define C_HEX "\x03""hex"
#define C_BASE64 "\x06""base64"
#define C_DATA "\x04""data"
#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 },
{ C_HEX, YP_THEX, YP_VNONE },
{ C_BASE64, YP_TB64, YP_VNONE },
{ NULL }
};
static const knot_lookup_t opts[] = {
{ 1, "one" },
{ 10, "ten" },
{ 0, NULL }
};
static const yp_item_t static_schema[] = {
{ 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 },
{ NULL }
};
static void schema_find_test(void)
{
yp_item_t *schema = NULL;
int ret = yp_schema_copy(&schema, static_schema);
is_int(KNOT_EOK, ret, "schema copy");
const yp_item_t *i = yp_schema_find(C_OPT, NULL, schema);
ok(i != NULL, "schema find");
if (i == NULL) {
goto error_schema;
}
ok(strcmp(&i->name[1], &C_OPT[1]) == 0, "name check");
i = yp_schema_find(C_STR, C_GRP, schema);
ok(i != NULL, "schema find with parent");
if (i == NULL) {
goto error_schema;
}
ok(strcmp(&i->name[1], &C_STR[1]) == 0, "name check");
i = yp_schema_find(C_ADDR, NULL, schema);
ok(i == NULL, "schema not find");
i = yp_schema_find(C_ADDR, C_GRP, schema);
ok(i == NULL, "schema not find with parent");
error_schema:
yp_schema_free(schema);
}
static void schema_merge_test(void)
{
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 }
};
yp_item_t *schema = NULL;
yp_item_t *tmp = NULL;
int ret = yp_schema_copy(&tmp, items1);
is_int(KNOT_EOK, ret, "schema copy");
ret = yp_schema_merge(&schema, items1, items2);
is_int(KNOT_EOK, ret, "schema merge");
yp_schema_free(tmp);
for (uint8_t i = 0; i < 4; i++) {
yp_name_t name[3] = { '\x01', '1' + i };
const yp_item_t *item = yp_schema_find(name, NULL, schema);
ok(item != NULL, "schema find");
}
yp_schema_free(schema);
}
#define SET_INPUT_STR(str) \
ret = yp_set_input_string(yp, str, strlen(str)); \
is_int(KNOT_EOK, ret, "set input string");
#define PARSER_CHECK(depth) \
ret = yp_parse(yp); \
is_int(KNOT_EOK, ret, "parse"); \
ret = yp_schema_check_parser(ctx, yp); \
is_int(KNOT_EOK, ret, "check parser"); \
node = &ctx->nodes[ctx->current]; \
parent = node->parent; \
ok(ctx->current == depth, "depth check");
#define PARSER_RET_CHECK(code) \
ret = yp_parse(yp); \
is_int(KNOT_EOK, ret, "parse"); \
ret = yp_schema_check_parser(ctx, yp); \
ok(ret == code, "return check parser");
static void parser_test(void)
{
yp_parser_t yparser;
yp_parser_t *yp = &yparser;
yp_item_t *schema = NULL;
yp_check_ctx_t *ctx = NULL;
yp_init(yp);
int ret = yp_schema_copy(&schema, static_schema);
is_int(KNOT_EOK, ret, "schema copy");
if (ret != KNOT_EOK) {
goto error_parser;
}
ctx = yp_schema_check_init(&schema);
ok(ctx != NULL, "create check ctx");
if (ctx == NULL) {
goto error_parser;
}
yp_node_t *node;
yp_node_t *parent;
const yp_item_t *id;
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:
yp_schema_check_deinit(ctx);
yp_schema_free(schema);
yp_deinit(yp);
}
#define STR_CHECK(depth, key0, key1, id, data) \
ret = yp_schema_check_str(ctx, key0, key1, id, data); \
is_int(KNOT_EOK, ret, "check str"); \
ok(ctx->current == depth, "depth check"); \
node = &ctx->nodes[ctx->current]; \
parent = node->parent;
#define STR_RET_CHECK(code, key0, key1, id, data) \
ret = yp_schema_check_str(ctx, key0, key1, id, data); \
ok(ret == code, "return check str");
static void str_test(void)
{
yp_item_t *schema;
yp_check_ctx_t *ctx = NULL;
int ret = yp_schema_copy(&schema, static_schema);
is_int(KNOT_EOK, ret, "schema copy");
if (ret != KNOT_EOK) {
goto error_str;
}
ctx = yp_schema_check_init(&schema);
ok(ctx != NULL, "create check ctx");
if (ctx == NULL) {
goto error_str;
}
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:
yp_schema_check_deinit(ctx);
yp_schema_free(schema);
}
int main(int argc, char *argv[])
{
plan_lazy();
schema_find_test();
schema_merge_test();
parser_test();
str_test();
return 0;
}