/* SPDX-FileCopyrightText: 2026 - Sébastien Wilmet <swilmet@gnome.org>
 * SPDX-License-Identifier: LGPL-3.0-or-later
 */

#include <gfls/gfls.h>

static void
test_iconv_open_failure (void)
{
	GBytes *input_bytes;
	GBytes *output_bytes = NULL;
	GflsBytesRegion *output_bytes_valid_region = NULL;
	gboolean success;
	GError *error = NULL;

	input_bytes = g_bytes_new_static ("a", 1);

	success = gfls_encoding_convert (input_bytes,
					 "UTF-8",
					 "CANNOT_POSSIBLY_WORK",
					 TRUE,
					 &output_bytes,
					 &output_bytes_valid_region,
					 &error);

	g_assert_false (success);
	g_assert_nonnull (error);

	g_bytes_unref (input_bytes);
	g_bytes_unref (output_bytes);
	gfls_bytes_region_free (output_bytes_valid_region);
	g_clear_error (&error);
}

static void
test_basic (void)
{
	GBytes *input_bytes;
	GBytes *output_bytes = NULL;
	GflsBytesRegion *output_bytes_valid_region = NULL;
	gboolean success;
	gchar *region_str;
	GError *error = NULL;

	input_bytes = g_bytes_new_static ("oh", 2);

	success = gfls_encoding_convert (input_bytes,
					 "UTF-8",
					 "ISO-8859-15",
					 TRUE,
					 &output_bytes,
					 &output_bytes_valid_region,
					 &error);

	g_assert_true (success);
	g_assert_no_error (error);

	g_assert_true (g_bytes_equal (input_bytes, output_bytes));

	region_str = gfls_bytes_region_to_string (output_bytes_valid_region);
	g_assert_cmpstr ("[0, 2, 1]\n", ==, region_str);

	g_bytes_unref (input_bytes);
	g_bytes_unref (output_bytes);
	gfls_bytes_region_free (output_bytes_valid_region);
	g_free (region_str);
}

static void
test_illegal_sequence (void)
{
	guint8 input_buffer[1] = { 255 }; // See also test-iconv.c
	GBytes *input_bytes;
	GBytes *output_bytes = NULL;
	GflsBytesRegion *output_bytes_valid_region = NULL;
	gboolean success;
	gchar *region_str;
	GError *error = NULL;

	input_bytes = g_bytes_new_static (input_buffer, 1);

	success = gfls_encoding_convert (input_bytes,
					 "UTF-8",
					 "UTF-8",
					 TRUE,
					 &output_bytes,
					 &output_bytes_valid_region,
					 &error);

	g_assert_true (success);
	g_assert_no_error (error);

	g_assert_true (g_bytes_equal (input_bytes, output_bytes));

	region_str = gfls_bytes_region_to_string (output_bytes_valid_region);
	g_assert_cmpstr ("[0, 1, 0]\n", ==, region_str);

	g_bytes_unref (input_bytes);
	g_bytes_unref (output_bytes);
	gfls_bytes_region_free (output_bytes_valid_region);
	g_free (region_str);
}

static void
test_incomplete_input (void)
{
	guint8 input_buffer[1] = { 195 }; // See also test-iconv.c
	GBytes *input_bytes;
	GBytes *output_bytes = NULL;
	GflsBytesRegion *output_bytes_valid_region = NULL;
	gboolean success;
	gchar *region_str;
	GError *error = NULL;

	input_bytes = g_bytes_new_static (input_buffer, 1);

	success = gfls_encoding_convert (input_bytes,
					 "UTF-8",
					 "UTF-8",
					 TRUE,
					 &output_bytes,
					 &output_bytes_valid_region,
					 &error);

	g_assert_true (success);
	g_assert_no_error (error);

	g_assert_true (g_bytes_equal (input_bytes, output_bytes));

	region_str = gfls_bytes_region_to_string (output_bytes_valid_region);
	g_assert_cmpstr ("[0, 1, 0]\n", ==, region_str);

	g_bytes_unref (input_bytes);
	g_bytes_unref (output_bytes);
	gfls_bytes_region_free (output_bytes_valid_region);
	g_free (region_str);
}

static void
test_buffer_full (void)
{
	gsize input_size = 32 * 1024;
	gchar *input_str;
	GBytes *input_bytes;
	GBytes *output_bytes = NULL;
	GflsBytesRegion *output_bytes_valid_region = NULL;
	gboolean success;
	gchar *region_str;
	GError *error = NULL;

	input_str = g_strnfill (input_size, 'a');
	input_bytes = g_bytes_new_take (input_str, input_size);
	input_str = NULL;

	success = gfls_encoding_convert (input_bytes,
					 "UTF-16LE",
					 "UTF-8",
					 TRUE,
					 &output_bytes,
					 &output_bytes_valid_region,
					 &error);

	g_assert_true (success);
	g_assert_no_error (error);

	{
		const guint8 *output_data;
		gsize output_size = 0;

		output_data = g_bytes_get_data (output_bytes, &output_size);

		g_assert_cmpuint (output_size, ==, input_size * 2);
		g_assert_cmpuint (output_data[0], ==, 97);
		g_assert_cmpuint (output_data[1], ==, 0);
		g_assert_cmpuint (output_data[2], ==, 97);
		g_assert_cmpuint (output_data[3], ==, 0);
		g_assert_cmpuint (output_data[4], ==, 97);
		g_assert_cmpuint (output_data[5], ==, 0);
		// Etc.
	}

	region_str = gfls_bytes_region_to_string (output_bytes_valid_region);
	g_assert_cmpstr ("[0, 65536, 1]\n", ==, region_str);

	g_bytes_unref (input_bytes);
	g_bytes_unref (output_bytes);
	gfls_bytes_region_free (output_bytes_valid_region);
	g_free (region_str);
}

static void
test_lossy_conversion (void)
{
	// See also test-iconv.c.
	// "é": Latin Small Letter E With Acute (U+00E9)
	guint8 input_buffer[2] = { 195, 169 };
	GBytes *input_bytes;
	GBytes *output_bytes = NULL;
	GflsBytesRegion *output_bytes_valid_region = NULL;
	gboolean success;
	GError *error = NULL;

	input_bytes = g_bytes_new_static (input_buffer, 2);

	success = gfls_encoding_convert (input_bytes,
					 "ASCII//TRANSLIT",
					 "UTF-8",
					 TRUE,
					 &output_bytes,
					 &output_bytes_valid_region,
					 &error);

	g_assert_false (success);
	g_assert_null (output_bytes);
	g_assert_null (output_bytes_valid_region);
	g_assert_error (error, G_CONVERT_ERROR, G_CONVERT_ERROR_FAILED);

	g_bytes_unref (input_bytes);
	g_clear_error (&error);

	// For better code coverage (output_bytes_valid_region is NULL).
	gfls_bytes_region_free (output_bytes_valid_region);
}

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

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

	g_test_add_func ("/EncodingConvert/iconv_open_failure", test_iconv_open_failure);
	g_test_add_func ("/EncodingConvert/basic", test_basic);
	g_test_add_func ("/EncodingConvert/illegal_sequence", test_illegal_sequence);
	g_test_add_func ("/EncodingConvert/incomplete_input", test_incomplete_input);
	g_test_add_func ("/EncodingConvert/buffer_full", test_buffer_full);
	g_test_add_func ("/EncodingConvert/lossy_conversion", test_lossy_conversion);

	exit_status = g_test_run ();
	gfls_finalize ();

	return exit_status;
}
