/*
 * Copyright (C) 2022 Guido Berhoerster <guido+ubports@berhoerster.name>
 *
 * This program is free software: you can redistribute it and/or modify it
 * under the terms of the GNU General Public License version 3, as published
 * by the Free Software Foundation.
 *
 * This program is distributed in the hope that it will be useful, but
 * WITHOUT ANY WARRANTY; without even the implied warranties of
 * MERCHANTABILITY, SATISFACTORY QUALITY, 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, see <http://www.gnu.org/licenses/>.
 */
#include <errno.h>
#include <stdlib.h>
#include <unistd.h>

#include <glib.h>
#include <json-glib/json-glib.h>
#include <lomiri-app-launch.h>

#include "find-helper.h"

typedef struct {
	gchar *tmpdir;
	gchar *datafile;
} LpsFindHelperFixture;

static void
lps_find_helper_fixture_set_up(LpsFindHelperFixture *fixture,
    gconstpointer user_data)
{
	const gchar	tmpl[] = "lps-find-helper-test-XXXXXX";
	GError		*error = NULL;
	gchar		*datadir;

	fixture->tmpdir = g_dir_make_tmp(tmpl, &error);
	if (fixture->tmpdir == NULL) {
		g_error("failed to create temporary directory: %s",
		    error->message);
	}
	datadir = g_build_path("/", fixture->tmpdir, "lomiri-push-service",
	    NULL);
	fixture->datafile = g_build_path("/", datadir, "helpers_data.json",
	    NULL);

	if (g_mkdir_with_parents(datadir, 0700) < 0) {
		g_error("failed to create %s: %s", datadir, g_strerror(errno));
	}

	g_setenv("XDG_DATA_HOME", fixture->tmpdir, TRUE);

	g_free(datadir);
}

static void
lps_find_helper_fixture_tear_down(LpsFindHelperFixture *fixture,
    gconstpointer user_data)
{
	gchar		*datadir;

	unlink(fixture->datafile);
	datadir = g_build_path("/", fixture->tmpdir, "lomiri-push-service",
	    NULL);
	rmdir(datadir);

	g_unsetenv("XDG_DATA_HOME");

	g_free(datadir);
	g_free(fixture->datafile);
	g_free(fixture->tmpdir);
}

static void
lps_find_helper_fixture_create_datafile(LpsFindHelperFixture *fixture,
    const char *content)
{
	GError	*error = NULL;

	if (!g_file_set_contents(fixture->datafile, content, -1, &error)) {
		g_error("%s", error->message);
	}
}

static void
test_find_helper_basic(LpsFindHelperFixture *fixture, gconstpointer user_data)
{
	gchar	*package = NULL;
	gchar	*app = NULL;
	gchar	*helper = NULL;

	lps_find_helper_fixture_create_datafile(fixture,
	    "{\"com.example.test\": {\"helper_id\": \"com.example.test_"
	    "test-helper_1\", \"exec\": \"tsthlpr\"}}");
	g_assert_true(lomiri_app_launch_app_id_parse(
	    "com.example.test_test-app_1", &package, &app, NULL));
	helper = find_helper(package, NULL, NULL);
	g_assert_cmpstr(helper, ==, "tsthlpr");

	g_free(app);
	g_free(package);
	g_free(helper);
}

static void
test_find_helper_finds_specific(LpsFindHelperFixture *fixture,
    gconstpointer user_data)
{
	gchar	*package = NULL;
	gchar	*app = NULL;
	gchar	*helper = NULL;

	lps_find_helper_fixture_create_datafile(fixture,
	    "{\"com.example.test_test-other-app\": {\"exec\": \"aaaaaaa\", "
	    "\"helper_id\": \"com.example.test_aaaa-helper_1\"}, "
	    "\"com.example.test_test-app\": {\"exec\": \"tsthlpr\", "
	    "\"helper_id\": \"com.example.test_test-helper_1\"}}");
	g_assert_true(lomiri_app_launch_app_id_parse(
	    "com.example.test_test-app_1", &package, &app, NULL));
	helper = find_helper(package, app, NULL);
	g_assert_cmpstr(helper, ==, "tsthlpr");

	g_free(app);
	g_free(package);
	g_free(helper);
}

static void
test_find_helper_can_fail(LpsFindHelperFixture *fixture,
    gconstpointer user_data)
{
	gchar	*package = NULL;
	gchar	*app = NULL;
	gchar	*helper = NULL;
	GError	*error = NULL;

	lps_find_helper_fixture_create_datafile(fixture,
	    "{\"com.example.test_test-other-app\": {\"exec\": \"aaaaaaa\", "
	    "\"helper_id\": \"com.example.test_aaaa-helper_1\"}}");
	g_assert_true(lomiri_app_launch_app_id_parse(
	    "com.example.test_test-app_1", &package, &app, NULL));
	helper = find_helper(package, app, &error);
	g_assert_null(helper);
	g_assert_error(error, LPS_FIND_HELPER_ERROR,
	    LPS_FIND_HELPER_ERROR_NO_HELPER);

	g_error_free(error);
	g_free(app);
	g_free(package);
	g_free(helper);
}

static void
test_find_helper_fail_invalid_json(LpsFindHelperFixture *fixture,
    gconstpointer user_data)
{
	gchar	*package = NULL;
	gchar	*app = NULL;
	gchar	*helper = NULL;
	GError	*error = NULL;

	lps_find_helper_fixture_create_datafile(fixture,
	    "{invalid json\"com.example.test_test-other-app\": {\"exec\": "
	    "\"aaaaaaa\", \"helper_id\": \"com.example.test_aaaa-helper_1\"}}");
	g_assert_true(lomiri_app_launch_app_id_parse(
	    "com.example.test_test-app_1", &package, &app, NULL));
	helper = find_helper(package, app, &error);
	g_assert_null(helper);
	g_assert_error(error, JSON_PARSER_ERROR,
	    JSON_PARSER_ERROR_INVALID_BAREWORD);

	g_error_free(error);
	g_free(app);
	g_free(package);
	g_free(helper);
}

static void
test_find_helper_fail_missing_exec(LpsFindHelperFixture *fixture,
    gconstpointer user_data)
{
	gchar	*package = NULL;
	gchar	*app = NULL;
	gchar	*helper = NULL;
	GError	*error = NULL;

	lps_find_helper_fixture_create_datafile(fixture,
	    "{\"com.example.test_test-app\": {\"helper_id\": "
	    "\"com.example.test_aaaa-helper_1\"}}");
	g_assert_true(lomiri_app_launch_app_id_parse(
	    "com.example.test_test-app_1", &package, &app, NULL));
	helper = find_helper(package, app, &error);
	g_assert_null(helper);
	g_assert_error(error, LPS_FIND_HELPER_ERROR,
	    LPS_FIND_HELPER_ERROR_NO_HELPER);

	g_error_free(error);
	g_free(app);
	g_free(package);
	g_free(helper);
}

int
main(int argc, char *argv[])
{
	g_test_init (&argc, &argv, NULL);

	g_test_add("/lps-find-helper/basic", LpsFindHelperFixture, NULL,
	    lps_find_helper_fixture_set_up, test_find_helper_basic,
	    lps_find_helper_fixture_tear_down);

	g_test_add("/lps-find-helper/finds_specific", LpsFindHelperFixture,
	    NULL, lps_find_helper_fixture_set_up,
	    test_find_helper_finds_specific,
	    lps_find_helper_fixture_tear_down);

	g_test_add("/lps-find-helper/can_fail", LpsFindHelperFixture, NULL,
	    lps_find_helper_fixture_set_up, test_find_helper_can_fail,
	    lps_find_helper_fixture_tear_down);

	g_test_add("/lps-find-helper/fail_invalid_json", LpsFindHelperFixture,
	    NULL, lps_find_helper_fixture_set_up,
	    test_find_helper_fail_invalid_json,
	    lps_find_helper_fixture_tear_down);

	g_test_add("/lps-find-helper/fail_missing_exec", LpsFindHelperFixture,
	    NULL, lps_find_helper_fixture_set_up,
	    test_find_helper_fail_missing_exec,
	    lps_find_helper_fixture_tear_down);

	exit(g_test_run());
}
