package jmri.jmrit.logixng; import static org.junit.jupiter.api.Assertions.assertDoesNotThrow; import static org.junit.jupiter.api.Assertions.assertFalse; import static org.junit.jupiter.api.Assertions.assertNotNull; import static org.junit.jupiter.api.Assertions.assertTrue; import static org.junit.jupiter.api.Assumptions.assumeFalse; import java.util.*; import jmri.*; import jmri.jmrit.logixng.swing.SwingConfiguratorInterface; import jmri.jmrit.logixng.swing.SwingTools; import jmri.util.JUnitUtil; import jmri.util.junit.annotations.DisabledIfHeadless; import org.junit.jupiter.api.*; /** * Try to do a lot of random female socket operations on the female sockets * to see if it works. This test does not checks the result, but at least * tries to check if a socket operation throws an exception. */ public class SocketOperationTest { private CreateLogixNGTreeScaffold createLogixNGTreeScaffold; @Test @DisabledIfHeadless public void testAddRemoveChildren() { assumeFalse( Boolean.getBoolean("jmri.skipTestsRequiringSeparateRunning"), "Ignoring intermittent test"); runTest(true, false); } @Test @DisabledIfHeadless public void testFemaleSockets() { assumeFalse( Boolean.getBoolean("jmri.skipTestsRequiringSeparateRunning"), "Ignoring intermittent test"); runTest(false, true); } @Test @DisabledIfHeadless public void testAddRemoveChildrenAndFemaleSockets() { assumeFalse( Boolean.getBoolean("jmri.skipTestsRequiringSeparateRunning"), "Ignoring intermittent test"); runTest(true, true); } // int countIterations = 0; // final int total = 873; private final Set listOfSockets = new HashSet<>(); private final Map, SwingConfiguratorInterface> sciSet = new HashMap<>(); private void runTest(boolean addRemoveChildren, boolean testSocketOperations) { // Add new LogixNG actions and expressions to jmri.jmrit.logixng.CreateLogixNGTreeScaffold assertDoesNotThrow( () -> createLogixNGTreeScaffold.createLogixNGTree() ); LogixNG_Manager logixNG_Manager = InstanceManager.getDefault(LogixNG_Manager.class); java.util.Set newLogixNG_Set = new java.util.HashSet<>(logixNG_Manager.getNamedBeanSet()); for (LogixNG aLogixNG : newLogixNG_Set) { for (int i=0; i < aLogixNG.getNumConditionalNGs(); i++) { final int ii = i; assertDoesNotThrow( () -> { aLogixNG.getConditionalNG(ii).forEntireTreeWithException((b) -> { // System.out.format("Count: %3d / %3d, Percent: %2d%n", ++countIterations, total, (int)(100.0*countIterations/total)); if (b instanceof FemaleSocket) { FemaleSocket originSocket = (FemaleSocket)b; if (originSocket.isConnected()) { Base socket = originSocket.getConnectedSocket(); listOfSockets.add(socket); } } }); }); assertDoesNotThrow( () -> testSockets(addRemoveChildren, testSocketOperations) ); } } } private void testSockets(boolean addRemoveChildren, boolean testSocketOperations) throws SocketAlreadyConnectedException { for (Base socket : listOfSockets) { for (int count=0; count < 100; count++) { if (socket.getChildCount() > 0) { FemaleSocket child = socket.getChild( JUnitUtil.getRandom().nextInt(socket.getChildCount())); if (addRemoveChildren) { testAddRemoveChild(child); } if (testSocketOperations) { testFemaleSocketOperations(child); } } } } } private void testAddRemoveChild(FemaleSocket child) throws SocketAlreadyConnectedException { int oper = JUnitUtil.getRandom().nextInt(5); switch (oper) { case 0: // Add if (!child.isConnected()) { tryToAddChild(child); } break; case 1: // Remove if (child.isConnected()) { assertTrue(child.canDisconnect()); assertTrue(child.isConnected()); child.disconnect(); assertFalse(child.isConnected()); } break; default: // Do nothing } } @SuppressWarnings("null") // if (categoryList.isEmpty()) { false positive, should be fixed in JUnit6 private void tryToAddChild(FemaleSocket child) throws SocketAlreadyConnectedException { assertFalse(child.isConnected()); Map>> connectableClasses = child.getConnectableClasses(); assertFalse(connectableClasses.isEmpty()); int count = 0; List> categoryList = null; Set categorySet = new HashSet<>(); while (count++ < 200 && (categoryList == null || categoryList.isEmpty())) { Category category = Category.values().get(JUnitUtil.getRandom().nextInt(Category.values().size())); categoryList = connectableClasses.get(category); categorySet.add(category); } assertNotNull(categoryList); if (categoryList.isEmpty()) { StringBuilder sb = new StringBuilder(); for (Category c : categorySet) { sb.append(c.name()); sb.append(", "); } log.error("Item: {}, child: {}, Category: {}", child.getParent().getLongDescription(), child.getName(), sb.toString()); } assertFalse(categoryList.isEmpty()); Class clazz = categoryList.get(JUnitUtil.getRandom().nextInt(categoryList.size())); SwingConfiguratorInterface sci = sciSet.get(clazz); if (sci == null) { sci = SwingTools.getSwingConfiguratorForClass(clazz); sci.setJDialog(new javax.swing.JDialog()); sci.getConfigPanel(new javax.swing.JPanel()); sciSet.put(clazz, sci); } sci.setDefaultValues(); MaleSocket maleSocket = sci.createNewObject(sci.getAutoSystemName(), null); child.connect(maleSocket); assertTrue(child.isConnected()); } private void testFemaleSocketOperations(FemaleSocket child) { FemaleSocketOperation fso = FemaleSocketOperation.values()[ JUnitUtil.getRandom().nextInt(FemaleSocketOperation.values().length)]; if (child.isSocketOperationAllowed(fso)) { child.doSocketOperation(fso); } } @BeforeEach public void setUp() { JUnitUtil.setUp(); createLogixNGTreeScaffold = new CreateLogixNGTreeScaffold(); createLogixNGTreeScaffold.setUpScaffold(); } @AfterEach public void tearDown() { // JUnitAppender.clearBacklog(); // REMOVE THIS!!! createLogixNGTreeScaffold.tearDownScaffold(); JUnitUtil.tearDown(); } private static final org.slf4j.Logger log = org.slf4j.LoggerFactory.getLogger(SocketOperationTest.class); }