text: // SPDX-License-Identifier: GPL-2.0-only
  #define pr_fmt(fmt) "min_heap_test: " fmt
  
  /*
   * Test cases for the min max heap.
   */
  
  #include <linux/log2.h>
  #include <linux/min_heap.h>
  #include <linux/module.h>
  #include <linux/printk.h>
  #include <linux/random.h>
  
  static __init bool less_than(const void *lhs, const void *rhs)
  {
  	return *(int *)lhs < *(int *)rhs;
  }
  
  static __init bool greater_than(const void *lhs, const void *rhs)
  {
  	return *(int *)lhs > *(int *)rhs;
  }
  
  static __init void swap_ints(void *lhs, void *rhs)
  {
  	int temp = *(int *)lhs;
  
  	*(int *)lhs = *(int *)rhs;
  	*(int *)rhs = temp;
  }
  
  static __init int pop_verify_heap(bool min_heap,
  				struct min_heap *heap,
  				const struct min_heap_callbacks *funcs)
  {
  	int *values = heap->data;
  	int err = 0;
  	int last;
  
  	last = values[0];
  	min_heap_pop(heap, funcs);
  	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);
  	}
  	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 heap = {
  		.data = values,
  		.nr = ARRAY_SIZE(values),
  		.size =  ARRAY_SIZE(values),
  	};
  	struct min_heap_callbacks funcs = {
  		.elem_size = sizeof(int),
  		.less = min_heap ? less_than : greater_than,
  		.swp = swap_ints,
  	};
  	int i, err;
  
  	/* Test with known set of values. */
  	min_heapify_all(&heap, &funcs);
  	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_int();
  
  	min_heapify_all(&heap, &funcs);
  	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 heap = {
  		.data = values,
  		.nr = 0,
  		.size =  ARRAY_SIZE(values),
  	};
  	struct min_heap_callbacks funcs = {
  		.elem_size = sizeof(int),
  		.less = min_heap ? less_than : greater_than,
  		.swp = swap_ints,
  	};
  	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);
  
  	err = pop_verify_heap(min_heap, &heap, &funcs);
  
  	/* Test with randomly generated values. */
  	while (heap.nr < heap.size) {
  		temp = get_random_int();
  		min_heap_push(&heap, &temp, &funcs);
  	}
  	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 heap = {
  		.data = values,
  		.nr = 0,
  		.size =  ARRAY_SIZE(values),
  	};
  	struct min_heap_callbacks funcs = {
  		.elem_size = sizeof(int),
  		.less = min_heap ? less_than : greater_than,
  		.swp = swap_ints,
  	};
  	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);
  
  	/* 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);
  
  	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);
  
  	/* Test with randomly generated values. */
  	for (i = 0; i < ARRAY_SIZE(data); i++) {
  		temp = get_random_int();
  		min_heap_pop_push(&heap, &temp, &funcs);
  	}
  	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);
  	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_LICENSE("GPL");
  