/*
 * test_attr.c
 *
 * Copyright 2022 Jonathan Schöbel <jonathan@Ubermos-2019>
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
 * MA 02110-1301, USA.
 *
 *
 */


#include <check.h>
#include <stdlib.h>

#include "status.h"

#include "attr.c"


START_TEST(test_attr1_no_status)
{
	struct SH_Attr * attr;
	const char * name = "name";

	attr = SH_Attr_new (name, NULL, NULL);
	ck_assert_ptr_ne (NULL, attr);
	ck_assert_ptr_ne (name, attr->name);
	ck_assert_str_eq (name, attr->name);
	ck_assert_ptr_eq (NULL, attr->value);

	SH_Attr_free (attr);
}
END_TEST

START_TEST(test_attr1_with_status)
{
	struct SH_Status status;
	struct SH_Attr * attr;
	const char * name = "name";

	_status_preinit (status);
	attr = SH_Attr_new (name, NULL, &status);
	ck_assert_ptr_ne (NULL, attr);
	ck_assert (succeed (&status));
	ck_assert_ptr_ne (name, attr->name);
	ck_assert_str_eq (name, attr->name);
	ck_assert_ptr_eq (NULL, attr->value);

	SH_Attr_free (attr);
}
END_TEST

START_TEST(test_attr2_no_status)
{
	struct SH_Attr * attr;
	const char * name = "name";
	const char * value = "value";

	attr = SH_Attr_new (name, value, NULL);
	ck_assert_ptr_ne (NULL, attr);
	ck_assert_ptr_ne (name, attr->name);
	ck_assert_str_eq (name, attr->name);
	ck_assert_ptr_ne (value, attr->value);
	ck_assert_str_eq (value, attr->value);

	SH_Attr_free (attr);
}
END_TEST

START_TEST(test_attr2_with_status)
{
	struct SH_Status status;
	struct SH_Attr * attr;
	const char * name = "name";
	const char * value = "value";

	_status_preinit (status);
	attr = SH_Attr_new (name, value, &status);
	ck_assert_ptr_ne (NULL, attr);
	ck_assert (succeed (&status));
	ck_assert_ptr_ne (name, attr->name);
	ck_assert_str_eq (name, attr->name);
	ck_assert_ptr_ne (value, attr->value);
	ck_assert_str_eq (value, attr->value);

	SH_Attr_free (attr);
}
END_TEST

START_TEST(test_attr_raw1_no_status)
{
	struct SH_Attr * attr;
	char * name = strdup ("name");

	attr = SH_Attr_raw_new (name, NULL, NULL);
	ck_assert_ptr_ne (NULL, attr);
	ck_assert_ptr_eq (name, attr->name);
	ck_assert_ptr_eq (NULL, attr->value);

	SH_Attr_free (attr);
}
END_TEST

START_TEST(test_attr_raw1_with_status)
{
	struct SH_Status status;
	struct SH_Attr * attr;
	char * name = strdup ("name");

	_status_preinit (status);
	attr = SH_Attr_raw_new (name, NULL, &status);
	ck_assert_ptr_ne (NULL, attr);
	ck_assert (succeed (&status));
	ck_assert_ptr_eq (name, attr->name);
	ck_assert_ptr_eq (NULL, attr->value);

	SH_Attr_free (attr);
}
END_TEST

START_TEST(test_attr_raw2_no_status)
{
	struct SH_Attr * attr;
	char * name = strdup ("name");
	char * value = strdup ("value");

	attr = SH_Attr_raw_new (name, value, NULL);
	ck_assert_ptr_ne (NULL, attr);
	ck_assert_ptr_eq (name, attr->name);
	ck_assert_ptr_eq (value, attr->value);

	SH_Attr_free (attr);
}
END_TEST

START_TEST(test_attr_raw2_with_status)
{
	struct SH_Status status;
	struct SH_Attr * attr;
	char * name = strdup ("name");
	char * value = strdup ("value");

	_status_preinit (status);
	attr = SH_Attr_raw_new (name, value, &status);
	ck_assert_ptr_ne (NULL, attr);
	ck_assert (succeed (&status));
	ck_assert_ptr_eq (name, attr->name);
	ck_assert_ptr_eq (value, attr->value);

	SH_Attr_free (attr);
}
END_TEST

START_TEST(test_attr_copy1_no_status)
{
	struct SH_Attr * attr;
	struct SH_Attr * copy;
	const char * name = "name";

	attr = SH_Attr_new (name, NULL, NULL);

	copy = SH_Attr_copy (attr, NULL);
	ck_assert_ptr_ne (NULL, copy);
	ck_assert_ptr_ne (attr->name, copy->name);
	ck_assert_str_eq (attr->name, copy->name);
	ck_assert_ptr_eq (NULL, copy->value);

	SH_Attr_free (attr);
	SH_Attr_free (copy);
}
END_TEST

START_TEST(test_attr_copy1_with_status)
{
	struct SH_Status status;
	struct SH_Attr * attr;
	struct SH_Attr * copy;
	const char * name = "name";

	attr = SH_Attr_new (name, NULL, NULL);

	_status_preinit (status);
	copy = SH_Attr_copy (attr, &status);
	ck_assert_ptr_ne (NULL, copy);
	ck_assert (succeed (&status));
	ck_assert_ptr_ne (attr->name, copy->name);
	ck_assert_str_eq (attr->name, copy->name);
	ck_assert_ptr_eq (NULL, copy->value);

	SH_Attr_free (attr);
	SH_Attr_free (copy);
}
END_TEST

START_TEST(test_attr_copy2_no_status)
{
	struct SH_Attr * attr;
	struct SH_Attr * copy;
	const char * name = "name";
	const char * value = "value";

	attr = SH_Attr_new (name, value, NULL);

	copy = SH_Attr_copy (attr, NULL);
	ck_assert_ptr_ne (NULL, copy);
	ck_assert_ptr_ne (attr->name, copy->name);
	ck_assert_str_eq (attr->name, copy->name);
	ck_assert_ptr_ne (attr->value, copy->value);
	ck_assert_str_eq (attr->value, copy->value);

	SH_Attr_free (attr);
	SH_Attr_free (copy);
}
END_TEST

START_TEST(test_attr_copy2_with_status)
{
	struct SH_Status status;
	struct SH_Attr * attr;
	struct SH_Attr * copy;
	const char * name = "name";
	const char * value = "value";

	attr = SH_Attr_new (name, value, NULL);

	_status_preinit (status);
	copy = SH_Attr_copy (attr, &status);
	ck_assert_ptr_ne (NULL, copy);
	ck_assert (succeed (&status));
	ck_assert_ptr_ne (attr->name, copy->name);
	ck_assert_str_eq (attr->name, copy->name);
	ck_assert_ptr_ne (attr->value, copy->value);
	ck_assert_str_eq (attr->value, copy->value);

	SH_Attr_free (attr);
	SH_Attr_free (copy);
}
END_TEST

START_TEST(test_attr_name_no_status)
{
	struct SH_Attr * attr;
	const char * name1 = "name1";
	const char * name2 = "name2";
	char * name;
	bool result;

	attr = SH_Attr_new (name1, NULL, NULL);
	ck_assert_ptr_ne (NULL, attr);
	ck_assert_ptr_ne (name1, attr->name);
	ck_assert_str_eq (name1, attr->name);

	name = SH_Attr_get_name (attr, NULL);
	ck_assert_ptr_ne (NULL, name);
	ck_assert_ptr_ne (name1, name);
	ck_assert_str_eq (name1, name);
	free (name);

	result = SH_Attr_set_name (attr, name2, NULL);
	ck_assert_int_eq (TRUE, result);
	ck_assert_ptr_ne (name2, attr->name);
	ck_assert_str_eq (name2, attr->name);

	name = SH_Attr_get_name (attr, NULL);
	ck_assert_ptr_ne (NULL, name);
	ck_assert_ptr_ne (name2, name);
	ck_assert_str_eq (name2, name);
	free (name);

	SH_Attr_free (attr);
}
END_TEST

START_TEST(test_attr_name_with_status)
{
	struct SH_Status status;
	struct SH_Attr * attr;
	const char * name1 = "name1";
	const char * name2 = "name2";
	char * name;
	bool result;

	_status_preinit (status);
	attr = SH_Attr_new (name1, NULL, &status);
	ck_assert_ptr_ne (NULL, attr);
	ck_assert (succeed (&status));
	ck_assert_ptr_ne (name1, attr->name);
	ck_assert_str_eq (name1, attr->name);

	_status_preinit (status);
	name = SH_Attr_get_name (attr, &status);
	ck_assert_ptr_ne (NULL, name);
	ck_assert (succeed (&status));
	ck_assert_ptr_ne (name1, name);
	ck_assert_str_eq (name1, name);
	free (name);

	_status_preinit (status);
	result = SH_Attr_set_name (attr, name2, &status);
	ck_assert_int_eq (TRUE, result);
	ck_assert (succeed (&status));
	ck_assert_ptr_ne (name2, attr->name);
	ck_assert_str_eq (name2, attr->name);

	_status_preinit (status);
	name = SH_Attr_get_name (attr, &status);
	ck_assert_ptr_ne (NULL, name);
	ck_assert (succeed (&status));
	ck_assert_ptr_ne (name2, name);
	ck_assert_str_eq (name2, name);
	free (name);

	SH_Attr_free (attr);
}
END_TEST

START_TEST(test_attr_name_raw)
{
	struct SH_Attr * attr;
	char * name1 = strdup ("name1");
	char * name2 = strdup ("name2");
	const char * name;

	attr = SH_Attr_raw_new (name1, NULL, NULL);
	ck_assert_ptr_ne (NULL, attr);
	ck_assert_ptr_eq (name1, attr->name);

	name = SH_Attr_raw_get_name (attr);
	ck_assert_ptr_ne (NULL, name);
	ck_assert_ptr_eq (name1, name);

	SH_Attr_raw_set_name (attr, name2);
	ck_assert_ptr_eq (name2, attr->name);

	name = SH_Attr_raw_get_name (attr);
	ck_assert_ptr_ne (NULL, name);
	ck_assert_ptr_eq (name2, name);

	SH_Attr_free (attr);
}
END_TEST

START_TEST(test_attr_value_no_status)
{
	struct SH_Attr * attr;
	const char * name = "name";
	const char * value1 = "value1";
	const char * value2 = "value2";
	char * value;
	bool result;

	attr = SH_Attr_new (name, NULL, NULL);
	ck_assert_ptr_ne (NULL, attr);
	ck_assert_ptr_eq (NULL, attr->value);

	value = SH_Attr_get_value (attr, NULL);
	ck_assert_ptr_eq (NULL, value);

	result = SH_Attr_has_value (attr);
	ck_assert_int_eq (FALSE, result);

	result = SH_Attr_set_value (attr, value1, NULL);
	ck_assert_int_eq (TRUE, result);
	ck_assert_ptr_ne (value1, attr->value);
	ck_assert_str_eq (value1, attr->value);

	value = SH_Attr_get_value (attr, NULL);
	ck_assert_ptr_ne (NULL, value);
	ck_assert_ptr_ne (value1, value);
	ck_assert_str_eq (value1, value);
	free (value);

	result = SH_Attr_has_value (attr);
	ck_assert_int_eq (TRUE, result);

	result = SH_Attr_set_value (attr, value2, NULL);
	ck_assert_int_eq (TRUE, result);
	ck_assert_ptr_ne (value2, attr->value);
	ck_assert_str_eq (value2, attr->value);

	SH_Attr_free (attr);
}
END_TEST

START_TEST(test_attr_value_with_status)
{
	struct SH_Status status;
	struct SH_Attr * attr;
	const char * name = "name";
	const char * value1 = "value1";
	const char * value2 = "value2";
	char * value;
	bool result;

	_status_preinit (status);
	attr = SH_Attr_new (name, NULL, &status);
	ck_assert_ptr_ne (NULL, attr);
	ck_assert (succeed (&status));
	ck_assert_ptr_eq (NULL, attr->value);

	_status_preinit (status);
	value = SH_Attr_get_value (attr, &status);
	ck_assert_ptr_eq (NULL, value);
	ck_assert (succeed (&status));

	_status_preinit (status);
	result = SH_Attr_set_value (attr, value1, &status);
	ck_assert_int_eq (TRUE, result);
	ck_assert (succeed (&status));
	ck_assert_ptr_ne (value1, attr->value);
	ck_assert_str_eq (value1, attr->value);

	_status_preinit (status);
	value = SH_Attr_get_value (attr, &status);
	ck_assert_ptr_ne (NULL, value);
	ck_assert (succeed (&status));
	ck_assert_ptr_ne (value1, value);
	ck_assert_str_eq (value1, value);
	free (value);

	_status_preinit (status);
	result = SH_Attr_set_value (attr, value2, &status);
	ck_assert_int_eq (TRUE, result);
	ck_assert (succeed (&status));
	ck_assert_ptr_ne (value2, attr->value);
	ck_assert_str_eq (value2, attr->value);

	SH_Attr_free (attr);
}
END_TEST

START_TEST(test_attr_value_raw)
{
	struct SH_Attr * attr;
	char * name = strdup ("name");
	char * value1 = strdup ("value1");
	char * value2 = strdup ("value2");
	const char * value;
	bool result;

	attr = SH_Attr_raw_new (name, NULL, NULL);
	ck_assert_ptr_ne (NULL, attr);
	ck_assert_ptr_eq (NULL, attr->value);

	value = SH_Attr_raw_get_value (attr);
	ck_assert_ptr_eq (NULL, value);

	result = SH_Attr_has_value (attr);
	ck_assert_int_eq (FALSE, result);

	SH_Attr_raw_set_value (attr, value1);
	ck_assert_ptr_eq (value1, attr->value);

	value = SH_Attr_raw_get_value (attr);
	ck_assert_ptr_ne (NULL, value);
	ck_assert_ptr_eq (value1, value);

	result = SH_Attr_has_value (attr);
	ck_assert_int_eq (TRUE, result);

	SH_Attr_raw_set_value (attr, value2);
	ck_assert_ptr_eq (value2, attr->value);

	SH_Attr_free (attr);
}
END_TEST

START_TEST(test_attr_equal)
{
	struct
	{
		struct
		{
			char * name;
			char * value;
		} _[2];
		bool result;
	} tests[] =
	{
		{{{"name", NULL}, {"name", NULL}}, TRUE},
		{{{"name", "value"}, {"name", NULL}}, FALSE},
		{{{"name", "value"}, {"name", "value"}}, TRUE},
		{{{"name", "value1"}, {"name", "value2"}}, FALSE},
		{{{"name1", NULL}, {"name2", NULL}}, FALSE},
		{{{"name1", "value"}, {"name2", NULL}}, FALSE},
		{{{"name1", "value"}, {"name2", "value"}}, FALSE},
		{{{"name1", "value1"}, {"name2", "value2"}}, FALSE}
	};
	const size_t size = sizeof (tests) / sizeof (tests[0]);
	size_t index;

	for (index = 0; index < size; index++)
	{
		struct SH_Attr * attr1;
		struct SH_Attr * attr2;
		bool result;

		attr1 = SH_Attr_new (tests[index]._[0].name,
		                     tests[index]._[0].value, NULL);
		ck_assert_ptr_ne (NULL, attr1);

		attr2 = SH_Attr_new (tests[index]._[1].name,
		                     tests[index]._[1].value, NULL);
		ck_assert_ptr_ne (NULL, attr2);

		result = SH_Attr_is_equal (attr1, attr2);
		ck_assert_int_eq (result, tests[index].result);

		result = SH_Attr_is_equal (attr2, attr1);
		ck_assert_int_eq (result, tests[index].result);

		result = Attr_is_equal (attr1, attr2);
		ck_assert_int_eq (result, tests[index].result);

		result = Attr_is_equal (attr2, attr1);
		ck_assert_int_eq (result, tests[index].result);

		SH_Attr_free (attr1);
		SH_Attr_free (attr2);
	}
}

START_TEST(test_attr_equal_name)
{
	struct
	{
		struct
		{
			char * name;
			char * value;
		} _[2];
		bool result;
	} tests[] =
	{
		{{{"name", NULL}, {"name", NULL}}, TRUE},
		{{{"name", "value"}, {"name", NULL}}, TRUE},
		{{{"name", "value"}, {"name", "value"}}, TRUE},
		{{{"name", "value1"}, {"name", "value2"}}, TRUE},
		{{{"name1", NULL}, {"name2", NULL}}, FALSE},
		{{{"name1", "value"}, {"name2", NULL}}, FALSE},
		{{{"name1", "value"}, {"name2", "value"}}, FALSE},
		{{{"name1", "value1"}, {"name2", "value2"}}, FALSE}
	};
	const size_t size = sizeof (tests) / sizeof (tests[0]);
	size_t index;

	for (index = 0; index < size; index++)
	{
		struct SH_Attr * attr1;
		struct SH_Attr * attr2;
		bool result;

		attr1 = SH_Attr_new (tests[index]._[0].name,
		                     tests[index]._[0].value, NULL);
		ck_assert_ptr_ne (NULL, attr1);

		attr2 = SH_Attr_new (tests[index]._[1].name,
		                     tests[index]._[1].value, NULL);
		ck_assert_ptr_ne (NULL, attr2);

		result = SH_Attr_is_equal_name (attr1, attr2);
		ck_assert_int_eq (result, tests[index].result);

		result = SH_Attr_is_equal_name (attr2, attr1);
		ck_assert_int_eq (result, tests[index].result);

		result = Attr_is_equal_name (attr1, attr2);
		ck_assert_int_eq (result, tests[index].result);

		result = Attr_is_equal_name (attr2, attr1);
		ck_assert_int_eq (result, tests[index].result);

		SH_Attr_free (attr1);
		SH_Attr_free (attr2);
	}
}

Suite * test_suite (void)
{
	Suite *s;
	TCase *tc_core;

	s = suite_create ("Testsuite SeFHT Attr");

	/* Core test case */
	tc_core = tcase_create ("Core");

	tcase_add_test (tc_core, test_attr1_no_status);
	tcase_add_test (tc_core, test_attr1_with_status);
	tcase_add_test (tc_core, test_attr2_no_status);
	tcase_add_test (tc_core, test_attr2_with_status);

	tcase_add_test (tc_core, test_attr_raw1_no_status);
	tcase_add_test (tc_core, test_attr_raw1_with_status);
	tcase_add_test (tc_core, test_attr_raw2_no_status);
	tcase_add_test (tc_core, test_attr_raw2_with_status);

	tcase_add_test (tc_core, test_attr_copy1_no_status);
	tcase_add_test (tc_core, test_attr_copy1_with_status);
	tcase_add_test (tc_core, test_attr_copy2_no_status);
	tcase_add_test (tc_core, test_attr_copy2_with_status);

	tcase_add_test (tc_core, test_attr_name_no_status);
	tcase_add_test (tc_core, test_attr_name_with_status);
	tcase_add_test (tc_core, test_attr_name_raw);

	tcase_add_test (tc_core, test_attr_value_no_status);
	tcase_add_test (tc_core, test_attr_value_with_status);
	tcase_add_test (tc_core, test_attr_value_raw);

	tcase_add_test (tc_core, test_attr_equal);
	tcase_add_test (tc_core, test_attr_equal_name);

	suite_add_tcase (s, tc_core);

	return s;
}

int main (void)
{
	int number_failed;
	Suite *s;
	SRunner *sr;

	s = test_suite ();
	sr = srunner_create (s);

	srunner_run_all (sr, CK_NORMAL);
	number_failed = srunner_ntests_failed (sr);
	srunner_free (sr);

	return (number_failed == 0) ? EXIT_SUCCESS : EXIT_FAILURE;
}