package jmri.jmrit.logixng.actions; import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertNotNull; import static org.junit.jupiter.api.Assertions.assertSame; import static org.junit.jupiter.api.Assertions.assertThrows; import static org.junit.jupiter.api.Assertions.assertTrue; import java.io.IOException; import java.util.*; import jmri.*; import jmri.jmrit.logixng.*; import jmri.jmrit.logixng.implementation.DefaultConditionalNGScaffold; import jmri.jmrit.logixng.util.parser.ParserException; import jmri.util.JUnitUtil; import org.junit.jupiter.api.AfterEach; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; /** * Test ForEach * * @author Daniel Bergqvist 2024 */ public class ForEachTest extends AbstractDigitalActionTestBase { private Memory _memory; private Memory _memoryResult; private LogixNG _logixNG; private ConditionalNG _conditionalNG; private ForEach _forEach; private MaleSocket _maleSocket; private DigitalFormula _formula; @Override public ConditionalNG getConditionalNG() { return _conditionalNG; } @Override public LogixNG getLogixNG() { return _logixNG; } @Override public MaleSocket getConnectableChild() { DigitalMany action = new DigitalMany("IQDA999", null); MaleSocket maleSocket = InstanceManager.getDefault(DigitalActionManager.class).registerAction(action); return maleSocket; } @Override public String getExpectedPrintedTree() { return String.format( "For each value, set variable \"item\" and execute action A. Values from memory IM1 ::: Use default%n" + " ::: Local variable \"item\", init to None \"null\"%n" + " ! A%n" + " Digital Formula: writeMemory(\"IMResult\", readMemory(\"IMResult\") + item + \", \") ::: Use default%n" + " ?* E1%n" + " Socket not connected%n"); } @Override public String getExpectedPrintedTreeFromRoot() { return String.format( "LogixNG: A new logix for test%n" + " ConditionalNG: A conditionalNG%n" + " ! A%n" + " For each value, set variable \"item\" and execute action A. Values from memory IM1 ::: Use default%n" + " ::: Local variable \"item\", init to None \"null\"%n" + " ! A%n" + " Digital Formula: writeMemory(\"IMResult\", readMemory(\"IMResult\") + item + \", \") ::: Use default%n" + " ?* E1%n" + " Socket not connected%n"); } @Override public NamedBean createNewBean(String systemName) { return new TableForEach(systemName, null); } @Override public boolean addNewSocket() { return false; } @Test public void testCtor() { TableForEach t = new TableForEach("IQDA321", null); assertNotNull( t, "exists"); t = new TableForEach("IQDA321", null); assertNotNull( t, "exists"); } @Test public void testGetChild() { assertEquals( 1, _forEach.getChildCount(), "getChildCount() returns 1"); assertNotNull( _forEach.getChild(0), "getChild(0) returns a non null value"); IllegalArgumentException ex = assertThrows( IllegalArgumentException.class, () -> _forEach.getChild(1), "Exception is thrown"); assertEquals( "index has invalid value: 1", ex.getMessage(), "Error message is correct"); } @Test public void testCategory() { assertSame( LogixNG_Category.FLOW_CONTROL, _base.getCategory(), "Category matches"); } @Test public void testDescription() { ForEach a1 = new ForEach("IQDA321", null); assertEquals( "For each", a1.getShortDescription(), "strings are equal"); ForEach a2 = new ForEach("IQDA321", null); assertEquals( "For each value, set variable \"\" and execute action A. Values from Sensors", a2.getLongDescription(), "strings are equal"); } @Test public void testExecute() throws IOException, SocketAlreadyConnectedException, ParserException { _memory.setValue(new ArrayList()); _memoryResult.setValue(""); _formula.setFormula("writeMemory(\"IMResult\", readMemory(\"IMResult\") + item + \", \")"); _logixNG.execute(); assertEquals("", _memoryResult.getValue()); assertEquals("For each value, set variable \"item\" and execute action A. Values from memory IM1", _forEach.getLongDescription()); List list = new ArrayList<>(); list.add("A"); list.add("B"); list.add("C"); _memory.setValue(list); _memoryResult.setValue(""); _formula.setFormula("writeMemory(\"IMResult\", readMemory(\"IMResult\") + item + \", \")"); _logixNG.execute(); assertEquals("A, B, C, ", _memoryResult.getValue()); assertEquals("For each value, set variable \"item\" and execute action A. Values from memory IM1", _forEach.getLongDescription()); Map map = new HashMap<>(); map.put("A", 10); map.put("B", 20); map.put("C", -3); _memory.setValue(map); _memoryResult.setValue(""); _formula.setFormula("writeMemory(\"IMResult\", readMemory(\"IMResult\") + item.getKey() + \":\" + str(item.getValue()) + \", \")"); _logixNG.execute(); assertEquals("A:10, B:20, C:-3, ", _memoryResult.getValue()); assertEquals("For each value, set variable \"item\" and execute action A. Values from memory IM1", _forEach.getLongDescription()); map = new HashMap<>(); map.put("A", 8); map.put("B", -55); map.put("C", 32); _memory.setValue(map); _memoryResult.setValue(""); _formula.setFormula("writeMemory(\"IMResult\", readMemory(\"IMResult\") + \"toString:>\" + item.toString() + \"<\" + \", \")"); _logixNG.execute(); assertEquals("toString:>A=8<, toString:>B=-55<, toString:>C=32<, ", _memoryResult.getValue()); assertEquals("For each value, set variable \"item\" and execute action A. Values from memory IM1", _forEach.getLongDescription()); map = new HashMap<>(); map.put("A", 8); map.put("B", -55); map.put("C", 32); _memory.setValue(map); _memoryResult.setValue(""); _formula.setFormula("writeMemory(\"IMResult\", readMemory(\"IMResult\") + \"getClass().getName():>\" + item.getClass().getName() + \"<\" + \", \")"); _logixNG.execute(); assertEquals("getClass().getName():>java.util.HashMap$Node<, getClass().getName():>java.util.HashMap$Node<, getClass().getName():>java.util.HashMap$Node<, ", _memoryResult.getValue()); assertEquals("For each value, set variable \"item\" and execute action A. Values from memory IM1", _forEach.getLongDescription()); _memory.setValue(new String[]{"A", "B", "C"}); _memoryResult.setValue(""); _formula.setFormula("writeMemory(\"IMResult\", readMemory(\"IMResult\") + item + \", \")"); _logixNG.execute(); assertEquals("A, B, C, ", _memoryResult.getValue()); assertEquals("For each value, set variable \"item\" and execute action A. Values from memory IM1", _forEach.getLongDescription()); _memoryResult.setValue(""); _forEach.setUseCommonSource(true); _forEach.setCommonManager(CommonManager.Sensors); InstanceManager.getDefault(SensorManager.class).provideSensor("ISSomething"); InstanceManager.getDefault(SensorManager.class).provideSensor("ISSomethingElse"); _formula.setFormula("writeMemory(\"IMResult\", readMemory(\"IMResult\") + item.getSystemName() + \", \")"); _logixNG.execute(); assertEquals("ISCLOCKRUNNING, ISSomething, ISSomethingElse, ", _memoryResult.getValue()); assertEquals("For each value, set variable \"item\" and execute action A. Values from Sensors", _forEach.getLongDescription()); _memoryResult.setValue(""); _forEach.setUseCommonSource(true); _forEach.setCommonManager(CommonManager.Turnouts); InstanceManager.getDefault(TurnoutManager.class).provideTurnout("ITSomething"); InstanceManager.getDefault(TurnoutManager.class).provideTurnout("ITSomethingElse"); _formula.setFormula("writeMemory(\"IMResult\", readMemory(\"IMResult\") + item.getSystemName() + \", \")"); _logixNG.execute(); assertEquals("ITSomething, ITSomethingElse, ", _memoryResult.getValue()); assertEquals("For each value, set variable \"item\" and execute action A. Values from Turnouts", _forEach.getLongDescription()); _memoryResult.setValue(""); _forEach.setUseCommonSource(true); _forEach.setCommonManager(CommonManager.Lights); InstanceManager.getDefault(LightManager.class).provideLight("ILSomething"); InstanceManager.getDefault(LightManager.class).provideLight("ILSomethingElse"); _formula.setFormula("writeMemory(\"IMResult\", readMemory(\"IMResult\") + item.getSystemName() + \", \")"); _logixNG.execute(); assertEquals("ILSomething, ILSomethingElse, ", _memoryResult.getValue()); assertEquals("For each value, set variable \"item\" and execute action A. Values from Lights", _forEach.getLongDescription()); _memoryResult.setValue(""); _forEach.setUseCommonSource(true); _forEach.setCommonManager(CommonManager.Memories); InstanceManager.getDefault(MemoryManager.class).provideMemory("IMSomething"); InstanceManager.getDefault(MemoryManager.class).provideMemory("IMSomethingElse"); _formula.setFormula("writeMemory(\"IMResult\", readMemory(\"IMResult\") + item.getSystemName() + \", \")"); _logixNG.execute(); assertEquals("IM1, IMCURRENTTIME, IMRATEFACTOR, IMResult, IMSomething, IMSomethingElse, ", _memoryResult.getValue()); assertEquals("For each value, set variable \"item\" and execute action A. Values from Memories", _forEach.getLongDescription()); } @Test @Override public void testIsActive() { _logixNG.setEnabled(true); super.testIsActive(); } @Test @Override public void testMaleSocketIsActive() { _logixNG.setEnabled(true); super.testMaleSocketIsActive(); } @BeforeEach public void setUp() throws SocketAlreadyConnectedException, ParserException { JUnitUtil.setUp(); JUnitUtil.resetInstanceManager(); JUnitUtil.resetProfileManager(); JUnitUtil.initConfigureManager(); JUnitUtil.initInternalSensorManager(); JUnitUtil.initInternalTurnoutManager(); JUnitUtil.initLogixNGManager(); _category = LogixNG_Category.OTHER; _isExternal = false; _memory = InstanceManager.getDefault(MemoryManager.class).provideMemory("IM1"); // NOI18N _memory.setValue(new ArrayList()); _memoryResult = InstanceManager.getDefault(MemoryManager.class).provideMemory("IMResult"); // NOI18N _memoryResult.setValue(""); _logixNG = InstanceManager.getDefault(LogixNG_Manager.class).createLogixNG("A new logix for test"); // NOI18N _conditionalNG = new DefaultConditionalNGScaffold("IQC1", "A conditionalNG"); // NOI18N; InstanceManager.getDefault(ConditionalNG_Manager.class).register(_conditionalNG); _conditionalNG.setEnabled(true); _conditionalNG.setRunDelayed(false); _logixNG.addConditionalNG(_conditionalNG); _forEach = new ForEach("IQDA321", null); _forEach.setUserSpecifiedSource(ForEach.UserSpecifiedSource.Memory); _forEach.setUseCommonSource(false); _forEach.getSelectMemoryNamedBean().setNamedBean(_memory); _forEach.setLocalVariableName("item"); _maleSocket = InstanceManager.getDefault(DigitalActionManager.class).registerAction(_forEach); _maleSocket.addLocalVariable("item", SymbolTable.InitialValueType.None, null); _conditionalNG.getChild(0).connect(_maleSocket); _base = _forEach; _baseMaleSocket = _maleSocket; _formula = new DigitalFormula( InstanceManager.getDefault(DigitalActionManager.class).getAutoSystemName(), null); _formula.setFormula("writeMemory(\"IMResult\", readMemory(\"IMResult\") + item + \", \")"); _forEach.getChild(0).connect(InstanceManager.getDefault(DigitalActionManager.class) .registerAction(_formula)); assertTrue( _logixNG.setParentForAllChildren(new ArrayList<>())); _logixNG.activate(); _logixNG.setEnabled(false); } @AfterEach public void tearDown() { _logixNG.setEnabled(false); jmri.jmrit.logixng.util.LogixNG_Thread.stopAllLogixNGThreads(); JUnitUtil.deregisterBlockManagerShutdownTask(); JUnitUtil.tearDown(); _category = null; _memory = null; _memoryResult = null; _logixNG = null; _conditionalNG = null; _forEach = null; _base = null; _baseMaleSocket = null; _maleSocket = null; } }