/*
 * Copyright (c) 2019 Intel Corporation
 *
 * SPDX-License-Identifier: Apache-2.0
 */

#include <ztest.h>
#include <zephyr.h>
#include <sys/fdtable.h>
#include <errno.h>

/* The thread will test that the refcounting of fd object will
 * work as expected.
 */
static struct k_thread fd_thread;
static int shared_fd;

static struct fd_op_vtable fd_vtable = { 0 };

#define VTABLE_INIT (&fd_vtable)

K_THREAD_STACK_DEFINE(fd_thread_stack, CONFIG_ZTEST_STACKSIZE +
		      CONFIG_TEST_EXTRA_STACKSIZE);

void test_z_reserve_fd(void)
{
	int fd = z_reserve_fd(); /* function being tested */

	zassert_true(fd >= 0, "fd < 0");

	z_free_fd(fd);
}

void test_z_get_fd_obj_and_vtable(void)
{
	const struct fd_op_vtable *vtable;

	int fd = z_reserve_fd();
	zassert_true(fd >= 0, "fd < 0");

	int *obj;
	obj = z_get_fd_obj_and_vtable(fd, &vtable,
				      NULL); /* function being tested */

	zassert_is_null(obj, "obj is not NULL");

	z_free_fd(fd);
}

void test_z_get_fd_obj(void)
{
	int fd = z_reserve_fd();
	zassert_true(fd >= 0, "fd < 0");

	int err = -1;
	const struct fd_op_vtable *vtable = 0;
	const struct fd_op_vtable *vtable2 = vtable+1;

	int *obj = z_get_fd_obj(fd, vtable, err); /* function being tested */

	/* take branch -- if (_check_fd(fd) < 0) */
	zassert_is_null(obj, "obj not is NULL");

	obj = (void *)1;
	vtable = NULL;

	/* This will set obj and vtable properly */
	z_finalize_fd(fd, obj, vtable);

	obj = z_get_fd_obj(-1, vtable, err); /* function being tested */

	zassert_equal_ptr(obj, NULL, "obj is not NULL when fd < 0");
	zassert_equal(errno, EBADF, "fd: out of bounds error");

	/* take branch -- if (vtable != NULL && fd_entry->vtable != vtable) */
	obj = z_get_fd_obj(fd, vtable2, err); /* function being tested */

	zassert_equal_ptr(obj, NULL, "obj is not NULL - vtable doesn't match");
	zassert_equal(errno, err, "vtable matches");

	z_free_fd(fd);
}

void test_z_finalize_fd(void)
{
	const struct fd_op_vtable *vtable;

	int fd = z_reserve_fd();
	zassert_true(fd >= 0, NULL);

	int *obj = z_get_fd_obj_and_vtable(fd, &vtable, NULL);

	const struct fd_op_vtable *original_vtable = vtable;
	int *original_obj = obj;

	z_finalize_fd(fd, obj, vtable); /* function being tested */

	obj = z_get_fd_obj_and_vtable(fd, &vtable, NULL);

	zassert_equal_ptr(obj, original_obj, "obj is different after finalizing");
	zassert_equal_ptr(vtable, original_vtable, "vtable is different after finalizing");

	z_free_fd(fd);
}

void test_z_alloc_fd(void)
{
	const struct fd_op_vtable *vtable = NULL;
	int *obj = NULL;

	int fd = z_alloc_fd(obj, vtable); /* function being tested */
	zassert_true(fd >= 0, NULL);

	obj = z_get_fd_obj_and_vtable(fd, &vtable, NULL);

	zassert_equal_ptr(obj, NULL, "obj is different after allocating");
	zassert_equal_ptr(vtable, NULL, "vtable is different after allocating");

	z_free_fd(fd);
}

void test_z_free_fd(void)
{
	const struct fd_op_vtable *vtable = NULL;

	int fd = z_reserve_fd();
	zassert_true(fd >= 0, NULL);

	z_free_fd(fd); /* function being tested */

	int *obj = z_get_fd_obj_and_vtable(fd, &vtable, NULL);

	zassert_equal_ptr(obj, NULL, "obj is not NULL after freeing");
}

static void test_cb(void *fd_ptr)
{
	int fd = POINTER_TO_INT(fd_ptr);
	const struct fd_op_vtable *vtable;
	int *obj;

	obj = z_get_fd_obj_and_vtable(fd, &vtable, NULL);

	zassert_not_null(obj, "obj is null");
	zassert_not_null(vtable, "vtable is null");

	z_free_fd(fd);

	obj = z_get_fd_obj_and_vtable(fd, &vtable, NULL);
	zassert_is_null(obj, "obj is still there");
	zassert_equal(errno, EBADF, "fd was found");
}

void test_z_fd_multiple_access(void)
{
	const struct fd_op_vtable *vtable = VTABLE_INIT;
	void *obj = (void *)vtable;

	shared_fd = z_reserve_fd();
	zassert_true(shared_fd >= 0, "fd < 0");

	z_finalize_fd(shared_fd, obj, vtable);

	k_thread_create(&fd_thread, fd_thread_stack,
			K_THREAD_STACK_SIZEOF(fd_thread_stack),
			(k_thread_entry_t)test_cb,
			INT_TO_POINTER(shared_fd), NULL, NULL,
			CONFIG_ZTEST_THREAD_PRIORITY, 0, K_NO_WAIT);

	k_thread_join(&fd_thread, K_FOREVER);

	/* should be null since freed in the other thread */
	obj = z_get_fd_obj_and_vtable(shared_fd, &vtable, NULL);
	zassert_is_null(obj, "obj is still there");
	zassert_equal(errno, EBADF, "fd was found");
}

void test_main(void)
{
	ztest_test_suite(test_fdtable,
			 ztest_unit_test(test_z_reserve_fd),
			 ztest_unit_test(test_z_get_fd_obj_and_vtable),
			 ztest_unit_test(test_z_get_fd_obj),
			 ztest_unit_test(test_z_finalize_fd),
			 ztest_unit_test(test_z_alloc_fd),
			 ztest_unit_test(test_z_free_fd),
			 ztest_unit_test(test_z_fd_multiple_access)
		);
	ztest_run_test_suite(test_fdtable);
}
