524 lines
20 KiB
Java
524 lines
20 KiB
Java
package jmri.implementation;
|
|
|
|
import static org.junit.jupiter.api.Assertions.assertEquals;
|
|
import static org.junit.jupiter.api.Assertions.assertFalse;
|
|
import static org.junit.jupiter.api.Assertions.assertNotNull;
|
|
import static org.junit.jupiter.api.Assertions.assertNull;
|
|
import static org.junit.jupiter.api.Assertions.assertTrue;
|
|
|
|
import static org.junit.jupiter.api.Assumptions.assumeTrue;
|
|
|
|
import java.beans.PropertyChangeListener;
|
|
|
|
import jmri.*;
|
|
import jmri.util.JUnitUtil;
|
|
|
|
import org.junit.jupiter.api.*;
|
|
|
|
/**
|
|
* Abstract base class for Turnout tests in specific jmrix.* packages
|
|
*
|
|
* This is not itself a test class, e.g. should not be added to a suite.
|
|
* Instead, this forms the base for test classes, including providing some
|
|
* common tests.
|
|
*
|
|
* @author Bob Jacobsen
|
|
*/
|
|
public abstract class AbstractTurnoutTestBase {
|
|
|
|
/**
|
|
* Implementing classes must overload to load t with actual object; create scaffolds as needed
|
|
*/
|
|
@BeforeEach
|
|
public void setUp() {
|
|
JUnitUtil.setUp();
|
|
}
|
|
|
|
@AfterEach
|
|
public void tearDown() {
|
|
t = null; // to save space, as JU4 doesn't garbage collect this object
|
|
JUnitUtil.tearDown();
|
|
}
|
|
|
|
/**
|
|
* @return number of listeners registered with the TrafficController by the object under test
|
|
* util for test clean up
|
|
*/
|
|
abstract public int numListeners();
|
|
|
|
abstract public void checkThrownMsgSent() throws InterruptedException;
|
|
|
|
abstract public void checkClosedMsgSent() throws InterruptedException;
|
|
|
|
protected Turnout t = null; // holds object under test; set by setUp()
|
|
|
|
protected boolean listenerResult = false;
|
|
protected int listenStatus = Turnout.UNKNOWN;
|
|
protected java.util.List<String> propChangeNames;
|
|
|
|
public class Listen implements PropertyChangeListener {
|
|
|
|
public Listen(){
|
|
propChangeNames = new java.util.ArrayList<>();
|
|
}
|
|
|
|
@Override
|
|
public void propertyChange(java.beans.PropertyChangeEvent e) {
|
|
listenerResult = true;
|
|
propChangeNames.add(e.getPropertyName());
|
|
if (e.getPropertyName().equals("KnownState")) {
|
|
listenStatus = (Integer) e.getNewValue();
|
|
}
|
|
}
|
|
}
|
|
|
|
// start of common tests
|
|
// test creation - real work is in the setup() routine
|
|
@Test
|
|
public void testCreate() {
|
|
// initial commanded state when created must be UNKNOWN
|
|
assertEquals( Turnout.UNKNOWN, t.getCommandedState(), "initial commanded state 1");
|
|
// initial known state when created must be UNKNOWN
|
|
assertEquals( Turnout.UNKNOWN, t.getKnownState(), "initial known state");
|
|
assertEquals( Turnout.UNKNOWN, t.getState(), "initial commanded state 2");
|
|
}
|
|
|
|
@Test
|
|
public void testAddListener() {
|
|
t.addPropertyChangeListener(new Listen());
|
|
listenerResult = false;
|
|
t.setUserName("user id");
|
|
assertTrue( listenerResult, "listener invoked by setUserName");
|
|
listenerResult = false;
|
|
t.setCommandedState(Turnout.CLOSED);
|
|
assertTrue( listenerResult, "listener invoked by setCommandedState");
|
|
}
|
|
|
|
@Test
|
|
public void testRemoveListener() {
|
|
Listen ln = new Listen();
|
|
t.addPropertyChangeListener(ln);
|
|
t.removePropertyChangeListener(ln);
|
|
listenerResult = false;
|
|
t.setUserName("user id");
|
|
assertFalse( listenerResult,
|
|
"listener should not have heard message after removeListener");
|
|
}
|
|
|
|
@Test
|
|
public void testDispose() {
|
|
t.setCommandedState(Turnout.CLOSED); // in case registration with TrafficController is deferred to after first use
|
|
t.dispose();
|
|
assertEquals( 0, numListeners(), "controller listeners remaining");
|
|
}
|
|
|
|
@Test
|
|
public void testRemoveListenerOnDispose() {
|
|
int startListeners = t.getNumPropertyChangeListeners();
|
|
t.addPropertyChangeListener(new Listen());
|
|
assertEquals( startListeners+1, t.getNumPropertyChangeListeners(),
|
|
"controller listener added");
|
|
t.dispose();
|
|
assertTrue( t.getNumPropertyChangeListeners() < 1, "controller listeners remaining < 1");
|
|
}
|
|
|
|
@Test
|
|
public void testCommandClosed() throws InterruptedException {
|
|
t.setCommandedState(Turnout.CLOSED);
|
|
// check
|
|
assertEquals( Turnout.CLOSED, t.getCommandedState(), "commanded state 1");
|
|
checkClosedMsgSent();
|
|
((AbstractTurnout)t).setKnownStateToCommanded();
|
|
assertEquals( Turnout.CLOSED, t.getState(), "commanded state 2");
|
|
assertEquals( "Closed", t.describeState(t.getState()), "commanded state 3");
|
|
}
|
|
|
|
@Test
|
|
public void testCommandThrown() throws InterruptedException {
|
|
t.setCommandedState(Turnout.THROWN);
|
|
// check
|
|
assertEquals( Turnout.THROWN, t.getCommandedState(), "commanded state 1");
|
|
checkThrownMsgSent();
|
|
((AbstractTurnout)t).setKnownStateToCommanded();
|
|
assertEquals( Turnout.THROWN, t.getState(), "commanded state 2");
|
|
assertEquals( "Thrown", t.describeState(t.getState()), "commanded state 3");
|
|
}
|
|
|
|
private static class TestSensor extends AbstractSensor {
|
|
boolean request = false;
|
|
|
|
private TestSensor(String sysName, String userName){
|
|
super(sysName, userName);
|
|
}
|
|
|
|
@Override
|
|
public void requestUpdateFromLayout(){
|
|
request = true;
|
|
}
|
|
|
|
boolean getRequest(){
|
|
return request;
|
|
}
|
|
|
|
void resetRequest(){
|
|
request=false;
|
|
}
|
|
}
|
|
|
|
@Test
|
|
public void testRequestUpdate() throws JmriException {
|
|
TestSensor s1 = new TestSensor("IS1", "username1");
|
|
TestSensor s2 = new TestSensor("IS2", "username2");
|
|
InstanceManager.sensorManagerInstance().register(s1);
|
|
InstanceManager.sensorManagerInstance().register(s2);
|
|
|
|
t.provideFirstFeedbackSensor("IS1");
|
|
t.setFeedbackMode(Turnout.ONESENSOR);
|
|
|
|
t.requestUpdateFromLayout();
|
|
assertTrue( s1.getRequest(), "update requested, one sensor");
|
|
s1.resetRequest();
|
|
|
|
t.provideSecondFeedbackSensor("IS2");
|
|
t.setFeedbackMode(Turnout.TWOSENSOR);
|
|
|
|
t.requestUpdateFromLayout();
|
|
assertTrue( s1.getRequest(), "update requested, two sensor s1");
|
|
assertTrue( s2.getRequest(), "update requested, two sensor s2");
|
|
}
|
|
|
|
@Test
|
|
public void testGetAndSetInverted() {
|
|
assumeTrue(t.canInvert(), "Turnout does not invert");
|
|
t.addPropertyChangeListener(new Listen());
|
|
assertFalse( t.getInverted(), "Default Inverted State");
|
|
t.setInverted(true);
|
|
assertTrue( t.getInverted(), "set Inverted");
|
|
assertTrue( propChangeNames.contains("inverted"), "Inverted propertychange");
|
|
|
|
t.addPropertyChangeListener(new Listen()); // reset PCLs
|
|
|
|
t.setInverted(false);
|
|
assertFalse( t.getInverted(), "Unset Inverted");
|
|
assertTrue( propChangeNames.contains("inverted"), "Inverted propertychange");
|
|
|
|
|
|
}
|
|
|
|
@Test
|
|
public void testInvertedCommandClosed() throws InterruptedException {
|
|
assumeTrue(t.canInvert(), "Turnout does not invert");
|
|
t.setInverted(true);
|
|
t.setCommandedState(Turnout.CLOSED);
|
|
// check
|
|
assertEquals( Turnout.CLOSED, t.getCommandedState(), "commanded state 1");
|
|
checkThrownMsgSent();
|
|
((AbstractTurnout) t).setKnownStateToCommanded();
|
|
assertEquals( Turnout.CLOSED, t.getState(), "commanded state 2");
|
|
assertEquals( "Closed", t.describeState(t.getState()), "commanded state 3");
|
|
|
|
}
|
|
|
|
@Test
|
|
public void testInvertedCommandThrown() throws InterruptedException {
|
|
assumeTrue(t.canInvert(), "Turnout does not invert");
|
|
t.setInverted(true);
|
|
t.setCommandedState(Turnout.THROWN);
|
|
// check
|
|
assertEquals( Turnout.THROWN, t.getCommandedState(), "commanded state 1");
|
|
checkClosedMsgSent();
|
|
((AbstractTurnout) t).setKnownStateToCommanded();
|
|
assertEquals( Turnout.THROWN, t.getState(), "commanded state 2");
|
|
assertEquals( "Thrown", t.describeState(t.getState()), "commanded state 3");
|
|
|
|
}
|
|
|
|
@Test
|
|
public void testSetGetReportLocked() throws InterruptedException {
|
|
assertTrue( t.getReportLocked(), "Turnout starts reporting locked attempted access");
|
|
t.addPropertyChangeListener(new Listen()); // reset PCLs
|
|
t.setReportLocked(true);
|
|
assertFalse( propChangeNames.contains("reportlocked"),
|
|
"SetGetReportLocked nochange");
|
|
|
|
t.setReportLocked(false);
|
|
assertFalse( t.getReportLocked(), "SetGetReportLocked sets false");
|
|
assertTrue( propChangeNames.contains("reportlocked"),
|
|
"SetGetReportLocked propertychange");
|
|
|
|
t.addPropertyChangeListener(new Listen()); // reset PCLs
|
|
t.setReportLocked(true);
|
|
assertTrue( t.getReportLocked(), "SetGetReportLocked sets true");
|
|
assertTrue( propChangeNames.contains("reportlocked"),
|
|
"SetGetReportLocked propertychange");
|
|
|
|
}
|
|
|
|
@Test
|
|
public void testSetFeedbackModePCL() throws InterruptedException {
|
|
t.setFeedbackMode(Turnout.UNKNOWN);
|
|
assertEquals( Turnout.UNKNOWN,t.getFeedbackMode(), "No feedback set at start");
|
|
|
|
t.addPropertyChangeListener(new Listen());
|
|
t.setFeedbackMode(Turnout.UNKNOWN);
|
|
assertFalse( propChangeNames.contains("feedbackchange"),
|
|
"setFeedbackMode propertychange");
|
|
|
|
t.setFeedbackMode(Turnout.ONESENSOR);
|
|
assertTrue( propChangeNames.contains("feedbackchange"),
|
|
"setFeedbackMode propertychange");
|
|
}
|
|
|
|
@Test
|
|
public void testSetDecoderNamePCL() throws InterruptedException {
|
|
|
|
// assertNull( t.getDecoderName(), "No decoder set at start");
|
|
// In AbstractTurnout this String defaults to PushbuttonPacket.unknown , ie "None"
|
|
// which is different to the javadoc in Turnout which indicates should return null for unset.
|
|
|
|
// so we set it manually here so starting this particular test from a known state.
|
|
t.setDecoderName(null);
|
|
assertNull( t.getDecoderName(), "No decoder set at start");
|
|
|
|
t.addPropertyChangeListener(new Listen());
|
|
t.setDecoderName(null);
|
|
assertFalse( propChangeNames.contains("decoderNameChange"),
|
|
"setDecoderName no change");
|
|
|
|
t.setDecoderName("Test Name");
|
|
assertTrue( propChangeNames.contains("decoderNameChange"),
|
|
"SetDecoderName propertychange");
|
|
}
|
|
|
|
@Test
|
|
public void testProvideFirstFeedbackSensor() throws jmri.JmriException {
|
|
t.addPropertyChangeListener(new Listen());
|
|
t.provideFirstFeedbackSensor("IS1");
|
|
assertNotNull( t.getFirstSensor(), "first feedback sensor");
|
|
assertTrue( propChangeNames.contains("turnoutFeedbackFirstSensorChange"),
|
|
"1st feedback sensor propertychange");
|
|
}
|
|
|
|
@Test
|
|
public void testProvideSecondFeedbackSensor() throws jmri.JmriException {
|
|
t.addPropertyChangeListener(new Listen());
|
|
t.provideSecondFeedbackSensor("IS2");
|
|
assertNotNull( t.getSecondSensor(), "first feedback sensor");
|
|
assertTrue( propChangeNames.contains("turnoutFeedbackSecondSensorChange"),
|
|
"2nd feedback sensor propertychange");
|
|
}
|
|
|
|
@Test
|
|
public void testOneSensorFeedback() throws jmri.JmriException {
|
|
Sensor s1 = InstanceManager.getDefault(jmri.SensorManager.class).provideSensor("IS1");
|
|
t.setFeedbackMode(Turnout.ONESENSOR);
|
|
listenStatus = Turnout.UNKNOWN;
|
|
t.addPropertyChangeListener(new Listen());
|
|
t.provideFirstFeedbackSensor("IS1");
|
|
s1.setKnownState(Sensor.INACTIVE);
|
|
assertEquals( Turnout.CLOSED, t.getKnownState(),
|
|
"known state for ONESENSOR feedback Inactive");
|
|
assertEquals( Turnout.CLOSED,listenStatus,
|
|
"listener notified of change for ONESENSOR feedback");
|
|
s1.setKnownState(Sensor.ACTIVE);
|
|
assertEquals( Turnout.THROWN, listenStatus,
|
|
"listener notified of change for ONESENSOR feedback");
|
|
assertEquals( Turnout.THROWN, t.getKnownState(),
|
|
"known state for ONESENSOR feedback active");
|
|
|
|
s1.setKnownState(Sensor.UNKNOWN);
|
|
|
|
assertEquals( Turnout.INCONSISTENT, t.getKnownState(),
|
|
() -> "unknown state for ONESENSOR feedback, was " + t.describeState(t.getKnownState()));
|
|
assertEquals( Turnout.INCONSISTENT, listenStatus,
|
|
"listener notified of change for ONESENSOR feedback unknown");
|
|
|
|
s1.setKnownState(Sensor.INACTIVE);
|
|
assertEquals( Turnout.CLOSED, t.getKnownState(),
|
|
"known state for ONESENSOR feedback Inactive");
|
|
assertEquals( Turnout.CLOSED, listenStatus,
|
|
"listener notified of change for ONESENSOR feedback reset");
|
|
|
|
s1.setKnownState(Sensor.INCONSISTENT);
|
|
assertEquals( Turnout.INCONSISTENT, listenStatus,
|
|
"listener notified of change for ONESENSOR feedback INCONSISTENT");
|
|
assertEquals( Turnout.INCONSISTENT, t.getKnownState(),
|
|
"INCONSISTENT state for ONESENSOR feedback");
|
|
|
|
}
|
|
|
|
// Order of the 2 Sensor Conditions in same order as support page jmrit/beantable/TurnoutTable.shtml
|
|
@Test
|
|
public void testTwoSensorFeedback() throws jmri.JmriException {
|
|
Sensor s1 = InstanceManager.getDefault(jmri.SensorManager.class).provideSensor("IS1");
|
|
Sensor s2 = InstanceManager.getDefault(jmri.SensorManager.class).provideSensor("IS2");
|
|
t.provideFirstFeedbackSensor("IS1");
|
|
t.provideSecondFeedbackSensor("IS2");
|
|
t.setFeedbackMode(Turnout.TWOSENSOR);
|
|
assertEquals( Turnout.UNKNOWN, t.getKnownState(),
|
|
"known state for TWOSENSOR feedback (UNKNOWN,UNKNOWN)");
|
|
|
|
listenStatus = Turnout.UNKNOWN;
|
|
t.addPropertyChangeListener(new Listen());
|
|
|
|
s1.setKnownState(Sensor.ACTIVE);
|
|
s2.setKnownState(Sensor.INACTIVE);
|
|
|
|
JUnitUtil.waitFor( () -> t.getKnownState() != Turnout.UNKNOWN,"Turnout did not go Thrown");
|
|
|
|
assertEquals( Turnout.THROWN, t.getKnownState(),
|
|
"state changed by TWOSENSOR feedback (Active, Inactive)");
|
|
assertEquals( Turnout.THROWN, listenStatus,
|
|
"listener notified of change for TWOSENSOR feedback");
|
|
|
|
|
|
s1.setKnownState(Sensor.INACTIVE);
|
|
s2.setKnownState(Sensor.ACTIVE);
|
|
assertEquals( Turnout.CLOSED, t.getKnownState(),
|
|
"state changed by TWOSENSOR feedback (Inactive, Active)");
|
|
assertEquals( Turnout.CLOSED, listenStatus,
|
|
"listener notified of change for TWOSENSOR feedback ");
|
|
|
|
|
|
s1.setKnownState(Sensor.INACTIVE);
|
|
s2.setKnownState(Sensor.INACTIVE);
|
|
assertEquals( Turnout.INCONSISTENT, t.getKnownState(),
|
|
"known state for TWOSENSOR feedback (Inactive, Inactive)");
|
|
|
|
|
|
s1.setKnownState(Sensor.UNKNOWN);
|
|
s2.setKnownState(Sensor.UNKNOWN);
|
|
assertEquals( Turnout.UNKNOWN, t.getKnownState(),
|
|
() -> "state changed by TWOSENSOR feedback (UNKNOWN, UNKNOWN), was "+ t.describeState(t.getKnownState()));
|
|
|
|
|
|
s1.setKnownState(Sensor.ACTIVE);
|
|
s2.setKnownState(Sensor.ACTIVE);
|
|
assertEquals( Turnout.INCONSISTENT, t.getKnownState(),
|
|
() -> "state changed by TWOSENSOR feedback (ACTIVE, ACTIVE) was " + t.describeState(t.getKnownState()));
|
|
|
|
|
|
s1.setKnownState(Sensor.ACTIVE);
|
|
s2.setKnownState(Sensor.INCONSISTENT);
|
|
assertEquals( Turnout.INCONSISTENT, t.getKnownState(),
|
|
() -> "state changed by TWOSENSOR feedback (ACTIVE, INCONSISTENT), was "+ t.describeState(t.getKnownState()));
|
|
|
|
|
|
s1.setKnownState(Sensor.INACTIVE);
|
|
s2.setKnownState(Sensor.INCONSISTENT);
|
|
assertEquals( Turnout.INCONSISTENT, t.getKnownState(),
|
|
() -> "state changed by TWOSENSOR feedback (INACTIVE, INCONSISTENT) was " + t.describeState(t.getKnownState()));
|
|
|
|
|
|
s1.setKnownState(Sensor.INCONSISTENT);
|
|
s2.setKnownState(Sensor.ACTIVE);
|
|
assertEquals( Turnout.INCONSISTENT, t.getKnownState(),
|
|
() -> "state changed by TWOSENSOR feedback (INCONSISTENT, ACTIVE) was " + t.describeState(t.getKnownState()));
|
|
|
|
|
|
s1.setKnownState(Sensor.INCONSISTENT);
|
|
s2.setKnownState(Sensor.INACTIVE);
|
|
assertEquals( Turnout.INCONSISTENT, t.getKnownState(),
|
|
() -> "state changed by TWOSENSOR feedback (INCONSISTENT, INACTIVE) was " + t.describeState(t.getKnownState()));
|
|
|
|
|
|
s1.setKnownState(Sensor.UNKNOWN);
|
|
s2.setKnownState(Sensor.ACTIVE);
|
|
assertEquals( Turnout.INCONSISTENT, t.getKnownState(),
|
|
() -> "state changed by TWOSENSOR feedback (UNKNOWN, ACTIVE), was " + t.describeState(t.getKnownState()));
|
|
|
|
|
|
s1.setKnownState(Sensor.UNKNOWN);
|
|
s2.setKnownState(Sensor.INACTIVE);
|
|
assertEquals( Turnout.INCONSISTENT, t.getKnownState(),
|
|
() -> "state changed by TWOSENSOR feedback (UNKNOWN, INACTIVE), was " + t.describeState(t.getKnownState()));
|
|
|
|
|
|
s1.setKnownState(Sensor.UNKNOWN);
|
|
s2.setKnownState(Sensor.INCONSISTENT);
|
|
assertEquals( Turnout.INCONSISTENT, t.getKnownState(),
|
|
() -> "state changed by TWOSENSOR feedback (UNKNOWN, INCONSISTENT), was " + t.describeState(t.getKnownState()));
|
|
|
|
|
|
s1.setKnownState(Sensor.INCONSISTENT);
|
|
s2.setKnownState(Sensor.UNKNOWN);
|
|
assertEquals( Turnout.INCONSISTENT, t.getKnownState(),
|
|
() -> "state changed by TWOSENSOR feedback (INCONSISTENT, UNKNOWN), was " + t.describeState(t.getKnownState()));
|
|
|
|
|
|
s1.setKnownState(Sensor.ACTIVE);
|
|
s2.setKnownState(Sensor.UNKNOWN);
|
|
assertEquals( Turnout.INCONSISTENT, t.getKnownState(),
|
|
() -> "state changed by TWOSENSOR feedback (ACTIVE, UNKNOWN), was " + t.describeState(t.getKnownState()));
|
|
|
|
|
|
s1.setKnownState(Sensor.INACTIVE);
|
|
s2.setKnownState(Sensor.UNKNOWN);
|
|
assertEquals( Turnout.INCONSISTENT, t.getKnownState(),
|
|
() -> "state changed by TWOSENSOR feedback (INACTIVE, UNKNOWN), was " + t.describeState(t.getKnownState()));
|
|
|
|
|
|
s1.setKnownState(Sensor.INCONSISTENT);
|
|
s2.setKnownState(Sensor.INCONSISTENT);
|
|
assertEquals( Turnout.INCONSISTENT, t.getKnownState(),
|
|
() -> "state changed by TWOSENSOR feedback (INCONSISTENT, INCONSISTENT), was " + t.describeState(t.getKnownState()));
|
|
}
|
|
|
|
@Test
|
|
public void testDirectFeedback() throws InterruptedException, jmri.JmriException {
|
|
|
|
// DIRECT mode is implemented in the AbstractTurnout class, so
|
|
// it is possible on all systems.
|
|
if (t.getFeedbackMode() != Turnout.DIRECT) {
|
|
t.setFeedbackMode(Turnout.DIRECT);
|
|
}
|
|
assertEquals(Turnout.DIRECT, t.getFeedbackMode());
|
|
|
|
listenStatus = Turnout.UNKNOWN;
|
|
t.addPropertyChangeListener(new Listen());
|
|
|
|
// Check that state changes appropriately
|
|
t.setCommandedState(Turnout.THROWN);
|
|
checkThrownMsgSent();
|
|
assertEquals(Turnout.THROWN, t.getState());
|
|
assertEquals( Turnout.THROWN, listenStatus,
|
|
"listener notified of change for DIRECT feedback");
|
|
|
|
t.setCommandedState(Turnout.CLOSED);
|
|
checkClosedMsgSent();
|
|
assertEquals(Turnout.CLOSED, t.getState());
|
|
assertEquals( Turnout.CLOSED, listenStatus,
|
|
"listener notified of change for DIRECT feedback");
|
|
}
|
|
|
|
@Test
|
|
public void testGetBeanType(){
|
|
assertEquals( t.getBeanType(), Bundle.getMessage("BeanNameTurnout"),
|
|
"bean type");
|
|
}
|
|
|
|
@Test
|
|
public void testIsCanFollow() {
|
|
assertFalse( t.isCanFollow(), "Abstract method should always return false");
|
|
}
|
|
|
|
@Test
|
|
public void testSetLeadingTurnout() {
|
|
assertNull( t.getLeadingTurnout(), "Defaults to null");
|
|
t.setLeadingTurnout(new AbstractTurnout("9999") {
|
|
|
|
@Override
|
|
protected void forwardCommandChangeToLayout(int s) {
|
|
// nothing to do
|
|
}
|
|
|
|
@Override
|
|
protected void turnoutPushbuttonLockout(boolean locked) {
|
|
// nothing to do
|
|
}
|
|
});
|
|
assertNull( t.getLeadingTurnout(), "Did not change from null");
|
|
}
|
|
|
|
}
|