/* Copyright (c) 2015-2018 Dovecot authors, see the included COPYING file */

#include "lib.h"
#include "array.h"
#include "str.h"
#include "unichar.h"
#include "test-common.h"
#include "lang-icu.h"

#include <unicode/uclean.h>

static void test_lang_icu_utf8_to_utf16_ascii_resize(void)
{
	ARRAY_TYPE(icu_utf16) dest;

	test_begin("lang_icu_utf8_to_utf16 ascii resize");
	t_array_init(&dest, 2);
	test_assert(buffer_get_writable_size(dest.arr.buffer) == 4);
	lang_icu_utf8_to_utf16(&dest, "12");
	test_assert(array_count(&dest) == 2);
	test_assert(buffer_get_writable_size(dest.arr.buffer) == 4);

	lang_icu_utf8_to_utf16(&dest, "123");
	test_assert(array_count(&dest) == 3);
	test_assert(buffer_get_writable_size(dest.arr.buffer) == 7);

	lang_icu_utf8_to_utf16(&dest, "12345");
	test_assert(array_count(&dest) == 5);

	test_end();
}

static void test_lang_icu_utf8_to_utf16_32bit_resize(void)
{
	ARRAY_TYPE(icu_utf16) dest;
	unsigned int i;

	test_begin("lang_icu_utf8_to_utf16 32bit resize");
	for (i = 1; i <= 2; i++) {
		t_array_init(&dest, i);
		test_assert(buffer_get_writable_size(dest.arr.buffer) == i*2);
		lang_icu_utf8_to_utf16(&dest, "\xF0\x90\x90\x80"); /* 0x10400 */
		test_assert(array_count(&dest) == 2);
	}

	test_end();
}

static void test_lang_icu_utf16_to_utf8(void)
{
	string_t *dest = t_str_new(64);
	const UChar src[] = { 0xbd, 'b', 'c' };
	unsigned int i;

	test_begin("lang_icu_utf16_to_utf8");
	for (i = N_ELEMENTS(src); i > 0; i--) {
		lang_icu_utf16_to_utf8(dest, src, i);
		test_assert(dest->used == i+1);
	}
	test_end();
}

static void test_lang_icu_utf16_to_utf8_resize(void)
{
	string_t *dest;
	const UChar src = UNICODE_REPLACEMENT_CHAR;
	unsigned int i;

	test_begin("lang_icu_utf16_to_utf8 resize");
	for (i = 2; i <= 6; i++) {
		dest = t_str_new(i);
		test_assert(buffer_get_writable_size(dest) == i);
		lang_icu_utf16_to_utf8(dest, &src, 1);
		test_assert(dest->used == 3);
		test_assert(strcmp(str_c(dest), UNICODE_REPLACEMENT_CHAR_UTF8) == 0);
	}

	test_end();
}

static UTransliterator *get_translit(const char *id)
{
	UTransliterator *translit;
	ARRAY_TYPE(icu_utf16) id_utf16;
	UErrorCode err = U_ZERO_ERROR;
	UParseError perr;

	t_array_init(&id_utf16, 8);
	lang_icu_utf8_to_utf16(&id_utf16, id);
	translit = utrans_openU(array_front(&id_utf16),
				array_count(&id_utf16),
				UTRANS_FORWARD, NULL, 0, &perr, &err);
	test_assert(!U_FAILURE(err));
	return translit;
}

static void test_lang_icu_translate(void)
{
	const char *translit_id = "Any-Lower";
	UTransliterator *translit;
	ARRAY_TYPE(icu_utf16) dest;
	const UChar src[] = { 0xbd, 'B', 'C' };
	const char *error;
	unsigned int i;

	test_begin("lang_icu_translate");
	t_array_init(&dest, 32);
	translit = get_translit(translit_id);
	for (i = N_ELEMENTS(src); i > 0; i--) {
		array_clear(&dest);
		test_assert(lang_icu_translate(&dest, src, i,
					      translit, &error) == 0);
		test_assert(array_count(&dest) == i);
	}
	utrans_close(translit);
	test_end();
}

static void test_lang_icu_translate_resize(void)
{
	const char *translit_id = "Any-Hex";
	const char *src_utf8 = "FOO";
	ARRAY_TYPE(icu_utf16) src_utf16, dest;
	UTransliterator *translit;
	const char *error;
	unsigned int i;

	test_begin("lang_icu_translate_resize resize");

	t_array_init(&src_utf16, 8);
	translit = get_translit(translit_id);
	for (i = 1; i <= 10; i++) {
		array_clear(&src_utf16);
		lang_icu_utf8_to_utf16(&src_utf16, src_utf8);
		t_array_init(&dest, i);
		test_assert(buffer_get_writable_size(dest.arr.buffer) == i*2);
		test_assert(lang_icu_translate(&dest, array_front(&src_utf16),
					      array_count(&src_utf16),
					      translit, &error) == 0);
	}

	utrans_close(translit);
	test_end();
}

int main(void)
{
	static void (*const test_functions[])(void) = {
		test_lang_icu_utf8_to_utf16_ascii_resize,
		test_lang_icu_utf8_to_utf16_32bit_resize,
		test_lang_icu_utf16_to_utf8,
		test_lang_icu_utf16_to_utf8_resize,
		test_lang_icu_translate,
		test_lang_icu_translate_resize,
		NULL
	};
	int ret = test_run(test_functions);
	lang_icu_deinit();
	return ret;
}
