package org.squirrelframework.foundation.fsm; import static org.hamcrest.Matchers.equalTo; import static org.hamcrest.Matchers.is; import static org.junit.Assert.assertNull; import static org.junit.Assert.assertThat; import static org.junit.Assert.assertTrue; import org.junit.Test; import org.squirrelframework.foundation.fsm.annotation.ContextInsensitive; import org.squirrelframework.foundation.fsm.annotation.State; import org.squirrelframework.foundation.fsm.annotation.StateMachineParameters; import org.squirrelframework.foundation.fsm.annotation.States; import org.squirrelframework.foundation.fsm.annotation.Transit; import org.squirrelframework.foundation.fsm.annotation.Transitions; import org.squirrelframework.foundation.fsm.impl.AbstractUntypedStateMachine; public class ExtensionMethodCallTest { @Transitions({ @Transit(from="A", to="B", on="ToB", callMethod="fromAToB", whenMvel="Excellect:::(context>=90)"), @Transit(from="A", to="C", on="ToC", callMethod="fromAToC"), @Transit(from="A", to="D", on="ToD", callMethod="fromAToD"), @Transit(from="A", to="E", on="ToE", callMethod="fromAToE"), @Transit(from="B", to="C", on="ToC", callMethod="fromBToCOnToC"), @Transit(from="B", to="C", on="StillToC", callMethod="fromBToCOnStillToC"), @Transit(from="B", to="D", on="ToD", callMethod="fromBToD"), @Transit(from="B", to="E", on="ToE", callMethod="fromBToE"), @Transit(from="B", to="E", on="*", callMethod="fromBToEOnAny"), @Transit(from="B", to="E", on="*", whenMvel="Excellect:::(context>=90)", callMethod="fromBToEOnAnyWithCondition") }) @States({ @State(name="A", exitCallMethod="leftA"), @State(name="B", entryCallMethod="enterB")}) @StateMachineParameters(stateType=String.class, eventType=String.class, contextType=Integer.class) @ContextInsensitive static class UntypedStateMachineBase extends AbstractUntypedStateMachine { protected StringBuilder logger = new StringBuilder(); protected void leftA(String from, String to, String event) { logger.append("leftA"); } protected void exitA(String from, String to, String event) { logger.append("exitA"); } protected void beforeExitAny(String from, String to, String event) { logger.append("beforeExitAny"); } protected void afterExitAny(String from, String to, String event) { logger.append("afterExitAny"); } protected void enterB(String from, String to, String event) { logger.append("enterB"); } protected void entryB(String from, String to, String event) { logger.append("entryB"); } protected void beforeEntryAny(String from, String to, String event) { logger.append("beforeEntryAny"); } protected void afterEntryAny(String from, String to, String event) { logger.append("afterEntryAny"); } protected void fromAToB(String from, String to, String event) { logger.append("fromAToB"); } protected void transitFromAToBOnToBWhenExcellect(String from, String to, String event) { logger.append("transitFromAToBOnToBWhenExcellect"); } protected void transitFromAToBOnToB(String from, String to, String event) { logger.append("transitFromAToBOnToB"); } protected void transitFromAnyToBOnToB(String from, String to, String event) { logger.append("transitFromAnyToBOnToB"); } protected void transitFromAnyToBOnToBEx(String from, String to, String event) { logger.append("transitFromAnyToBOnToBEx"); } protected void transitFromAToAnyOnToB(String from, String to, String event) { logger.append("transitFromAToAnyOnToB"); } protected void transitFromAToB(String from, String to, String event) { logger.append("transitFromAToB"); } protected void onToB(String from, String to, String event) { logger.append("onToB"); } protected void fromAToC(String from, String to, String event) { logger.append("fromAToC"); } protected void fromAnyToC(String from, String to, String event) { logger.append("fromAnyToC"); } protected void fromAToD(String from, String to, String event) { logger.append("fromAToD"); } protected void fromAToE(String from, String to, String event) { logger.append("fromAToE"); } protected void fromBToAny(String from, String to, String event) { logger.append("fromBToAny"); } protected void fromBToCOnToC(String from, String to, String event) { logger.append("fromBToCOnToC"); } protected void fromBToCOnStillToC(String from, String to, String event) { logger.append("fromBToCOnStillToC"); } protected void fromBToD(String from, String to, String event) { logger.append("fromBToD"); } protected void fromBToE(String from, String to, String event) { logger.append("fromBToE"); } protected void fromBToEOnAny(String from, String to, String event) { logger.append("fromBToEOnAny"); } protected void fromBToEOnAnyWithCondition(String from, String to, String event) { logger.append("fromBToEOnAnyWithCondition"); } @Override protected void beforeActionInvoked(Object fromState, Object toState, Object event, Object context) { addOptionalDot(); } private void addOptionalDot() { if (logger.length() > 0) { logger.append('.'); } } public String consumeLog() { final String result = logger.toString(); logger = new StringBuilder(); return result; } } @Test public void testExtensionMethodCallSequence() { UntypedStateMachineBuilder builder = StateMachineBuilderFactory.create(UntypedStateMachineBase.class); builder.transit().fromAny().to("B").on("ToB").callMethod("transitFromAnyToBOnToBEx"); UntypedStateMachineBase fsm = builder.newUntypedStateMachine("A", StateMachineConfiguration.create().enableDebugMode(true), new Object[0]); fsm.start(); fsm.consumeLog(); fsm.fire("ToB", 91); assertThat(fsm.consumeLog(), is(equalTo( "beforeExitAny.leftA.exitA.afterExitAny." + "fromAToB.transitFromAnyToBOnToBEx.transitFromAToBOnToBWhenExcellect.transitFromAToBOnToB." + "transitFromAnyToBOnToB.transitFromAToAnyOnToB.transitFromAToB.onToB." + "beforeEntryAny.enterB.entryB.afterEntryAny"))); fsm.terminate(); assertTrue(fsm.getListenerSize()==2); // start event listener to attach logger and terminate event listener to detach logger } @Test public void testDeferBoundActionFromAny() { UntypedStateMachineBuilder builder = StateMachineBuilderFactory.create(UntypedStateMachineBase.class); builder.transit().fromAny().to("C").on("ToC").callMethod("fromAnyToC"); UntypedStateMachineBase fsm = builder.newUntypedStateMachine("A"); assertNull(fsm.getCurrentState()); assertNull(fsm.getCurrentRawState()); fsm.start(); fsm.consumeLog(); fsm.fire("ToC"); assertThat(fsm.consumeLog(), is(equalTo( "beforeExitAny.leftA.exitA.afterExitAny.fromAToC.fromAnyToC.beforeEntryAny.afterEntryAny"))); fsm.terminate(); fsm.start(); // start again fsm.fire("ToB", 91); fsm.consumeLog(); fsm.fire("ToC"); assertThat(fsm.consumeLog(), is(equalTo( "beforeExitAny.afterExitAny.fromBToCOnToC.fromAnyToC.beforeEntryAny.afterEntryAny"))); fsm.terminate(); } @Test public void testDeferBoundActionToAny() { UntypedStateMachineBuilder builder = StateMachineBuilderFactory.create(UntypedStateMachineBase.class); builder.transit().from("B").toAny().on("ToC").callMethod("fromBToAny"); UntypedStateMachineBase fsm = builder.newUntypedStateMachine("B"); fsm.start(); fsm.consumeLog(); fsm.fire("ToC"); assertThat(fsm.consumeLog(), is(equalTo( "beforeExitAny.afterExitAny.fromBToCOnToC.fromBToAny.beforeEntryAny.afterEntryAny"))); fsm.terminate(); fsm.start(); fsm.consumeLog(); fsm.fire("ToD"); assertThat(fsm.consumeLog(), is(equalTo( "beforeExitAny.afterExitAny.fromBToD.beforeEntryAny.afterEntryAny"))); fsm.terminate(); } @Test public void testDeferBoundActionOnAny() { UntypedStateMachineBuilder builder = StateMachineBuilderFactory.create(UntypedStateMachineBase.class); builder.transit().from("B").toAny().onAny().callMethod("fromBToAny"); UntypedStateMachineBase fsm = builder.newUntypedStateMachine("B"); fsm.start(); fsm.consumeLog(); fsm.fire("ToD"); assertThat(fsm.consumeLog(), is(equalTo( "beforeExitAny.afterExitAny.fromBToD.fromBToAny.beforeEntryAny.afterEntryAny"))); fsm.terminate(); } @Test public void testDeferBoundActionAnnotation() { UntypedStateMachineBuilder builder = StateMachineBuilderFactory.create(UntypedStateMachineBase.class); UntypedStateMachineBase fsm = builder.newUntypedStateMachine("B"); fsm.start(); fsm.consumeLog(); fsm.fire("ToE"); assertThat(fsm.consumeLog(), is(equalTo( "beforeExitAny.afterExitAny.fromBToE.fromBToEOnAny..beforeEntryAny.afterEntryAny"))); fsm.terminate(); } @Test public void testDeferBoundActionAnnotation2() { UntypedStateMachineBuilder builder = StateMachineBuilderFactory.create(UntypedStateMachineBase.class); UntypedStateMachineBase fsm = builder.newUntypedStateMachine("B"); fsm.start(); fsm.consumeLog(); fsm.fire("ToE", 91); assertThat(fsm.consumeLog(), is(equalTo( "beforeExitAny.afterExitAny.fromBToE.fromBToEOnAny.fromBToEOnAnyWithCondition.beforeEntryAny.afterEntryAny"))); fsm.terminate(); } }