/** * Copyright (c) 2015 committers of YAKINDU and others. * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html * Contributors: * committers of YAKINDU - initial API and implementation * */ package org.yakindu.sct.model.sexec.transformation.test; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertSame; import static org.junit.Assert.assertTrue; import static org.junit.Assert.fail; import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; import java.util.Collections; import java.util.List; import org.yakindu.base.base.NamedElement; import org.yakindu.base.expressions.expressions.AssignmentExpression; import org.yakindu.base.expressions.expressions.AssignmentOperator; import org.yakindu.base.expressions.expressions.BoolLiteral; import org.yakindu.base.expressions.expressions.DoubleLiteral; import org.yakindu.base.expressions.expressions.ElementReferenceExpression; import org.yakindu.base.expressions.expressions.Expression; import org.yakindu.base.expressions.expressions.FeatureCall; import org.yakindu.base.expressions.expressions.FloatLiteral; import org.yakindu.base.expressions.expressions.IntLiteral; import org.yakindu.base.expressions.expressions.Literal; import org.yakindu.base.expressions.expressions.PrimitiveValueExpression; import org.yakindu.base.expressions.expressions.StringLiteral; import org.yakindu.sct.model.sexec.Call; import org.yakindu.sct.model.sexec.Execution; import org.yakindu.sct.model.sexec.ExecutionFlow; import org.yakindu.sct.model.sexec.ExecutionRegion; import org.yakindu.sct.model.sexec.ExecutionState; import org.yakindu.sct.model.sexec.HistoryEntry; import org.yakindu.sct.model.sexec.SaveHistory; import org.yakindu.sct.model.sexec.Sequence; import org.yakindu.sct.model.sexec.StateCase; import org.yakindu.sct.model.sexec.StateSwitch; import org.yakindu.sct.model.sexec.Step; public class Assert { public static void assertCall(Sequence seq, int pos, Step target) { assertCall(seq.getSteps().get(pos), target); } public static void assertCall(Step step, Step target) { assertNotNull("Step is null", step); assertNotNull("No target specified", target); assertTrue("Step is no Call (was " + step.getClass().getName() + ")", step instanceof Call); assertSame(target, ((Call) step).getStep()); } public static void assertAssignment(Sequence seq, int pos, String variableName, AssignmentOperator operator, String value) { assertAssignment(seq.getSteps().get(pos), variableName, operator, value); } public static void assertAssignment(Step step, String variableName, AssignmentOperator operator, String value) { assertClass(Execution.class, step); Execution exec = (Execution) step; assertTrue(exec.getStatement() instanceof AssignmentExpression); AssignmentExpression assignment = (AssignmentExpression) exec .getStatement(); assertEquals(operator, assignment.getOperator()); Expression varRef = assignment.getVarRef(); if (varRef instanceof ElementReferenceExpression) { ElementReferenceExpression elementRef = (ElementReferenceExpression) varRef; assertEquals(variableName, ((NamedElement) elementRef.getReference()).getName()); } else if (varRef instanceof FeatureCall) { FeatureCall call = (FeatureCall) varRef; assertEquals(variableName, ((NamedElement) call.getFeature()).getName()); } assertExpressionEquals(value, assignment.getExpression()); } public static void assertExpressionEquals(String expected, Expression current) { String currentValue = null; if (current instanceof PrimitiveValueExpression) { Literal literal = ((PrimitiveValueExpression) current).getValue(); if (literal instanceof BoolLiteral) { currentValue = Boolean.toString(((BoolLiteral) literal) .isValue()); } else if (literal instanceof IntLiteral) { currentValue = Long.toString(((IntLiteral) literal) .getValue()); } else if (literal instanceof DoubleLiteral) { currentValue = Double.toString(((DoubleLiteral) literal) .getValue()); } else if (literal instanceof FloatLiteral) { currentValue = Double.toString(((FloatLiteral) literal) .getValue()); } else if (literal instanceof StringLiteral) { currentValue = (((StringLiteral) literal) .getValue()); } } assertEquals(expected, currentValue); } public static StateCase assertedStateCase(Step step, ExecutionState state) { assertNotNull("Step is null", step); assertNotNull("No state specified", state); assertTrue("Step is no StateSwitch (was " + step.getClass().getName() + ")", step instanceof StateSwitch); for (StateCase sCase : ((StateSwitch) step).getCases()) { if (sCase.getState() == state) return sCase; } fail("No case for state '" + state.getSimpleName() + "' exists."); return null; } public static Sequence assertedSequence(Step step) { assertNotNull("Step is null", step); assertTrue("Step is no Sequence (was " + step.getClass().getName() + ")", step instanceof Sequence); return (Sequence) step; } public static StateSwitch assertedSwitch(Step step) { assertNotNull("Step is null", step); assertTrue("Step is no StateSwitch (was " + step.getClass().getName() + ") '" + stepAsString(step) + "'", step instanceof StateSwitch); return (StateSwitch) step; } public static ExecutionState assertedState(ExecutionFlow flow, int idx, String id) { assertTrue("Execution flow does not contain an state #" + idx + "!", flow.getStates().size() > idx); ExecutionState es = flow.getStates().get(idx); assertEquals("wrong state id !", id, es.getName()); return es; } public static void assertSequenceSize(int size, Step seq) { assertNotNull("Sequence is null", seq); assertTrue( "Step is no Sequence (was " + seq.getClass().getName() + ")", seq instanceof Sequence); assertEquals("Sequence has wrong number of steps: " + stepListAsString((Sequence) seq), size, ((Sequence) seq) .getSteps().size()); } public static void assertStateSwitch(Step step, ExecutionState... states) { assertNotNull("Step is null", step); assertTrue("Step is no StateSwitch (was " + step.getClass().getName() + ")", step instanceof StateSwitch); List<ExecutionState> stateList = Arrays.asList(states); List<ExecutionState> stateCases = new ArrayList<ExecutionState>(); for (StateCase aCase : ((StateSwitch) step).getCases()) { stateCases.add(aCase.getState()); } assertEquals("StateSwitch cases do not match!", stateList, stateCases); } public static String stepListAsString(Sequence seq) { StringBuilder r = new StringBuilder(); for (Step s : seq.getSteps()) { r.append(stepAsString(s) + "; "); } return r.toString(); } public static String stepAsString(Step step) { if (step instanceof Call) return "call to : " + ((Call) step).getStep().getComment(); else if (step instanceof StateSwitch) return "switch on " + ((StateSwitch) step).getStateConfigurationIdx(); return step.toString(); } @SuppressWarnings("unchecked") /** * Assertion, that the given Object is of type T. If it is, the casted object is returned. * @param clazz * @param actual * @return */ public static <T> T assertClass(Class<T> clazz, Object actual) { assertTrue(clazz.getSimpleName() + " expected, but got " + actual.getClass().getSimpleName(), clazz.isInstance(actual)); return (T) actual; } public static void assertedOrder(Step step, Collection<? extends ExecutionState> currentStates, List<? extends AbstractStep> requiredSteps) { assertedOrder_intern(step, currentStates, requiredSteps); if (!requiredSteps.isEmpty()) { fail("Step was missing: " + requiredSteps.toString()); } } private static void assertedOrder_intern(Step step, Collection<? extends ExecutionState> currentStates, List<? extends AbstractStep> requiredSteps) { if (requiredSteps.isEmpty()) { return; } boolean found = false; Iterable<Step> next = null; if (requiredSteps.get(0).matches(step)) { found = true; AbstractStep matched = requiredSteps.remove(0); if (matched.isLeaf()) { return; } next = matched.next(); } if (next == null) { next = findNext(step, currentStates, requiredSteps); } if (next != null) { for (Step s : next) { assertedOrder_intern(s, currentStates, requiredSteps); } } else if (found == false) { fail("Step without match: " + step); } } protected static Iterable<Step> findNext(Step step, Collection<? extends ExecutionState> currentStates, List<? extends AbstractStep> requiredSteps) { if (step instanceof Sequence) { return ((Sequence) step).getSteps(); } else if (step instanceof Call) { return Collections.singleton(((Call) step).getStep()); } else if (step instanceof StateSwitch) { StateCase stateCase = null; StringBuilder sb = new StringBuilder(); for (StateCase caze : ((StateSwitch) step).getCases()) { sb.append(", " + caze.getState().getName()); if (stateCase == null && currentStates.contains(caze.getState())) { stateCase = caze; } } assertNotNull("No state case found for " + currentStates + " in " + sb.toString(), stateCase); return Collections.singleton(stateCase.getStep()); } return null; } public abstract static class AbstractStep { public abstract boolean matches(Step s); public abstract boolean isLeaf(); public abstract Iterable<Step> next(); } public static class StepNode extends AbstractStep { public final Step step; protected boolean leaf; public boolean matches(Step s) { return s == step; } public boolean isLeaf() { return leaf; } public Iterable<Step> next() { return null; } public StepNode(Step step) { assertNotNull(step); this.step = step; leaf = false; } @Override public String toString() { return step.toString(); } } public static class StepLeaf extends StepNode { public StepLeaf(Step step) { super(step); leaf = true; } } public static class StepHistory extends StepNode { private final boolean history; public StepHistory(Step step, boolean withHistory) { super(step); this.history = withHistory; leaf = false; assertClass(HistoryEntry.class, step); } @Override public Iterable<Step> next() { if (history) { return Collections.singleton(((HistoryEntry) step) .getHistoryStep()); } else { return Collections.singleton(((HistoryEntry) step) .getInitialStep()); } } } public static class StepSaveHistory extends AbstractStep { private final ExecutionRegion region; public StepSaveHistory(ExecutionRegion region) { this.region = region; } @Override public boolean matches(Step s) { if (s instanceof SaveHistory && ((SaveHistory) s).getRegion() == region) { return true; } return false; } @Override public boolean isLeaf() { return true; } @Override public Iterable<Step> next() { return null; } } }