/* * Copyright 2015-2017 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.springframework.statemachine.support; import static org.hamcrest.Matchers.is; import static org.junit.Assert.assertThat; import java.util.ArrayList; import java.util.Collection; import java.util.HashMap; import java.util.Map; import java.util.UUID; import org.junit.Test; import org.springframework.expression.ExpressionParser; import org.springframework.expression.spel.standard.SpelExpressionParser; import org.springframework.expression.spel.support.StandardEvaluationContext; import org.springframework.messaging.Message; import org.springframework.messaging.MessageHeaders; import org.springframework.messaging.support.MessageBuilder; import org.springframework.statemachine.ExtendedState; import org.springframework.statemachine.StateContext; import org.springframework.statemachine.StateMachine; import org.springframework.statemachine.access.StateMachineAccessor; import org.springframework.statemachine.action.Action; import org.springframework.statemachine.action.ActionListener; import org.springframework.statemachine.listener.StateMachineListener; import org.springframework.statemachine.security.SecurityRule; import org.springframework.statemachine.state.EnumState; import org.springframework.statemachine.state.State; import org.springframework.statemachine.transition.Transition; import org.springframework.statemachine.transition.TransitionKind; import org.springframework.statemachine.trigger.Trigger; public class StateContextExpressionMethodsTests { @Test public void testGuardBooleanExpressions() { ExpressionParser parser = new SpelExpressionParser(); StandardEvaluationContext evaluationContext = new StandardEvaluationContext(); StateContextExpressionMethods methods = new StateContextExpressionMethods(evaluationContext); StateContext<SpelStates, SpelEvents> stateContext = mockStateContext(null); assertThat(methods.getValue(parser.parseExpression("true"), stateContext, Boolean.class), is(true)); assertThat(methods.getValue(parser.parseExpression("event.toString().equals('E1')"), stateContext, Boolean.class), is(true)); assertThat(methods.getValue(parser.parseExpression("event==T(org.springframework.statemachine.support.StateContextExpressionMethodsTests.SpelEvents).E1"), stateContext, Boolean.class), is(true)); assertThat(methods.getValue(parser.parseExpression("getExtendedState().getVariables().get('boolean1')"), stateContext, Boolean.class), is(true)); assertThat(methods.getValue(parser.parseExpression("extendedState.variables.get('boolean1')"), stateContext, Boolean.class), is(true)); assertThat(methods.getValue(parser.parseExpression("extendedState.variables.get('boolean1')&&!extendedState.variables.get('boolean2')"), stateContext, Boolean.class), is(true)); assertThat(methods.getValue(parser.parseExpression("extendedState.variables.get('boolean3')==NULL"), stateContext, Boolean.class), is(true)); assertThat(methods.getValue(parser.parseExpression("transition.source.id.toString().equals('S1')"), stateContext, Boolean.class), is(true)); } @Test public void testSendEvent() { ExpressionParser parser = new SpelExpressionParser(); StandardEvaluationContext evaluationContext = new StandardEvaluationContext(); StateContextExpressionMethods methods = new StateContextExpressionMethods(evaluationContext); MockStatemachine stateMachine = new MockStatemachine(); StateContext<SpelStates, SpelEvents> stateContext = mockStateContext(stateMachine); assertThat(methods.getValue(parser.parseExpression("stateMachine.sendEvent(T(org.springframework.statemachine.support.StateContextExpressionMethodsTests.SpelEvents).E1)"), stateContext, Boolean.class), is(true)); assertThat(stateMachine.events.size(), is(1)); } enum SpelStates { SI,S1,S2,S3,S4,SF,SH } public enum SpelEvents { E1,E2,E3,E4,EF } private StateContext<SpelStates, SpelEvents> mockStateContext(StateMachine<SpelStates, SpelEvents> stateMachine) { Map<String, Object> headers = new HashMap<String, Object>(); headers.put("foo", "bar"); MessageHeaders messageHeaders = new MessageHeaders(headers); ExtendedState extendedState = new DefaultExtendedState(); extendedState.getVariables().put("key1", "val1"); extendedState.getVariables().put("boolean1", true); extendedState.getVariables().put("boolean2", false); StateContext<SpelStates, SpelEvents> stateContext = new DefaultStateContext<SpelStates, SpelEvents>( null, MessageBuilder.withPayload(SpelEvents.E1).build(), messageHeaders, extendedState, new MockTransition(), stateMachine, null, null, null); return stateContext; } private static class MockTransition implements Transition<SpelStates, SpelEvents> { @Override public boolean transit(StateContext<SpelStates, SpelEvents> context) { return false; } @Override public void executeTransitionActions(StateContext<SpelStates, SpelEvents> context) { } @Override public State<SpelStates, SpelEvents> getSource() { return new EnumState<SpelStates, SpelEvents>(SpelStates.S1); } @Override public State<SpelStates, SpelEvents> getTarget() { return new EnumState<SpelStates, SpelEvents>(SpelStates.S2); } @Override public Collection<Action<SpelStates, SpelEvents>> getActions() { return null; } @Override public Trigger<SpelStates, SpelEvents> getTrigger() { return null; } @Override public TransitionKind getKind() { return null; } @Override public SecurityRule getSecurityRule() { return null; } @Override public void addActionListener(ActionListener<SpelStates, SpelEvents> listener) { } @Override public void removeActionListener(ActionListener<SpelStates, SpelEvents> listener) { } } private static class MockStatemachine implements StateMachine<SpelStates, SpelEvents> { ArrayList<Message<SpelEvents>> events = new ArrayList<Message<SpelEvents>>(); @Override public StateMachineAccessor<SpelStates, SpelEvents> getStateMachineAccessor() { return null; } @Override public void start() { } @Override public void stop() { } @Override public boolean sendEvent(Message<SpelEvents> event) { events.add(event); return true; } @Override public boolean sendEvent(SpelEvents event) { return sendEvent(MessageBuilder.createMessage(event, new MessageHeaders(new HashMap<String, Object>()))); } @Override public State<SpelStates, SpelEvents> getState() { return null; } @Override public Collection<State<SpelStates, SpelEvents>> getStates() { return null; } @Override public Collection<Transition<SpelStates, SpelEvents>> getTransitions() { return null; } @Override public boolean isComplete() { return false; } @Override public void setStateMachineError(Exception exception) { } @Override public boolean hasStateMachineError() { return false; } @Override public void addStateListener(StateMachineListener<SpelStates, SpelEvents> listener) { } @Override public void removeStateListener(StateMachineListener<SpelStates, SpelEvents> listener) { } @Override public State<SpelStates, SpelEvents> getInitialState() { return null; } @Override public ExtendedState getExtendedState() { return null; } @Override public UUID getUuid() { return null; } @Override public String getId() { return null; } } }