/*
* Copyright (C) 2006-2016 DLR, Germany
*
* All rights reserved
*
* http://www.rcenvironment.de/
*/
package de.rcenvironment.components.switchcmp.execution;
import static org.easymock.EasyMock.anyObject;
import java.io.File;
import java.io.IOException;
import junit.framework.Assert;
import org.easymock.EasyMock;
import org.junit.After;
import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.ExpectedException;
import de.rcenvironment.components.switchcmp.common.SwitchComponentConstants;
import de.rcenvironment.core.component.api.ComponentConstants;
import de.rcenvironment.core.component.api.ComponentException;
import de.rcenvironment.core.component.datamanagement.api.ComponentDataManagementService;
import de.rcenvironment.core.component.execution.api.Component;
import de.rcenvironment.core.component.execution.api.ComponentContext;
import de.rcenvironment.core.component.testutils.ComponentContextMock;
import de.rcenvironment.core.component.testutils.ComponentTestWrapper;
import de.rcenvironment.core.datamodel.api.DataType;
import de.rcenvironment.core.datamodel.api.TypedDatumFactory;
import de.rcenvironment.core.datamodel.api.TypedDatumService;
import de.rcenvironment.core.datamodel.types.api.FileReferenceTD;
import de.rcenvironment.core.scripting.ScriptingService;
import de.rcenvironment.core.scripting.testutils.ScriptingServiceStubFactory;
import de.rcenvironment.core.utils.common.TempFileServiceAccess;
/**
*
* Integration test for {@link SwitchComponent}.
*
* @author David Scholz
* @author Doreen Seider
*/
public class SwitchComponentTest {
private static final String SHIFT = " << 3";
private static final String AND = " and ";
private static final String INPUT_X = "x";
private static final String INPUT_Y = "y";
/**
* Expected exception if script/validation fails.
*/
@Rule
public ExpectedException scriptException = ExpectedException.none();
private ComponentTestWrapper component;
private ComponentContextMock context;
private TypedDatumFactory typedDatumFactory;
/**
* Common setup.
*
* @throws IOException e
*/
@Before
public void setUp() throws IOException {
context = new ComponentContextMock();
component = new ComponentTestWrapper(new SwitchComponent(), context);
TempFileServiceAccess.setupUnitTestEnvironment();
typedDatumFactory = context.getService(TypedDatumService.class).getFactory();
ComponentDataManagementService componentDataManagementServiceMock = EasyMock.createMock(ComponentDataManagementService.class);
FileReferenceTD dummyFileReference = typedDatumFactory.createFileReference("", "");
EasyMock.expect(componentDataManagementServiceMock.createFileReferenceTDFromLocalFile(anyObject(ComponentContext.class),
anyObject(File.class), anyObject(String.class))).andReturn(dummyFileReference);
EasyMock.replay(componentDataManagementServiceMock);
context.addService(ScriptingService.class, ScriptingServiceStubFactory.createDefaultInstance());
context.addService(ComponentDataManagementService.class, componentDataManagementServiceMock);
}
/**
* Common cleanup.
*/
@After
public void tearDown() {
component.tearDown(Component.FinalComponentState.FINISHED);
component.dispose();
}
/**
* Tests behavior if no script is defined.
*
* @throws ComponentException on unexpected component failures.
*/
@Test
public void testNoScriptInput() throws ComponentException {
context.addSimulatedInput(SwitchComponentConstants.DATA_INPUT_NAME, SwitchComponentConstants.DATA_INPUT_NAME, DataType.Float,
false,
null);
context.setInputValue(SwitchComponentConstants.DATA_INPUT_NAME, typedDatumFactory.createFloat(3.0));
context.setConfigurationValue(SwitchComponentConstants.CONDITION_KEY, "");
scriptException.expect(ComponentException.class);
scriptException.expectMessage("No condition is defined");
component.start();
}
/**
*
* Test behavior if condition is true. (with historyDataItem)
*
* @throws ComponentException on unexpected component failures.
*/
@Test
public void testTrueScript() throws ComponentException {
addSimpleInputAndOutput();
context.setConfigurationValue(SwitchComponentConstants.CONDITION_KEY, INPUT_X + " < " + INPUT_Y);
context.setConfigurationValue(ComponentConstants.CONFIG_KEY_STORE_DATA_ITEM, Boolean.toString(true));
component.start();
component.processInputs();
Assert.assertEquals(1, context.getCapturedOutput(SwitchComponentConstants.TRUE_OUTPUT).size());
Assert.assertEquals(0, context.getCapturedOutput(SwitchComponentConstants.FALSE_OUTPUT).size());
}
/**
*
* Test behavior if condition is false. (with historyDataItem)
*
* @throws ComponentException on unexpected component failures.
*/
@Test
public void testFalseScript() throws ComponentException {
addSimpleInputAndOutput();
context.setConfigurationValue(SwitchComponentConstants.CONDITION_KEY, INPUT_X + " > " + INPUT_Y);
context.setConfigurationValue(ComponentConstants.CONFIG_KEY_STORE_DATA_ITEM, Boolean.toString(true));
component.start();
component.processInputs();
Assert.assertEquals(0, context.getCapturedOutput(SwitchComponentConstants.TRUE_OUTPUT).size());
Assert.assertEquals(1, context.getCapturedOutput(SwitchComponentConstants.FALSE_OUTPUT).size());
}
/**
*
* Test if syntax errors in script are recognized.
*
* @throws ComponentException on unexpected component failures.
*/
@Test
public void testSyntaxErrorInScript() throws ComponentException {
addSimpleInputAndOutput();
context.setConfigurationValue(SwitchComponentConstants.CONDITION_KEY, "(" + INPUT_Y + ">" + INPUT_X);
scriptException.expect(ComponentException.class);
scriptException.expectMessage("Syntax error: ");
component.start();
}
/**
* Test if invalid input names are recognized.
*
* @throws ComponentException on unexpected component failures.
*/
@Test
public void testUseOfInvalidInputNames() throws ComponentException {
addSimpleInputAndOutput();
context.setConfigurationValue(SwitchComponentConstants.CONDITION_KEY, INPUT_Y + ">" + "EvilName");
scriptException.expect(ComponentException.class);
scriptException.expectMessage("not defined");
component.start();
}
/**
*
* Test behavior if invalid data types are used.
*
* @throws ComponentException on unexpected component failures.
*/
@Test
public void testUseOfInvalidDataTypesInScript() throws ComponentException {
context.addSimulatedInput(SwitchComponentConstants.DATA_INPUT_NAME, SwitchComponentConstants.DATA_INPUT_NAME,
DataType.Matrix, false, null);
context.setInputValue(SwitchComponentConstants.DATA_INPUT_NAME, typedDatumFactory.createMatrix(2, 2));
context.setConfigurationValue(SwitchComponentConstants.CONDITION_KEY, SwitchComponentConstants.DATA_INPUT_NAME + " < 3");
scriptException.expect(ComponentException.class);
scriptException.expectMessage("not supported in script");
component.start();
}
/**
* Test operators.
*
* @throws ComponentException on unexpected component failures.
*/
@Test
public void testAllOperators() throws ComponentException {
addSimpleInputAndOutput();
StringBuilder sb = new StringBuilder();
for (String operator : SwitchComponentConstants.OPERATORS) {
sb.append(INPUT_X);
if (operator.equals("not")) {
sb.append(AND + operator + " ");
} else if (operator.equals("False") || operator.equals("True")) {
sb.append("==" + operator + " or ");
} else {
sb.append(" " + operator + " ");
}
sb.append(INPUT_Y);
sb.append(AND);
}
sb.append(INPUT_Y);
context.setConfigurationValue(SwitchComponentConstants.CONDITION_KEY, sb.toString());
component.start();
component.processInputs();
}
/**
*
* Test valid data types in script.
*
* @throws ComponentException on unexpected component failures.
*/
@Test
public void testValidDataTypes() throws ComponentException {
context.addSimulatedInput(INPUT_X, SwitchComponentConstants.CONDITION_INPUT_ID, DataType.Float, true, null);
context.addSimulatedInput(INPUT_Y, SwitchComponentConstants.CONDITION_INPUT_ID, DataType.Integer, true, null);
context.addSimulatedInput(SwitchComponentConstants.DATA_INPUT_NAME, SwitchComponentConstants.DATA_INPUT_NAME,
DataType.Boolean, false, null);
context.addSimulatedOutput(SwitchComponentConstants.TRUE_OUTPUT, SwitchComponentConstants.TRUE_OUTPUT, DataType.Boolean, false,
null);
context.addSimulatedOutput(SwitchComponentConstants.FALSE_OUTPUT, SwitchComponentConstants.FALSE_OUTPUT, DataType.Boolean, false,
null);
context.setInputValue(INPUT_X, typedDatumFactory.createFloat(1.0));
context.setInputValue(INPUT_Y, typedDatumFactory.createInteger(2));
context.setInputValue(SwitchComponentConstants.DATA_INPUT_NAME, typedDatumFactory.createBoolean(true));
context.setConfigurationValue(SwitchComponentConstants.CONDITION_KEY, INPUT_X + " < " + INPUT_Y + " or "
+ SwitchComponentConstants.DATA_INPUT_NAME);
component.start();
component.processInputs();
}
/**
*
* Test behavior if script is null.
*
* @throws ComponentException on unexpected component failures.
*/
@Test
public void testNullSwitch() throws ComponentException {
context.addSimulatedInput(SwitchComponentConstants.DATA_INPUT_NAME, SwitchComponentConstants.DATA_INPUT_NAME, DataType.Float,
false,
null);
context.setInputValue(SwitchComponentConstants.DATA_INPUT_NAME, typedDatumFactory.createFloat(3.0));
context.setConfigurationValue(SwitchComponentConstants.CONDITION_KEY, null);
scriptException.expect(ComponentException.class);
scriptException.expectMessage("No condition is defined");
component.start();
}
/**
*
* Test behavior if script contains "<<" or ">>".
*
* @throws ComponentException on unexpected component failures.
*/
@Test
public void testScriptWithShiftAndFloatInputs() throws ComponentException {
context.addSimulatedInput(INPUT_X, SwitchComponentConstants.CONDITION_INPUT_ID, DataType.Float, true, null);
context.setConfigurationValue(SwitchComponentConstants.CONDITION_KEY, INPUT_X + SHIFT);
scriptException.expect(ComponentException.class);
scriptException.expectMessage("Syntax error: ");
component.start();
}
/**
*
* Test behavior if script contains "<<" or ">>".
*
* @throws ComponentException on unexpected component failures.
*/
@Test
public void testScriptWithShiftAndIntegerInputs() throws ComponentException {
context.addSimulatedInput(INPUT_X, SwitchComponentConstants.CONDITION_INPUT_ID, DataType.Integer, true, null);
context.setConfigurationValue(SwitchComponentConstants.CONDITION_KEY, INPUT_X + SHIFT);
component.start();
}
/**
*
* Test behavior if script contains "<<" or ">>".
*
* @throws ComponentException on unexpected component failures.
*/
@Test
public void testScriptWithShiftAndBooleanInputs() throws ComponentException {
context.addSimulatedInput(INPUT_X, SwitchComponentConstants.CONDITION_INPUT_ID, DataType.Boolean, true, null);
context.setConfigurationValue(SwitchComponentConstants.CONDITION_KEY, INPUT_X + SHIFT);
component.start();
}
/**
*
* Tests if outputs are closed properly based on the configuration set.
*
* @throws ComponentException on unexpected component failures.
*/
@Test
public void testOutputsNotClosed() throws ComponentException {
testClosingOutputs(SwitchComponentConstants.NEVER_CLOSE_OUTPUTS_KEY, true, false, false, false);
}
/**
*
* Tests if outputs are closed properly based on the configuration set.
*
* @throws ComponentException on unexpected component failures.
*/
@Test
public void testClosingOutputsOnTrue() throws ComponentException {
testClosingOutputs(SwitchComponentConstants.CLOSE_OUTPUTS_ON_TRUE_KEY, false, false, true, true);
}
/**
*
* Tests if outputs are closed properly based on the configuration set.
*
* @throws ComponentException on unexpected component failures.
*/
@Test
public void testClosingOutputsOnFalse() throws ComponentException {
testClosingOutputs(SwitchComponentConstants.CLOSE_OUTPUTS_ON_FALSE_KEY, true, false, false, true);
}
private void testClosingOutputs(String config, boolean firstValue, boolean outputsClosedAfterFirstRun,
boolean secondValue, boolean outputsClosedAfterSecondRun) throws ComponentException {
context.addSimulatedInput(SwitchComponentConstants.DATA_INPUT_NAME, null,
DataType.Boolean, false, null);
context.addSimulatedOutput(SwitchComponentConstants.TRUE_OUTPUT, null, DataType.Boolean, false, null);
context.addSimulatedOutput(SwitchComponentConstants.FALSE_OUTPUT, null, DataType.Boolean, false, null);
context.setConfigurationValue(SwitchComponentConstants.CONDITION_KEY, SwitchComponentConstants.DATA_INPUT_NAME);
context.setConfigurationValue(config, "true");
component.start();
context.setInputValue(SwitchComponentConstants.DATA_INPUT_NAME, typedDatumFactory.createBoolean(firstValue));
component.processInputs();
if (outputsClosedAfterFirstRun) {
Assert.assertEquals(2, context.getCapturedOutputClosings().size());
} else {
Assert.assertEquals(0, context.getCapturedOutputClosings().size());
}
context.setInputValue(SwitchComponentConstants.DATA_INPUT_NAME, typedDatumFactory.createBoolean(secondValue));
component.processInputs();
if (outputsClosedAfterSecondRun) {
Assert.assertEquals(2, context.getCapturedOutputClosings().size());
} else {
Assert.assertEquals(0, context.getCapturedOutputClosings().size());
}
}
private void addSimpleInputAndOutput() {
context.addSimulatedInput(INPUT_X, SwitchComponentConstants.CONDITION_INPUT_ID, DataType.Float, true, null);
context.addSimulatedInput(INPUT_Y, SwitchComponentConstants.CONDITION_INPUT_ID, DataType.Float, true, null);
context.addSimulatedInput(SwitchComponentConstants.DATA_INPUT_NAME, SwitchComponentConstants.DATA_INPUT_NAME, DataType.Float,
false,
null);
context.addSimulatedOutput(SwitchComponentConstants.TRUE_OUTPUT, SwitchComponentConstants.TRUE_OUTPUT, DataType.Float, false, null);
context.addSimulatedOutput(SwitchComponentConstants.FALSE_OUTPUT, SwitchComponentConstants.FALSE_OUTPUT, DataType.Float, false,
null);
context.setInputValue(INPUT_X, typedDatumFactory.createFloat(1.0));
context.setInputValue(INPUT_Y, typedDatumFactory.createFloat(2.0));
context.setInputValue(SwitchComponentConstants.DATA_INPUT_NAME, typedDatumFactory.createFloat(3.0));
}
}