421 lines
16 KiB
Java
421 lines
16 KiB
Java
package jmri.jmrit.blockboss;
|
|
|
|
import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
|
|
|
|
import java.util.ArrayList;
|
|
import jmri.InstanceManager;
|
|
import jmri.Sensor;
|
|
import jmri.SignalHead;
|
|
import jmri.util.JUnitUtil;
|
|
|
|
import org.junit.jupiter.api.*;
|
|
|
|
import static org.assertj.core.api.Assertions.assertThat;
|
|
|
|
/**
|
|
* Tests for the BlockBossLogic class
|
|
*
|
|
* @author Bob Jacobsen
|
|
*/
|
|
public class BlockBossLogicTest {
|
|
|
|
// test creation
|
|
@Test
|
|
public void testCreate() {
|
|
p = new BlockBossLogic("IH2");
|
|
assertThat(p.getDrivenSignal()).withFailMessage("driven signal name").isEqualTo("IH2");
|
|
}
|
|
|
|
// test simplest block, just signal following
|
|
@Test
|
|
public void testSimpleBlock() {
|
|
setupSimpleBlock();
|
|
startLogic();
|
|
assertThat(p.getDrivenSignal()).withFailMessage("driven signal name").isEqualTo("IH1");
|
|
|
|
JUnitUtil.setBeanStateAndWait(h2, SignalHead.YELLOW);
|
|
JUnitUtil.waitFor(()-> SignalHead.GREEN == h1.getAppearance(), "Stuck at "+h1.getAppearance()+" so yellow sets green"); // wait and test
|
|
|
|
JUnitUtil.setBeanStateAndWait(h2, SignalHead.RED);
|
|
JUnitUtil.waitFor(()-> SignalHead.YELLOW == h1.getAppearance(), "Stuck at "+h1.getAppearance()+" so red sets yellow"); // wait and test
|
|
|
|
JUnitUtil.setBeanStateAndWait(h2, SignalHead.GREEN);
|
|
JUnitUtil.waitFor(()-> SignalHead.GREEN == h1.getAppearance(), "Stuck at "+h1.getAppearance()+" so green sets green"); // wait and test
|
|
}
|
|
|
|
// test that initial conditions are set right
|
|
@Test
|
|
public void testSimpleBlockInitial() {
|
|
setupSimpleBlock();
|
|
startLogic();
|
|
|
|
JUnitUtil.waitFor(()-> SignalHead.YELLOW == h1.getAppearance(), "initial red sets yellow"); // wait and test
|
|
}
|
|
|
|
// occupancy check
|
|
@Test
|
|
public void testSimpleBlockOccupancy() {
|
|
setupSimpleBlock();
|
|
p.setSensor1("IS1");
|
|
startLogic();
|
|
JUnitUtil.setBeanState(s1, Sensor.INACTIVE);
|
|
|
|
JUnitUtil.setBeanStateAndWait(h2, SignalHead.YELLOW);
|
|
JUnitUtil.waitFor(()-> SignalHead.GREEN == h1.getAppearance(), "Stuck at "+h1.getAppearance()+" so yellow sets green"); // wait and test
|
|
|
|
JUnitUtil.setBeanState(s1, Sensor.ACTIVE);
|
|
JUnitUtil.waitFor(()-> SignalHead.RED == h1.getAppearance(), "Stuck at "+h1.getAppearance()+" so occupied sets red"); // wait and test
|
|
|
|
JUnitUtil.setBeanState(s1, Sensor.INACTIVE);
|
|
JUnitUtil.waitFor(()-> SignalHead.GREEN == h1.getAppearance(), "Stuck at "+h1.getAppearance()+" so unoccupied sets green"); // wait and test
|
|
}
|
|
|
|
// test signal following in distant simple block
|
|
@Test
|
|
public void testSimpleBlockDistant() {
|
|
setupSimpleBlock();
|
|
p.setDistantSignal(true);
|
|
startLogic();
|
|
|
|
assertThat(p.getDrivenSignal()).withFailMessage("driven signal name").isEqualTo("IH1");
|
|
|
|
JUnitUtil.setBeanStateAndWait(h2, SignalHead.YELLOW);
|
|
JUnitUtil.waitFor(()-> SignalHead.YELLOW == h1.getAppearance(), "yellow sets yellow"); // wait and test
|
|
|
|
JUnitUtil.setBeanStateAndWait(h2, SignalHead.RED);
|
|
JUnitUtil.waitFor(()-> SignalHead.RED == h1.getAppearance(), "red sets red"); // wait and test
|
|
|
|
JUnitUtil.setBeanStateAndWait(h2, SignalHead.GREEN);
|
|
JUnitUtil.waitFor(()-> SignalHead.GREEN == h1.getAppearance(), "green sets green"); // wait and test
|
|
}
|
|
|
|
// test signal following in limited simple block
|
|
// (not particularly interesting, as next signal can't set red)
|
|
@Test
|
|
public void testSimpleBlockLimited() {
|
|
setupSimpleBlock();
|
|
p.setLimitSpeed1(true);
|
|
startLogic();
|
|
|
|
JUnitUtil.setBeanStateAndWait(h2, SignalHead.RED);
|
|
JUnitUtil.waitFor(()-> SignalHead.YELLOW == h1.getAppearance(), "red sets yellow"); // wait and test
|
|
|
|
JUnitUtil.setBeanStateAndWait(h2, SignalHead.YELLOW);
|
|
JUnitUtil.waitFor(()-> SignalHead.YELLOW == h1.getAppearance(), "yellow sets yellow"); // wait and test
|
|
|
|
JUnitUtil.setBeanStateAndWait(h2, SignalHead.GREEN);
|
|
JUnitUtil.waitFor(()-> SignalHead.YELLOW == h1.getAppearance(), "green sets yellow"); // wait and test
|
|
}
|
|
|
|
// test signal following in distant, limited simple block
|
|
@Test
|
|
public void testSimpleBlockDistantLimited() {
|
|
setupSimpleBlock();
|
|
p.setDistantSignal(true);
|
|
p.setLimitSpeed1(true);
|
|
startLogic();
|
|
|
|
JUnitUtil.setBeanStateAndWait(h2, SignalHead.YELLOW);
|
|
JUnitUtil.waitFor(()-> SignalHead.YELLOW == h1.getAppearance(), "yellow sets yellow"); // wait and test
|
|
|
|
JUnitUtil.setBeanStateAndWait(h2, SignalHead.RED);
|
|
JUnitUtil.waitFor(()-> SignalHead.RED == h1.getAppearance(), "red sets red"); // wait and test
|
|
|
|
JUnitUtil.setBeanStateAndWait(h2, SignalHead.GREEN);
|
|
JUnitUtil.waitFor(()-> SignalHead.YELLOW == h1.getAppearance(), "green sets yellow"); // wait and test
|
|
}
|
|
|
|
// test signal following in restricting simple block
|
|
@Test
|
|
public void testSimpleBlockRestricting() {
|
|
JUnitUtil.setBeanState(s1, Sensor.INACTIVE);
|
|
|
|
setupSimpleBlock();
|
|
p.setSensor1("IS1");
|
|
p.setRestrictingSpeed1(true);
|
|
startLogic();
|
|
|
|
JUnitUtil.setBeanStateAndWait(h2, SignalHead.YELLOW);
|
|
JUnitUtil.waitFor(()-> SignalHead.FLASHRED == h1.getAppearance(), "yellow sets flashing red"); // wait and test
|
|
|
|
JUnitUtil.setBeanState(s1, Sensor.ACTIVE);
|
|
JUnitUtil.waitFor(()-> SignalHead.RED == h1.getAppearance(), "Stuck at "+h1.getAppearance()+" so occupied sets red"); // wait and test
|
|
|
|
JUnitUtil.setBeanStateAndWait(h2, SignalHead.GREEN);
|
|
JUnitUtil.setBeanState(s1, Sensor.INACTIVE);
|
|
JUnitUtil.waitFor(()-> SignalHead.FLASHRED == h1.getAppearance(), "Stuck at "+h1.getAppearance()+" so unoccupied green sets flashing red"); // wait and test
|
|
}
|
|
|
|
// if no next signal, next signal considered green
|
|
@Test
|
|
public void testSimpleBlockNoNext() throws jmri.JmriException {
|
|
s1.setState(Sensor.INACTIVE);
|
|
|
|
p = new BlockBossLogic("IH1");
|
|
p.setSensor1("1");
|
|
p.setMode(BlockBossLogic.SINGLEBLOCK);
|
|
startLogic();
|
|
|
|
JUnitUtil.waitFor(()-> SignalHead.GREEN == h1.getAppearance(), "missing signal is green"); // wait and test
|
|
}
|
|
|
|
// if no next signal, next signal is considered green
|
|
@Test
|
|
public void testSimpleBlockNoNextLimited() throws jmri.JmriException {
|
|
s1.setState(Sensor.INACTIVE);
|
|
|
|
p = new BlockBossLogic("IH1");
|
|
p.setMode(BlockBossLogic.SINGLEBLOCK);
|
|
p.setSensor1("1");
|
|
p.setLimitSpeed1(true);
|
|
|
|
startLogic();
|
|
|
|
JUnitUtil.waitFor(()-> SignalHead.YELLOW == h1.getAppearance(), "missing signal is green, show yellow"); // wait and test
|
|
}
|
|
|
|
// check for basic not-fail if no signal name was set
|
|
@Test
|
|
public void testSimpleBlockNoSignal() {
|
|
Exception ex = Assertions.assertThrows(NullPointerException.class, () -> {
|
|
var bbl = getThrowNpeBlockBossLogic();
|
|
Assertions.fail("Should have thrown NPE on line above, not created " + bbl);
|
|
});
|
|
Assertions.assertNotNull(ex);
|
|
Assertions.assertEquals("BlockBossLogic name cannot be null", ex.getMessage());
|
|
}
|
|
|
|
@SuppressFBWarnings("NP_NONNULL_PARAM_VIOLATION") // passing null to test exception
|
|
private BlockBossLogic getThrowNpeBlockBossLogic() {
|
|
return new BlockBossLogic(null);
|
|
}
|
|
|
|
// check for basic not-fail if empty signal name was set
|
|
@Test
|
|
public void testSimpleBlockEmptyName() {
|
|
Exception ex = Assertions.assertThrows(IllegalArgumentException.class, () -> {
|
|
Assertions.assertNull(new BlockBossLogic(""));});
|
|
Assertions.assertNotNull(ex);
|
|
Assertions.assertEquals("SignalHead \"\" does not exist", ex.getMessage());
|
|
jmri.util.JUnitAppender.assertWarnMessage("Signal Head \"\" was not found");
|
|
}
|
|
|
|
// test interruption
|
|
@Test
|
|
public void testInterrupt() throws jmri.JmriException {
|
|
s1.setState(Sensor.INACTIVE);
|
|
|
|
forceInterrupt = false;
|
|
p = new BlockBossLogic("IH1") {
|
|
@Override
|
|
public void setOutput() {
|
|
testThread = this.thread;
|
|
if (forceInterrupt) {
|
|
testThread.interrupt(); // force an interrupt of the SSL thread
|
|
}
|
|
super.setOutput();
|
|
}
|
|
};
|
|
p.setMode(BlockBossLogic.SINGLEBLOCK);
|
|
p.setSensor1("1");
|
|
p.setLimitSpeed1(true);
|
|
|
|
startLogic();
|
|
|
|
JUnitUtil.waitFor(()-> p.isRunning(), "is running");
|
|
|
|
forceInterrupt = true;
|
|
s1.setState(Sensor.ACTIVE);
|
|
|
|
JUnitUtil.waitFor(()-> !p.isRunning(), "is stopped");
|
|
}
|
|
|
|
|
|
// check that user names were preserved
|
|
@Test
|
|
public void testUserNamesRetained() {
|
|
p = new BlockBossLogic("IH1");
|
|
|
|
p.setSensor1("1");
|
|
p.setSensor2("2");
|
|
p.setSensor3("3");
|
|
p.setSensor4("4");
|
|
p.setSensor5("10");
|
|
|
|
p.setTurnout("1");
|
|
|
|
p.setWatchedSignal1("1", false);
|
|
p.setWatchedSignal1Alt("2");
|
|
p.setWatchedSignal2("3");
|
|
p.setWatchedSignal2Alt("4");
|
|
|
|
p.setWatchedSensor1("5");
|
|
p.setWatchedSensor1Alt("6");
|
|
p.setWatchedSensor2("7");
|
|
p.setWatchedSensor2Alt("8");
|
|
|
|
p.setApproachSensor1("9");
|
|
|
|
assertThat(p.getSensor1()).withFailMessage("sensor1").isEqualTo("1");
|
|
assertThat(p.getSensor2()).withFailMessage("sensor2").isEqualTo("2");
|
|
assertThat(p.getSensor3()).withFailMessage("sensor3").isEqualTo("3");
|
|
assertThat(p.getSensor4()).withFailMessage("sensor4").isEqualTo("4");
|
|
assertThat(p.getSensor5()).withFailMessage("sensor5").isEqualTo("10");
|
|
|
|
assertThat(p.getTurnout()).withFailMessage("turnout1").isEqualTo("1");
|
|
|
|
assertThat(p.getWatchedSignal1()).withFailMessage("watchedsignal1").isEqualTo("1");
|
|
assertThat(p.getWatchedSignal1Alt()).withFailMessage("watchedsignal1alt").isEqualTo("2");
|
|
assertThat(p.getWatchedSignal2()).withFailMessage("watchedsignal2").isEqualTo("3");
|
|
assertThat(p.getWatchedSignal2Alt()).withFailMessage("watchedsignal2alt").isEqualTo("4");
|
|
|
|
assertThat(p.getWatchedSensor1()).withFailMessage("watchedsensor1").isEqualTo("5");
|
|
assertThat(p.getWatchedSensor1Alt()).withFailMessage("watchedsensor1alt").isEqualTo("6");
|
|
assertThat(p.getWatchedSensor2()).withFailMessage("watchedsensor2").isEqualTo("7");
|
|
assertThat(p.getWatchedSensor2Alt()).withFailMessage("watchedsensor2alt").isEqualTo("8");
|
|
|
|
assertThat(p.getApproachSensor1()).withFailMessage("approach").isEqualTo("9");
|
|
|
|
}
|
|
|
|
// check that system names were preserved
|
|
@Test
|
|
public void testSystemNamesRetained() {
|
|
p = new BlockBossLogic("IH1");
|
|
|
|
p.setSensor1("IS1");
|
|
p.setSensor2("IS2");
|
|
p.setSensor3("IS3");
|
|
p.setSensor4("IS4");
|
|
p.setSensor5("IS10");
|
|
|
|
p.setTurnout("IT1");
|
|
|
|
p.setWatchedSignal1("IH1", false);
|
|
p.setWatchedSignal1Alt("IH2");
|
|
p.setWatchedSignal2("IH3");
|
|
p.setWatchedSignal2Alt("IH4");
|
|
|
|
p.setWatchedSensor1("IS5");
|
|
p.setWatchedSensor1Alt("IS6");
|
|
p.setWatchedSensor2("IS7");
|
|
p.setWatchedSensor2Alt("IS8");
|
|
|
|
p.setApproachSensor1("IS9");
|
|
|
|
assertThat(p.getSensor1()).withFailMessage("sensor1").isEqualTo("IS1");
|
|
assertThat(p.getSensor2()).withFailMessage("sensor2").isEqualTo("IS2");
|
|
assertThat(p.getSensor3()).withFailMessage("sensor3").isEqualTo("IS3");
|
|
assertThat(p.getSensor4()).withFailMessage("sensor4").isEqualTo("IS4");
|
|
assertThat(p.getSensor5()).withFailMessage("sensor5").isEqualTo("IS10");
|
|
|
|
assertThat(p.getTurnout()).withFailMessage("turnout1").isEqualTo("IT1");
|
|
|
|
assertThat(p.getWatchedSignal1()).withFailMessage("watchedsignal1").isEqualTo("IH1");
|
|
assertThat(p.getWatchedSignal1Alt()).withFailMessage("watchedsignal1alt").isEqualTo("IH2");
|
|
assertThat(p.getWatchedSignal2()).withFailMessage("watchedsignal2").isEqualTo("IH3");
|
|
assertThat(p.getWatchedSignal2Alt()).withFailMessage("watchedsignal2alt").isEqualTo("IH4");
|
|
|
|
assertThat(p.getWatchedSensor1()).withFailMessage("watchedsensor1").isEqualTo("IS5");
|
|
assertThat(p.getWatchedSensor1Alt()).withFailMessage("watchedsensor1alt").isEqualTo("IS6");
|
|
assertThat(p.getWatchedSensor2()).withFailMessage("watchedsensor2").isEqualTo("IS7");
|
|
assertThat(p.getWatchedSensor2Alt()).withFailMessage("watchedsensor2alt").isEqualTo("IS8");
|
|
|
|
assertThat(p.getApproachSensor1()).withFailMessage("approach").isEqualTo("IS9");
|
|
|
|
}
|
|
|
|
// Turnout t1, t2, t3;
|
|
private Sensor s1; //, s2, s3, s4, s5, s6, s7, s8, s9, s10;
|
|
private SignalHead h1, h2, h3, h4;
|
|
private BlockBossLogic p;
|
|
|
|
private Thread testThread = null;
|
|
private boolean forceInterrupt = false;
|
|
|
|
protected void startLogic() {
|
|
if (p != null) {
|
|
p.start();
|
|
}
|
|
}
|
|
|
|
protected void stopLogic() {
|
|
if (p != null) {
|
|
p.stop();
|
|
}
|
|
}
|
|
|
|
void setupSimpleBlock() {
|
|
p = new BlockBossLogic("IH1");
|
|
p.setMode(BlockBossLogic.SINGLEBLOCK);
|
|
p.setWatchedSignal1("IH2", false);
|
|
}
|
|
|
|
/**
|
|
* Test-by test initialization. Does log4j for standalone use, and then
|
|
* creates a set of turnouts, sensors and signals as common background for
|
|
* testing
|
|
*/
|
|
@BeforeEach
|
|
public void setUp() {
|
|
// reset InstanceManager
|
|
JUnitUtil.setUp();
|
|
|
|
JUnitUtil.initInternalSensorManager();
|
|
JUnitUtil.initInternalTurnoutManager();
|
|
JUnitUtil.initInternalSignalHeadManager();
|
|
|
|
// clear the BlockBossLogic static list
|
|
ArrayList<SignalHead> heads = new ArrayList<>();
|
|
|
|
for (BlockBossLogic b : InstanceManager.getDefault(BlockBossLogicProvider.class).provideAll()) {
|
|
heads.add(b.getDrivenSignalNamedBean().getBean());
|
|
}
|
|
for (SignalHead head : heads) { // avoids ConcurrentModificationException
|
|
BlockBossLogic.getStoppedObject(head);
|
|
}
|
|
|
|
// t1 = InstanceManager.turnoutManagerInstance().newTurnout("IT1", "1");
|
|
// t2 = InstanceManager.turnoutManagerInstance().newTurnout("IT2", "2");
|
|
// t3 = InstanceManager.turnoutManagerInstance().newTurnout("IT3", "3");
|
|
|
|
s1 = InstanceManager.sensorManagerInstance().newSensor("IS1", "1");
|
|
// s2 = InstanceManager.sensorManagerInstance().newSensor("IS2", "2");
|
|
// s3 = InstanceManager.sensorManagerInstance().newSensor("IS3", "3");
|
|
// s4 = InstanceManager.sensorManagerInstance().newSensor("IS4", "4");
|
|
// s5 = InstanceManager.sensorManagerInstance().newSensor("IS5", "5");
|
|
// s6 = InstanceManager.sensorManagerInstance().newSensor("IS6", "6");
|
|
// s7 = InstanceManager.sensorManagerInstance().newSensor("IS7", "7");
|
|
// s8 = InstanceManager.sensorManagerInstance().newSensor("IS8", "8");
|
|
// s9 = InstanceManager.sensorManagerInstance().newSensor("IS9", "9");
|
|
// s10 = InstanceManager.sensorManagerInstance().newSensor("IS10", "10");
|
|
|
|
h1 = new jmri.implementation.VirtualSignalHead("IH1", "1");
|
|
InstanceManager.getDefault(jmri.SignalHeadManager.class).register(h1);
|
|
JUnitUtil.setBeanStateAndWait(h1, SignalHead.RED); // ensure starting point
|
|
|
|
h2 = new jmri.implementation.VirtualSignalHead("IH2", "2");
|
|
InstanceManager.getDefault(jmri.SignalHeadManager.class).register(h2);
|
|
JUnitUtil.setBeanStateAndWait(h2, SignalHead.RED); // ensure starting point
|
|
|
|
h3 = new jmri.implementation.VirtualSignalHead("IH3", "3");
|
|
InstanceManager.getDefault(jmri.SignalHeadManager.class).register(h3);
|
|
JUnitUtil.setBeanStateAndWait(h3, SignalHead.RED); // ensure starting point
|
|
|
|
h4 = new jmri.implementation.VirtualSignalHead("IH4", "4");
|
|
InstanceManager.getDefault(jmri.SignalHeadManager.class).register(h4);
|
|
JUnitUtil.setBeanStateAndWait(h4, SignalHead.RED); // ensure starting point
|
|
}
|
|
|
|
@AfterEach
|
|
public void tearDown() {
|
|
// t1=t2=t3=null;
|
|
s1=null; // s2=s3=s4=s5=s6=s7=s8=s9=s10=null;
|
|
h1=h2=h3=h4=null;
|
|
testThread = null;
|
|
stopLogic();
|
|
// reset InstanceManager
|
|
JUnitUtil.tearDown();
|
|
}
|
|
}
|