package org.squirrelframework.foundation.issues;
import junit.framework.Assert;
import org.junit.Test;
import org.squirrelframework.foundation.fsm.Condition;
import org.squirrelframework.foundation.fsm.StateMachineBuilderFactory;
import org.squirrelframework.foundation.fsm.UntypedStateMachineBuilder;
import org.squirrelframework.foundation.fsm.annotation.ContextInsensitive;
import org.squirrelframework.foundation.fsm.annotation.StateMachineParameters;
import org.squirrelframework.foundation.fsm.impl.AbstractUntypedStateMachine;
/**
* Created by kailianghe on 7/5/14.
*/
public class Issue18 {
enum Issue18State {A, B}
enum Issue18Event {GO}
@ContextInsensitive
@StateMachineParameters(stateType=Issue18State.class, eventType=Issue18Event.class, contextType=Void.class)
static class Issue18StateMachine extends AbstractUntypedStateMachine {
StringBuilder logger = new StringBuilder();
void onA2A(Issue18State from, Issue18State to, Issue18Event cause) {
logger.append("onA2A");
}
void onA2B(Issue18State from, Issue18State to, Issue18Event cause) {
logger.append("onA2B");
}
void onB2B(Issue18State from, Issue18State to, Issue18Event cause) {
logger.append("onB2B");
}
void onB2A(Issue18State from, Issue18State to, Issue18Event cause) {
logger.append("onB2A");
}
String consumeLog() {
final String result = logger.toString();
logger = new StringBuilder();
return result;
}
@Override
protected void beforeActionInvoked(Object fromState, Object toState, Object event, Object context) {
if (logger.length() > 0) {
logger.append('.');
}
}
}
@Test
public void testIssue18() {
final UntypedStateMachineBuilder builder = StateMachineBuilderFactory.create(Issue18StateMachine.class);
builder.externalTransition(10).from(Issue18State.A).to(Issue18State.B).on(Issue18Event.GO).
when(new CounterCondition(5, "Count_5_A")).callMethod("onA2B");
builder.internalTransition(1).within(Issue18State.A).on(Issue18Event.GO).callMethod("onA2A");
builder.externalTransition(10).from(Issue18State.B).to(Issue18State.A).on(Issue18Event.GO).
when(new CounterCondition(5, "Count_5_B")).callMethod("onB2A");
builder.internalTransition(1).within(Issue18State.B).on(Issue18Event.GO).callMethod("onB2B");
Issue18StateMachine fsm = builder.newUntypedStateMachine(Issue18State.A);
fsm.start();
fsm.fire(Issue18Event.GO);
fsm.fire(Issue18Event.GO);
fsm.fire(Issue18Event.GO);
fsm.fire(Issue18Event.GO);
fsm.fire(Issue18Event.GO);
Assert.assertTrue("onA2A.onA2A.onA2A.onA2A.onA2B".equals(fsm.consumeLog()));
fsm.fire(Issue18Event.GO);
fsm.fire(Issue18Event.GO);
fsm.fire(Issue18Event.GO);
fsm.fire(Issue18Event.GO);
fsm.fire(Issue18Event.GO);
Assert.assertTrue("onB2B.onB2B.onB2B.onB2B.onB2A".equals(fsm.consumeLog()));
}
}
class CounterCondition implements Condition<Object> {
int counter;
final String name;
CounterCondition(int init, String name) {
this.counter = init;
this.name = name;
}
@Override
public boolean isSatisfied(Object context) {
return --counter==0;
}
@Override
public String name() {
return name;
}
}