18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only
28c2ecf20Sopenharmony_ci#define pr_fmt(fmt) "min_heap_test: " fmt
38c2ecf20Sopenharmony_ci
48c2ecf20Sopenharmony_ci/*
58c2ecf20Sopenharmony_ci * Test cases for the min max heap.
68c2ecf20Sopenharmony_ci */
78c2ecf20Sopenharmony_ci
88c2ecf20Sopenharmony_ci#include <linux/log2.h>
98c2ecf20Sopenharmony_ci#include <linux/min_heap.h>
108c2ecf20Sopenharmony_ci#include <linux/module.h>
118c2ecf20Sopenharmony_ci#include <linux/printk.h>
128c2ecf20Sopenharmony_ci#include <linux/random.h>
138c2ecf20Sopenharmony_ci
148c2ecf20Sopenharmony_cistatic __init bool less_than(const void *lhs, const void *rhs)
158c2ecf20Sopenharmony_ci{
168c2ecf20Sopenharmony_ci	return *(int *)lhs < *(int *)rhs;
178c2ecf20Sopenharmony_ci}
188c2ecf20Sopenharmony_ci
198c2ecf20Sopenharmony_cistatic __init bool greater_than(const void *lhs, const void *rhs)
208c2ecf20Sopenharmony_ci{
218c2ecf20Sopenharmony_ci	return *(int *)lhs > *(int *)rhs;
228c2ecf20Sopenharmony_ci}
238c2ecf20Sopenharmony_ci
248c2ecf20Sopenharmony_cistatic __init void swap_ints(void *lhs, void *rhs)
258c2ecf20Sopenharmony_ci{
268c2ecf20Sopenharmony_ci	int temp = *(int *)lhs;
278c2ecf20Sopenharmony_ci
288c2ecf20Sopenharmony_ci	*(int *)lhs = *(int *)rhs;
298c2ecf20Sopenharmony_ci	*(int *)rhs = temp;
308c2ecf20Sopenharmony_ci}
318c2ecf20Sopenharmony_ci
328c2ecf20Sopenharmony_cistatic __init int pop_verify_heap(bool min_heap,
338c2ecf20Sopenharmony_ci				struct min_heap *heap,
348c2ecf20Sopenharmony_ci				const struct min_heap_callbacks *funcs)
358c2ecf20Sopenharmony_ci{
368c2ecf20Sopenharmony_ci	int *values = heap->data;
378c2ecf20Sopenharmony_ci	int err = 0;
388c2ecf20Sopenharmony_ci	int last;
398c2ecf20Sopenharmony_ci
408c2ecf20Sopenharmony_ci	last = values[0];
418c2ecf20Sopenharmony_ci	min_heap_pop(heap, funcs);
428c2ecf20Sopenharmony_ci	while (heap->nr > 0) {
438c2ecf20Sopenharmony_ci		if (min_heap) {
448c2ecf20Sopenharmony_ci			if (last > values[0]) {
458c2ecf20Sopenharmony_ci				pr_err("error: expected %d <= %d\n", last,
468c2ecf20Sopenharmony_ci					values[0]);
478c2ecf20Sopenharmony_ci				err++;
488c2ecf20Sopenharmony_ci			}
498c2ecf20Sopenharmony_ci		} else {
508c2ecf20Sopenharmony_ci			if (last < values[0]) {
518c2ecf20Sopenharmony_ci				pr_err("error: expected %d >= %d\n", last,
528c2ecf20Sopenharmony_ci					values[0]);
538c2ecf20Sopenharmony_ci				err++;
548c2ecf20Sopenharmony_ci			}
558c2ecf20Sopenharmony_ci		}
568c2ecf20Sopenharmony_ci		last = values[0];
578c2ecf20Sopenharmony_ci		min_heap_pop(heap, funcs);
588c2ecf20Sopenharmony_ci	}
598c2ecf20Sopenharmony_ci	return err;
608c2ecf20Sopenharmony_ci}
618c2ecf20Sopenharmony_ci
628c2ecf20Sopenharmony_cistatic __init int test_heapify_all(bool min_heap)
638c2ecf20Sopenharmony_ci{
648c2ecf20Sopenharmony_ci	int values[] = { 3, 1, 2, 4, 0x8000000, 0x7FFFFFF, 0,
658c2ecf20Sopenharmony_ci			 -3, -1, -2, -4, 0x8000000, 0x7FFFFFF };
668c2ecf20Sopenharmony_ci	struct min_heap heap = {
678c2ecf20Sopenharmony_ci		.data = values,
688c2ecf20Sopenharmony_ci		.nr = ARRAY_SIZE(values),
698c2ecf20Sopenharmony_ci		.size =  ARRAY_SIZE(values),
708c2ecf20Sopenharmony_ci	};
718c2ecf20Sopenharmony_ci	struct min_heap_callbacks funcs = {
728c2ecf20Sopenharmony_ci		.elem_size = sizeof(int),
738c2ecf20Sopenharmony_ci		.less = min_heap ? less_than : greater_than,
748c2ecf20Sopenharmony_ci		.swp = swap_ints,
758c2ecf20Sopenharmony_ci	};
768c2ecf20Sopenharmony_ci	int i, err;
778c2ecf20Sopenharmony_ci
788c2ecf20Sopenharmony_ci	/* Test with known set of values. */
798c2ecf20Sopenharmony_ci	min_heapify_all(&heap, &funcs);
808c2ecf20Sopenharmony_ci	err = pop_verify_heap(min_heap, &heap, &funcs);
818c2ecf20Sopenharmony_ci
828c2ecf20Sopenharmony_ci
838c2ecf20Sopenharmony_ci	/* Test with randomly generated values. */
848c2ecf20Sopenharmony_ci	heap.nr = ARRAY_SIZE(values);
858c2ecf20Sopenharmony_ci	for (i = 0; i < heap.nr; i++)
868c2ecf20Sopenharmony_ci		values[i] = get_random_int();
878c2ecf20Sopenharmony_ci
888c2ecf20Sopenharmony_ci	min_heapify_all(&heap, &funcs);
898c2ecf20Sopenharmony_ci	err += pop_verify_heap(min_heap, &heap, &funcs);
908c2ecf20Sopenharmony_ci
918c2ecf20Sopenharmony_ci	return err;
928c2ecf20Sopenharmony_ci}
938c2ecf20Sopenharmony_ci
948c2ecf20Sopenharmony_cistatic __init int test_heap_push(bool min_heap)
958c2ecf20Sopenharmony_ci{
968c2ecf20Sopenharmony_ci	const int data[] = { 3, 1, 2, 4, 0x80000000, 0x7FFFFFFF, 0,
978c2ecf20Sopenharmony_ci			     -3, -1, -2, -4, 0x80000000, 0x7FFFFFFF };
988c2ecf20Sopenharmony_ci	int values[ARRAY_SIZE(data)];
998c2ecf20Sopenharmony_ci	struct min_heap heap = {
1008c2ecf20Sopenharmony_ci		.data = values,
1018c2ecf20Sopenharmony_ci		.nr = 0,
1028c2ecf20Sopenharmony_ci		.size =  ARRAY_SIZE(values),
1038c2ecf20Sopenharmony_ci	};
1048c2ecf20Sopenharmony_ci	struct min_heap_callbacks funcs = {
1058c2ecf20Sopenharmony_ci		.elem_size = sizeof(int),
1068c2ecf20Sopenharmony_ci		.less = min_heap ? less_than : greater_than,
1078c2ecf20Sopenharmony_ci		.swp = swap_ints,
1088c2ecf20Sopenharmony_ci	};
1098c2ecf20Sopenharmony_ci	int i, temp, err;
1108c2ecf20Sopenharmony_ci
1118c2ecf20Sopenharmony_ci	/* Test with known set of values copied from data. */
1128c2ecf20Sopenharmony_ci	for (i = 0; i < ARRAY_SIZE(data); i++)
1138c2ecf20Sopenharmony_ci		min_heap_push(&heap, &data[i], &funcs);
1148c2ecf20Sopenharmony_ci
1158c2ecf20Sopenharmony_ci	err = pop_verify_heap(min_heap, &heap, &funcs);
1168c2ecf20Sopenharmony_ci
1178c2ecf20Sopenharmony_ci	/* Test with randomly generated values. */
1188c2ecf20Sopenharmony_ci	while (heap.nr < heap.size) {
1198c2ecf20Sopenharmony_ci		temp = get_random_int();
1208c2ecf20Sopenharmony_ci		min_heap_push(&heap, &temp, &funcs);
1218c2ecf20Sopenharmony_ci	}
1228c2ecf20Sopenharmony_ci	err += pop_verify_heap(min_heap, &heap, &funcs);
1238c2ecf20Sopenharmony_ci
1248c2ecf20Sopenharmony_ci	return err;
1258c2ecf20Sopenharmony_ci}
1268c2ecf20Sopenharmony_ci
1278c2ecf20Sopenharmony_cistatic __init int test_heap_pop_push(bool min_heap)
1288c2ecf20Sopenharmony_ci{
1298c2ecf20Sopenharmony_ci	const int data[] = { 3, 1, 2, 4, 0x80000000, 0x7FFFFFFF, 0,
1308c2ecf20Sopenharmony_ci			     -3, -1, -2, -4, 0x80000000, 0x7FFFFFFF };
1318c2ecf20Sopenharmony_ci	int values[ARRAY_SIZE(data)];
1328c2ecf20Sopenharmony_ci	struct min_heap heap = {
1338c2ecf20Sopenharmony_ci		.data = values,
1348c2ecf20Sopenharmony_ci		.nr = 0,
1358c2ecf20Sopenharmony_ci		.size =  ARRAY_SIZE(values),
1368c2ecf20Sopenharmony_ci	};
1378c2ecf20Sopenharmony_ci	struct min_heap_callbacks funcs = {
1388c2ecf20Sopenharmony_ci		.elem_size = sizeof(int),
1398c2ecf20Sopenharmony_ci		.less = min_heap ? less_than : greater_than,
1408c2ecf20Sopenharmony_ci		.swp = swap_ints,
1418c2ecf20Sopenharmony_ci	};
1428c2ecf20Sopenharmony_ci	int i, temp, err;
1438c2ecf20Sopenharmony_ci
1448c2ecf20Sopenharmony_ci	/* Fill values with data to pop and replace. */
1458c2ecf20Sopenharmony_ci	temp = min_heap ? 0x80000000 : 0x7FFFFFFF;
1468c2ecf20Sopenharmony_ci	for (i = 0; i < ARRAY_SIZE(data); i++)
1478c2ecf20Sopenharmony_ci		min_heap_push(&heap, &temp, &funcs);
1488c2ecf20Sopenharmony_ci
1498c2ecf20Sopenharmony_ci	/* Test with known set of values copied from data. */
1508c2ecf20Sopenharmony_ci	for (i = 0; i < ARRAY_SIZE(data); i++)
1518c2ecf20Sopenharmony_ci		min_heap_pop_push(&heap, &data[i], &funcs);
1528c2ecf20Sopenharmony_ci
1538c2ecf20Sopenharmony_ci	err = pop_verify_heap(min_heap, &heap, &funcs);
1548c2ecf20Sopenharmony_ci
1558c2ecf20Sopenharmony_ci	heap.nr = 0;
1568c2ecf20Sopenharmony_ci	for (i = 0; i < ARRAY_SIZE(data); i++)
1578c2ecf20Sopenharmony_ci		min_heap_push(&heap, &temp, &funcs);
1588c2ecf20Sopenharmony_ci
1598c2ecf20Sopenharmony_ci	/* Test with randomly generated values. */
1608c2ecf20Sopenharmony_ci	for (i = 0; i < ARRAY_SIZE(data); i++) {
1618c2ecf20Sopenharmony_ci		temp = get_random_int();
1628c2ecf20Sopenharmony_ci		min_heap_pop_push(&heap, &temp, &funcs);
1638c2ecf20Sopenharmony_ci	}
1648c2ecf20Sopenharmony_ci	err += pop_verify_heap(min_heap, &heap, &funcs);
1658c2ecf20Sopenharmony_ci
1668c2ecf20Sopenharmony_ci	return err;
1678c2ecf20Sopenharmony_ci}
1688c2ecf20Sopenharmony_ci
1698c2ecf20Sopenharmony_cistatic int __init test_min_heap_init(void)
1708c2ecf20Sopenharmony_ci{
1718c2ecf20Sopenharmony_ci	int err = 0;
1728c2ecf20Sopenharmony_ci
1738c2ecf20Sopenharmony_ci	err += test_heapify_all(true);
1748c2ecf20Sopenharmony_ci	err += test_heapify_all(false);
1758c2ecf20Sopenharmony_ci	err += test_heap_push(true);
1768c2ecf20Sopenharmony_ci	err += test_heap_push(false);
1778c2ecf20Sopenharmony_ci	err += test_heap_pop_push(true);
1788c2ecf20Sopenharmony_ci	err += test_heap_pop_push(false);
1798c2ecf20Sopenharmony_ci	if (err) {
1808c2ecf20Sopenharmony_ci		pr_err("test failed with %d errors\n", err);
1818c2ecf20Sopenharmony_ci		return -EINVAL;
1828c2ecf20Sopenharmony_ci	}
1838c2ecf20Sopenharmony_ci	pr_info("test passed\n");
1848c2ecf20Sopenharmony_ci	return 0;
1858c2ecf20Sopenharmony_ci}
1868c2ecf20Sopenharmony_cimodule_init(test_min_heap_init);
1878c2ecf20Sopenharmony_ci
1888c2ecf20Sopenharmony_cistatic void __exit test_min_heap_exit(void)
1898c2ecf20Sopenharmony_ci{
1908c2ecf20Sopenharmony_ci	/* do nothing */
1918c2ecf20Sopenharmony_ci}
1928c2ecf20Sopenharmony_cimodule_exit(test_min_heap_exit);
1938c2ecf20Sopenharmony_ci
1948c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL");
195