Loading...
// SPDX-License-Identifier: GPL-2.0+
/*
 * Copyright 2023 Google LLC
 * Written by Simon Glass <sjg@chromium.org>
 */

#include <alist.h>
#include <string.h>
#include <test/lib.h>
#include <test/test.h>
#include <test/ut.h>

struct my_struct {
	uint val;
	uint other_val;
};

enum {
	obj_size	= sizeof(struct my_struct),
};

/* Test alist_init() */
static int lib_test_alist_init(struct unit_test_state *uts)
{
	struct alist lst;
	ulong start;

	start = ut_check_free();

	/* with a size of 0, the fields should be inited, with no memory used */
	memset(&lst, '\xff', sizeof(lst));
	ut_assert(alist_init_struct(&lst, struct my_struct));
	ut_asserteq_ptr(NULL, lst.data);
	ut_asserteq(0, lst.count);
	ut_asserteq(0, lst.alloc);
	ut_assertok(ut_check_delta(start));
	alist_uninit(&lst);
	ut_asserteq_ptr(NULL, lst.data);
	ut_asserteq(0, lst.count);
	ut_asserteq(0, lst.alloc);

	/* use an impossible size */
	ut_asserteq(false, alist_init(&lst, obj_size,
				      CONFIG_SYS_MALLOC_LEN));
	ut_assertnull(lst.data);
	ut_asserteq(0, lst.count);
	ut_asserteq(0, lst.alloc);

	/* use a small size */
	ut_assert(alist_init(&lst, obj_size, 4));
	ut_assertnonnull(lst.data);
	ut_asserteq(0, lst.count);
	ut_asserteq(4, lst.alloc);

	/* free it */
	alist_uninit(&lst);
	ut_asserteq_ptr(NULL, lst.data);
	ut_asserteq(0, lst.count);
	ut_asserteq(0, lst.alloc);
	ut_assertok(ut_check_delta(start));

	/* Check for memory leaks */
	ut_assertok(ut_check_delta(start));

	return 0;
}
LIB_TEST(lib_test_alist_init, 0);

/* Test alist_get() and alist_getd() */
static int lib_test_alist_get(struct unit_test_state *uts)
{
	struct alist lst;
	ulong start;
	void *ptr;

	start = ut_check_free();

	ut_assert(alist_init(&lst, obj_size, 3));
	ut_asserteq(0, lst.count);
	ut_asserteq(3, lst.alloc);

	ut_assertnull(alist_get_ptr(&lst, 2));
	ut_assertnull(alist_get_ptr(&lst, 3));

	ptr = alist_ensure_ptr(&lst, 1);
	ut_assertnonnull(ptr);
	ut_asserteq(2, lst.count);
	ptr = alist_ensure_ptr(&lst, 2);
	ut_asserteq(3, lst.count);
	ut_assertnonnull(ptr);

	ptr = alist_ensure_ptr(&lst, 3);
	ut_assertnonnull(ptr);
	ut_asserteq(4, lst.count);
	ut_asserteq(6, lst.alloc);

	ut_assertnull(alist_get_ptr(&lst, 4));

	alist_uninit(&lst);

	/* Check for memory leaks */
	ut_assertok(ut_check_delta(start));

	return 0;
}
LIB_TEST(lib_test_alist_get, 0);

/* Test alist_has() */
static int lib_test_alist_has(struct unit_test_state *uts)
{
	struct alist lst;
	ulong start;
	void *ptr;

	start = ut_check_free();

	ut_assert(alist_init(&lst, obj_size, 3));

	ut_assert(!alist_has(&lst, 0));
	ut_assert(!alist_has(&lst, 1));
	ut_assert(!alist_has(&lst, 2));
	ut_assert(!alist_has(&lst, 3));

	/* create a new one to force expansion */
	ptr = alist_ensure_ptr(&lst, 4);
	ut_assertnonnull(ptr);

	ut_assert(alist_has(&lst, 0));
	ut_assert(alist_has(&lst, 1));
	ut_assert(alist_has(&lst, 2));
	ut_assert(alist_has(&lst, 3));
	ut_assert(alist_has(&lst, 4));
	ut_assert(!alist_has(&lst, 5));

	alist_uninit(&lst);

	/* Check for memory leaks */
	ut_assertok(ut_check_delta(start));

	return 0;
}
LIB_TEST(lib_test_alist_has, 0);

/* Test alist_ensure() */
static int lib_test_alist_ensure(struct unit_test_state *uts)
{
	struct my_struct *ptr3, *ptr4;
	struct alist lst;
	ulong start;

	start = ut_check_free();

	ut_assert(alist_init_struct(&lst, struct my_struct));
	ut_asserteq(obj_size, lst.obj_size);
	ut_asserteq(0, lst.count);
	ut_asserteq(0, lst.alloc);
	ptr3 = alist_ensure_ptr(&lst, 3);
	ut_asserteq(4, lst.count);
	ut_asserteq(4, lst.alloc);
	ut_assertnonnull(ptr3);
	ptr3->val = 3;

	ptr4 = alist_ensure_ptr(&lst, 4);
	ut_asserteq(8, lst.alloc);
	ut_asserteq(5, lst.count);
	ut_assertnonnull(ptr4);
	ptr4->val = 4;
	ut_asserteq(4, alist_get(&lst, 4, struct my_struct)->val);

	ut_asserteq_ptr(ptr4, alist_ensure(&lst, 4, struct my_struct));

	alist_ensure(&lst, 4, struct my_struct)->val = 44;
	ut_asserteq(44, alist_get(&lst, 4, struct my_struct)->val);
	ut_asserteq(3, alist_get(&lst, 3, struct my_struct)->val);
	ut_assertnull(alist_get(&lst, 7, struct my_struct));
	ut_asserteq(8, lst.alloc);
	ut_asserteq(5, lst.count);

	/* add some more, checking handling of malloc() failure */
	malloc_enable_testing(0);
	ut_assertnonnull(alist_ensure(&lst, 7, struct my_struct));
	ut_assertnull(alist_ensure(&lst, 8, struct my_struct));
	malloc_disable_testing();

	lst.flags &= ~ALISTF_FAIL;
	ut_assertnonnull(alist_ensure(&lst, 8, struct my_struct));
	ut_asserteq(16, lst.alloc);
	ut_asserteq(9, lst.count);

	alist_uninit(&lst);

	/* Check for memory leaks */
	ut_assertok(ut_check_delta(start));

	return 0;
}
LIB_TEST(lib_test_alist_ensure, 0);

/* Test alist_add() bits not tested by lib_test_alist_ensure() */
static int lib_test_alist_add(struct unit_test_state *uts)
{
	struct my_struct data, *ptr, *ptr2;
	const struct my_struct *chk;
	struct alist lst;
	ulong start;

	start = ut_check_free();

	ut_assert(alist_init_struct(&lst, struct my_struct));

	data.val = 123;
	data.other_val = 456;
	ptr = alist_add(&lst, data);
	ut_assertnonnull(ptr);
	ut_asserteq(4, lst.alloc);
	ut_asserteq(1, lst.count);

	ut_asserteq(123, ptr->val);
	ut_asserteq(456, ptr->other_val);

	ptr2 = alist_add_placeholder(&lst);
	ut_assertnonnull(ptr2);

	ptr2->val = 321;
	ptr2->other_val = 654;

	chk = alist_get(&lst, 1, struct my_struct);
	ut_asserteq(321, chk->val);
	ut_asserteq(654, chk->other_val);

	ptr2 = alist_getw(&lst, 1, struct my_struct);
	ut_asserteq(321, ptr2->val);
	ut_asserteq(654, ptr2->other_val);

	alist_uninit(&lst);

	/* Check for memory leaks */
	ut_assertok(ut_check_delta(start));

	return 0;
}
LIB_TEST(lib_test_alist_add, 0);