summaryrefslogtreecommitdiffstats
path: root/test/rspamd_heap_test.c
diff options
context:
space:
mode:
Diffstat (limited to 'test/rspamd_heap_test.c')
-rw-r--r--test/rspamd_heap_test.c182
1 files changed, 182 insertions, 0 deletions
diff --git a/test/rspamd_heap_test.c b/test/rspamd_heap_test.c
new file mode 100644
index 0000000..dcc7bbc
--- /dev/null
+++ b/test/rspamd_heap_test.c
@@ -0,0 +1,182 @@
+/*-
+ * Copyright 2016 Vsevolod Stakhov
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "config.h"
+#include "rspamd.h"
+#include "heap.h"
+#include "ottery.h"
+
+static const guint niter = 100500;
+static const guint nrem = 100;
+
+static inline struct rspamd_min_heap_elt *
+new_elt(guint pri)
+{
+ struct rspamd_min_heap_elt *elt;
+
+ elt = g_slice_alloc0(sizeof(*elt));
+ elt->pri = pri;
+
+ return elt;
+}
+
+static gdouble
+heap_nelts_test(guint nelts)
+{
+ struct rspamd_min_heap *heap;
+ struct rspamd_min_heap_elt *elts;
+ gdouble t1, t2;
+ guint i;
+
+ heap = rspamd_min_heap_create(nelts);
+ /* Preallocate all elts */
+ elts = g_slice_alloc(sizeof(*elts) * nelts);
+
+ for (i = 0; i < nelts; i++) {
+ elts[i].pri = ottery_rand_uint32() % G_MAXINT32 + 1;
+ elts[i].idx = 0;
+ }
+
+ t1 = rspamd_get_virtual_ticks();
+ for (i = 0; i < nelts; i++) {
+ rspamd_min_heap_push(heap, &elts[i]);
+ }
+
+ for (i = 0; i < nelts; i++) {
+ (void) rspamd_min_heap_pop(heap);
+ }
+ t2 = rspamd_get_virtual_ticks();
+
+ g_slice_free1(sizeof(*elts) * nelts, elts);
+ rspamd_min_heap_destroy(heap);
+
+ return (t2 - t1);
+}
+
+void rspamd_heap_test_func(void)
+{
+ struct rspamd_min_heap *heap;
+ struct rspamd_min_heap_elt *elt, *telt;
+ guint i;
+ guint prev;
+ gdouble t[16];
+
+ /* Push + update */
+ heap = rspamd_min_heap_create(32);
+ elt = new_elt(2);
+ elt->data = GINT_TO_POINTER(1);
+ rspamd_min_heap_push(heap, elt);
+ elt = new_elt(3);
+ elt->data = GINT_TO_POINTER(2);
+ rspamd_min_heap_push(heap, elt);
+ elt = new_elt(4);
+ elt->data = GINT_TO_POINTER(3);
+ rspamd_min_heap_push(heap, elt);
+
+ rspamd_min_heap_update_elt(heap, elt, 0);
+ elt = rspamd_min_heap_pop(heap);
+ g_assert(elt->data == GINT_TO_POINTER(3));
+
+ rspamd_min_heap_destroy(heap);
+
+ /* Push + remove */
+ heap = rspamd_min_heap_create(32);
+ elt = new_elt(2);
+ elt->data = GINT_TO_POINTER(1);
+ rspamd_min_heap_push(heap, elt);
+ rspamd_min_heap_remove_elt(heap, elt);
+ elt = new_elt(3);
+ elt->data = GINT_TO_POINTER(2);
+ rspamd_min_heap_push(heap, elt);
+ elt = rspamd_min_heap_pop(heap);
+ g_assert(elt->data == GINT_TO_POINTER(2));
+ elt = rspamd_min_heap_pop(heap);
+ g_assert(elt == NULL);
+
+ /* Push + push + remove + pop */
+ elt = new_elt(2);
+ elt->data = GINT_TO_POINTER(1);
+ rspamd_min_heap_push(heap, elt);
+ telt = elt;
+ elt = new_elt(3);
+ elt->data = GINT_TO_POINTER(2);
+ rspamd_min_heap_push(heap, elt);
+ rspamd_min_heap_remove_elt(heap, telt);
+ elt = rspamd_min_heap_pop(heap);
+ g_assert(elt->data == GINT_TO_POINTER(2));
+ rspamd_min_heap_destroy(heap);
+
+ /* Bulk test */
+ heap = rspamd_min_heap_create(32);
+
+ for (i = 100; i > 0; i--) {
+ elt = new_elt(i - 1);
+ rspamd_min_heap_push(heap, elt);
+ }
+
+ for (i = 0; i < 100; i++) {
+ elt = rspamd_min_heap_pop(heap);
+ g_assert(elt->pri == i);
+ }
+
+ rspamd_min_heap_destroy(heap);
+
+ /* Fuzz test */
+ heap = rspamd_min_heap_create(128);
+
+ /* Add */
+ for (i = 0; i < niter; i++) {
+ elt = new_elt(ottery_rand_uint32() % G_MAXINT32 + 1);
+ rspamd_min_heap_push(heap, elt);
+ }
+
+ /* Remove */
+ for (i = 0; i < nrem; i++) {
+ elt = rspamd_min_heap_index(heap, ottery_rand_uint32() % niter);
+ rspamd_min_heap_remove_elt(heap, elt);
+ }
+
+ /* Update */
+ for (i = 0; i < niter / 10; i++) {
+ elt = rspamd_min_heap_index(heap, ottery_rand_uint32() % (niter - nrem));
+ rspamd_min_heap_update_elt(heap, elt,
+ ottery_rand_uint32() % G_MAXINT32 + 1);
+ }
+
+ prev = 0;
+
+ /* Pop and check invariant */
+ for (i = 0; i < niter - nrem; i++) {
+ elt = rspamd_min_heap_pop(heap);
+
+ if (prev != 0) {
+ g_assert(elt->pri >= prev);
+ }
+
+ prev = elt->pri;
+ }
+
+ rspamd_min_heap_destroy(heap);
+
+ /* Complexity test (should be O(n * logn) */
+ for (i = 1; i <= G_N_ELEMENTS(t); i++) {
+ t[i - 1] = heap_nelts_test(0x1 << (i + 4));
+ }
+
+ for (i = 1; i <= G_N_ELEMENTS(t); i++) {
+ rspamd_printf("Elements: %d, time: %.4f\n", 0x1 << (i + 4), t[i - 1]);
+ }
+}