#include <catch2/catch.hpp>

#include <automaton/FSM/EpsilonNFA.h>

#include "automaton/properties/EpsilonClosure.h"
#include "automaton/properties/AllEpsilonClosure.h"

TEST_CASE ( "Epsilon Closure", "[unit][algo][automaton]" ) {
	SECTION ( "Test closure" ) {
		DefaultStateType q0 = DefaultStateType ("q0");
		DefaultStateType q1 = DefaultStateType ("q1");
		DefaultStateType q2 = DefaultStateType ("q2");
		DefaultStateType q3 = DefaultStateType ("q3");
		DefaultStateType q4 = DefaultStateType ("q4");
		DefaultStateType q5 = DefaultStateType ("q5");
		DefaultStateType q6 = DefaultStateType ("q6");
		DefaultStateType q7 = DefaultStateType ("q7");
		DefaultStateType q8 = DefaultStateType ("q8");
		DefaultStateType q9 = DefaultStateType ("q9");

		automaton::EpsilonNFA < > automaton(q0);
		automaton.setStates({q0, q1, q2, q3, q4, q5, q6, q7, q8, q9});

		automaton.addTransition(q0, q1);
		automaton.addTransition(q1, q2);
		automaton.addTransition(q2, q3);
		automaton.addTransition(q3, q4);
		automaton.addTransition(q4, q1);
		automaton.addTransition(q5, q6);
		automaton.addTransition(q6, q1);
		automaton.addTransition(q8, q8);

		ext::map<DefaultStateType, ext::set<DefaultStateType>> allClosures = automaton::properties::AllEpsilonClosure::allEpsilonClosure(automaton);

		for(const DefaultStateType& state : automaton.getStates()) {
			CHECK(automaton::properties::EpsilonClosure::epsilonClosure(automaton, state) == allClosures[state]);
		}
	}
}
