162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only
262306a36Sopenharmony_ci#define pr_fmt(fmt) "min_heap_test: " fmt
362306a36Sopenharmony_ci
462306a36Sopenharmony_ci/*
562306a36Sopenharmony_ci * Test cases for the min max heap.
662306a36Sopenharmony_ci */
762306a36Sopenharmony_ci
862306a36Sopenharmony_ci#include <linux/log2.h>
962306a36Sopenharmony_ci#include <linux/min_heap.h>
1062306a36Sopenharmony_ci#include <linux/module.h>
1162306a36Sopenharmony_ci#include <linux/printk.h>
1262306a36Sopenharmony_ci#include <linux/random.h>
1362306a36Sopenharmony_ci
1462306a36Sopenharmony_cistatic __init bool less_than(const void *lhs, const void *rhs)
1562306a36Sopenharmony_ci{
1662306a36Sopenharmony_ci	return *(int *)lhs < *(int *)rhs;
1762306a36Sopenharmony_ci}
1862306a36Sopenharmony_ci
1962306a36Sopenharmony_cistatic __init bool greater_than(const void *lhs, const void *rhs)
2062306a36Sopenharmony_ci{
2162306a36Sopenharmony_ci	return *(int *)lhs > *(int *)rhs;
2262306a36Sopenharmony_ci}
2362306a36Sopenharmony_ci
2462306a36Sopenharmony_cistatic __init void swap_ints(void *lhs, void *rhs)
2562306a36Sopenharmony_ci{
2662306a36Sopenharmony_ci	int temp = *(int *)lhs;
2762306a36Sopenharmony_ci
2862306a36Sopenharmony_ci	*(int *)lhs = *(int *)rhs;
2962306a36Sopenharmony_ci	*(int *)rhs = temp;
3062306a36Sopenharmony_ci}
3162306a36Sopenharmony_ci
3262306a36Sopenharmony_cistatic __init int pop_verify_heap(bool min_heap,
3362306a36Sopenharmony_ci				struct min_heap *heap,
3462306a36Sopenharmony_ci				const struct min_heap_callbacks *funcs)
3562306a36Sopenharmony_ci{
3662306a36Sopenharmony_ci	int *values = heap->data;
3762306a36Sopenharmony_ci	int err = 0;
3862306a36Sopenharmony_ci	int last;
3962306a36Sopenharmony_ci
4062306a36Sopenharmony_ci	last = values[0];
4162306a36Sopenharmony_ci	min_heap_pop(heap, funcs);
4262306a36Sopenharmony_ci	while (heap->nr > 0) {
4362306a36Sopenharmony_ci		if (min_heap) {
4462306a36Sopenharmony_ci			if (last > values[0]) {
4562306a36Sopenharmony_ci				pr_err("error: expected %d <= %d\n", last,
4662306a36Sopenharmony_ci					values[0]);
4762306a36Sopenharmony_ci				err++;
4862306a36Sopenharmony_ci			}
4962306a36Sopenharmony_ci		} else {
5062306a36Sopenharmony_ci			if (last < values[0]) {
5162306a36Sopenharmony_ci				pr_err("error: expected %d >= %d\n", last,
5262306a36Sopenharmony_ci					values[0]);
5362306a36Sopenharmony_ci				err++;
5462306a36Sopenharmony_ci			}
5562306a36Sopenharmony_ci		}
5662306a36Sopenharmony_ci		last = values[0];
5762306a36Sopenharmony_ci		min_heap_pop(heap, funcs);
5862306a36Sopenharmony_ci	}
5962306a36Sopenharmony_ci	return err;
6062306a36Sopenharmony_ci}
6162306a36Sopenharmony_ci
6262306a36Sopenharmony_cistatic __init int test_heapify_all(bool min_heap)
6362306a36Sopenharmony_ci{
6462306a36Sopenharmony_ci	int values[] = { 3, 1, 2, 4, 0x8000000, 0x7FFFFFF, 0,
6562306a36Sopenharmony_ci			 -3, -1, -2, -4, 0x8000000, 0x7FFFFFF };
6662306a36Sopenharmony_ci	struct min_heap heap = {
6762306a36Sopenharmony_ci		.data = values,
6862306a36Sopenharmony_ci		.nr = ARRAY_SIZE(values),
6962306a36Sopenharmony_ci		.size =  ARRAY_SIZE(values),
7062306a36Sopenharmony_ci	};
7162306a36Sopenharmony_ci	struct min_heap_callbacks funcs = {
7262306a36Sopenharmony_ci		.elem_size = sizeof(int),
7362306a36Sopenharmony_ci		.less = min_heap ? less_than : greater_than,
7462306a36Sopenharmony_ci		.swp = swap_ints,
7562306a36Sopenharmony_ci	};
7662306a36Sopenharmony_ci	int i, err;
7762306a36Sopenharmony_ci
7862306a36Sopenharmony_ci	/* Test with known set of values. */
7962306a36Sopenharmony_ci	min_heapify_all(&heap, &funcs);
8062306a36Sopenharmony_ci	err = pop_verify_heap(min_heap, &heap, &funcs);
8162306a36Sopenharmony_ci
8262306a36Sopenharmony_ci
8362306a36Sopenharmony_ci	/* Test with randomly generated values. */
8462306a36Sopenharmony_ci	heap.nr = ARRAY_SIZE(values);
8562306a36Sopenharmony_ci	for (i = 0; i < heap.nr; i++)
8662306a36Sopenharmony_ci		values[i] = get_random_u32();
8762306a36Sopenharmony_ci
8862306a36Sopenharmony_ci	min_heapify_all(&heap, &funcs);
8962306a36Sopenharmony_ci	err += pop_verify_heap(min_heap, &heap, &funcs);
9062306a36Sopenharmony_ci
9162306a36Sopenharmony_ci	return err;
9262306a36Sopenharmony_ci}
9362306a36Sopenharmony_ci
9462306a36Sopenharmony_cistatic __init int test_heap_push(bool min_heap)
9562306a36Sopenharmony_ci{
9662306a36Sopenharmony_ci	const int data[] = { 3, 1, 2, 4, 0x80000000, 0x7FFFFFFF, 0,
9762306a36Sopenharmony_ci			     -3, -1, -2, -4, 0x80000000, 0x7FFFFFFF };
9862306a36Sopenharmony_ci	int values[ARRAY_SIZE(data)];
9962306a36Sopenharmony_ci	struct min_heap heap = {
10062306a36Sopenharmony_ci		.data = values,
10162306a36Sopenharmony_ci		.nr = 0,
10262306a36Sopenharmony_ci		.size =  ARRAY_SIZE(values),
10362306a36Sopenharmony_ci	};
10462306a36Sopenharmony_ci	struct min_heap_callbacks funcs = {
10562306a36Sopenharmony_ci		.elem_size = sizeof(int),
10662306a36Sopenharmony_ci		.less = min_heap ? less_than : greater_than,
10762306a36Sopenharmony_ci		.swp = swap_ints,
10862306a36Sopenharmony_ci	};
10962306a36Sopenharmony_ci	int i, temp, err;
11062306a36Sopenharmony_ci
11162306a36Sopenharmony_ci	/* Test with known set of values copied from data. */
11262306a36Sopenharmony_ci	for (i = 0; i < ARRAY_SIZE(data); i++)
11362306a36Sopenharmony_ci		min_heap_push(&heap, &data[i], &funcs);
11462306a36Sopenharmony_ci
11562306a36Sopenharmony_ci	err = pop_verify_heap(min_heap, &heap, &funcs);
11662306a36Sopenharmony_ci
11762306a36Sopenharmony_ci	/* Test with randomly generated values. */
11862306a36Sopenharmony_ci	while (heap.nr < heap.size) {
11962306a36Sopenharmony_ci		temp = get_random_u32();
12062306a36Sopenharmony_ci		min_heap_push(&heap, &temp, &funcs);
12162306a36Sopenharmony_ci	}
12262306a36Sopenharmony_ci	err += pop_verify_heap(min_heap, &heap, &funcs);
12362306a36Sopenharmony_ci
12462306a36Sopenharmony_ci	return err;
12562306a36Sopenharmony_ci}
12662306a36Sopenharmony_ci
12762306a36Sopenharmony_cistatic __init int test_heap_pop_push(bool min_heap)
12862306a36Sopenharmony_ci{
12962306a36Sopenharmony_ci	const int data[] = { 3, 1, 2, 4, 0x80000000, 0x7FFFFFFF, 0,
13062306a36Sopenharmony_ci			     -3, -1, -2, -4, 0x80000000, 0x7FFFFFFF };
13162306a36Sopenharmony_ci	int values[ARRAY_SIZE(data)];
13262306a36Sopenharmony_ci	struct min_heap heap = {
13362306a36Sopenharmony_ci		.data = values,
13462306a36Sopenharmony_ci		.nr = 0,
13562306a36Sopenharmony_ci		.size =  ARRAY_SIZE(values),
13662306a36Sopenharmony_ci	};
13762306a36Sopenharmony_ci	struct min_heap_callbacks funcs = {
13862306a36Sopenharmony_ci		.elem_size = sizeof(int),
13962306a36Sopenharmony_ci		.less = min_heap ? less_than : greater_than,
14062306a36Sopenharmony_ci		.swp = swap_ints,
14162306a36Sopenharmony_ci	};
14262306a36Sopenharmony_ci	int i, temp, err;
14362306a36Sopenharmony_ci
14462306a36Sopenharmony_ci	/* Fill values with data to pop and replace. */
14562306a36Sopenharmony_ci	temp = min_heap ? 0x80000000 : 0x7FFFFFFF;
14662306a36Sopenharmony_ci	for (i = 0; i < ARRAY_SIZE(data); i++)
14762306a36Sopenharmony_ci		min_heap_push(&heap, &temp, &funcs);
14862306a36Sopenharmony_ci
14962306a36Sopenharmony_ci	/* Test with known set of values copied from data. */
15062306a36Sopenharmony_ci	for (i = 0; i < ARRAY_SIZE(data); i++)
15162306a36Sopenharmony_ci		min_heap_pop_push(&heap, &data[i], &funcs);
15262306a36Sopenharmony_ci
15362306a36Sopenharmony_ci	err = pop_verify_heap(min_heap, &heap, &funcs);
15462306a36Sopenharmony_ci
15562306a36Sopenharmony_ci	heap.nr = 0;
15662306a36Sopenharmony_ci	for (i = 0; i < ARRAY_SIZE(data); i++)
15762306a36Sopenharmony_ci		min_heap_push(&heap, &temp, &funcs);
15862306a36Sopenharmony_ci
15962306a36Sopenharmony_ci	/* Test with randomly generated values. */
16062306a36Sopenharmony_ci	for (i = 0; i < ARRAY_SIZE(data); i++) {
16162306a36Sopenharmony_ci		temp = get_random_u32();
16262306a36Sopenharmony_ci		min_heap_pop_push(&heap, &temp, &funcs);
16362306a36Sopenharmony_ci	}
16462306a36Sopenharmony_ci	err += pop_verify_heap(min_heap, &heap, &funcs);
16562306a36Sopenharmony_ci
16662306a36Sopenharmony_ci	return err;
16762306a36Sopenharmony_ci}
16862306a36Sopenharmony_ci
16962306a36Sopenharmony_cistatic int __init test_min_heap_init(void)
17062306a36Sopenharmony_ci{
17162306a36Sopenharmony_ci	int err = 0;
17262306a36Sopenharmony_ci
17362306a36Sopenharmony_ci	err += test_heapify_all(true);
17462306a36Sopenharmony_ci	err += test_heapify_all(false);
17562306a36Sopenharmony_ci	err += test_heap_push(true);
17662306a36Sopenharmony_ci	err += test_heap_push(false);
17762306a36Sopenharmony_ci	err += test_heap_pop_push(true);
17862306a36Sopenharmony_ci	err += test_heap_pop_push(false);
17962306a36Sopenharmony_ci	if (err) {
18062306a36Sopenharmony_ci		pr_err("test failed with %d errors\n", err);
18162306a36Sopenharmony_ci		return -EINVAL;
18262306a36Sopenharmony_ci	}
18362306a36Sopenharmony_ci	pr_info("test passed\n");
18462306a36Sopenharmony_ci	return 0;
18562306a36Sopenharmony_ci}
18662306a36Sopenharmony_cimodule_init(test_min_heap_init);
18762306a36Sopenharmony_ci
18862306a36Sopenharmony_cistatic void __exit test_min_heap_exit(void)
18962306a36Sopenharmony_ci{
19062306a36Sopenharmony_ci	/* do nothing */
19162306a36Sopenharmony_ci}
19262306a36Sopenharmony_cimodule_exit(test_min_heap_exit);
19362306a36Sopenharmony_ci
19462306a36Sopenharmony_ciMODULE_LICENSE("GPL");
195