/* SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-only */
/* Copyright (c) 2024 Brett Sheffield <bacs@librecast.net> */

/* create a random network topology, following a few rules:
 *
 * 1) All routers will be connected to at least one other router.
 * 2) All routers have a path to all other routers.
 * 3) Routers can be connected to another router by more than one link.
 * 4) Routers are not directly connected to themselves.
 */

#include "test.h"
#include <librecast_pvt.h>
#include <librecast/router.h>

#define ROUTERS 7
#define PORTS ROUTERS - 1

int main(void)
{
	lc_ctx_t *lctx;
	lc_router_t *r[ROUTERS];
	int rc;

	test_name("lc_router_net() - LC_TOPO_RANDOM");

	lctx = lc_ctx_new();
	if (!test_assert(lctx != NULL, "lc_ctx_new()")) return test_status;

	/* create a random topology */
	rc = lc_router_net(lctx, r, ROUTERS, LC_TOPO_RANDOM, 0, 0);
	if (rc) perror("lc_router_net");
	if (!test_assert(rc == 0, "lc_router_net()")) goto err_ctx_free;
	for (int i = 0; i < ROUTERS; i++) {
		test_log("====== ROUTER %i\n", i);

		/* check router parameters */
		if (!test_assert(r[i] != NULL, "r[%i] allocated", i))
			goto err_ctx_free;
		if (!test_assert(r[i]->ctx == lctx, "context set"))
			goto err_ctx_free;
		if (!test_assert((r[i]->flags & ~LC_ROUTER_FLAG_VISIT) == 0, "flags set"))
			goto err_ctx_free;
		if (!test_assert(r[i]->ports >= PORTS, "ports == %i", r[i]->ports))
			goto err_ctx_free;
	}

	for (int i = 0; i < ROUTERS; i++) {
		/* Rule (1) - all routers are connected to at least one other router */
		int ok = 0, fail = 0;
		for (int port = 0; port < (int)r[i]->ports; port++) {
			if (r[i]->port[port]) {
				if (r[i]->port[port]->pair->router != r[i]) {
					ok++;
					break;
				}
				else fail++;
			}
		}
		test_assert(ok, "r[%i] is connected (Rule 1)", i);
		/* Rule (2) = all routers have a path to all other routers */
		for (int j = 0; j < ROUTERS; j++) {
			if (i >= j) continue;
			test_assert(lc_router_has_path(r, ROUTERS, r[i], r[j]),
				"r[%i] has path to r[%i] (Rule 2)", i, j);
		}
		/* Rule (4) - routers are not directly connected to themselves */
		test_assert(!fail, "r[%i] is not looped-back to itself (Rule 4)", i);
	}

err_ctx_free:
	lc_ctx_free(lctx);
	return test_status;
}
