/*
 * Copyright (C) 2023 Hasl Developers
 *
 * 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, see <https://www.gnu.org/licenses/>.
 */

#include <glib.h>

#include <hasl.h>

/******************************************************************************
 * Tests
 *****************************************************************************/
static void
test_hasl_version_constants(void) {
	/* Since we are hasl, our build time versions will always match our compile
	 * time versions, so we can check that those are in fact, equal.
	 */

	g_assert_cmpuint(HASL_MAJOR_VERSION, ==, hasl_major_version);
	g_assert_cmpuint(HASL_MINOR_VERSION, ==, hasl_minor_version);
	g_assert_cmpuint(HASL_MICRO_VERSION, ==, hasl_micro_version);
	g_assert_cmpstr(HASL_VERSION, ==, hasl_version);
}

static void
test_hash_version_runtime_check(void) {
	const char *reason = NULL;

	/* We can't do this until 1.0.0 is released as it underflows. */
#if HASL_CHECK_VERSION(1, 0, 0)
	reason = hasl_check_version(hasl_major_version - 1, 0, 0);
	g_assert_cmpstr(reason, ==, "hasl version too new (major mismatch)");
#endif /* HASL_CHECK_VERSION */

	/* Old minors from the same version are compatible. */
	reason = hasl_check_version(hasl_major_version, hasl_minor_version - 1, 0);
	g_assert_null(reason);

#if HASL_CHECK_VERSION(HASL_MAJOR_VERSION, HASL_MINOR_VERSION, 1)
	/* Old micros from the same major and minors are compatible. */
	reason = hasl_check_version(hasl_major_version, hasl_minor_version,
	                            hasl_micro_version - 1);
	g_assert_null(reason);
#endif

	/* Exact versions are compatible. */
	reason = hasl_check_version(hasl_major_version, hasl_minor_version,
	                            hasl_micro_version);
	g_assert_null(reason);

	/* Requiring newer majors should fail. */
	reason  = hasl_check_version(hasl_major_version + 1, 0, 0);
	g_assert_cmpstr(reason, ==, "hasl version too old (major mismatch)");

	/* Requiring newer minors with the same major should fail. */
	reason = hasl_check_version(hasl_major_version, hasl_minor_version + 1, 0);
	g_assert_cmpstr(reason, ==, "hasl version too old (minor mismatch)");

	/* Requiring new micros with the same major and minor should fail. */
	reason = hasl_check_version(hasl_major_version, hasl_minor_version,
	                            hasl_micro_version + 1);
	g_assert_cmpstr(reason, ==, "hasl version too old (micro mismatch)");
}

static void
test_hash_version_compile_time_check(void) {
	/* Check the major versions. */
#if HASL_CHECK_VERSION(HASL_MAJOR_VERSION - 1, 0, 0)
	g_assert_not_reached();
#endif

#if !HASL_CHECK_VERSION(HASL_MAJOR_VERSION, 0, 0)
	g_assert_not_reached();
#endif

#if HASL_CHECK_VERSION(HASL_MAJOR_VERSION + 1, 0, 0)
	g_assert_not_reached();
#endif

	/* Check the minor version. */
#if !HASL_CHECK_VERSION(HASL_MAJOR_VERSION, HASL_MINOR_VERSION - 1, 0)
	g_assert_not_reached();
#endif

#if !HASL_CHECK_VERSION(HASL_MAJOR_VERSION, HASL_MINOR_VERSION, 0)
	g_assert_not_reached();
#endif

#if HASL_CHECK_VERSION(HASL_MAJOR_VERSION, HASL_MINOR_VERSION + 1, 0)
	g_assert_not_reached();
#endif

	/* Check the micro version. */
#if !HASL_CHECK_VERSION(HASL_MAJOR_VERSION, HASL_MINOR_VERSION, \
                        HASL_MICRO_VERSION - 1)
	g_assert_not_reached();
#endif

#if !HASL_CHECK_VERSION(HASL_MAJOR_VERSION, HASL_MINOR_VERSION, \
                        HASL_MICRO_VERSION)
	g_assert_not_reached();
#endif

#if HASL_CHECK_VERSION(HASL_MAJOR_VERSION, HASL_MINOR_VERSION, \
                       HASL_MICRO_VERSION + 1)
	g_assert_not_reached();
#endif
}

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

	g_test_add_func("/hasl/version/constants", test_hasl_version_constants);
	g_test_add_func("/hasl/version/runtime-check",
	                test_hash_version_runtime_check);
	g_test_add_func("/hasl/version/compile-time-check",
	                test_hash_version_compile_time_check);

	return g_test_run();
}
