#ifndef lint
static char *rcsid = "$Id: mapselector.tsy,v 1.1.1.1 2003/06/04 00:26:55 marka Exp $";
#endif

/*
 * Copyright (c) 2002 Japan Network Information Center.
 * All rights reserved.
 *  
 * By using this file, you agree to the terms and conditions set forth bellow.
 * 
 * 			LICENSE TERMS AND CONDITIONS 
 * 
 * The following License Terms and Conditions apply, unless a different
 * license is obtained from Japan Network Information Center ("JPNIC"),
 * a Japanese association, Kokusai-Kougyou-Kanda Bldg 6F, 2-3-4 Uchi-Kanda,
 * Chiyoda-ku, Tokyo 101-0047, Japan.
 * 
 * 1. Use, Modification and Redistribution (including distribution of any
 *    modified or derived work) in source and/or binary forms is permitted
 *    under this License Terms and Conditions.
 * 
 * 2. Redistribution of source code must retain the copyright notices as they
 *    appear in each source code file, this License Terms and Conditions.
 * 
 * 3. Redistribution in binary form must reproduce the Copyright Notice,
 *    this License Terms and Conditions, in the documentation and/or other
 *    materials provided with the distribution.  For the purposes of binary
 *    distribution the "Copyright Notice" refers to the following language:
 *    "Copyright (c) 2000-2002 Japan Network Information Center.  All rights reserved."
 * 
 * 4. The name of JPNIC may not be used to endorse or promote products
 *    derived from this Software without specific prior written approval of
 *    JPNIC.
 * 
 * 5. Disclaimer/Limitation of Liability: THIS SOFTWARE IS PROVIDED BY JPNIC
 *    "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 *    LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
 *    PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL JPNIC BE LIABLE
 *    FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
 *    CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
 *    SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
 *    BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
 *    WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
 *    OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
 *    ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.
 */

#include <stddef.h>
#include <stdio.h>
#include <stdlib.h>
#include <stdarg.h>
#include <idn/mapselector.h>
#include <idn/ucs4.h>
#include <idn/log.h>

#include "testutil.h"

#define CONF_FILENAME		"test.conf"
#define MAP_FILENAME		"test.map"

/*
 * Sample TLDs.
 */
static const char *utf8_tlds_jp[] = {"jp", ".jp", "JP", ".JP"};
static const char *utf8_tlds_tw[] = {"tw", ".tw", "TW", ".TW"};

static const unsigned long ucs4_tlds_jp[][4] = {{'j', 'p', '\0', '\0'},
						{'.', 'j', 'p',  '\0'},
						{'J', 'P', '\0', '\0'},
						{'.', 'J', 'P',  '\0'}};

static const unsigned long ucs4_tlds_tw[][4] = {{'t', 'w', '\0', '\0'},
						{'.', 't', 'w',  '\0'},
						{'T', 'W', '\0', '\0'},
						{'.', 'T', 'W',  '\0'}};

/* How many elements in `utf8_tlds_{jp|tw}[]' and `ucs4_tlds_{jp|tw}[]'. */
#define TLD_NVARIANTS 		4

/*
 * Sample input string for mapping. (UCS4)
 */
static const unsigned long in_string[] = {0x00C0, 0x2212, 0};

/*
 * Sample mapping results of IN_STRING.
 *
 * OUT_STRING_FILEMAP is the result of file-mapping (U+2212 -> U+002D).
 * OUT_STRING_NAMEPREP is the result of the latest nameprep
 * OUT_STRING_BOTH is the result of both file-mapping and nameprep.
 */
static const unsigned long out_string_filemap[]	 = {0x00C0, 0x002D, 0};
static const unsigned long out_string_nameprep[] = {0x00E0, 0x2212, 0};
static const unsigned long out_string_both[]     = {0x00E0, 0x002D, 0};

#define MAP_FILENAME		"test.map"

//--------------------------------------------------------------------
// Setups and Teardowns.
//--------------------------------------------------------------------

//# SETUP
//      group: generic-init
{
	idn_result_t r;
	idn_mapselector_t ctxs[TLD_NVARIANTS];
	unsigned long to[256];

	{
		int i;
		for (i = 0; i < TLD_NVARIANTS; i++)
			ctxs[i] = NULL;
	}

	r = idn_mapselector_initialize();
	ASSERT_RESULT(r, idn_success);

	{
		int i;
		for (i = 0; i < TLD_NVARIANTS; i++) {
			r = idn_mapselector_create(&ctxs[i]);
			ASSERT_RESULT(r, idn_success);
		}
	}
}

//# TEARDOWN
//      group: generic-init
{
	{
		int i;

		for (i = 0; i < TLD_NVARIANTS; i++) {
			if (ctxs[i] != NULL)
				idn_mapselector_destroy(ctxs[i]);
			remove(CONF_FILENAME);
		}
	}
}

//# SETUP
//	group: quiet
{
	int saved_log_level;

	saved_log_level = idn_log_getlevel();
	idn_log_setlevel(idn_log_level_fatal);
}

//# TEARDOWN
//	group: quiet
{
	idn_log_setlevel(saved_log_level);
}

//# SETUP
//	group: generic-filemap
{
	create_conf_file(MAP_FILENAME, 0,
			 "U+2212; U+002D",
			 NULL);
}

//# TEARDOWN
//	group: generic-filemap
{
	remove(MAP_FILENAME);
}

//--------------------------------------------------------------------
// Testcases.
//--------------------------------------------------------------------

//# TESTCASE
//	title: call initialize() twice.
//
{
	idn_result_t r;

	r = idn_mapselector_initialize();
	ASSERT_RESULT(r, idn_success);

	r = idn_mapselector_initialize();
	ASSERT_RESULT(r, idn_success);
}

//# TESTCASE
//	title: call create()
{
	idn_result_t r;
	idn_mapselector_t ctx;

	r = idn_mapselector_initialize();
	ASSERT_RESULT(r, idn_success);

	r = idn_mapselector_create(&ctx);
	ASSERT_RESULT(r, idn_success);

	idn_mapselector_destroy(ctx);
}

//# TESTCASE
//	title: call add(filemap) and map()
//	group: generic-init generic-filemap
{
	int i, j;

	for (i = 0; i < TLD_NVARIANTS; i++) {
		r = idn_mapselector_add(ctxs[i], utf8_tlds_jp[i],
					"filemap:" MAP_FILENAME);
		ASSERT_RESULT(r, idn_success);
	}

	for (i = 0; i < TLD_NVARIANTS; i++) {
		for (j = 0; j < TLD_NVARIANTS; j++) {
			r = idn_mapselector_map(ctxs[i], in_string,
						utf8_tlds_jp[j], to,
						sizeof(to) / sizeof(*to));
			ASSERT_RESULT(r, idn_success);
			ASSERT_UCS4STRING(to, out_string_filemap);

			r = idn_mapselector_map(ctxs[i], in_string,
						utf8_tlds_tw[j], to,
						sizeof(to) / sizeof(*to));
			ASSERT_RESULT(r, idn_success);
			ASSERT_UCS4STRING(to, in_string);
		}
	}
}

//# TESTCASE
//	title: call add(nameprep) and map()
//	group: generic-init generic-filemap
{
	int i, j;

	for (i = 0; i < TLD_NVARIANTS; i++) {
		r = idn_mapselector_add(ctxs[i], utf8_tlds_jp[i],
					IDN_NAMEPREP_CURRENT);
		ASSERT_RESULT(r, idn_success);
	}

	for (i = 0; i < TLD_NVARIANTS; i++) {
		for (j = 0; j < TLD_NVARIANTS; j++) {
			r = idn_mapselector_map(ctxs[i], in_string,
						utf8_tlds_jp[j], to,
						sizeof(to) / sizeof(*to));
			ASSERT_RESULT(r, idn_success);
			ASSERT_UCS4STRING(to, out_string_nameprep);

			r = idn_mapselector_map(ctxs[i], in_string,
						utf8_tlds_tw[j], to,
						sizeof(to) / sizeof(*to));
			ASSERT_RESULT(r, idn_success);
			ASSERT_UCS4STRING(to, in_string);
		}
	}
}

//# TESTCASE
//	title: call add(filemap) and map2()
//	group: generic-init generic-filemap
{
	int i, j;

	for (i = 0; i < TLD_NVARIANTS; i++) {
		r = idn_mapselector_add(ctxs[i], utf8_tlds_jp[i],
					"filemap:" MAP_FILENAME);
		ASSERT_RESULT(r, idn_success);
	}

	for (i = 0; i < TLD_NVARIANTS; i++) {
		for (j = 0; j < TLD_NVARIANTS; j++) {
			r = idn_mapselector_map2(ctxs[i], in_string,
						 ucs4_tlds_jp[j], to,
						 sizeof(to) / sizeof(*to));
			ASSERT_RESULT(r, idn_success);
			ASSERT_UCS4STRING(to, out_string_filemap);

			r = idn_mapselector_map2(ctxs[i], in_string,
						 ucs4_tlds_tw[j], to,
						 sizeof(to) / sizeof(*to));
			ASSERT_RESULT(r, idn_success);
			ASSERT_UCS4STRING(to, in_string);
		}
	}
}

//# TESTCASE
//	title: call add(nameprep) and map2()
//	group: generic-init generic-filemap
{
	int i, j;

	for (i = 0; i < TLD_NVARIANTS; i++) {
		r = idn_mapselector_add(ctxs[i], utf8_tlds_jp[i],
					IDN_NAMEPREP_CURRENT);
		ASSERT_RESULT(r, idn_success);
	}

	for (i = 0; i < TLD_NVARIANTS; i++) {
		for (j = 0; j < TLD_NVARIANTS; j++) {
			r = idn_mapselector_map2(ctxs[i], in_string,
						 ucs4_tlds_jp[j], to,
						 sizeof(to) / sizeof(*to));
			ASSERT_RESULT(r, idn_success);
			ASSERT_UCS4STRING(to, out_string_nameprep);

			r = idn_mapselector_map2(ctxs[i], in_string,
						 ucs4_tlds_tw[j], to,
						 sizeof(to) / sizeof(*to));
			ASSERT_RESULT(r, idn_success);
			ASSERT_UCS4STRING(to, in_string);
		}
	}
}

//# TESTCASE
//	title: call add(filemap) and map()
//	group: generic-init generic-filemap
{
	int i, j;

	for (i = 0; i < TLD_NVARIANTS; i++) {
		r = idn_mapselector_add(ctxs[i], utf8_tlds_jp[i],
					"filemap:" MAP_FILENAME);
		ASSERT_RESULT(r, idn_success);
	}

	for (i = 0; i < TLD_NVARIANTS; i++) {
		for (j = 0; j < TLD_NVARIANTS; j++) {
			r = idn_mapselector_map(ctxs[i], in_string,
						utf8_tlds_jp[j], to,
						sizeof(to) / sizeof(*to));
			ASSERT_RESULT(r, idn_success);
			ASSERT_UCS4STRING(to, out_string_filemap);

			r = idn_mapselector_map(ctxs[i], in_string,
						utf8_tlds_tw[j], to,
						sizeof(to) / sizeof(*to));
			ASSERT_RESULT(r, idn_success);
			ASSERT_UCS4STRING(to, in_string);
		}
	}
}

//# TESTCASE
//	title: call add(nameprep) and map()
//	group: generic-init generic-filemap
{
	int i, j;

	for (i = 0; i < TLD_NVARIANTS; i++) {
		r = idn_mapselector_add(ctxs[i], utf8_tlds_jp[i],
					IDN_NAMEPREP_CURRENT);
		ASSERT_RESULT(r, idn_success);
	}

	for (i = 0; i < TLD_NVARIANTS; i++) {
		for (j = 0; j < TLD_NVARIANTS; j++) {
			r = idn_mapselector_map(ctxs[i], in_string,
						utf8_tlds_jp[j], to,
						sizeof(to) / sizeof(*to));
			ASSERT_RESULT(r, idn_success);
			ASSERT_UCS4STRING(to, out_string_nameprep);

			r = idn_mapselector_map(ctxs[i], in_string,
						utf8_tlds_tw[j], to,
						sizeof(to) / sizeof(*to));
			ASSERT_RESULT(r, idn_success);
			ASSERT_UCS4STRING(to, in_string);
		}
	}
}

//# TESTCASE
//	title: call addall()
//	group: generic-init generic-filemap
{
	static const char *names[] = {
		"filemap:" MAP_FILENAME,
		IDN_NAMEPREP_CURRENT
	};
	int i, j;

	for (i = 0; i < TLD_NVARIANTS; i++) {
		r = idn_mapselector_addall(ctxs[i], utf8_tlds_jp[i], names,
					   sizeof(names) / sizeof(*names));
		ASSERT_RESULT(r, idn_success);
	}

	for (i = 0; i < TLD_NVARIANTS; i++) {
		for (j = 0; j < TLD_NVARIANTS; j++) {
			r = idn_mapselector_map2(ctxs[i], in_string,
						 ucs4_tlds_jp[j], to,
						 sizeof(to) / sizeof(*to));
			ASSERT_RESULT(r, idn_success);
			ASSERT_UCS4STRING(to, out_string_both);

			r = idn_mapselector_map2(ctxs[i], in_string,
						 ucs4_tlds_tw[j], to,
						 sizeof(to) / sizeof(*to));
			ASSERT_RESULT(r, idn_success);
			ASSERT_UCS4STRING(to, in_string);
		}
	}
}

//# TESTCASE
//	title: call addall() with nnames=0
//	group: generic-init
{
	static const char *names[] = {IDN_NAMEPREP_CURRENT};

	r = idn_mapselector_addall(ctxs[0], ".", names, 0);
	ASSERT_RESULT(r, idn_success);
}

//# TESTCASE
//	title: call add() with empty tld
//	group: generic-init
{
	r = idn_mapselector_add(ctxs[0], "", IDN_NAMEPREP_CURRENT);
	ASSERT_RESULT(r, idn_success);
}

//# TESTCASE
//	title: call addall() with empty tld
//	group: generic-init
{
	static const char *names[] = {IDN_NAMEPREP_CURRENT};

	r = idn_mapselector_addall(ctxs[0], "", names, 1);
	ASSERT_RESULT(r, idn_success);
}

//# TESTCASE
//	title: call add() with too long tld
//	group: generic-init quiet
{
	r = idn_mapselector_add(ctxs[0],
				"ABCDEFGHIJKLMNOPQRSTUVWXYZ"
				"ABCDEFGHIJKLMNOPQRSTUVWXYZ"
				"ABCDEFGHIJK",
				IDN_NAMEPREP_CURRENT);
	ASSERT_RESULT(r, idn_success);

	r = idn_mapselector_add(ctxs[0],
				"."
				"ABCDEFGHIJKLMNOPQRSTUVWXYZ"
				"ABCDEFGHIJKLMNOPQRSTUVWXYZ"
				"ABCDEFGHIJK",
				IDN_NAMEPREP_CURRENT);
	ASSERT_RESULT(r, idn_success);

	r = idn_mapselector_add(ctxs[0],
				"ABCDEFGHIJKLMNOPQRSTUVWXYZ"
				"ABCDEFGHIJKLMNOPQRSTUVWXYZ"
				"ABCDEFGHIJKL",
				IDN_NAMEPREP_CURRENT);
	ASSERT_RESULT(r, idn_invalid_name);

	r = idn_mapselector_add(ctxs[0],
				"."
				"ABCDEFGHIJKLMNOPQRSTUVWXYZ"
				"ABCDEFGHIJKLMNOPQRSTUVWXYZ"
				"ABCDEFGHIJKL",
				IDN_NAMEPREP_CURRENT);
	ASSERT_RESULT(r, idn_invalid_name);
}

//# TESTCASE
//	title: call addall() with too long tld
//	group: generic-init quiet
{
	static const char *names[] = {IDN_NAMEPREP_CURRENT};

	r = idn_mapselector_addall(ctxs[0],
				   "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
				   "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
				   "ABCDEFGHIJK",
				   names, 1);
	ASSERT_RESULT(r, idn_success);

	r = idn_mapselector_addall(ctxs[0],
				   "."
				   "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
				   "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
				   "ABCDEFGHIJK",
				   names, 1);
	ASSERT_RESULT(r, idn_success);

	r = idn_mapselector_addall(ctxs[0],
				   "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
				   "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
				   "ABCDEFGHIJKL",
				   names, 1);
	ASSERT_RESULT(r, idn_invalid_name);

	r = idn_mapselector_addall(ctxs[0],
				   "."
				   "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
				   "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
				   "ABCDEFGHIJKL",
				   names, 1);
	ASSERT_RESULT(r, idn_invalid_name);
}

//# TESTCASE
//	title: overrun test for arg `to' of map()
//	group: generic-init
{
	r = idn_mapselector_add(ctxs[0], utf8_tlds_jp[0],
				IDN_NAMEPREP_CURRENT);
	ASSERT_RESULT(r, idn_success);

	r = idn_mapselector_map(ctxs[0], in_string, utf8_tlds_jp[0], to,
				idn_ucs4_strlen(out_string_nameprep) + 1);
	ASSERT_RESULT(r, idn_success);
	ASSERT_UCS4STRING(to, out_string_nameprep);

	r = idn_mapselector_map(ctxs[0], in_string, utf8_tlds_tw[0], to,
				idn_ucs4_strlen(in_string) + 1);
	ASSERT_RESULT(r, idn_success);
	ASSERT_UCS4STRING(to, in_string);

	r = idn_mapselector_map(ctxs[0], in_string, utf8_tlds_jp[0], to,
				idn_ucs4_strlen(out_string_nameprep));
	ASSERT_RESULT(r, idn_buffer_overflow);

	r = idn_mapselector_map(ctxs[0], in_string, utf8_tlds_tw[0], to,
				idn_ucs4_strlen(in_string));
	ASSERT_RESULT(r, idn_buffer_overflow);
}

//# TESTCASE
//	title: overrun test for arg `to' of map2()
//	group: generic-init
{
	r = idn_mapselector_add(ctxs[0], utf8_tlds_jp[0],
				IDN_NAMEPREP_CURRENT);
	ASSERT_RESULT(r, idn_success);

	r = idn_mapselector_map2(ctxs[0], in_string, ucs4_tlds_jp[0], to,
				 idn_ucs4_strlen(out_string_nameprep) + 1);
	ASSERT_RESULT(r, idn_success);
	ASSERT_UCS4STRING(to, out_string_nameprep);

	r = idn_mapselector_map2(ctxs[0], in_string, ucs4_tlds_tw[0], to,
				 idn_ucs4_strlen(in_string) + 1);
	ASSERT_RESULT(r, idn_success);
	ASSERT_UCS4STRING(to, in_string);

	r = idn_mapselector_map2(ctxs[0], in_string, ucs4_tlds_jp[0], to,
				 idn_ucs4_strlen(out_string_nameprep));
	ASSERT_RESULT(r, idn_buffer_overflow);

	r = idn_mapselector_map2(ctxs[0], in_string, ucs4_tlds_tw[0], to,
				 idn_ucs4_strlen(in_string));
	ASSERT_RESULT(r, idn_buffer_overflow);
}

//# TESTCASE
//	title: call map() with tolen=0
//	group: generic-init
{
	r = idn_mapselector_add(ctxs[0], utf8_tlds_jp[0],
				IDN_NAMEPREP_CURRENT);
	ASSERT_RESULT(r, idn_success);

	r = idn_mapselector_map(ctxs[0], in_string, utf8_tlds_jp[0], to, 0);
	ASSERT_RESULT(r, idn_buffer_overflow);

	r = idn_mapselector_map(ctxs[0], in_string, utf8_tlds_tw[0], to, 0);
	ASSERT_RESULT(r, idn_buffer_overflow);
}

//# TESTCASE
//	title: call map2() with tolen=0
//	group: generic-init
{
	r = idn_mapselector_add(ctxs[0], utf8_tlds_jp[0],
				IDN_NAMEPREP_CURRENT);
	ASSERT_RESULT(r, idn_success);

	r = idn_mapselector_map2(ctxs[0], in_string, ucs4_tlds_jp[0], to, 0);
	ASSERT_RESULT(r, idn_buffer_overflow);

	r = idn_mapselector_map2(ctxs[0], in_string, ucs4_tlds_tw[0], to, 0);
	ASSERT_RESULT(r, idn_buffer_overflow);
}

