// SPDX-License-Identifier: GPL-2.0-only #define pr_fmt(fmt) "min_heap_test: " fmt /* * Test cases for the min max heap. */ #include #include #include #include #include DEFINE_MIN_HEAP(int, min_heap_test); static __init bool less_than(const void *lhs, const void *rhs, void __always_unused *args) { return *(int *)lhs < *(int *)rhs; } static __init bool greater_than(const void *lhs, const void *rhs, void __always_unused *args) { return *(int *)lhs > *(int *)rhs; } static __init int pop_verify_heap(bool min_heap, struct min_heap_test *heap, const struct min_heap_callbacks *funcs) { int *values = heap->data; int err = 0; int last; last = values[0]; min_heap_pop(heap, funcs, NULL); while (heap->nr > 0) { if (min_heap) { if (last > values[0]) { pr_err("error: expected %d <= %d\n", last, values[0]); err++; } } else { if (last < values[0]) { pr_err("error: expected %d >= %d\n", last, values[0]); err++; } } last = values[0]; min_heap_pop(heap, funcs, NULL); } return err; } static __init int test_heapify_all(bool min_heap) { int values[] = { 3, 1, 2, 4, 0x8000000, 0x7FFFFFF, 0, -3, -1, -2, -4, 0x8000000, 0x7FFFFFF }; struct min_heap_test heap = { .data = values, .nr = ARRAY_SIZE(values), .size = ARRAY_SIZE(values), }; struct min_heap_callbacks funcs = { .less = min_heap ? less_than : greater_than, .swp = NULL, }; int i, err; /* Test with known set of values. */ min_heapify_all(&heap, &funcs, NULL); err = pop_verify_heap(min_heap, &heap, &funcs); /* Test with randomly generated values. */ heap.nr = ARRAY_SIZE(values); for (i = 0; i < heap.nr; i++) values[i] = get_random_u32(); min_heapify_all(&heap, &funcs, NULL); err += pop_verify_heap(min_heap, &heap, &funcs); return err; } static __init int test_heap_push(bool min_heap) { const int data[] = { 3, 1, 2, 4, 0x80000000, 0x7FFFFFFF, 0, -3, -1, -2, -4, 0x80000000, 0x7FFFFFFF }; int values[ARRAY_SIZE(data)]; struct min_heap_test heap = { .data = values, .nr = 0, .size = ARRAY_SIZE(values), }; struct min_heap_callbacks funcs = { .less = min_heap ? less_than : greater_than, .swp = NULL, }; int i, temp, err; /* Test with known set of values copied from data. */ for (i = 0; i < ARRAY_SIZE(data); i++) min_heap_push(&heap, &data[i], &funcs, NULL); err = pop_verify_heap(min_heap, &heap, &funcs); /* Test with randomly generated values. */ while (heap.nr < heap.size) { temp = get_random_u32(); min_heap_push(&heap, &temp, &funcs, NULL); } err += pop_verify_heap(min_heap, &heap, &funcs); return err; } static __init int test_heap_pop_push(bool min_heap) { const int data[] = { 3, 1, 2, 4, 0x80000000, 0x7FFFFFFF, 0, -3, -1, -2, -4, 0x80000000, 0x7FFFFFFF }; int values[ARRAY_SIZE(data)]; struct min_heap_test heap = { .data = values, .nr = 0, .size = ARRAY_SIZE(values), }; struct min_heap_callbacks funcs = { .less = min_heap ? less_than : greater_than, .swp = NULL, }; int i, temp, err; /* Fill values with data to pop and replace. */ temp = min_heap ? 0x80000000 : 0x7FFFFFFF; for (i = 0; i < ARRAY_SIZE(data); i++) min_heap_push(&heap, &temp, &funcs, NULL); /* Test with known set of values copied from data. */ for (i = 0; i < ARRAY_SIZE(data); i++) min_heap_pop_push(&heap, &data[i], &funcs, NULL); err = pop_verify_heap(min_heap, &heap, &funcs); heap.nr = 0; for (i = 0; i < ARRAY_SIZE(data); i++) min_heap_push(&heap, &temp, &funcs, NULL); /* Test with randomly generated values. */ for (i = 0; i < ARRAY_SIZE(data); i++) { temp = get_random_u32(); min_heap_pop_push(&heap, &temp, &funcs, NULL); } err += pop_verify_heap(min_heap, &heap, &funcs); return err; } static __init int test_heap_del(bool min_heap) { int values[] = { 3, 1, 2, 4, 0x8000000, 0x7FFFFFF, 0, -3, -1, -2, -4, 0x8000000, 0x7FFFFFF }; struct min_heap_test heap; min_heap_init(&heap, values, ARRAY_SIZE(values)); heap.nr = ARRAY_SIZE(values); struct min_heap_callbacks funcs = { .less = min_heap ? less_than : greater_than, .swp = NULL, }; int i, err; /* Test with known set of values. */ min_heapify_all(&heap, &funcs, NULL); for (i = 0; i < ARRAY_SIZE(values) / 2; i++) min_heap_del(&heap, get_random_u32() % heap.nr, &funcs, NULL); err = pop_verify_heap(min_heap, &heap, &funcs); /* Test with randomly generated values. */ heap.nr = ARRAY_SIZE(values); for (i = 0; i < heap.nr; i++) values[i] = get_random_u32(); min_heapify_all(&heap, &funcs, NULL); for (i = 0; i < ARRAY_SIZE(values) / 2; i++) min_heap_del(&heap, get_random_u32() % heap.nr, &funcs, NULL); err += pop_verify_heap(min_heap, &heap, &funcs); return err; } static int __init test_min_heap_init(void) { int err = 0; err += test_heapify_all(true); err += test_heapify_all(false); err += test_heap_push(true); err += test_heap_push(false); err += test_heap_pop_push(true); err += test_heap_pop_push(false); err += test_heap_del(true); err += test_heap_del(false); if (err) { pr_err("test failed with %d errors\n", err); return -EINVAL; } pr_info("test passed\n"); return 0; } module_init(test_min_heap_init); static void __exit test_min_heap_exit(void) { /* do nothing */ } module_exit(test_min_heap_exit); MODULE_DESCRIPTION("Test cases for the min max heap"); MODULE_LICENSE("GPL");