package org.squirrelframework.foundation.issues;
import static org.hamcrest.Matchers.containsInAnyOrder;
import static org.junit.Assert.assertThat;
import java.util.Arrays;
import java.util.List;
import java.util.Random;
import org.junit.Test;
import org.squirrelframework.foundation.fsm.StateMachine;
import org.squirrelframework.foundation.fsm.StateMachineBuilder;
import org.squirrelframework.foundation.fsm.StateMachineBuilderFactory;
import org.squirrelframework.foundation.fsm.impl.AbstractStateMachine;
public class Issue5 {
@Test
public void parallelStatesTest() {
final Random random = new Random(System.currentTimeMillis());
// setup FSM
final StateMachineBuilder<FSM, St, Ev, Object> builder =
StateMachineBuilderFactory.create(FSM.class, St.class, Ev.class, Object.class);
builder.defineParallelStatesOn(St.Root, St.St1_1, St.St2_1);
builder.externalTransition().from(St.St1_1).to(St.St1_2).on(Ev.Ev1_1);
builder.externalTransition().from(St.St1_2).to(St.St1_1).on(Ev.Ev1_2);
builder.externalTransition().from(St.St2_1).to(St.St2_2).on(Ev.Ev2_1);
builder.externalTransition().from(St.St2_2).to(St.St2_1).on(Ev.Ev2_2);
final FSM fsm = builder.newStateMachine(St.Root);
fsm.addTransitionCompleteListener(new StateMachine.TransitionCompleteListener<FSM, St, Ev, Object>() {
@Override
public void transitionComplete(StateMachine.TransitionCompleteEvent<FSM, St, Ev, Object> event) {
System.err.println("FSM transition completed from " + event.getSourceState().toString() + " to " + event.getTargetState().toString());
}
});
fsm.start();
// run random events firing to see how transactions goes
final List<Ev> possibleEvents = Arrays.asList(Ev.values());
final int eventsCount = possibleEvents.size();
for (int i = 0; i < 100; ++i) {
Ev eventToThrow = possibleEvents.get(random.nextInt(eventsCount));
System.err.println("FSM will get event " + eventToThrow.toString());
fsm.fire(eventToThrow, null);
}
}
@Test
public void parallelStatesTestFixed() {
// setup FSM
final StateMachineBuilder<FSM, St, Ev, Object> builder =
StateMachineBuilderFactory.create(FSM.class, St.class, Ev.class, Object.class);
builder.defineParallelStatesOn(St.Root, St.Pr1, St.Pr2);
builder.defineSequentialStatesOn(St.Pr1, St.St1_1, St.St1_2);
builder.externalTransition().from(St.St1_1).to(St.St1_2).on(Ev.Ev1_1);
builder.externalTransition().from(St.St1_2).to(St.St1_1).on(Ev.Ev1_2);
builder.defineSequentialStatesOn(St.Pr2, St.St2_1, St.St2_2);
builder.externalTransition().from(St.St2_1).to(St.St2_2).on(Ev.Ev2_1);
builder.externalTransition().from(St.St2_2).to(St.St2_1).on(Ev.Ev2_2);
final FSM fsm = builder.newStateMachine(St.Root);
fsm.addTransitionCompleteListener(new StateMachine.TransitionCompleteListener<FSM, St, Ev, Object>() {
@Override
public void transitionComplete(StateMachine.TransitionCompleteEvent<FSM, St, Ev, Object> event) {
System.err.println("FSM transition completed from " + event.getSourceState().toString() + " to " + event.getTargetState().toString());
}
});
fsm.start();
List<St> subStates = fsm.getSubStatesOn(St.Root);
assertThat(subStates, containsInAnyOrder(St.St1_1, St.St2_1));
fsm.fire(Ev.Ev1_1, null);
subStates = fsm.getSubStatesOn(St.Root);
assertThat(subStates, containsInAnyOrder(St.St1_2, St.St2_1));
fsm.fire(Ev.Ev2_1, null);
subStates = fsm.getSubStatesOn(St.Root);
assertThat(subStates, containsInAnyOrder(St.St1_2, St.St2_2));
}
private static class FSM extends AbstractStateMachine<FSM, St, Ev, Object> {
}
private static enum St {
Root,
Pr1, // parallel region state 1
Pr2, // parallel region state 2
St1_1,
St1_2,
St2_1,
St2_2
}
private static enum Ev {
Ev1_1,
Ev1_2,
Ev2_1,
Ev2_2
}
}