package jmri.implementation; import jmri.*; import jmri.util.JUnitAppender; import jmri.util.JUnitUtil; import org.junit.Assert; import org.junit.Assume; import org.junit.jupiter.api.*; /** * Tests for the LightControl class. * * @author Paul Bender Copyright (C) 2016 * @author Steve Young Copyright (C) 2019 */ public class LightControlTest { @Test public void testCtor() { LightControl lca = new DefaultLightControl(); Assert.assertNotNull("LightControl not null", lca); } @Test public void testCLighttor() { Assert.assertNotNull("LightControl not null", lc); } @Test public void testLightControlCopyCtor() { LightControl copyOfl = new DefaultLightControl(lc); Assert.assertNotNull("LightControl Copy not null", copyOfl); } @Test @SuppressWarnings("unlikely-arg-type") // String seems to be unrelated to LightControl public void testEquals() { Light o = new AbstractLight("IL1", "test light") { }; LightControl l1 = new DefaultLightControl(o); Assert.assertFalse(l1.equals(null)); Assert.assertTrue(l1.equals(l1)); Assert.assertFalse(l1.equals("")); LightControl l2 = new DefaultLightControl(o); Assert.assertTrue(l1.equals(l2)); l1.setControlType(999); Assert.assertFalse(l1.equals(l2)); l2.setControlType(999); Assert.assertTrue(l1.equals(l2)); JUnitAppender.assertWarnMessage("Unexpected _controlType = 999"); l1.setControlType(Light.SENSOR_CONTROL); Assert.assertFalse(l1.equals(l2)); l2.setControlType(Light.SENSOR_CONTROL); Assert.assertTrue(l1.equals(l2)); l1.setControlSensorName("S2"); Assert.assertFalse(l1.equals(l2)); l2.setControlSensorName("S2"); Assert.assertTrue(l1.equals(l2)); l1.setControlSensorSense(Sensor.ACTIVE); Assert.assertTrue(l1.equals(l2)); // default is ACTIVE l1.setControlSensorSense(Sensor.INACTIVE); Assert.assertFalse(l1.equals(l2)); l2.setControlSensorSense(Sensor.INACTIVE); Assert.assertTrue(l1.equals(l2)); l1.setControlType(Light.FAST_CLOCK_CONTROL); Assert.assertFalse(l1.equals(l2)); l2.setControlType(Light.FAST_CLOCK_CONTROL); Assert.assertTrue(l1.equals(l2)); l1.setFastClockControlSchedule(0, 0, 0, 0); // onHr, OnMin, OffHr, OffMin default Assert.assertTrue(l1.equals(l2)); l1.setFastClockControlSchedule(1, 0, 0, 0); // onHr, OnMin, OffHr, OffMin Assert.assertFalse(l1.equals(l2)); l1.setFastClockControlSchedule(0, 1, 0, 0); // onHr, OnMin, OffHr, OffMin Assert.assertFalse(l1.equals(l2)); l1.setFastClockControlSchedule(0, 0, 1, 0); // onHr, OnMin, OffHr, OffMin Assert.assertFalse(l1.equals(l2)); l1.setFastClockControlSchedule(0, 0, 0, 1); // onHr, OnMin, OffHr, OffMin Assert.assertFalse(l1.equals(l2)); l1.setControlType(Light.TURNOUT_STATUS_CONTROL); Assert.assertFalse(l1.equals(l2)); l2.setControlType(Light.TURNOUT_STATUS_CONTROL); Assert.assertTrue(l1.equals(l2)); l1.setControlTurnout("T1"); Assert.assertFalse(l1.equals(l2)); l2.setControlTurnout("T1"); Assert.assertTrue(l1.equals(l2)); l1.setControlTurnoutState(Turnout.CLOSED); // default CLOSED Assert.assertTrue(l1.equals(l2)); l1.setControlTurnoutState(Turnout.THROWN); Assert.assertFalse(l1.equals(l2)); l2.setControlTurnoutState(Turnout.THROWN); Assert.assertTrue(l1.equals(l2)); l1.setControlType(Light.TIMED_ON_CONTROL); Assert.assertFalse(l1.equals(l2)); l2.setControlType(Light.TIMED_ON_CONTROL); Assert.assertTrue(l1.equals(l2)); l1.setControlTimedOnSensorName("S1"); Assert.assertFalse(l1.equals(l2)); l2.setControlTimedOnSensorName("S1"); Assert.assertTrue(l1.equals(l2)); l1.setTimedOnDuration(77); Assert.assertFalse(l1.equals(l2)); l2.setTimedOnDuration(77); Assert.assertTrue(l1.equals(l2)); l1.setControlType(Light.TWO_SENSOR_CONTROL); Assert.assertFalse(l1.equals(l2)); l2.setControlType(Light.TWO_SENSOR_CONTROL); Assert.assertTrue(l1.equals(l2)); l1.setControlSensorName("S1"); Assert.assertFalse(l1.equals(l2)); l2.setControlSensorName("S1"); Assert.assertTrue(l1.equals(l2)); l1.setControlSensor2Name("S2"); Assert.assertFalse(l1.equals(l2)); l2.setControlSensor2Name("S2"); Assert.assertTrue(l1.equals(l2)); l1.setControlSensorSense(Sensor.ACTIVE); Assert.assertFalse(l1.equals(l2)); l2.setControlSensorSense(Sensor.ACTIVE); Assert.assertTrue(l1.equals(l2)); Assert.assertNotNull("Has Hashcode", l1.hashCode()); } @Test public void testSetGetNames() { // used while editing the control with no Sensors / turnouts etc. attached lc.setControlSensorName("MySensor"); Assert.assertEquals("Same Name", "MySensor", lc.getControlSensorName()); lc.setControlTimedOnSensorName("Shirley"); Assert.assertEquals("Same Name", "Shirley", lc.getControlTimedOnSensorName()); lc.setControlSensor2Name("DownMain7"); Assert.assertEquals("Same Name", "DownMain7", lc.getControlSensor2Name()); } @Test public void testInvalidControlType() { lc.activateLightControl(); JUnitAppender.assertErrorMessage("Unexpected control type when activating Light: ILL1"); } @Test public void testActivateNoLight() { lc.setParentLight(null); lc.activateLightControl(); JUnitAppender.assertErrorMessage("No Parent Light when activating LightControl"); } @Test public void testSingleSensorFollower() throws jmri.JmriException { Sensor s = InstanceManager.getDefault(jmri.SensorManager.class).provideSensor("S2"); int startListeners = s.getPropertyChangeListeners().length; lc.setControlType(Light.SENSOR_CONTROL); lc.setControlSensorName("S2"); lc.setControlSensorSense(Sensor.ACTIVE); l.addLightControl(lc); l.activateLight(); Assert.assertEquals("+1 listener", startListeners + 1, s.getPropertyChangeListeners().length); Assert.assertEquals("Sensor unknown state", Sensor.UNKNOWN, s.getState()); Assert.assertEquals("Light OFF state", Light.OFF, l.getState()); // lights are OFF by default s.setState(Sensor.ON); Assert.assertEquals("ON state", Light.ON, l.getState()); s.setState(Sensor.OFF); Assert.assertEquals("OFF state", Light.OFF, l.getState()); s.setState(Sensor.ON); Assert.assertEquals("ON state", Light.ON, l.getState()); l.deactivateLight(); Assert.assertEquals("releases listener", startListeners, s.getPropertyChangeListeners().length); lc.setControlSensorSense(Sensor.INACTIVE); Assert.assertEquals("ON state", Light.ON, l.getState()); l.activateLight(); Assert.assertEquals("OFF state", Light.OFF, l.getState()); s.setState(Sensor.OFF); Assert.assertEquals("ON state", Light.ON, l.getState()); s.setState(Sensor.ON); Assert.assertEquals("OFF state", Light.OFF, l.getState()); l.setEnabled(false); s.setState(Sensor.OFF); Assert.assertEquals("does not change", Light.OFF, l.getState()); } @Test public void testNoSensor() { lc.setControlType(Light.SENSOR_CONTROL); l.addLightControl(lc); l.activateLight(); JUnitAppender.assertErrorMessage("Light ILL1 is linked to a Sensor that does not exist:"); } @Test public void testNoTurnout() { lc.setControlType(Light.TURNOUT_STATUS_CONTROL); l.addLightControl(lc); l.activateLight(); JUnitAppender.assertErrorMessageStartsWith("Invalid system name for Turnout: System name must start with \"IT\"."); JUnitAppender.assertErrorMessageStartsWith("Light ILL1 is linked to a Turnout that does not exist"); lc.setControlTurnoutState(999); JUnitAppender.assertErrorMessageStartsWith("Incorrect Turnout State Set"); } @Test public void testTurnoutFollower() throws jmri.JmriException { Turnout t = InstanceManager.getDefault(jmri.TurnoutManager.class).provideTurnout("T1"); int startListeners = t.getPropertyChangeListeners().length; lc.setControlType(Light.TURNOUT_STATUS_CONTROL); lc.setControlTurnout("T1"); lc.setControlTurnoutState(Turnout.THROWN); l.addLightControl(lc); l.activateLight(); Assert.assertEquals("+1 listener", startListeners + 1, t.getPropertyChangeListeners().length); Assert.assertEquals("Turnout unknown state", Turnout.UNKNOWN, t.getState()); Assert.assertEquals("Light OFF state", Light.OFF, l.getState()); // lights are OFF by default t.setState(Turnout.THROWN); Assert.assertEquals("Light ON state", Light.ON, l.getState()); t.setState(Turnout.CLOSED); Assert.assertEquals("Light OFF state", Light.OFF, l.getState()); t.setState(Turnout.THROWN); Assert.assertEquals("Light ON state", Light.ON, l.getState()); t.setState(Turnout.UNKNOWN); Assert.assertEquals("Light ON state", Light.ON, l.getState()); t.setState(Turnout.CLOSED); Assert.assertEquals("Light OFF state", Light.OFF, l.getState()); l.deactivateLight(); Assert.assertEquals("releases turnout listener", startListeners, t.getPropertyChangeListeners().length); lc.setControlTurnoutState(Turnout.CLOSED); l.activateLight(); Assert.assertEquals("Activation polls the Turnout", Light.ON, l.getState()); t.setState(Turnout.THROWN); Assert.assertEquals("Light OFF state", Light.OFF, l.getState()); t.setState(Turnout.CLOSED); Assert.assertEquals("Light ON state", Light.ON, l.getState()); l.setEnabled(false); t.setState(Turnout.THROWN); Assert.assertEquals("does not update when light not enabled", Light.ON, l.getState()); } @Test public void testFastClockFollowingOneControl() throws TimebaseRateException { Timebase timebase = InstanceManager.getDefault(Timebase.class); timebase.setRun(false); java.util.Calendar cal = new java.util.GregorianCalendar(); cal.set(2018, 1, 12, 2, 00, 00); // 02:00:00 timebase.setTime(cal.getTime()); Assert.assertEquals("OFF state by default", Light.OFF, l.getState()); // lights are OFF by default Assert.assertEquals("enabled by default", true, l.getEnabled()); // lights are enabled by default int startListeners = timebase.getMinuteChangeListeners().length; lc.setControlType(Light.FAST_CLOCK_CONTROL); lc.setFastClockControlSchedule(3, 0, 4, 0); // onHr, OnMin, OffHr, OffMin Assert.assertTrue("Total On Time",180==lc.getFastClockOnCombined()); Assert.assertTrue("Total Off Time",240==lc.getFastClockOffCombined()); l.addLightControl(lc); l.activateLight(); Assert.assertEquals("+1 listener", startListeners + 1, timebase.getMinuteChangeListeners().length); // JUnitUtil.waitFor(()->{return l.getState()==Light.OFF;},"Light goes OFF at 02:00"); Assert.assertEquals("OFF at 02:00 when control 03:00 - 04:00", Light.OFF, l.getState()); cal.set(2018, 1, 12, 2, 59, 00); // 02:59:00 timebase.setTime(cal.getTime()); Assert.assertEquals("OFF at 02:59 when control 03:00 - 04:00", Light.OFF, l.getState()); cal.set(2018, 1, 12, 3, 00, 00); // 03:00:00 timebase.setTime(cal.getTime()); Assert.assertEquals("ON at 03:00 when control 03:00 - 04:00", Light.ON, l.getState()); cal.set(2018, 1, 12, 3, 59, 00); // 03:59:00 timebase.setTime(cal.getTime()); Assert.assertEquals("ON at 03:59 when control 03:00 - 04:00", Light.ON, l.getState()); cal.set(2018, 1, 12, 4, 00, 00); // 04:00:00 timebase.setTime(cal.getTime()); Assert.assertEquals("OFF at 04:00 when control 03:00 - 04:00", Light.OFF, l.getState()); cal.set(2018, 1, 12, 4, 01, 00); // 04:01:00 timebase.setTime(cal.getTime()); Assert.assertEquals("OFF at 04:01 when control 03:00 - 04:00", Light.OFF, l.getState()); l.deactivateLight(); Assert.assertEquals("listener removed", startListeners, timebase.getMinuteChangeListeners().length); } @Test public void testFastClockFollowingOneControlStartOn() throws TimebaseRateException { Timebase timebase = InstanceManager.getDefault(Timebase.class); timebase.setRun(false); java.util.Calendar cal = new java.util.GregorianCalendar(); cal.set(2018, 1, 12, 21, 00, 00); // 21:00:00 timebase.setTime(cal.getTime()); Assert.assertEquals("OFF state by default", Light.OFF, l.getState()); // lights are OFF by default lc.setControlType(Light.FAST_CLOCK_CONTROL); lc.setFastClockControlSchedule(18, 0, 7, 0); // onHr, OnMin, OffHr, OffMin l.addLightControl(lc); l.activateLight(); Assert.assertEquals("ON when starting at 21:00 control 18:00 - 07:00", Light.ON, l.getState()); l.setState(Light.OFF); Assert.assertEquals("goes OFF when set by something else", Light.OFF, l.getState()); cal.set(2018, 1, 12, 21, 01, 00); // 21:01:00 timebase.setTime(cal.getTime()); Assert.assertEquals("goes back ON on next minute update", Light.ON, l.getState()); l.setEnabled(false); cal.set(2018, 1, 12, 7, 59, 00); // 07:59:00 timebase.setTime(cal.getTime()); Assert.assertEquals("Light still on", Light.ON, l.getState()); cal.set(2018, 1, 12, 8, 00, 00); // 08:00:00 timebase.setTime(cal.getTime()); Assert.assertEquals("Light still on as not enabled", Light.ON, l.getState()); l.setEnabled(true); cal.set(2018, 1, 12, 8, 01, 00); // 08:01:00 timebase.setTime(cal.getTime()); Assert.assertEquals("Light goes off on next update re-enabled", Light.OFF, l.getState()); } @Test public void testFastClockFollowingTwoControls() throws TimebaseRateException { Timebase timebase = InstanceManager.getDefault(Timebase.class); timebase.setRun(false); java.util.Calendar cal = new java.util.GregorianCalendar(); cal.set(2018, 1, 12, 21, 00, 00); // 21:00:00 timebase.setTime(cal.getTime()); Assert.assertEquals("OFF state by default", Light.OFF, l.getState()); // lights are OFF by default lc.setControlType(Light.FAST_CLOCK_CONTROL); lc.setFastClockControlSchedule(3, 0, 4, 0); // onHr, OnMin, OffHr, OffMin LightControl lcb = new DefaultLightControl(l); lcb.setControlType(Light.FAST_CLOCK_CONTROL); lcb.setFastClockControlSchedule(5, 0, 6, 0); // onHr, OnMin, OffHr, OffMin l.addLightControl(lc); l.addLightControl(lcb); l.activateLight(); Assert.assertEquals("OFF starting at 21:00 controls 03:00-04:00, 05:00-06:00", Light.OFF, l.getState()); // adding the PCL to check that we don't get flickering on the Light // ie "normal" amount of PCEvents for a state change. // NOT testing the actual PCListeners l.addPropertyChangeListener(new ControlListen()); cal.set(2018, 1, 12, 2, 59, 00); // 02:59:00 timebase.setTime(cal.getTime()); Assert.assertEquals("still OFF", Light.OFF, l.getState()); Assert.assertEquals("0 Light PropertyChangeEvents", 0, _listenerkicks); cal.set(2018, 1, 12, 3, 00, 00); // 03:00:00 timebase.setTime(cal.getTime()); // JUnitUtil.waitFor(()->{return l.getState()==Light.ON;},"Light goes ON at 03:00"); Assert.assertEquals("goes ON", Light.ON, l.getState()); // At time of writing there are 2 PCE's on Light state change // "TargetIntensity" and "KnownState" Assert.assertEquals("2 Light PropertyChangeEvents", 2, _listenerkicks); cal.set(2018, 1, 12, 3, 59, 00); // 03:59:00 timebase.setTime(cal.getTime()); Assert.assertEquals("still ON", Light.ON, l.getState()); Assert.assertEquals("2 Light PropertyChangeEvents", 2, _listenerkicks); cal.set(2018, 1, 12, 4, 00, 00); // 04:00:00 timebase.setTime(cal.getTime()); Assert.assertEquals("goes OFF", Light.OFF, l.getState()); Assert.assertEquals("4 Light PropertyChangeEvents", 4, _listenerkicks); cal.set(2018, 1, 12, 4, 59, 00); // 04:00:00 timebase.setTime(cal.getTime()); Assert.assertEquals("still OFF", Light.OFF, l.getState()); Assert.assertEquals("4 Light PropertyChangeEvents", 4, _listenerkicks); cal.set(2018, 1, 12, 5, 00, 00); // 05:00:00 timebase.setTime(cal.getTime()); Assert.assertEquals("goes ON", Light.ON, l.getState()); Assert.assertEquals("6 Light PropertyChangeEvents", 6, _listenerkicks); cal.set(2018, 1, 12, 5, 59, 00); // 05:59:00 timebase.setTime(cal.getTime()); Assert.assertEquals("still ON", Light.ON, l.getState()); Assert.assertEquals("6 Light PropertyChangeEvents", 6, _listenerkicks); cal.set(2018, 1, 12, 6, 00, 00); // 06:00:00 timebase.setTime(cal.getTime()); Assert.assertEquals("goes OFF", Light.OFF, l.getState()); Assert.assertEquals("8 Light PropertyChangeEvents for 4 actual changes", 8, _listenerkicks); } @Test public void testFastClockFollowingTwoControlsOverlap() throws TimebaseRateException { Timebase timebase = InstanceManager.getDefault(Timebase.class); timebase.setRun(false); java.util.Calendar cal = new java.util.GregorianCalendar(); cal.set(2018, 1, 12, 02, 59, 00); // 02:59:00 timebase.setTime(cal.getTime()); lc.setControlType(Light.FAST_CLOCK_CONTROL); lc.setFastClockControlSchedule(3, 0, 4, 0); // onHr, OnMin, OffHr, OffMin LightControl lcb = new DefaultLightControl(l); lcb.setControlType(Light.FAST_CLOCK_CONTROL); lcb.setFastClockControlSchedule(3, 30, 4, 30); // onHr, OnMin, OffHr, OffMin Assert.assertTrue("Total On Time",210==lcb.getFastClockOnCombined()); Assert.assertTrue("Total Off Time",270==lcb.getFastClockOffCombined()); l.addLightControl(lc); l.addLightControl(lcb); l.activateLight(); Assert.assertEquals("OFF starting at 02:59 controls 03:00-04:00, 03:30-04:30", Light.OFF, l.getState()); // adding the PCL to check that we don't get flickering on the Light // ie "normal" amount of PCEvents for a state change. // NOT testing the actual PCListeners l.addPropertyChangeListener(new ControlListen()); cal.set(2018, 1, 12, 3, 00, 00); // 03:00:00 timebase.setTime(cal.getTime()); Assert.assertEquals("goes ON", Light.ON, l.getState()); Assert.assertEquals("2 Light PropertyChangeEvents", 2, _listenerkicks); cal.set(2018, 1, 12, 3, 29, 00); // 03:29:00 timebase.setTime(cal.getTime()); Assert.assertEquals("still ON", Light.ON, l.getState()); Assert.assertEquals("2 Light PropertyChangeEvents", 2, _listenerkicks); cal.set(2018, 1, 12, 3, 30, 00); // 03:30:00 timebase.setTime(cal.getTime()); Assert.assertEquals("still ON", Light.ON, l.getState()); Assert.assertEquals("2 Light PropertyChangeEvents", 2, _listenerkicks); cal.set(2018, 1, 12, 3, 59, 00); // 03:59:00 timebase.setTime(cal.getTime()); Assert.assertEquals("still ON", Light.ON, l.getState()); Assert.assertEquals("2 Light PropertyChangeEvents", 2, _listenerkicks); cal.set(2018, 1, 12, 4, 00, 00); // 04:00:00 timebase.setTime(cal.getTime()); Assert.assertEquals("goes OFF", Light.OFF, l.getState()); Assert.assertEquals("4 Light PropertyChangeEvents for 2 actual changes", 4, _listenerkicks); cal.set(2018, 1, 12, 4, 29, 00); // 04:29:00 timebase.setTime(cal.getTime()); Assert.assertEquals("still OFF", Light.OFF, l.getState()); Assert.assertEquals("4 Light PropertyChangeEvents for 2 actual changes", 4, _listenerkicks); cal.set(2018, 1, 12, 4, 30, 00); // 06:00:00 timebase.setTime(cal.getTime()); Assert.assertEquals("still OFF", Light.OFF, l.getState()); Assert.assertEquals("4 Light PropertyChangeEvents for 2 actual changes", 4, _listenerkicks); cal.set(2018, 1, 12, 4, 31, 00); // 04:31:00 timebase.setTime(cal.getTime()); Assert.assertEquals("still OFF", Light.OFF, l.getState()); Assert.assertEquals("4 Light PropertyChangeEvents for 2 actual changes", 4, _listenerkicks); } @Test public void testTimedSensorFollowing() throws jmri.JmriException { Assume.assumeFalse("Ignoring intermittent test", Boolean.getBoolean("jmri.skipTestsRequiringSeparateRunning")); Sensor s = InstanceManager.getDefault(jmri.SensorManager.class).provideSensor("S2"); int startListeners = s.getPropertyChangeListeners().length; lc.setControlType(Light.TIMED_ON_CONTROL); lc.setControlTimedOnSensorName("S2"); l.setState(Light.ON); // should go OFF when light enabled and Timed Sensor Control activated // adding the PCL to check the Light changes // ie "normal" amount of PCEvents for a state change. // NOT testing the actual PCListeners l.addPropertyChangeListener(new ControlListen()); l.addLightControl(lc); l.activateLight(); Assert.assertEquals("+1 listener", startListeners + 1, s.getPropertyChangeListeners().length); Assert.assertEquals("Sensor unknown state", Sensor.UNKNOWN, s.getState()); Assert.assertEquals("Light OFF state", Light.OFF, l.getState()); // light set OFF by default Assert.assertEquals("2 Light PropertyChangeEvents", 2, _listenerkicks); s.setState(Sensor.ON); JUnitUtil.waitFor(() -> { return 6 == _listenerkicks; }, "Light goes ON, then OFF v quickly as time is 0"); Assert.assertEquals("Light OFF state", Light.OFF, l.getState()); // light set OFF after timeout s.setState(Sensor.OFF); Assert.assertEquals("still 6 Light PropertyChangeEvents", 6, _listenerkicks); l.deactivateLight(); Assert.assertEquals("releases listener", startListeners, s.getPropertyChangeListeners().length); lc.setTimedOnDuration(40); // ms l.activateLight(); s.setState(Sensor.ON); s.setState(Sensor.OFF); Assert.assertEquals("Light goes ON at start timer", Light.ON, l.getState()); Assert.assertEquals("8 Light PropertyChangeEvents", 8, _listenerkicks); JUnitUtil.waitFor(() -> { return Light.OFF == l.getState(); }, "Light goes back OFF after timer"); Assert.assertEquals("10 Light PropertyChangeEvents", 10, _listenerkicks); l.setEnabled(false); s.setState(Sensor.ON); s.setState(Sensor.OFF); Assert.assertEquals("Light not enabled", Light.OFF, l.getState()); l.deactivateLight(); l.setState(Light.ON); l.activateLight(); Assert.assertEquals("Light not enabled so not switched off", Light.ON, l.getState()); l.deactivateLight(); // deactivate light mid-timing l.setEnabled(true); lc.setTimedOnDuration(4000); // ms l.activateLight(); Assert.assertEquals("Light enabled", Light.OFF, l.getState()); s.setState(Sensor.ON); s.setState(Sensor.OFF); Assert.assertEquals("Light triggered", Light.ON, l.getState()); l.deactivateLight(); Assert.assertEquals("Light still on", Light.ON, l.getState()); l.activateLight(); Assert.assertEquals("Light enabled", Light.OFF, l.getState()); lc.activateLightControl(); Assert.assertEquals("Light still off", Light.OFF, l.getState()); } @Test public void testNoTimedSensor() { lc.setControlType(Light.TIMED_ON_CONTROL); l.addLightControl(lc); l.activateLight(); JUnitAppender.assertErrorMessage("Light ILL1 is linked to a Sensor that does not exist:"); } @Test public void testTwoSensorFollowingNoSensorSet() { lc.setControlType(Light.TWO_SENSOR_CONTROL); lc.setControlSensorName(""); lc.setControlSensor2Name(""); l.addLightControl(lc); l.activateLight(); JUnitAppender.assertErrorMessage("Light ILL1 with 2 Sensor Control is linked to a Sensor that does not exist."); lc.setControlSensorName("S1"); lc.setControlSensor2Name(""); l.activateLight(); JUnitAppender.assertErrorMessage("Light ILL1 with 2 Sensor Control is linked to a Sensor that does not exist."); lc.setControlSensorName(""); lc.setControlSensor2Name("S2"); l.activateLight(); JUnitAppender.assertErrorMessage("Light ILL1 with 2 Sensor Control is linked to a Sensor that does not exist."); lc.setControlSensorSense(999); JUnitAppender.assertErrorMessage("Incorrect Sensor State Set"); } @Test public void testTwoSensorFollowing() throws jmri.JmriException { Sensor sOne = InstanceManager.getDefault(jmri.SensorManager.class).provideSensor("S1"); Sensor sTwo = InstanceManager.getDefault(jmri.SensorManager.class).provideSensor("S2"); lc.setControlType(Light.TWO_SENSOR_CONTROL); lc.setControlSensorName("S1"); lc.setControlSensor2Name("S2"); lc.setControlSensorSense(Sensor.ACTIVE); int startListenersOne = sOne.getPropertyChangeListeners().length; int startListenersTwo = sTwo.getPropertyChangeListeners().length; l.addLightControl(lc); l.activateLight(); Assert.assertEquals("+1 listener", startListenersOne + 1, sOne.getPropertyChangeListeners().length); Assert.assertEquals("+1 listener", startListenersTwo + 1, sTwo.getPropertyChangeListeners().length); Assert.assertEquals("Sensor unknown state", Sensor.UNKNOWN, sOne.getState()); Assert.assertEquals("Sensor unknown state", Sensor.UNKNOWN, sTwo.getState()); Assert.assertEquals("Light OFF state", Light.OFF, l.getState()); // lights are OFF by default sOne.setState(Sensor.ON); Assert.assertEquals("Light ON state", Light.ON, l.getState()); sOne.setState(Sensor.OFF); Assert.assertEquals("Light OFF state", Light.OFF, l.getState()); sTwo.setState(Sensor.ON); Assert.assertEquals("Light ON state", Light.ON, l.getState()); sTwo.setState(Sensor.OFF); Assert.assertEquals("Light OFF state", Light.OFF, l.getState()); sOne.setState(Sensor.ON); sTwo.setState(Sensor.ON); Assert.assertEquals("Light ON state", Light.ON, l.getState()); sOne.setState(Sensor.OFF); Assert.assertEquals("Light ON state as Stwo still ACTIVE", Light.ON, l.getState()); sOne.setState(Sensor.ON); sTwo.setState(Sensor.OFF); Assert.assertEquals("Light ON state as sOne still ACTIVE", Light.ON, l.getState()); sOne.setState(Sensor.OFF); Assert.assertEquals("Light OFF state", Light.OFF, l.getState()); l.deactivateLight(); Assert.assertEquals("releases listener", startListenersOne, sOne.getPropertyChangeListeners().length); Assert.assertEquals("releases listener", startListenersTwo, sTwo.getPropertyChangeListeners().length); sOne.setState(Sensor.ON); Assert.assertEquals("Light OFF state", Light.OFF, l.getState()); l.activateLight(); Assert.assertEquals("Light ON state", Light.ON, l.getState()); l.setEnabled(false); sOne.setState(Sensor.OFF); Assert.assertEquals("does not change", Light.ON, l.getState()); } @Test public void testTwoSensorFollowingInactive() throws jmri.JmriException { Sensor sOne = InstanceManager.getDefault(jmri.SensorManager.class).provideSensor("S1"); Sensor sTwo = InstanceManager.getDefault(jmri.SensorManager.class).provideSensor("S2"); lc.setControlType(Light.TWO_SENSOR_CONTROL); lc.setControlSensorName("S1"); lc.setControlSensor2Name("S2"); lc.setControlSensorSense(Sensor.INACTIVE); l.addLightControl(lc); l.activateLight(); // adding the PCL to check the Light changes // ie "normal" amount of PCEvents for a state change. // NOT testing the actual PCListeners l.addPropertyChangeListener(new ControlListen()); Assert.assertEquals("Sensor unknown state", Sensor.UNKNOWN, sOne.getState()); Assert.assertEquals("Sensor unknown state", Sensor.UNKNOWN, sTwo.getState()); Assert.assertEquals("Light OFF state", Light.OFF, l.getState()); // lights are OFF by default sOne.setState(Sensor.ACTIVE); sTwo.setState(Sensor.ACTIVE); Assert.assertEquals("Light OFF state", Light.OFF, l.getState()); Assert.assertEquals("0 Light PropertyChangeEvents", 0, _listenerkicks); sOne.setState(Sensor.INACTIVE); Assert.assertEquals("Light ON state", Light.ON, l.getState()); Assert.assertEquals("2 Light PropertyChangeEvents", 2, _listenerkicks); sTwo.setState(Sensor.INACTIVE); Assert.assertEquals("Light ON state", Light.ON, l.getState()); Assert.assertEquals("2 Light PropertyChangeEvents", 2, _listenerkicks); sOne.setState(Sensor.ACTIVE); Assert.assertEquals("Light ON state", Light.ON, l.getState()); Assert.assertEquals("2 Light PropertyChangeEvents", 2, _listenerkicks); sOne.setState(Sensor.ACTIVE); sTwo.setState(Sensor.INACTIVE); Assert.assertEquals("Light ON state", Light.ON, l.getState()); Assert.assertEquals("2 Light PropertyChangeEvents", 2, _listenerkicks); sTwo.setState(Sensor.ACTIVE); Assert.assertEquals("Light OFF state", Light.OFF, l.getState()); Assert.assertEquals("4 Light PropertyChangeEvents, 2 actual changes", 4, _listenerkicks); } @Test public void testUniqueTimes() { lc.setControlType(Light.FAST_CLOCK_CONTROL); lc.setFastClockControlSchedule(0, 0, 0, 0); // onHr, OnMin, OffHr, OffMin Assert.assertTrue(lc.onOffTimesFaulty()); lc.setFastClockControlSchedule(1, 2, 3, 4); // onHr, OnMin, OffHr, OffMin Assert.assertFalse(lc.onOffTimesFaulty()); LightControl lcb = new DefaultLightControl(l); lcb.setControlType(Light.FAST_CLOCK_CONTROL); lcb.setFastClockControlSchedule(1, 2, 0, 0); // onHr, OnMin, OffHr, OffMin l.addLightControl(lc); Assert.assertFalse(lc.areFollowerTimesFaulty(l.getLightControlList())); l.addLightControl(lcb); Assert.assertTrue(lcb.areFollowerTimesFaulty(l.getLightControlList())); lcb.setFastClockControlSchedule(0, 0, 0, 0); // onHr, OnMin, OffHr, OffMin Assert.assertTrue(lcb.areFollowerTimesFaulty(l.getLightControlList())); lcb.setFastClockControlSchedule(9, 0, 10, 0); // onHr, OnMin, OffHr, OffMin Assert.assertFalse(lcb.areFollowerTimesFaulty(l.getLightControlList())); lcb.setFastClockControlSchedule(0, 0, 3, 4); // onHr, OnMin, OffHr, OffMin Assert.assertTrue(lcb.areFollowerTimesFaulty(l.getLightControlList())); l.activateLight(); JUnitAppender.assertErrorMessage("Light has multiple actions for the same time in Light Controller ILL1 ON at 01:02, OFF at 03:04."); JUnitAppender.assertErrorMessage("Light has multiple actions for the same time in Light Controller ILL1 ON at 00:00, OFF at 03:04."); } private int _listenerkicks; // internal PCL event counter private class ControlListen implements java.beans.PropertyChangeListener { @Override public void propertyChange(java.beans.PropertyChangeEvent e) { _listenerkicks++; // log.warn("{}",e); } } private Light l; private LightControl lc; @BeforeEach public void setUp() { JUnitUtil.setUp(); jmri.util.JUnitUtil.resetInstanceManager(); jmri.util.JUnitUtil.initInternalTurnoutManager(); jmri.util.JUnitUtil.initInternalLightManager(); jmri.util.JUnitUtil.initInternalSensorManager(); _listenerkicks = 0; l = InstanceManager.getDefault(jmri.LightManager.class).provideLight("L1"); lc = new DefaultLightControl(l); } @AfterEach public void tearDown() { JUnitUtil.tearDown(); l.deactivateLight(); l.dispose(); l = null; lc = null; } // private static final Logger log = LoggerFactory.getLogger(LightControlTest.class); }