knot-dns/tests/libknot/test_yptrafo.c
2025-03-24 09:53:50 +01:00

405 lines
12 KiB
C

/* Copyright (C) CZ.NIC, z.s.p.o. and contributors
* SPDX-License-Identifier: GPL-2.0-or-later
* For more information, see <https://www.knot-dns.cz/>
*/
#include <stdlib.h>
#include <stdint.h>
#include <string.h>
#include <sys/socket.h>
#include <tap/basic.h>
#include "libknot/yparser/yptrafo.h"
#include "libknot/libknot.h"
static void int_test(const char *txt, int64_t num, yp_style_t s,
int64_t min, int64_t max)
{
int ret;
uint8_t b[64];
size_t b_len = sizeof(b);
char t[64];
size_t t_len = sizeof(t);
yp_item_t i = { NULL, YP_TINT, YP_VINT = { min, max, YP_NIL, s } };
diag("integer \"%s\":", txt);
ret = yp_item_to_bin(&i, txt, strlen(txt), b, &b_len);
is_int(KNOT_EOK, ret, "txt to bin");
ok(yp_int(b) == num, "compare");
ret = yp_item_to_txt(&i, b, b_len, t, &t_len, s | YP_SNOQUOTE);
is_int(KNOT_EOK, ret, "bin to txt");
ok(strlen(t) == t_len, "txt ret length");
ok(strlen(txt) == t_len, "txt length");
ok(memcmp(txt, t, t_len) == 0, "compare");
}
static void int_bad_test(const char *txt, int code, yp_style_t s,
int64_t min, int64_t max)
{
int ret;
uint8_t b[64];
size_t b_len = sizeof(b);
yp_item_t i = { NULL, YP_TINT, YP_VINT = { min, max, YP_NIL, s } };
diag("integer \"%s\":", txt);
ret = yp_item_to_bin(&i, txt, strlen(txt), b, &b_len);
ok(ret == code, "invalid txt to bin");
}
static void bool_test(const char *txt, bool val)
{
int ret;
uint8_t b[64];
size_t b_len = sizeof(b);
char t[64];
size_t t_len = sizeof(t);
yp_item_t i = { NULL, YP_TBOOL, YP_VNONE };
diag("boolean \"%s\":", txt);
ret = yp_item_to_bin(&i, txt, strlen(txt), b, &b_len);
is_int(KNOT_EOK, ret, "txt to bin");
ok(yp_bool(b) == val, "compare");
ret = yp_item_to_txt(&i, b, b_len, t, &t_len, YP_SNOQUOTE);
is_int(KNOT_EOK, ret, "bin to txt");
ok(strlen(t) == t_len, "txt ret length");
ok(strlen(txt) == t_len, "txt length");
ok(memcmp(txt, t, t_len) == 0, "compare");
}
static void bool_bad_test(const char *txt, int code)
{
int ret;
uint8_t b[64];
size_t b_len = sizeof(b);
yp_item_t i = { NULL, YP_TBOOL, YP_VNONE };
diag("boolean \"%s\":", txt);
ret = yp_item_to_bin(&i, txt, strlen(txt), b, &b_len);
ok(ret == code, "invalid txt to bin");
}
static void opt_test(const char *txt, unsigned val, const knot_lookup_t *opts)
{
int ret;
uint8_t b[64];
size_t b_len = sizeof(b);
char t[64];
size_t t_len = sizeof(t);
yp_item_t i = { NULL, YP_TOPT, YP_VOPT = { opts } };
diag("option \"%s\":", txt);
ret = yp_item_to_bin(&i, txt, strlen(txt), b, &b_len);
is_int(KNOT_EOK, ret, "txt to bin");
ok(b_len == 1, "compare length");
ok(yp_opt(b) == val, "compare");
ret = yp_item_to_txt(&i, b, b_len, t, &t_len, YP_SNOQUOTE);
is_int(KNOT_EOK, ret, "bin to txt");
ok(strlen(t) == t_len, "txt ret length");
ok(strlen(txt) == t_len, "txt length");
ok(memcmp(txt, t, t_len) == 0, "compare");
}
static void opt_bad_test(const char *txt, int code, const knot_lookup_t *opts)
{
int ret;
uint8_t b[64];
size_t b_len = sizeof(b);
yp_item_t i = { NULL, YP_TOPT, YP_VOPT = { opts } };
diag("option \"%s\":", txt);
ret = yp_item_to_bin(&i, txt, strlen(txt), b, &b_len);
ok(ret == code, "invalid txt to bin");
}
static void str_test(const char *txt, const char *val)
{
int ret;
uint8_t b[64];
size_t b_len = sizeof(b);
char t[64];
size_t t_len = sizeof(t);
yp_item_t i = { NULL, YP_TSTR, YP_VNONE };
diag("string \"%s\":", txt);
ret = yp_item_to_bin(&i, txt, strlen(txt), b, &b_len);
is_int(KNOT_EOK, ret, "txt to bin");
ok(b_len == strlen(txt) + 1, "compare length");
ok(memcmp(yp_str(b), val, b_len) == 0, "compare");
ret = yp_item_to_txt(&i, b, b_len, t, &t_len, YP_SNOQUOTE);
is_int(KNOT_EOK, ret, "bin to txt");
ok(strlen(t) == t_len, "txt ret length");
ok(strlen(txt) == t_len, "txt length");
ok(memcmp(txt, t, t_len) == 0, "compare");
}
static void addr_test(const char *txt, bool port)
{
int ret;
uint8_t b[64];
size_t b_len = sizeof(b);
char t[64];
size_t t_len = sizeof(t);
yp_item_t i = { NULL, YP_TADDR, YP_VNONE };
diag("address \"%s\":", txt);
ret = yp_item_to_bin(&i, txt, strlen(txt), b, &b_len);
is_int(KNOT_EOK, ret, "txt to bin");
bool no_port;
yp_addr(b, &no_port);
ok(no_port == port, "compare port presence");
ret = yp_item_to_txt(&i, b, b_len, t, &t_len, YP_SNOQUOTE);
is_int(KNOT_EOK, ret, "bin to txt");
ok(strlen(t) == t_len, "txt ret length");
ok(strlen(txt) == t_len, "txt length");
ok(memcmp(txt, t, t_len) == 0, "compare");
}
static void addr_bad_test(const char *txt, int code)
{
int ret;
uint8_t b[64];
size_t b_len = sizeof(b);
yp_item_t i = { NULL, YP_TADDR, YP_VNONE };
diag("address \"%s\":", txt);
ret = yp_item_to_bin(&i, txt, strlen(txt), b, &b_len);
ok(ret == code, "invalid txt to bin");
}
static void addr_range_test(const char *txt)
{
int ret;
uint8_t b[64];
size_t b_len = sizeof(b);
char t[64];
size_t t_len = sizeof(t);
yp_item_t i = { NULL, YP_TNET, YP_VNONE };
diag("address range \"%s\":", txt);
ret = yp_item_to_bin(&i, txt, strlen(txt), b, &b_len);
is_int(KNOT_EOK, ret, "txt to bin");
ret = yp_item_to_txt(&i, b, b_len, t, &t_len, YP_SNOQUOTE);
is_int(KNOT_EOK, ret, "bin to txt");
ok(strlen(t) == t_len, "txt ret length");
ok(strlen(txt) == t_len, "txt length");
ok(memcmp(txt, t, t_len) == 0, "compare");
}
static void addr_range_bad_test(const char *txt, int code)
{
int ret;
uint8_t b[64];
size_t b_len = sizeof(b);
yp_item_t i = { NULL, YP_TNET, YP_VNONE };
diag("address range \"%s\":", txt);
ret = yp_item_to_bin(&i, txt, strlen(txt), b, &b_len);
ok(ret == code, "invalid txt to bin");
}
static void dname_test(const char *txt, const char *val)
{
int ret;
uint8_t b[64];
size_t b_len = sizeof(b);
char t[64];
size_t t_len = sizeof(t);
yp_item_t i = { NULL, YP_TDNAME, YP_VNONE };
diag("dname \"%s\":", txt);
ret = yp_item_to_bin(&i, txt, strlen(txt), b, &b_len);
is_int(KNOT_EOK, ret, "txt to bin");
ok(memcmp(yp_dname(b), val, b_len) == 0, "compare");
ret = yp_item_to_txt(&i, b, b_len, t, &t_len, YP_SNOQUOTE);
is_int(KNOT_EOK, ret, "bin to txt");
ok(strlen(t) == t_len, "txt ret length");
ok(strlen(txt) == t_len, "txt length");
ok(memcmp(txt, t, t_len) == 0, "compare");
}
static void hex_test(const char *txt, const char *val, const char *txt_out)
{
int ret;
uint8_t b[64];
size_t b_len = sizeof(b);
char t[64];
size_t t_len = sizeof(t);
yp_item_t i = { NULL, YP_THEX, YP_VNONE };
if (txt_out == NULL) {
txt_out = txt;
}
diag("hex \"%s\":", txt);
ret = yp_item_to_bin(&i, txt, strlen(txt), b, &b_len);
is_int(KNOT_EOK, ret, "txt to bin");
ok(memcmp(yp_bin(b), val, yp_bin_len(b)) == 0, "compare");
ret = yp_item_to_txt(&i, b, b_len, t, &t_len, YP_SNOQUOTE);
is_int(KNOT_EOK, ret, "bin to txt");
ok(strlen(t) == t_len, "txt ret length");
ok(strlen(txt_out) == t_len, "txt length");
ok(memcmp(txt_out, t, t_len) == 0, "compare");
}
static void hex_bad_test(const char *txt, int code)
{
int ret;
uint8_t b[64];
size_t b_len = sizeof(b);
yp_item_t i = { NULL, YP_THEX, YP_VNONE };
diag("hex \"%s\":", txt);
ret = yp_item_to_bin(&i, txt, strlen(txt), b, &b_len);
ok(ret == code, "invalid txt to bin");
}
static void base64_test(const char *txt, const char *val)
{
int ret;
uint8_t b[64];
size_t b_len = sizeof(b);
char t[64];
size_t t_len = sizeof(t);
yp_item_t i = { NULL, YP_TB64, YP_VNONE };
diag("base64 \"%s\":", txt);
ret = yp_item_to_bin(&i, txt, strlen(txt), b, &b_len);
is_int(KNOT_EOK, ret, "txt to bin");
ok(memcmp(yp_bin(b), val, yp_bin_len(b)) == 0, "compare");
ret = yp_item_to_txt(&i, b, b_len, t, &t_len, YP_SNOQUOTE);
is_int(KNOT_EOK, ret, "bin to txt");
ok(strlen(t) == t_len, "txt ret length");
ok(strlen(txt) == t_len, "txt length");
ok(memcmp(txt, t, t_len) == 0, "compare");
}
static void ref_test(const char *txt, bool val)
{
int ret;
uint8_t b[64];
size_t b_len = sizeof(b);
char t[64];
size_t t_len = sizeof(t);
yp_item_t id = { NULL, YP_TBOOL, YP_VNONE };
yp_item_t ref = { NULL, YP_TGRP, YP_VNONE };
yp_item_t i = { NULL, YP_TREF, YP_VNONE };
ref.var.g.id = &id;
i.var.r.ref = &ref;
diag("reference to boolean \"%s\":", txt);
ret = yp_item_to_bin(&i, txt, strlen(txt), b, &b_len);
is_int(KNOT_EOK, ret, "txt to bin");
ok(yp_bool(b) == val, "compare");
ret = yp_item_to_txt(&i, b, b_len, t, &t_len, YP_SNOQUOTE);
is_int(KNOT_EOK, ret, "bin to txt");
ok(strlen(t) == t_len, "txt ret length");
ok(strlen(txt) == t_len, "txt length");
ok(memcmp(txt, t, t_len) == 0, "compare");
}
int main(int argc, char *argv[])
{
plan_lazy();
/* Integer tests. */
int64_t min = -20000000000, max = 20000000000;
int_test("5", 5, YP_SNONE, min, max);
int_test("0", 0, YP_SNONE, min, max);
int_test("-5", -5, YP_SNONE, min, max);
int_test("20000000000", max, YP_SNONE, min, max);
int_test("-20000000000", min, YP_SNONE, min, max);
int_test("11B", 11LL * 1, YP_SSIZE, min, max);
int_test("11K", 11LL * 1024, YP_SSIZE, min, max);
int_test("11M", 11LL * 1024 * 1024, YP_SSIZE, min, max);
int_test("11G", 11LL * 1024 * 1024 * 1024, YP_SSIZE, min, max);
int_test("11s", 11LL * 1, YP_STIME, min, max);
int_test("11m", 11LL * 60, YP_STIME, min, max);
int_test("11h", 11LL * 3600, YP_STIME, min, max);
int_test("6d", 6LL * 24 * 3600, YP_STIME, min, max);
int_test("4w", 4LL * 7 * 24 * 3600, YP_STIME, min, max);
int_test("11M", 11LL * 30 * 24 * 3600, YP_STIME, min, max);
int_test("2y", 2LL * 365 * 24 * 3600, YP_STIME, min, max);
int_test("1025B", 1025LL, YP_SSIZE, min, max);
int_test("61s", 61LL, YP_STIME, min, max);
int_bad_test("20000000001", KNOT_ERANGE, YP_SNONE, min, max);
int_bad_test("-20000000001", KNOT_ERANGE, YP_SNONE, min, max);
int_bad_test("1x", KNOT_EINVAL, YP_SNONE, min, max);
int_bad_test("1sx", KNOT_EINVAL, YP_STIME, min, max);
/* Boolean tests. */
bool_test("on", true);
bool_test("off", false);
bool_bad_test("onx", KNOT_EINVAL);
bool_bad_test("enable", KNOT_EINVAL);
/* Option tests. */
static const knot_lookup_t opts[] = {
{ 1, "one" },
{ 10, "ten" },
{ 255, "max" },
{ 0, NULL }
};
opt_test("one", 1, opts);
opt_test("ten", 10, opts);
opt_test("max", 255, opts);
opt_bad_test("onex", KNOT_EINVAL, opts);
opt_bad_test("word", KNOT_EINVAL, opts);
/* String tests. */
str_test("Test string!", "Test string!");
/* Address tests. */
addr_test("192.168.123.1", true);
addr_test("192.168.123.1@12345", false);
addr_test("2001:db8::1", true);
addr_test("::1@12345", false);
addr_test("/tmp/test.sock", true);
addr_test("eth1@53", true);
addr_test("::1%lo", true);
addr_test("::1%2", true);
addr_test("::1%lo@12345", false);
addr_test("::1%4@12345", false);
addr_bad_test("192.168.123.x", KNOT_EINVAL);
addr_bad_test("192.168.123.1@", KNOT_EINVAL);
addr_bad_test("192.168.123.1@1x", KNOT_EINVAL);
addr_bad_test("192.168.123.1@65536", KNOT_ERANGE);
addr_bad_test("::1%", KNOT_EINVAL);
addr_bad_test("::1%@53", KNOT_EINVAL);
/* Address range tests. */
addr_range_test("/tmp/unix.sock");
addr_range_test("1.1.1.1");
addr_range_test("1.1.1.1/0");
addr_range_test("1.1.1.1/32");
addr_range_test("1.1.1.1-1.2.3.4");
addr_range_test("::1");
addr_range_test("::1/0");
addr_range_test("::1/32");
addr_range_test("::1%lo/32");
addr_range_test("1::-5::");
addr_range_test("1::%lo-5::%lo");
addr_range_bad_test("unix", KNOT_EINVAL);
addr_range_bad_test("1.1.1", KNOT_EINVAL);
addr_range_bad_test("1.1.1.1/", KNOT_EINVAL);
addr_range_bad_test("1.1.1.1/33", KNOT_ERANGE);
addr_range_bad_test("1.1.1.1-", KNOT_EINVAL);
addr_range_bad_test("1.1.1.1-::1", KNOT_EINVAL);
/* Dname tests. */
dname_test("example.com.", "\x07""example""\x03""com""\x00");
/* Hex tests. */
hex_test("", "", NULL);
hex_test("0x", "", "");
hex_test("Hello World!", "Hello World!", NULL);
hex_test("0x0155FF", "\x01\x55\xFF", NULL);
hex_bad_test("0xA", KNOT_EINVAL);
/* Base64 tests. */
base64_test("Zm9vYmFy", "foobar");
/* Ref tests. */
ref_test("on", true);
return 0;
}