/**
 * @file check-leaftag.c Test suite
 *
 * @Copyright (C) 2005-2006 Christian Hammond
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library 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
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the
 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
 * Boston, MA  02111-1307, USA.
 */
#include <glib.h>
#include <libleaftag/leaftag.h>
#include <libleaftag/db.h>
#include <libleaftag/priv.h>
#include <check.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>

static void
empty_database(void)
{
	lt_db_exec("DELETE FROM tags");
	lt_db_exec("DELETE FROM sources");
	lt_db_exec("DELETE FROM associations");
}

static LtSource *
create_source(const char *uri)
{
	LtSource *source = lt_create_source(uri);
	fail_unless(source != NULL, "Unable to create source with URI '%s'", uri);
	return source;
}

static LtTag *
populate_sources(void)
{
	LtTag *tag;
	GList *tags = NULL;

	tag = lt_create_tag("search");
	fail_unless(tag != NULL, "Unable to create tag 'search'");

	tags = g_list_append(tags, tag);
	lt_source_tag(create_source("http://www.google.com/"), tags);
	lt_source_tag(create_source("http://www.yahoo.com/"), tags);
	lt_source_tag(create_source("/home/chipx86/search-data.txt"), tags);
	g_list_free(tags);

	return tag;
}

static void
populate_tags(LtSource *source)
{
	GList *tags = NULL;

	tags = g_list_append(tags, "search");
	tags = g_list_append(tags, "daily");
	lt_source_tag_with_names(source, tags);
	g_list_free(tags);
}

static void
check_resulting_tags(GList *tags, const char *with, ...)
{
	GList *l;
	va_list args;

	fail_unless(tags != NULL,
				"Unable to retrieve any tags %s", with == NULL ? "" : with);

	va_start(args, with);

	for (l = tags; l != NULL; l = l->next)
	{
		LtTag *tag = (LtTag *)l->data;
		const char *checked_tag_name = va_arg(args, char *);

		g_assert(checked_tag_name != NULL);

		if (strcmp(checked_tag_name, lt_tag_get_name(tag)))
		{
			fail("Didn't find required tags %s", with == NULL ? "" : with);
			return;
		}
	}

	va_end(args);
}

static void
check_standard_resulting_tags(GList *tags, const char *with)
{
	check_resulting_tags(tags, with, "daily", "search");
}

static void
check_resulting_sources(GList *sources, const char *with)
{
	GList *l;
	gboolean matched_google = FALSE;
	gboolean matched_yahoo = FALSE;
	gboolean matched_file = FALSE;

	fail_unless(sources != NULL,
				"Unable to retrieve any sources %s", with == NULL ? "" : with);

	for (l = sources; l != NULL; l = l->next)
	{
		LtSource *source = LT_SOURCE(l->data);

		if (!strcmp(lt_source_get_uri(source), "http://www.google.com"))
			matched_google = TRUE;
		else if (!strcmp(lt_source_get_uri(source), "http://www.yahoo.com"))
			matched_yahoo = TRUE;
		else if (!strcmp(lt_source_get_uri(source),
						 "file:///home/chipx86/search-data.txt"))
		{
			matched_file = TRUE;
		}
		else
			fail("Found unexpected URI '%s'", lt_source_get_uri(source));
	}

	fail_unless(matched_google && matched_yahoo && matched_file,
				"Didn't find all sources %s",  with == NULL ? "" : with);
}

static void
check_single_source(GList *sources, const char *uri, const char *with)
{
	fail_unless(sources != NULL,
				"Unable to retrieve URIs %s", with);
	fail_unless(g_list_length(sources) == 1,
				"Retrieved too many URIs %s", with);
	fail_unless(!strcmp(lt_source_get_uri((LtSource *)sources->data), uri),
				"Didn't find correct URI %s", with);
}

START_TEST(test_init_db)
{
	lt_db_init();
	fail_unless(lt_db_is_initted(), "Fresh install of a database failed.");
	lt_db_uninit();

	lt_db_init();
	fail_unless(lt_db_is_initted(), "Open of existing database failed.");
	lt_db_uninit();
}
END_TEST

START_TEST(test_uri_parse)
{
	char *schema, *path;

#define CHECK_URI_PARSE(uri, schema_str, path_str) \
	lt_uri_parse((uri), &schema, &path); \
	fail_unless(!strcmp(schema, (schema_str)) && !strcmp(path, (path_str)), \
				"URI parsing failed. URI = '%s', Schema = '%s', path = '%s'", \
				(uri), schema, path); \
	g_free(schema); \
	g_free(path);

	CHECK_URI_PARSE("http://www.google.com", "http", "www.google.com");
	CHECK_URI_PARSE("urn:foo:bar:foobar", "urn", "foo:bar:foobar");
	CHECK_URI_PARSE("file:///root/sekret", "file", "/root/sekret");
	CHECK_URI_PARSE("/root/sekret", "file", "/root/sekret");

#undef CHECK_URI_PARSE
}
END_TEST

START_TEST(test_uri_normalize)
{
	char *temp;

#define CHECK_URI_NORMALIZE(uri, check_uri) \
	temp = lt_uri_normalize((uri)); \
	fail_unless(!strcmp(temp, (check_uri)), \
				"URI normalization failed. '%s' != '%s'", (uri), (check_uri)); \
	g_free(temp)

	CHECK_URI_NORMALIZE("http://www.google.com/", "http://www.google.com");
	CHECK_URI_NORMALIZE("file:///root/sekret/", "file:///root/sekret");
	CHECK_URI_NORMALIZE("/root/sekret/", "file:///root/sekret");

#undef CHECK_URI_NORMALIZE
}
END_TEST

START_TEST(test_create_source_with_uri)
{
	LtSource *source = create_source("http://www.google.com/");
	g_object_unref(source);
}
END_TEST

START_TEST(test_create_source_with_file_uri)
{
	LtSource *source = create_source("file:///root/sekret");
	g_object_unref(source);
}
END_TEST

START_TEST(test_create_source_with_file_path)
{
	LtSource *source = create_source("/root/sekret");
	g_object_unref(source);
}
END_TEST

START_TEST(test_tagging)
{
	GList *tags;
	LtSource *source;

	empty_database();

	source = create_source("http://www.google.com/");
	populate_tags(source);

	tags = lt_source_get_tags(source);
	check_standard_resulting_tags(tags, NULL);
	g_list_free(tags);

	g_object_unref(source);
}
END_TEST

START_TEST(test_get_all_tags)
{
	GList *tags = NULL;
	LtSource *source;

	empty_database();

	source = create_source("http://www.google.com/");
	populate_tags(source);
	g_object_unref(source);

	tags = lt_get_all_tags();
	check_standard_resulting_tags(tags, NULL);
	g_list_free(tags);
}
END_TEST

START_TEST(test_lt_source_untag)
{
	GList *tags = NULL;
	LtSource *source;
	size_t len;

	empty_database();

	source = create_source("http://www.google.com/");

	tags = g_list_append(NULL, "a");
	tags = g_list_append(tags, "b");
	tags = g_list_append(tags, "c");
	tags = g_list_append(tags, "d");
	tags = g_list_append(tags, "e");
	lt_source_tag_with_names(source, tags);
	g_list_free(tags);

	tags = g_list_append(NULL, "b");
	tags = g_list_append(tags, "d");
	lt_source_untag_with_names(source, tags);
	g_list_free(tags);

	tags = lt_source_get_tags(source);
	fail_unless(tags != NULL, "Unable to retrieve any tags");
	len = g_list_length(tags);
	fail_unless(len == 3, "Retrieved wrong number of tags (%d). Expected 3.",
				len);
	check_resulting_tags(tags, NULL, "a", "c", "e");
	g_list_free(tags);

	tags = g_list_append(NULL, lt_tag_lookup("a"));
	tags = g_list_append(tags, lt_tag_lookup("e"));
	lt_source_untag(source, tags);
	g_list_free(tags);

	tags = lt_source_get_tags(source);
	fail_unless(tags != NULL, "Unable to retrieve any tags");
	len = g_list_length(tags);
	fail_unless(len == 1, "Retrieved wrong number of tags (%d). Expected 1.",
				len);
	check_resulting_tags(tags, NULL, "c");
	g_list_free(tags);
}
END_TEST

START_TEST(test_lt_get_visible_tags)
{
	GList *tags = NULL;
	LtSource *source;
	LtTag *tag;

	empty_database();

	source = create_source("http://www.google.com/");
	populate_tags(source);
	g_object_unref(source);

	tag = lt_tag_lookup("search");
	lt_tag_set_hidden(tag, TRUE);

	tags = lt_get_visible_tags();
	fail_unless(tags != NULL, "Unable to retrieve visible tags");
	fail_unless(g_list_length(tags) == 1, "Retrieved too many visible tags");
	fail_unless(!strcmp(lt_tag_get_name(LT_TAG(tags->data)), "daily"),
				"Didn't find correct visible tag 'daily'");
	g_list_free(tags);
}
END_TEST

START_TEST(test_lt_tag_get_uris)
{
	GList *sources = NULL;
	LtTag *tag;

	empty_database();
	tag = populate_sources();

	sources = lt_tag_get_sources(tag, NULL);
	check_resulting_sources(sources, "tagged with 'search'");
	g_list_free(sources);

	/* Search with a schema */
	sources = lt_tag_get_sources(tag, "file");
	check_single_source(sources, "file:///home/chipx86/search-data.txt",
						"tagged with 'search' with schema 'file'");
	g_list_free(sources);
}
END_TEST

START_TEST(test_lt_get_all_sources)
{
	GList *sources = NULL;

	empty_database();
	populate_sources();

	sources = lt_get_all_sources();
	fail_unless(sources != NULL, "Unable to retrieve any sources");
	check_resulting_sources(sources, NULL);
	g_list_free(sources);
}
END_TEST

START_TEST(test_lt_get_sources_with_schema)
{
	GList *sources = NULL;

	empty_database();
	populate_sources();

	sources = lt_get_sources_with_schema("file");
	check_single_source(sources, "file:///home/chipx86/search-data.txt",
						"with schema 'file'");
	g_list_free(sources);
}
END_TEST

START_TEST(test_lt_get_sources_with_tags)
{
	GList *sources = NULL;
	GList *tags = NULL;

	empty_database();
	populate_sources();

	tags = g_list_append(tags, lt_tag_lookup("search"));
	sources = lt_get_sources_with_tags(tags, NULL);
	check_resulting_sources(sources, "tagged with 'search'");
	g_list_free(sources);

	/* Search with a schema */
	sources = lt_get_sources_with_tags(tags, "file");
	check_single_source(sources, "file:///home/chipx86/search-data.txt",
						"tagged with 'search' with schema 'file'");
	g_list_free(sources);
	g_list_free(tags);
}
END_TEST

START_TEST(test_lt_get_sources_with_tag_names)
{
	GList *sources = NULL;
	GList *tags = NULL;

	empty_database();
	populate_sources();

	tags = g_list_append(tags, "search");
	sources = lt_get_sources_with_tag_names(tags, NULL);
	check_resulting_sources(sources, "tagged with 'search'");
	g_list_free(sources);

	/* Search with a schema */
	sources = lt_get_sources_with_tag_names(tags, "file");
	check_single_source(sources, "file:///home/chipx86/search-data.txt",
						"tagged with 'search' with schema 'file'");
	g_list_free(sources);
	g_list_free(tags);
}
END_TEST

#define ADD_TCASE(name, func) \
	tc = tcase_create(name); \
	tcase_add_test(tc, (func)); \
	suite_add_tcase(s, tc)

static Suite *
make_leaftag_suite(void)
{
	Suite *s;
	TCase *tc;

	s = suite_create("libleaftag");

	ADD_TCASE("init_db", test_init_db);
	ADD_TCASE("test_uri_parse", test_uri_parse);
	ADD_TCASE("test_uri_normalize", test_uri_normalize);
	ADD_TCASE("create_source_with_uri", test_create_source_with_uri);
	ADD_TCASE("create_source_with_file_uri",
			  test_create_source_with_file_uri);
	ADD_TCASE("create_source_with_file_path",
			  test_create_source_with_file_path);
	ADD_TCASE("tagging", test_tagging);
	ADD_TCASE("get_all_tags", test_get_all_tags);
	ADD_TCASE("lt_source_untag", test_lt_source_untag);
	ADD_TCASE("lt_get_visible_tags", test_lt_get_visible_tags);
	ADD_TCASE("lt_tag_get_uris", test_lt_tag_get_uris);
	ADD_TCASE("lt_get_all_sources", test_lt_get_all_sources);
	ADD_TCASE("lt_get_sources_with_schema", test_lt_get_sources_with_schema);
	ADD_TCASE("lt_get_sources_with_tags", test_lt_get_sources_with_tags);
	ADD_TCASE("lt_get_sources_with_tag_names",
			  test_lt_get_sources_with_tag_names);

	return s;
}

static void
error_handler(const gchar *log_domain, GLogLevelFlags log_level,
			  const gchar *message, gpointer user_data)
{
	fail(message);
}

int
main(int argc, char **argv)
{
	Suite *s;
	SRunner *sr;
	int nf;

	g_type_init();

	g_log_set_handler(NULL,
					  G_LOG_LEVEL_MASK | G_LOG_FLAG_FATAL |
					  G_LOG_FLAG_RECURSION,
					  error_handler, NULL);
	g_log_set_handler("GLib",
					  G_LOG_LEVEL_MASK | G_LOG_FLAG_FATAL |
					  G_LOG_FLAG_RECURSION,
					  error_handler, NULL);
	g_log_set_handler("Leaftag",
					  G_LOG_LEVEL_MASK | G_LOG_FLAG_FATAL |
					  G_LOG_FLAG_RECURSION,
					  error_handler, NULL);

	if (g_file_test("testsuite-tags.db", G_FILE_TEST_EXISTS))
		unlink("testsuite-tags.db");

	lt_db_set_filename("testsuite-tags.db");

	s = make_leaftag_suite();
	sr = srunner_create(s);

	srunner_set_log(sr, "check-leaftag.log");
	srunner_run_all(sr, CK_NORMAL);

	nf = srunner_ntests_failed(sr);

	srunner_free(sr);

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


syntax highlighted by Code2HTML, v. 0.9.1