/*
 * Ibis - IRCv3 Library
 * Copyright (C) 2022-2024 Ibis Developers
 *
 * Ibis is the legal property of its developers, whose names are too numerous
 * to list here.  Please refer to the COPYRIGHT file distributed with this
 * source distribution.
 *
 * 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 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, see <https://www.gnu.org/licenses/>.
 */

#include <glib.h>

#include <ibis.h>

/******************************************************************************
 * Basic Tests
 *****************************************************************************/
static void
test_ibis_ctcp_message_new_null(void) {
	if(g_test_subprocess()) {
		IbisCTCPMessage *message = NULL;

		message = ibis_ctcp_message_new(NULL);

		g_assert_finalize_object(message);

		g_assert_not_reached();
	}

	g_test_trap_subprocess(NULL, 0, 0);
	g_test_trap_assert_stderr("*Ibis-CRITICAL*ibis_str_is_empty*failed*");
}

static void
test_ibis_ctcp_message_new_normal(void) {
	IbisCTCPMessage *message = NULL;

	message = ibis_ctcp_message_new(IBIS_CTCP_VERSION);
	g_assert_true(IBIS_IS_CTCP_MESSAGE(message));

	g_assert_finalize_object(message);
}

static void
test_ibis_ctcp_message_properties(void) {
	IbisCTCPMessage *message = NULL;
	GStrv params1 = NULL;
	char *command = NULL;
	const char *params[] = {"Pidgin", "3.0", NULL};

	message = g_object_new(
		IBIS_TYPE_CTCP_MESSAGE,
		"command", IBIS_CTCP_VERSION,
		"params", params,
		NULL);

	g_assert_true(IBIS_IS_CTCP_MESSAGE(message));

	g_object_get(
		G_OBJECT(message),
		"command", &command,
		"params", &params1,
		NULL);

	g_assert_cmpstr(command, ==, IBIS_CTCP_VERSION);
	g_clear_pointer(&command, g_free);

	g_assert_cmpstrv(params1, params);
	g_strfreev(params1);

	g_assert_finalize_object(message);
}

static void
test_ibis_ctcp_message_is_command_null(void) {
	IbisCTCPMessage *message = NULL;
	gboolean result = FALSE;

	message = ibis_ctcp_message_new(IBIS_CTCP_VERSION);
	result = ibis_ctcp_message_is_command(message, NULL);
	g_assert_false(result);

	g_assert_finalize_object(message);
}

static void
test_ibis_ctcp_message_is_command_true(void) {
	IbisCTCPMessage *message = NULL;
	gboolean result = FALSE;

	message = ibis_ctcp_message_new(IBIS_CTCP_VERSION);
	result = ibis_ctcp_message_is_command(message, IBIS_CTCP_VERSION);
	g_assert_true(result);

	g_assert_finalize_object(message);
}

static void
test_ibis_ctcp_message_is_command_false(void) {
	IbisCTCPMessage *message = NULL;
	gboolean result = FALSE;

	message = ibis_ctcp_message_new(IBIS_CTCP_VERSION);
	result = ibis_ctcp_message_is_command(message, IBIS_CTCP_ACTION);
	g_assert_false(result);

	g_assert_finalize_object(message);
}

/******************************************************************************
 * Parse Tests
 *****************************************************************************/
static void
test_ibis_ctcp_message_parse_null(void) {
	IbisCTCPMessage *message = NULL;

	message = ibis_ctcp_message_parse(NULL);
	g_assert_null(message);
}

static void
test_ibis_ctcp_message_parse_not_ctcp(void) {
	IbisCTCPMessage *message = NULL;

	message = ibis_ctcp_message_parse("hiya");
	g_assert_null(message);
}

static void
test_ibis_ctcp_message_parse_leading_delimiter_only(void) {
	IbisCTCPMessage *message = NULL;
	const char *command = NULL;

	message = ibis_ctcp_message_parse("\001VERSION");
	g_assert_true(IBIS_IS_CTCP_MESSAGE(message));

	command = ibis_ctcp_message_get_command(message);
	g_assert_cmpstr(command, ==, "VERSION");

	g_assert_finalize_object(message);
}

static void
test_ibis_ctcp_message_parse_trailing_delimiter_only(void) {
	IbisCTCPMessage *message = NULL;

	message = ibis_ctcp_message_parse("VERSION\001");
	g_assert_null(message);
}

static void
test_ibis_ctcp_message_parse_command_only(void) {
	IbisCTCPMessage *message = NULL;
	const char *command = NULL;

	message = ibis_ctcp_message_parse("\001VERSION\001");
	g_assert_true(IBIS_IS_CTCP_MESSAGE(message));

	command = ibis_ctcp_message_get_command(message);
	g_assert_cmpstr(command, ==, "VERSION");

	g_assert_finalize_object(message);
}

static void
test_ibis_ctcp_message_parse_empty_params(void) {
	IbisCTCPMessage *message = NULL;
	GStrv params = NULL;
	const char *command = NULL;

	message = ibis_ctcp_message_parse("\001VERSION \001");
	g_assert_true(IBIS_IS_CTCP_MESSAGE(message));

	command = ibis_ctcp_message_get_command(message);
	g_assert_cmpstr(command, ==, "VERSION");

	params = ibis_ctcp_message_get_params(message);
	g_assert_null(params);

	g_assert_finalize_object(message);
}

static void
test_ibis_ctcp_message_parse_single_param(void) {
	IbisCTCPMessage *message = NULL;
	GStrv params = NULL;
	const char *expected[] = {"Foo", NULL};
	const char *command = NULL;

	message = ibis_ctcp_message_parse("\001PING Foo\001");
	g_assert_true(IBIS_IS_CTCP_MESSAGE(message));

	command = ibis_ctcp_message_get_command(message);
	g_assert_cmpstr(command, ==, "PING");

	params = ibis_ctcp_message_get_params(message);
	g_assert_cmpstrv(params, expected);

	g_assert_finalize_object(message);
}

static void
test_ibis_ctcp_message_parse_multiple_params(void) {
	IbisCTCPMessage *message = NULL;
	GStrv params = NULL;
	const char *expected[] = {"Pidgin", "3.0", "Final",
	                          "2038-01-19T03:14:07Z", NULL};
	const char *command = NULL;

	message = ibis_ctcp_message_parse("\001VERSION "
	                                  "Pidgin 3.0 Final 2038-01-19T03:14:07Z"
	                                  "\001");
	g_assert_true(IBIS_IS_CTCP_MESSAGE(message));

	command = ibis_ctcp_message_get_command(message);
	g_assert_cmpstr(command, ==, "VERSION");

	params = ibis_ctcp_message_get_params(message);
	g_assert_cmpstrv(params, expected);

	g_assert_finalize_object(message);
}

/******************************************************************************
 * Serialize Tests
 *****************************************************************************/
static void
test_ibis_ctcp_message_serialize_command_only(void) {
	IbisCTCPMessage *message = NULL;
	char *serialized = NULL;
	const char *expected = "\001" IBIS_CTCP_VERSION "\001";

	message = ibis_ctcp_message_new(IBIS_CTCP_VERSION);

	serialized = ibis_ctcp_message_serialize(message);
	g_assert_cmpstr(serialized, ==, expected);
	g_clear_pointer(&serialized, g_free);

	g_assert_finalize_object(message);
}

static void
test_ibis_ctcp_message_serialize_single_param(void) {
	IbisCTCPMessage *message = NULL;
	char *serialized = NULL;
	const char *expected = "\001" IBIS_CTCP_VERSION " Pidgin\001";
	const char *params[] = {"Pidgin", NULL};

	message = ibis_ctcp_message_new(IBIS_CTCP_VERSION);
	ibis_ctcp_message_set_paramsv(message, (GStrv)params);

	serialized = ibis_ctcp_message_serialize(message);
	g_assert_cmpstr(serialized, ==, expected);
	g_clear_pointer(&serialized, g_free);

	g_assert_finalize_object(message);
}

static void
test_ibis_ctcp_message_serialize_multiple_params(void) {
	IbisCTCPMessage *message = NULL;
	char *serialized = NULL;
	const char *expected = "\001" IBIS_CTCP_VERSION " Pidgin 3.0 Final\001";
	const char *params[] = {"Pidgin", "3.0", "Final", NULL};

	message = ibis_ctcp_message_new(IBIS_CTCP_VERSION);
	ibis_ctcp_message_set_paramsv(message, (GStrv)params);

	serialized = ibis_ctcp_message_serialize(message);
	g_assert_cmpstr(serialized, ==, expected);
	g_clear_pointer(&serialized, g_free);

	g_assert_finalize_object(message);
}

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

	g_test_add_func("/ibis/ctcp-message/new/null",
	                test_ibis_ctcp_message_new_null);
	g_test_add_func("/ibis/ctcp-message/new/normal",
	                test_ibis_ctcp_message_new_normal);

	g_test_add_func("/ibis/ctcp-message/properties",
	                test_ibis_ctcp_message_properties);

	g_test_add_func("/ibis/ctcp-message/is_command/null",
	                test_ibis_ctcp_message_is_command_null);
	g_test_add_func("/ibis/ctcp-message/is_command/true",
	                test_ibis_ctcp_message_is_command_true);
	g_test_add_func("/ibis/ctcp-message/is_command/false",
	                test_ibis_ctcp_message_is_command_false);

	g_test_add_func("/ibis/ctcp-message/parse/null",
	                test_ibis_ctcp_message_parse_null);
	g_test_add_func("/ibis/ctcp-message/parse/not-ctcp",
	                test_ibis_ctcp_message_parse_not_ctcp);
	g_test_add_func("/ibis/ctcp-message/parse/leading-delimiter-only",
	                test_ibis_ctcp_message_parse_leading_delimiter_only);
	g_test_add_func("/ibis/ctcp-message/parse/trailing-delimiter-only",
	                test_ibis_ctcp_message_parse_trailing_delimiter_only);
	g_test_add_func("/ibis/ctcp-message/parse/command-only",
	                test_ibis_ctcp_message_parse_command_only);
	g_test_add_func("/ibis/ctcp-message/parse/empty-params",
	                test_ibis_ctcp_message_parse_empty_params);
	g_test_add_func("/ibis/ctcp-message/parse/single-param",
	                test_ibis_ctcp_message_parse_single_param);
	g_test_add_func("/ibis/ctcp-message/parse/multiple-params",
	                test_ibis_ctcp_message_parse_multiple_params);

	g_test_add_func("/ibis/ctcp-message/serialize/command-only",
	                test_ibis_ctcp_message_serialize_command_only);
	g_test_add_func("/ibis/ctcp-message/serialize/single-param",
	                test_ibis_ctcp_message_serialize_single_param);
	g_test_add_func("/ibis/ctcp-message/serialize/multiple-params",
	                test_ibis_ctcp_message_serialize_multiple_params);

	return g_test_run();
}
