/* Copyright (C) 2022 CZ.NIC, z.s.p.o. 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 . */ #include #include #include #include "libknot/rdataset.c" #include "libknot/libknot.h" // Inits rdataset with given rdata. #define RDATASET_INIT_WITH(set, rdata) \ knot_rdataset_clear(&set, NULL); \ ret = knot_rdataset_add(&set, rdata, NULL); \ assert(ret == KNOT_EOK); static size_t rdataset_size(const knot_rdataset_t *rrs) { if (rrs == NULL || rrs->count == 0) { return 0; } const knot_rdata_t *last = rr_seek(rrs, rrs->count - 1); return (uint8_t *)last + knot_rdata_size(last->len) - (uint8_t *)rrs->rdata; } int main(int argc, char *argv[]) { plan_lazy(); // Test init knot_rdataset_t rdataset; knot_rdataset_init(&rdataset); ok(rdataset.rdata == NULL && rdataset.count == 0 && rdataset.size == 0, "rdataset: init."); // Test rdata addition uint8_t buf_gt[knot_rdata_size(4)]; knot_rdata_t *rdata_gt = (knot_rdata_t *)buf_gt; knot_rdata_init(rdata_gt, 4, (uint8_t *)"wxyz"); int ret = knot_rdataset_add(NULL, NULL, NULL); is_int(KNOT_EINVAL, ret, "rdataset: add NULL."); ret = knot_rdataset_add(&rdataset, rdata_gt, NULL); bool add_ok = ret == KNOT_EOK && rdataset.count == 1 && knot_rdata_cmp(rdata_gt, rdataset.rdata) == 0; ok(add_ok, "rdataset: add."); uint8_t buf_lo[knot_rdata_size(4)]; knot_rdata_t *rdata_lo = (knot_rdata_t *)buf_lo; knot_rdata_init(rdata_lo, 4, (uint8_t *)"abcd"); ret = knot_rdataset_add(&rdataset, rdata_lo, NULL); add_ok = ret == KNOT_EOK && rdataset.count == 2 && knot_rdata_cmp(rdata_lo, rdataset.rdata) == 0; ok(add_ok, "rdataset: add lower."); // Test getters ok(knot_rdata_cmp(knot_rdataset_at(&rdataset, 0), rdata_lo) == 0 && knot_rdata_cmp(knot_rdataset_at(&rdataset, 1), rdata_gt) == 0, "rdataset: at."); ok(rdataset_size(&rdataset) == knot_rdata_size(4) * 2, "rdataset: size."); ok(rdataset.size == rdataset_size(&rdataset), "rdataset: size precomputed (%u %zu).", rdataset.size, rdataset_size(&rdataset)); // Test copy ok(knot_rdataset_copy(NULL, NULL, NULL) == KNOT_EINVAL, "rdataset: copy NULL."); knot_rdataset_t copy; ret = knot_rdataset_copy(©, &rdataset, NULL); const bool copy_ok = ret == KNOT_EOK && copy.count == rdataset.count && rdataset_size(©) == rdataset_size(&rdataset) && rdataset.rdata != NULL && copy.rdata != NULL && memcmp(rdataset.rdata, copy.rdata, rdataset_size(&rdataset)) == 0; ok(copy_ok, "rdataset: copy"); ok(copy.size == rdataset_size(©), "copy: size precomputed."); // Test eq ok(knot_rdataset_eq(&rdataset, ©), "rdataset: equal"); // Test clear knot_rdataset_clear(©, NULL); ok(copy.count == 0 && copy.rdata == NULL, "rdataset: clear."); // Test not equal (different count) ok(!knot_rdataset_eq(&rdataset, ©), "rdataset: not equal - count"); // Test member uint8_t buf_not[knot_rdata_size(1)]; knot_rdata_t *not_a_member = (knot_rdata_t *)buf_not; knot_rdata_init(not_a_member, 1, (uint8_t *)"?"); ok(knot_rdataset_member(&rdataset, rdata_gt), "rdataset: is member."); ok(!knot_rdataset_member(&rdataset, not_a_member), "rdataset: is not member."); // Test merge ok(knot_rdataset_merge(NULL, NULL, NULL) == KNOT_EINVAL, "rdataset: merge NULL."); knot_rdataset_t empty; knot_rdataset_init(&empty); ret = knot_rdataset_merge(&empty, &rdataset, NULL); bool merge_ok = ret == KNOT_EOK && knot_rdataset_eq(&empty, &rdataset); ok(merge_ok, "rdataset: merge empty."); knot_rdata_t *data_before = rdataset.rdata; ret = knot_rdataset_merge(&rdataset, &rdataset, NULL); merge_ok = ret == KNOT_EOK && rdataset.count == 2 && data_before == rdataset.rdata; ok(merge_ok, "rdataset: merge self."); knot_rdataset_clear(&empty, NULL); // Init structs for merge sort testing knot_rdataset_t rdataset_lo; // "Lower" rdataset knot_rdataset_init(&rdataset_lo); RDATASET_INIT_WITH(rdataset_lo, rdata_lo); knot_rdataset_t rdataset_gt; // "Greater" rdataset knot_rdataset_init(&rdataset_gt); RDATASET_INIT_WITH(rdataset_gt, rdata_gt); // Test not equal - different data ok(!knot_rdataset_eq(&rdataset_gt, &rdataset_lo), "rdataset: data not equal."); // Test that merge keeps the sorted order ret = knot_rdataset_merge(&rdataset_lo, &rdataset_gt, NULL); merge_ok = ret == KNOT_EOK && knot_rdataset_eq(&rdataset_lo, &rdataset); ok(merge_ok, "rdataset: merge into lower."); RDATASET_INIT_WITH(rdataset_lo, rdata_lo); RDATASET_INIT_WITH(rdataset_gt, rdata_gt); ret = knot_rdataset_merge(&rdataset_gt, &rdataset_lo, NULL); merge_ok = ret == KNOT_EOK && knot_rdataset_eq(&rdataset_gt, &rdataset); ok(merge_ok, "rdataset: merge into greater."); // Test intersect ok(knot_rdataset_intersect(NULL, NULL, NULL, NULL) == KNOT_EINVAL, "rdataset: intersect NULL."); knot_rdataset_t intersection; ret = knot_rdataset_intersect(&rdataset, &rdataset, &intersection, NULL); bool intersect_ok = ret == KNOT_EOK && knot_rdataset_eq(&rdataset, &intersection); ok(intersect_ok, "rdataset: intersect self."); knot_rdataset_clear(&intersection, NULL); RDATASET_INIT_WITH(rdataset_lo, rdata_lo); RDATASET_INIT_WITH(rdataset_gt, rdata_gt); ret = knot_rdataset_intersect(&rdataset_lo, &rdataset_gt, &intersection, NULL); intersect_ok = ret == KNOT_EOK && intersection.count == 0; ok(intersect_ok, "rdataset: intersect no common."); ret = knot_rdataset_intersect(&rdataset, &rdataset_lo, &intersection, NULL); intersect_ok = ret == KNOT_EOK && knot_rdataset_eq(&intersection, &rdataset_lo); ok(intersect_ok, "rdataset: intersect normal."); knot_rdataset_clear(&intersection, NULL); // Test intersect2 ok(knot_rdataset_intersect2(NULL, NULL, NULL) == KNOT_EINVAL, "rdataset: intersect2 NULL."); ret = knot_rdataset_intersect2(&rdataset, &rdataset, NULL); intersect_ok = ret == KNOT_EOK && knot_rdataset_eq(&rdataset, &rdataset); ok(intersect_ok, "rdataset: intersect2 self."); knot_rdataset_clear(&intersection, NULL); RDATASET_INIT_WITH(rdataset_lo, rdata_lo); RDATASET_INIT_WITH(rdataset_gt, rdata_gt); ret = knot_rdataset_intersect2(&rdataset_lo, &rdataset_gt, NULL); intersect_ok = ret == KNOT_EOK && rdataset_lo.count == 0; ok(intersect_ok, "rdataset: intersect2 no common."); ret = knot_rdataset_copy(©, &rdataset, NULL); assert(ret == KNOT_EOK); ret = knot_rdataset_intersect2(©, &rdataset_lo, NULL); intersect_ok = ret == KNOT_EOK && knot_rdataset_eq(©, &rdataset_lo); ok(intersect_ok, "rdataset: intersect2 normal."); knot_rdataset_clear(©, NULL); // Test subtract ok(knot_rdataset_subtract(NULL, NULL, NULL) == KNOT_EINVAL, "rdataset: subtract NULL."); ret = knot_rdataset_copy(©, &rdataset, NULL); assert(ret == KNOT_EOK); ok(knot_rdataset_subtract(©, ©, NULL) == KNOT_EOK && copy.count == 0, "rdataset: subtract self."); ret = knot_rdataset_copy(©, &rdataset, NULL); assert(ret == KNOT_EOK); ret = knot_rdataset_subtract(©, &rdataset, NULL); bool subtract_ok = ret == KNOT_EOK && copy.count == 0; ok(subtract_ok, "rdataset: subtract identical."); RDATASET_INIT_WITH(rdataset_lo, rdata_lo); RDATASET_INIT_WITH(rdataset_gt, rdata_gt); data_before = rdataset_lo.rdata; ret = knot_rdataset_subtract(&rdataset_lo, &rdataset_gt, NULL); subtract_ok = ret == KNOT_EOK && rdataset_lo.count == 1 && rdataset_lo.rdata == data_before; ok(subtract_ok, "rdataset: subtract no common."); ret = knot_rdataset_subtract(&rdataset, &rdataset_gt, NULL); subtract_ok = ret == KNOT_EOK && rdataset.count == 1; ok(subtract_ok, "rdataset: subtract the second."); ret = knot_rdataset_subtract(&rdataset, &rdataset_lo, NULL); subtract_ok = ret == KNOT_EOK && rdataset.count == 0 && rdataset.rdata == NULL; ok(subtract_ok, "rdataset: subtract last."); knot_rdataset_clear(©, NULL); knot_rdataset_clear(&rdataset, NULL); knot_rdataset_clear(&rdataset_lo, NULL); knot_rdataset_clear(&rdataset_gt, NULL); return EXIT_SUCCESS; }