summaryrefslogtreecommitdiffstats
path: root/tests/ngtcp2_ksl_test.c
diff options
context:
space:
mode:
Diffstat (limited to 'tests/ngtcp2_ksl_test.c')
-rw-r--r--tests/ngtcp2_ksl_test.c502
1 files changed, 502 insertions, 0 deletions
diff --git a/tests/ngtcp2_ksl_test.c b/tests/ngtcp2_ksl_test.c
new file mode 100644
index 0000000..54bdd1b
--- /dev/null
+++ b/tests/ngtcp2_ksl_test.c
@@ -0,0 +1,502 @@
+/*
+ * ngtcp2
+ *
+ * Copyright (c) 2018 ngtcp2 contributors
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+ * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+ * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+ * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+#include "ngtcp2_ksl_test.h"
+
+#include <CUnit/CUnit.h>
+
+#include "ngtcp2_ksl.h"
+#include "ngtcp2_test_helper.h"
+
+static int less(const ngtcp2_ksl_key *lhs, const ngtcp2_ksl_key *rhs) {
+ return *(int64_t *)lhs < *(int64_t *)rhs;
+}
+
+void test_ngtcp2_ksl_insert(void) {
+ static const int64_t keys[] = {10, 3, 8, 11, 16, 12, 1, 5, 4,
+ 0, 13, 7, 9, 2, 14, 6, 15};
+ ngtcp2_ksl ksl;
+ const ngtcp2_mem *mem = ngtcp2_mem_default();
+ size_t i;
+ ngtcp2_ksl_it it;
+ int64_t k;
+
+ ngtcp2_ksl_init(&ksl, less, sizeof(int64_t), mem);
+
+ for (i = 0; i < ngtcp2_arraylen(keys); ++i) {
+ CU_ASSERT(0 == ngtcp2_ksl_insert(&ksl, NULL, &keys[i], NULL));
+ it = ngtcp2_ksl_lower_bound(&ksl, &keys[i]);
+
+ CU_ASSERT(keys[i] == *(int64_t *)ngtcp2_ksl_it_key(&it));
+ }
+
+ for (i = 0; i < ngtcp2_arraylen(keys); ++i) {
+ CU_ASSERT(0 == ngtcp2_ksl_remove(&ksl, NULL, &keys[i]));
+ it = ngtcp2_ksl_lower_bound(&ksl, &keys[i]);
+ if (!ngtcp2_ksl_it_end(&it)) {
+ CU_ASSERT(keys[i] < *(int64_t *)ngtcp2_ksl_it_key(&it));
+ }
+ }
+
+ ngtcp2_ksl_free(&ksl);
+
+ /* check the case that the right end range is removed */
+ ngtcp2_ksl_init(&ksl, less, sizeof(int64_t), mem);
+
+ for (i = 0; i < 32; ++i) {
+ k = (int64_t)i;
+ CU_ASSERT(0 == ngtcp2_ksl_insert(&ksl, NULL, &k, NULL));
+ }
+
+ /* Removing 15 which is the last node in a blk. */
+ k = 15;
+ CU_ASSERT(0 == ngtcp2_ksl_remove(&ksl, &it, &k));
+
+ CU_ASSERT(16 == *(int64_t *)ngtcp2_ksl_it_key(&it));
+
+ /* Insert 15 again works */
+ CU_ASSERT(0 == ngtcp2_ksl_insert(&ksl, NULL, &k, NULL));
+
+ k = 15;
+ it = ngtcp2_ksl_lower_bound(&ksl, &k);
+
+ CU_ASSERT(15 == *(int64_t *)ngtcp2_ksl_it_key(&it));
+
+ ngtcp2_ksl_free(&ksl);
+
+ /* Check the case that the intermediate node contains smaller key
+ than ancestor node. Make sure that inserting key larger than
+ that still works.*/
+ ngtcp2_ksl_init(&ksl, less, sizeof(int64_t), mem);
+
+ for (i = 0; i < 760; ++i) {
+ k = (int64_t)i;
+ CU_ASSERT(0 == ngtcp2_ksl_insert(&ksl, NULL, &k, NULL));
+ }
+
+ k = 255;
+ CU_ASSERT(0 == ngtcp2_ksl_remove(&ksl, NULL, &k));
+ k = 254;
+ CU_ASSERT(0 == ngtcp2_ksl_remove(&ksl, NULL, &k));
+ k = 253;
+ CU_ASSERT(0 == ngtcp2_ksl_remove(&ksl, NULL, &k));
+
+ k = 253;
+ CU_ASSERT(0 == ngtcp2_ksl_insert(&ksl, NULL, &k, NULL));
+ it = ngtcp2_ksl_lower_bound(&ksl, &k);
+
+ CU_ASSERT(253 == *(int64_t *)ngtcp2_ksl_it_key(&it));
+
+ ngtcp2_ksl_free(&ksl);
+
+ /* check merge node (head) */
+ ngtcp2_ksl_init(&ksl, less, sizeof(int64_t), mem);
+
+ for (i = 0; i < 32; ++i) {
+ k = (int64_t)i;
+ CU_ASSERT(0 == ngtcp2_ksl_insert(&ksl, NULL, &k, NULL));
+ }
+
+ /* Removing these 3 nodes kicks merging 2 nodes under head */
+ k = 15;
+ CU_ASSERT(0 == ngtcp2_ksl_remove(&ksl, NULL, &k));
+ k = 14;
+ CU_ASSERT(0 == ngtcp2_ksl_remove(&ksl, NULL, &k));
+ k = 13;
+ CU_ASSERT(0 == ngtcp2_ksl_remove(&ksl, NULL, &k));
+
+ CU_ASSERT(29 == ksl.head->n);
+
+ ngtcp2_ksl_free(&ksl);
+
+ /* check merge node (non head) */
+ ngtcp2_ksl_init(&ksl, less, sizeof(int64_t), mem);
+
+ for (i = 0; i < 32 + 18; ++i) {
+ k = (int64_t)i;
+ CU_ASSERT(0 == ngtcp2_ksl_insert(&ksl, NULL, &k, NULL));
+ }
+
+ /* Removing these 3 nodes kicks merging 2 nodes */
+ k = 15;
+ CU_ASSERT(0 == ngtcp2_ksl_remove(&ksl, NULL, &k));
+ k = 14;
+ CU_ASSERT(0 == ngtcp2_ksl_remove(&ksl, NULL, &k));
+ k = 13;
+ CU_ASSERT(0 == ngtcp2_ksl_remove(&ksl, NULL, &k));
+
+ CU_ASSERT(2 == ksl.head->n);
+ CU_ASSERT(29 == ngtcp2_ksl_nth_node(&ksl, ksl.head, 0)->blk->n);
+ CU_ASSERT(18 == ngtcp2_ksl_nth_node(&ksl, ksl.head, 1)->blk->n);
+
+ ngtcp2_ksl_free(&ksl);
+
+ /* Iterate backwards */
+ ngtcp2_ksl_init(&ksl, less, sizeof(int64_t), mem);
+
+ /* split nodes */
+ for (i = 0; i < 100; ++i) {
+ k = (int64_t)i;
+ CU_ASSERT(0 == ngtcp2_ksl_insert(&ksl, NULL, &k, NULL));
+ }
+
+ /* merge nodes */
+ for (i = 0; i < 50; ++i) {
+ k = (int64_t)i;
+ CU_ASSERT(0 == ngtcp2_ksl_remove(&ksl, NULL, &k));
+ }
+
+ i = 99;
+ for (it = ngtcp2_ksl_end(&ksl); !ngtcp2_ksl_it_begin(&it);) {
+ ngtcp2_ksl_it_prev(&it);
+
+ CU_ASSERT((int64_t)i-- == *(int64_t *)ngtcp2_ksl_it_key(&it));
+ }
+
+ /* head only */
+ for (i = 50; i < 88; ++i) {
+ k = (int64_t)i;
+ CU_ASSERT(0 == ngtcp2_ksl_remove(&ksl, NULL, &k));
+ }
+
+ i = 99;
+ for (it = ngtcp2_ksl_end(&ksl); !ngtcp2_ksl_it_begin(&it);) {
+ ngtcp2_ksl_it_prev(&it);
+
+ CU_ASSERT((int64_t)i-- == *(int64_t *)ngtcp2_ksl_it_key(&it));
+ }
+
+ ngtcp2_ksl_free(&ksl);
+}
+
+void test_ngtcp2_ksl_clear(void) {
+ ngtcp2_ksl ksl;
+ const ngtcp2_mem *mem = ngtcp2_mem_default();
+ ngtcp2_ksl_it it;
+ size_t i;
+ int64_t k;
+
+ ngtcp2_ksl_init(&ksl, less, sizeof(int64_t), mem);
+
+ for (i = 0; i < 100; ++i) {
+ k = (int64_t)i;
+ CU_ASSERT(0 == ngtcp2_ksl_insert(&ksl, NULL, &k, NULL));
+ }
+
+ ngtcp2_ksl_clear(&ksl);
+
+ CU_ASSERT(0 == ngtcp2_ksl_len(&ksl));
+
+ it = ngtcp2_ksl_begin(&ksl);
+
+ CU_ASSERT(ngtcp2_ksl_it_end(&it));
+
+ it = ngtcp2_ksl_end(&ksl);
+
+ CU_ASSERT(ngtcp2_ksl_it_end(&it));
+
+ ngtcp2_ksl_free(&ksl);
+}
+
+void test_ngtcp2_ksl_range(void) {
+ static const ngtcp2_range keys[] = {
+ {10, 11}, {3, 4}, {8, 9}, {11, 12}, {16, 17}, {12, 13},
+ {1, 2}, {5, 6}, {4, 5}, {0, 1}, {13, 14}, {7, 8},
+ {9, 10}, {2, 3}, {14, 15}, {6, 7}, {15, 16}, {17, 18},
+ {18, 19}, {19, 20}, {20, 21}, {202, 203}, {203, 204}, {204, 205},
+ {205, 206}, {206, 207}, {207, 208}, {208, 209}, {209, 210}, {210, 211},
+ {211, 212}, {212, 213}, {213, 214}, {214, 215}, {215, 216}};
+ ngtcp2_ksl ksl;
+ const ngtcp2_mem *mem = ngtcp2_mem_default();
+ size_t i;
+ ngtcp2_range r;
+ ngtcp2_ksl_it it;
+ ngtcp2_ksl_node *node;
+
+ ngtcp2_ksl_init(&ksl, ngtcp2_ksl_range_compar, sizeof(ngtcp2_range), mem);
+
+ for (i = 0; i < ngtcp2_arraylen(keys); ++i) {
+ CU_ASSERT(0 == ngtcp2_ksl_insert(&ksl, NULL, &keys[i], NULL));
+ it = ngtcp2_ksl_lower_bound_compar(&ksl, &keys[i],
+ ngtcp2_ksl_range_exclusive_compar);
+ r = *(ngtcp2_range *)ngtcp2_ksl_it_key(&it);
+
+ CU_ASSERT(ngtcp2_range_eq(&keys[i], &r));
+ }
+
+ for (i = 0; i < ngtcp2_arraylen(keys); ++i) {
+ CU_ASSERT(0 == ngtcp2_ksl_remove(&ksl, NULL, &keys[i]));
+ it = ngtcp2_ksl_lower_bound_compar(&ksl, &keys[i],
+ ngtcp2_ksl_range_exclusive_compar);
+
+ if (!ngtcp2_ksl_it_end(&it)) {
+ r = *(ngtcp2_range *)ngtcp2_ksl_it_key(&it);
+
+ CU_ASSERT(keys[i].end <= r.begin);
+ }
+ }
+
+ ngtcp2_ksl_free(&ksl);
+
+ /* check merge node (head) */
+ ngtcp2_ksl_init(&ksl, ngtcp2_ksl_range_compar, sizeof(ngtcp2_range), mem);
+
+ for (i = 0; i < 32; ++i) {
+ ngtcp2_range_init(&r, i, i + 1);
+ CU_ASSERT(0 == ngtcp2_ksl_insert(&ksl, NULL, &r, NULL));
+ }
+
+ /* Removing these 3 nodes kicks merging 2 nodes under head */
+ ngtcp2_range_init(&r, 13, 14);
+ CU_ASSERT(0 == ngtcp2_ksl_remove(&ksl, NULL, &r));
+
+ ngtcp2_range_init(&r, 14, 15);
+ CU_ASSERT(0 == ngtcp2_ksl_remove(&ksl, NULL, &r));
+
+ ngtcp2_range_init(&r, 15, 16);
+ CU_ASSERT(0 == ngtcp2_ksl_remove(&ksl, NULL, &r));
+
+ CU_ASSERT(29 == ksl.head->n);
+
+ ngtcp2_ksl_free(&ksl);
+
+ /* check merge node (non head) */
+ ngtcp2_ksl_init(&ksl, ngtcp2_ksl_range_compar, sizeof(ngtcp2_range), mem);
+
+ for (i = 0; i < 32 + 18; ++i) {
+ ngtcp2_range_init(&r, i, i + 1);
+ CU_ASSERT(0 == ngtcp2_ksl_insert(&ksl, NULL, &r, NULL));
+ }
+
+ /* Removing these 3 nodes kicks merging 2 nodes */
+ ngtcp2_range_init(&r, 13, 14);
+ CU_ASSERT(0 == ngtcp2_ksl_remove(&ksl, NULL, &r));
+
+ ngtcp2_range_init(&r, 14, 15);
+ CU_ASSERT(0 == ngtcp2_ksl_remove(&ksl, NULL, &r));
+
+ ngtcp2_range_init(&r, 15, 16);
+ CU_ASSERT(0 == ngtcp2_ksl_remove(&ksl, NULL, &r));
+
+ CU_ASSERT(2 == ksl.head->n);
+ CU_ASSERT(29 == ngtcp2_ksl_nth_node(&ksl, ksl.head, 0)->blk->n);
+ CU_ASSERT(18 == ngtcp2_ksl_nth_node(&ksl, ksl.head, 1)->blk->n);
+
+ ngtcp2_ksl_free(&ksl);
+
+ /* shift_left */
+ ngtcp2_ksl_init(&ksl, ngtcp2_ksl_range_compar, sizeof(ngtcp2_range), mem);
+
+ for (i = 1; i < 6400; i += 100) {
+ ngtcp2_range_init(&r, i, i + 1);
+ CU_ASSERT(0 == ngtcp2_ksl_insert(&ksl, NULL, &r, NULL));
+ }
+
+ ngtcp2_range_init(&r, 1501, 1502);
+ CU_ASSERT(0 == ngtcp2_ksl_remove(&ksl, NULL, &r));
+ ngtcp2_range_init(&r, 1401, 1402);
+ CU_ASSERT(0 == ngtcp2_ksl_remove(&ksl, NULL, &r));
+
+ r = *(ngtcp2_range *)(void *)ngtcp2_ksl_nth_node(
+ &ksl, ngtcp2_ksl_nth_node(&ksl, ksl.head, 1)->blk, 0)
+ ->key;
+
+ CU_ASSERT(1701 == r.begin);
+
+ ngtcp2_ksl_free(&ksl);
+
+ /* shift_right */
+ ngtcp2_ksl_init(&ksl, ngtcp2_ksl_range_compar, sizeof(ngtcp2_range), mem);
+
+ for (i = 0; i < 32; ++i) {
+ ngtcp2_range_init(&r, i, i + 1);
+ CU_ASSERT(0 == ngtcp2_ksl_insert(&ksl, NULL, &r, NULL));
+ }
+
+ ngtcp2_range_init(&r, 17, 18);
+ CU_ASSERT(0 == ngtcp2_ksl_remove(&ksl, NULL, &r));
+ ngtcp2_range_init(&r, 16, 17);
+ CU_ASSERT(0 == ngtcp2_ksl_remove(&ksl, NULL, &r));
+
+ node = ngtcp2_ksl_nth_node(&ksl, ksl.head, 0);
+ r = *(ngtcp2_range *)(void *)ngtcp2_ksl_nth_node(&ksl, node->blk,
+ node->blk->n - 1)
+ ->key;
+
+ CU_ASSERT(14 == r.begin);
+
+ ngtcp2_ksl_free(&ksl);
+}
+
+void test_ngtcp2_ksl_update_key_range(void) {
+ static ngtcp2_range ranges[] = {
+ {0, 5}, {10, 15}, {20, 25}, {30, 35}, {40, 45}, {50, 55},
+ {60, 65}, {70, 75}, {80, 85}, {90, 95}, {100, 105}, {110, 115},
+ {120, 125}, {130, 135}, {140, 145}, {150, 155}, {160, 165}, {170, 175}};
+ ngtcp2_ksl ksl;
+ const ngtcp2_mem *mem = ngtcp2_mem_default();
+ size_t i;
+ ngtcp2_range r;
+ ngtcp2_ksl_it it;
+
+ ngtcp2_ksl_init(&ksl, ngtcp2_ksl_range_compar, sizeof(ngtcp2_range), mem);
+
+ for (i = 0; i < ngtcp2_arraylen(ranges); ++i) {
+ CU_ASSERT(0 == ngtcp2_ksl_insert(&ksl, NULL, &ranges[i], NULL));
+ }
+
+ r.begin = 70;
+ r.end = 72;
+ ngtcp2_ksl_update_key(&ksl, &ranges[7], &r);
+
+ r.begin = 73;
+ r.end = 74;
+ CU_ASSERT(0 == ngtcp2_ksl_insert(&ksl, NULL, &r, NULL));
+
+ r.begin = 74;
+ r.end = 75;
+ CU_ASSERT(0 == ngtcp2_ksl_insert(&ksl, NULL, &r, NULL));
+
+ r.begin = 74;
+ r.end = 75;
+ it = ngtcp2_ksl_lower_bound_compar(&ksl, &r,
+ ngtcp2_ksl_range_exclusive_compar);
+
+ r = *(ngtcp2_range *)ngtcp2_ksl_it_key(&it);
+
+ CU_ASSERT(r.begin == 74);
+ CU_ASSERT(r.end == 75);
+
+ ngtcp2_ksl_free(&ksl);
+}
+
+static void shuffle(int64_t *a, size_t n) {
+ size_t i, j;
+ int64_t t;
+
+ for (i = n - 1; i >= 1; --i) {
+ j = (size_t)((double)(i + 1) * rand() / (RAND_MAX + 1.0));
+ t = a[j];
+ a[j] = a[i];
+ a[i] = t;
+ }
+}
+
+void test_ngtcp2_ksl_dup(void) {
+ static int64_t keys[16000];
+ size_t i, j;
+ ngtcp2_ksl ksl;
+ const ngtcp2_mem *mem = ngtcp2_mem_default();
+ ngtcp2_ksl_it it;
+
+ for (i = 0; i < ngtcp2_arraylen(keys); ++i) {
+ keys[i] = (int64_t)i;
+ }
+
+ for (j = 0; j < 10; ++j) {
+ ngtcp2_ksl_init(&ksl, less, sizeof(int64_t), mem);
+
+ shuffle(keys, ngtcp2_arraylen(keys));
+
+ for (i = 0; i < ngtcp2_arraylen(keys); ++i) {
+ CU_ASSERT(0 == ngtcp2_ksl_insert(&ksl, NULL, &keys[i], NULL));
+ CU_ASSERT(NGTCP2_ERR_INVALID_ARGUMENT ==
+ ngtcp2_ksl_insert(&ksl, NULL, &keys[i], NULL));
+
+ it = ngtcp2_ksl_lower_bound(&ksl, &keys[i]);
+
+ CU_ASSERT(keys[i] == *(int64_t *)ngtcp2_ksl_it_key(&it));
+ }
+
+ shuffle(keys, ngtcp2_arraylen(keys));
+
+ for (i = 0; i < ngtcp2_arraylen(keys); ++i) {
+ CU_ASSERT(0 == ngtcp2_ksl_remove(&ksl, NULL, &keys[i]));
+
+ it = ngtcp2_ksl_begin(&ksl);
+
+ CU_ASSERT(NGTCP2_ERR_INVALID_ARGUMENT ==
+ ngtcp2_ksl_remove(&ksl, &it, &keys[i]));
+ CU_ASSERT(ngtcp2_ksl_it_end(&it));
+
+ it = ngtcp2_ksl_lower_bound(&ksl, &keys[i]);
+
+ CU_ASSERT(ngtcp2_ksl_it_end(&it) ||
+ keys[i] < *(int64_t *)ngtcp2_ksl_it_key(&it));
+
+ CU_ASSERT(0 == ngtcp2_ksl_insert(&ksl, NULL, &keys[i], NULL));
+
+ it = ngtcp2_ksl_begin(&ksl);
+
+ CU_ASSERT(NGTCP2_ERR_INVALID_ARGUMENT ==
+ ngtcp2_ksl_insert(&ksl, &it, &keys[i], NULL));
+ CU_ASSERT(ngtcp2_ksl_it_end(&it));
+
+ it = ngtcp2_ksl_lower_bound(&ksl, &keys[i]);
+ CU_ASSERT(keys[i] == *(int64_t *)ngtcp2_ksl_it_key(&it));
+ }
+
+ ngtcp2_ksl_free(&ksl);
+ }
+}
+
+void test_ngtcp2_ksl_remove_hint(void) {
+ static int64_t keys[16000];
+ ngtcp2_ksl ksl;
+ const ngtcp2_mem *mem = ngtcp2_mem_default();
+ ngtcp2_ksl_it it;
+ size_t i, j;
+
+ for (i = 0; i < ngtcp2_arraylen(keys); ++i) {
+ keys[i] = (int64_t)i;
+ }
+
+ for (j = 0; j < 10; ++j) {
+ ngtcp2_ksl_init(&ksl, less, sizeof(int64_t), mem);
+
+ shuffle(keys, ngtcp2_arraylen(keys));
+
+ for (i = 0; i < ngtcp2_arraylen(keys); ++i) {
+ CU_ASSERT(0 == ngtcp2_ksl_insert(&ksl, NULL, &keys[i], NULL));
+ }
+
+ shuffle(keys, ngtcp2_arraylen(keys));
+
+ for (i = 0; i < ngtcp2_arraylen(keys); ++i) {
+ it = ngtcp2_ksl_lower_bound(&ksl, &keys[i]);
+
+ CU_ASSERT(!ngtcp2_ksl_it_end(&it));
+ CU_ASSERT(keys[i] == *(int64_t *)ngtcp2_ksl_it_key(&it));
+ CU_ASSERT(0 == ngtcp2_ksl_remove_hint(&ksl, &it, &it, &keys[i]));
+
+ it = ngtcp2_ksl_lower_bound(&ksl, &keys[i]);
+
+ CU_ASSERT(ngtcp2_ksl_it_end(&it) ||
+ keys[i] != *(int64_t *)ngtcp2_ksl_it_key(&it));
+ CU_ASSERT(ngtcp2_arraylen(keys) - i - 1 == ngtcp2_ksl_len(&ksl));
+ }
+
+ ngtcp2_ksl_free(&ksl);
+ }
+}