/* SPDX-FileCopyrightText: 2024-2026 - Sébastien Wilmet
 * SPDX-License-Identifier: LGPL-3.0-or-later
 */

#include <gfls/gfls.h>

typedef struct
{
	/* To run the async operation. */
	GMainLoop *main_loop;

	/* To check against the result of gfls_input_stream_read_finish(): */
	gsize result_size;
	guint result_is_truncated : 1;
} TestData;

static GInputStream *
create_input_stream (gsize size)
{
	gchar *str;
	GBytes *bytes;
	GInputStream *input_stream;

	str = g_strnfill (size, 'A');
	bytes = g_bytes_new_take (str, size);

	input_stream = g_memory_input_stream_new_from_bytes (bytes);
	g_bytes_unref (bytes);

	return input_stream;
}

static void
read_cb (GObject      *source_object,
	 GAsyncResult *result,
	 gpointer      user_data)
{
	GInputStream *input_stream = G_INPUT_STREAM (source_object);
	TestData *data = user_data;
	GBytes *bytes;
	gboolean is_truncated = FALSE;
	GError *error = NULL;

	bytes = gfls_input_stream_read_finish (input_stream, result, &is_truncated, &error);
	g_assert_no_error (error);
	g_assert_cmpint (is_truncated, ==, data->result_is_truncated);
	g_assert_nonnull (bytes);
	g_assert_cmpint (g_bytes_get_size (bytes), ==, data->result_size);

	g_bytes_unref (bytes);

	g_main_loop_quit (data->main_loop);
}

static void
check_read (gsize    input_stream_real_size,
	    gsize    input_stream_expected_size,
	    gsize    max_size,
	    gsize    result_size,
	    gboolean result_is_truncated)
{
	GInputStream *input_stream;
	TestData data;

	input_stream = create_input_stream (input_stream_real_size);

	data.main_loop = g_main_loop_new (NULL, FALSE);
	data.result_size = result_size;
	data.result_is_truncated = result_is_truncated != FALSE;

	gfls_input_stream_read_async (input_stream,
				      input_stream_expected_size,
				      max_size,
				      G_PRIORITY_DEFAULT,
				      NULL, NULL, NULL,
				      read_cb,
				      &data);

	g_main_loop_run (data.main_loop);
	g_object_unref (input_stream);
}

static void
test_read (void)
{
	check_read (0, 0, 0, 0, FALSE);
	check_read (0, 1, 0, 0, FALSE);
	check_read (1, 0, 100, 1, FALSE);
	check_read (100, 50, 200, 100, FALSE);
	check_read (100, 100, 200, 100, FALSE);
	check_read (100, 100, 100, 100, FALSE);

	/* Truncated */
	check_read (1, 0, 0, 0, TRUE);
	check_read (2, 2, 0, 0, TRUE);
	check_read (100, 50, 99, 99, TRUE);
}

int
main (int    argc,
      char **argv)
{
	int exit_status;

	gfls_init ();
	g_test_init (&argc, &argv, NULL);

	g_test_add_func ("/InputStream/read", test_read);

	exit_status = g_test_run ();
	gfls_finalize ();

	return exit_status;
}
