package org.webpieces.javasm.api; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.util.concurrent.CompletableFuture; import java.util.concurrent.ExecutionException; import java.util.logging.Logger; import junit.framework.TestCase; /** */ public class TestStateMachine extends TestCase { private static final Logger log = Logger.getLogger(TestStateMachine.class.getName()); private MockActionListener mockOffListener = new MockActionListener(); private MockActionListener mockOnListener = new MockActionListener(); private StateMachine sm; private String flipOn; private String flipOff; private State on; private Transition onToOff; /** * Creates an instance of TestStateMachine. * @param arg0 */ public TestStateMachine(String arg0) { super(arg0); } /** * @see junit.framework.TestCase#setUp() */ @Override protected void setUp() throws Exception { super.setUp(); StateMachineFactory factory = StateMachineFactory.createFactory(); sm = factory.createStateMachine("TestStateMachine"); flipOn = "flipOn"; flipOff = "flipOff"; on = sm.createState("on"); State off = sm.createState("off"); onToOff = sm.createTransition(on, off, flipOff); onToOff.addActionListener(mockOffListener); Transition offToOn = sm.createTransition(off, on, flipOn); offToOn.addActionListener(mockOnListener); } /** * @see junit.framework.TestCase#tearDown() */ @Override protected void tearDown() throws Exception { super.tearDown(); //make sure no more extra events mockOffListener.expectNoMethodCalls(); mockOnListener.expectNoMethodCalls(); } public void testBasic() { Memento memento = sm.createMementoFromState("id", on); //fire turn off sm.fireEvent(memento, flipOff); mockOnListener.expectNoMethodCalls(); mockOffListener.expectOneMethodCall(); //fire turn off again... sm.fireEvent(memento, flipOff); mockOnListener.expectNoMethodCalls(); mockOffListener.expectNoMethodCalls(); //fire turn on..... sm.fireEvent(memento, flipOn); mockOnListener.expectOneMethodCall(); mockOffListener.expectNoMethodCalls(); } /** * This makes sure an Exception causes the statemachine to not get corrupted. This covers a * bug we had where an exception would not allow future firing into statemachine. * */ public void testExceptionHandled() { Memento memento = sm.createMementoFromState("id", on); mockOffListener.addThrowException(() -> { throw new IllegalMonitorStateException(); }); CompletableFuture<State> future = sm.fireEvent(memento, flipOff); try { //fire turn off future.get(); fail("Should have thrown exception"); } catch (InterruptedException e) { fail("what"); } catch (ExecutionException e) { log.info("This exception is expected"); } mockOffListener.expectOneMethodCall(); //should now be able to fire in to statemachine still!!!!! sm.fireEvent(memento, flipOff); mockOnListener.expectNoMethodCalls(); mockOffListener.expectOneMethodCall(); } public void testOrder() { Memento memento = sm.createMementoFromState("id", on); MockFakeInterface mockFake = new MockFakeInterface(); onToOff.addActionListener(new FakeListener1(mockFake)); onToOff.addActionListener(new FakeListener2(mockFake)); //fire turn off sm.fireEvent(memento, flipOff); mockOffListener.expectOneMethodCall(); mockFake.expectCalls("first", "second"); } public interface FakeInterface { public void first(); public void second(); } private class FakeListener1 implements ActionListener { private FakeInterface fake; public FakeListener1(FakeInterface fake) { this.fake = fake; } public void actionPerformed(ActionEvent e) { fake.first(); } } private class FakeListener2 implements ActionListener { private FakeInterface fake; public FakeListener2(FakeInterface fake) { this.fake = fake; } public void actionPerformed(ActionEvent e) { fake.second(); } } }