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

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

#define ROUTERS 15

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

	test_name("lc_router_net_hasloop()");

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

	/* create a chain topology (no loop) */
	rc = lc_router_net(lctx, r, ROUTERS, LC_TOPO_CHAIN, 0, 0);
	if (!test_assert(rc == 0, "lc_router_net()")) goto err_ctx_free;

	/* verify that we do not have a routing loop */
	test_assert(!lc_router_net_hasloop(r, ROUTERS), "routing loop");

	/* connect the middle node to the end to make a loop */
	test_log("CONNECT R%i <--> R%i\n", ROUTERS/2, ROUTERS - 1);
	lc_router_connect(r[ROUTERS/2], r[ROUTERS - 1]);

	/* verify that we have a routing loop */
	for (int i = 0; i < ROUTERS; i++) lc_router_port_up(r[i], -1);
	test_assert(lc_router_net_hasloop(r, ROUTERS), "routing loop expected");

	lc_ctx_free(lctx);

	/*  R0 - R1
	 *   |
	 *  R3 - R2
	 *        |
	 *       R4
	 * => a spanning tree with no loop
	 */
	lctx = lc_ctx_new();
	if (!test_assert(lctx != NULL, "lc_ctx_new()")) return test_status;
	rc = lc_router_net(lctx, r, 5, LC_TOPO_NONE, 5, 0);
	if (!test_assert(rc == 0, "lc_router_net()")) goto err_ctx_free;
	lc_router_connect(r[0], r[1]);
	lc_router_connect(r[0], r[3]);
	lc_router_connect(r[2], r[3]);
	lc_router_connect(r[2], r[4]);

	test_assert(!lc_router_net_hasloop(r, 5), "routing loop not expected");

err_ctx_free:
	lc_ctx_free(lctx);
	return test_status;
}
