package jmri.jmrix.dccpp; import jmri.util.JUnitUtil; import jmri.util.junit.annotations.*; import jmri.util.JUnitAppender; import java.util.ArrayList; import java.util.LinkedHashMap; import org.junit.Assert; import org.junit.jupiter.api.*; /** * DCCppReplyTest.java *

* Test for the jmri.jmrix.dccpp.DCCppReply class * * @author Bob Jacobsen * @author Mark Underwood (C) 2015 * @author mstevetodd (C) 2021 */ public class DCCppReplyTest extends jmri.jmrix.AbstractMessageTestBase { private DCCppReply msg = null; // Test the string constructor. @Test public void testStringCtor() { msg = DCCppReply.parseDCCppReply("H 23 1"); Assert.assertEquals("length", 6, msg.getNumDataElements()); Assert.assertEquals("0th byte", 'H', msg.getElement(0) & 0xFF); Assert.assertEquals("1st byte", ' ', msg.getElement(1) & 0xFF); Assert.assertEquals("2nd byte", '2', msg.getElement(2) & 0xFF); Assert.assertEquals("3rd byte", '3', msg.getElement(3) & 0xFF); Assert.assertEquals("4th byte", ' ', msg.getElement(4) & 0xFF); Assert.assertEquals("5th byte", '1', msg.getElement(5) & 0xFF); } // check is direct mode response @Test public void testIsDirectModeResponse() { // CV 1 in direct mode. DCCppReply r = DCCppReply.parseDCCppReply("r 1234|87|23 12"); Assert.assertTrue(r.isProgramReply()); r = DCCppReply.parseDCCppReply("r 1234|66|23 4 1"); Assert.assertTrue(r.isProgramBitReply()); r = DCCppReply.parseDCCppReply("r 1234|82|23 4"); Assert.assertTrue(r.isProgramReply()); } // check get service mode CV Number response code. @Test @NotApplicable("Method under test is not implemented for DCC++") public void testGetServiceModeCVNumber() { } // check get service mode CV Value response code. @Test @NotApplicable("Method under test is not implemented for DCC++") public void testGetServiceModeCVValue() { } // Test Comm Type Reply @Test public void testCommTypeReply() { DCCppReply l = DCCppReply.parseDCCppReply("N0: SERIAL"); Assert.assertTrue(l.isCommTypeReply()); Assert.assertEquals('N', l.getOpCodeChar()); Assert.assertEquals(0, l.getCommTypeInt()); Assert.assertEquals("SERIAL", l.getCommTypeValueString()); l = DCCppReply.parseDCCppReply("N1: 192.168.0.1"); Assert.assertTrue(l.isCommTypeReply()); Assert.assertEquals('N', l.getOpCodeChar()); Assert.assertEquals(1, l.getCommTypeInt()); Assert.assertEquals("192.168.0.1", l.getCommTypeValueString()); l = DCCppReply.parseDCCppReply("N1: 192.168.0.1 XYZ 123"); //should ignore undefined values Assert.assertTrue(l.isCommTypeReply()); Assert.assertEquals('N', l.getOpCodeChar()); Assert.assertEquals(1, l.getCommTypeInt()); Assert.assertEquals("192.168.0.1", l.getCommTypeValueString()); } // Test power replies @Test public void testNamedPowerDistrictReply() { DCCppReply l = DCCppReply.parseDCCppReply("p 0 MAIN"); Assert.assertTrue(l.isNamedPowerReply()); Assert.assertEquals('p', l.getOpCodeChar()); Assert.assertEquals("MAIN", l.getPowerDistrictName()); Assert.assertEquals("OFF", l.getPowerDistrictStatus()); l = DCCppReply.parseDCCppReply("p 1 MAIN"); Assert.assertTrue(l.isNamedPowerReply()); Assert.assertEquals('p', l.getOpCodeChar()); Assert.assertEquals("MAIN", l.getPowerDistrictName()); Assert.assertEquals("ON", l.getPowerDistrictStatus()); l = DCCppReply.parseDCCppReply("p 2 MAIN"); Assert.assertTrue(l.isNamedPowerReply()); Assert.assertEquals('p', l.getOpCodeChar()); Assert.assertEquals("MAIN", l.getPowerDistrictName()); Assert.assertEquals("OVERLOAD", l.getPowerDistrictStatus()); l = DCCppReply.parseDCCppReply("p 1 MAIN XYZ 123"); //should ignore undefined values Assert.assertTrue(l.isNamedPowerReply()); Assert.assertEquals('p', l.getOpCodeChar()); Assert.assertEquals("MAIN", l.getPowerDistrictName()); Assert.assertEquals("ON", l.getPowerDistrictStatus()); l = DCCppReply.parseDCCppReply("p1 MAIN"); Assert.assertTrue(l.isNamedPowerReply()); Assert.assertEquals('p', l.getOpCodeChar()); Assert.assertEquals("MAIN", l.getPowerDistrictName()); Assert.assertEquals("ON", l.getPowerDistrictStatus()); l = DCCppReply.parseDCCppReply("p1"); Assert.assertTrue(l.isPowerReply()); Assert.assertFalse(l.isNamedPowerReply()); Assert.assertTrue(l.getPowerBool()); l = DCCppReply.parseDCCppReply("p0"); Assert.assertFalse(l.getPowerBool()); l = DCCppReply.parseDCCppReply("p 0"); Assert.assertFalse(l.getPowerBool()); l = DCCppReply.parseDCCppReply("p 1"); Assert.assertTrue(l.getPowerBool()); } // Test Meter replies @Test public void testMeterReply() { DCCppReply r = DCCppReply.parseDCCppReply("c MAINCurrent 1.7 C NoPrefix 0.0 100.0 0.1 80"); Assert.assertTrue(r.isMeterReply()); Assert.assertFalse(r.isCurrentReply()); Assert.assertFalse(r.isNamedCurrentReply()); Assert.assertEquals("MAINCurrent", r.getMeterName()); Assert.assertEquals(1.7, r.getMeterValue(), 0.00001); Assert.assertEquals(jmri.Meter.Unit.NoPrefix, r.getMeterUnit()); Assert.assertEquals(0.0, r.getMeterMinValue(), 0.00001); Assert.assertEquals(100.0, r.getMeterMaxValue(), 0.00001); Assert.assertEquals(0.1, r.getMeterResolution(), 0.00001); Assert.assertEquals(80.0, r.getMeterWarnValue(), 0.00001); Assert.assertFalse(r.isMeterTypeVolt()); Assert.assertTrue(r.isMeterTypeCurrent()); r = DCCppReply.parseDCCppReply("c CurrentMAIN -5 C Milli 0 4996 1 4996"); Assert.assertTrue(r.isMeterReply()); Assert.assertFalse(r.isCurrentReply()); Assert.assertFalse(r.isNamedCurrentReply()); Assert.assertEquals("CurrentMAIN", r.getMeterName()); Assert.assertEquals(-5, r.getMeterValue(), 0.00001); Assert.assertEquals(jmri.Meter.Unit.Milli, r.getMeterUnit()); Assert.assertEquals(0.0, r.getMeterMinValue(), 0.00001); Assert.assertEquals(4996.0, r.getMeterMaxValue(), 0.00001); Assert.assertEquals(1.0, r.getMeterResolution(), 0.00001); Assert.assertEquals(4996.0, r.getMeterWarnValue(), 0.00001); Assert.assertFalse(r.isMeterTypeVolt()); Assert.assertTrue(r.isMeterTypeCurrent()); r = DCCppReply.parseDCCppReply("c PROGVolts 18.2 V Milli 9.0 24.0 0.1 22.0"); Assert.assertEquals("PROGVolts", r.getMeterName()); Assert.assertEquals(18.2, r.getMeterValue(), 0.00001); Assert.assertEquals(jmri.Meter.Unit.Milli, r.getMeterUnit()); Assert.assertEquals(9.0, r.getMeterMinValue(), 0.00001); Assert.assertEquals(24.0, r.getMeterMaxValue(), 0.00001); Assert.assertEquals(0.1, r.getMeterResolution(), 0.00001); Assert.assertEquals(22.0, r.getMeterWarnValue(), 0.00001); Assert.assertTrue(r.isMeterTypeVolt()); Assert.assertFalse(r.isMeterTypeCurrent()); r = DCCppReply.parseDCCppReply("c testmeter99.99 12.34 C NoPrefix 0 99.99 0.01 77.77"); Assert.assertTrue(r.isMeterReply()); Assert.assertEquals("testmeter99.99", r.getMeterName()); Assert.assertEquals(12.34, r.getMeterValue(), 0.00001); Assert.assertEquals(jmri.Meter.Unit.NoPrefix, r.getMeterUnit()); Assert.assertEquals(0.0, r.getMeterMinValue(), 0.00001); Assert.assertEquals(99.99, r.getMeterMaxValue(), 0.00001); Assert.assertEquals(0.01, r.getMeterResolution(), 0.00001); Assert.assertEquals(77.77, r.getMeterWarnValue(), 0.00001); Assert.assertFalse(r.isMeterTypeVolt()); Assert.assertTrue(r.isMeterTypeCurrent()); r = DCCppReply.parseDCCppReply("c CurrentMAIN 19701 C Milli 0 -31744 1 -31744"); //sometimes returns negatives Assert.assertTrue(r.isMeterReply()); Assert.assertFalse(r.isCurrentReply()); Assert.assertFalse(r.isNamedCurrentReply()); Assert.assertEquals("CurrentMAIN", r.getMeterName()); Assert.assertEquals(19701.0, r.getMeterValue(), 0.00001); Assert.assertEquals(jmri.Meter.Unit.Milli, r.getMeterUnit()); Assert.assertEquals(0.0, r.getMeterMinValue(), 0.00001); Assert.assertEquals(-31744.0, r.getMeterMaxValue(), 0.00001); Assert.assertEquals(1.0, r.getMeterResolution(), 0.00001); Assert.assertEquals(-31744.0, r.getMeterWarnValue(), 0.00001); Assert.assertFalse(r.isMeterTypeVolt()); Assert.assertTrue(r.isMeterTypeCurrent()); r = DCCppReply.parseDCCppReply("c BadMeterType 0.3 X NoPrefix 0.0 5.0 0.01 5.0"); //bad meter type 'X' passed Assert.assertTrue( r.isMeterReply()); Assert.assertFalse(r.isMeterTypeCurrent()); JUnitAppender.assertWarnMessageStartingWith("Meter Type 'X' is not valid type in message 'c BadMeterType 0.3 X NoPrefix 0.0 5.0 0.01 5.0'"); Assert.assertFalse(r.isMeterTypeVolt()); JUnitAppender.assertWarnMessageStartingWith("Meter Type 'X' is not valid type in message 'c BadMeterType 0.3 X NoPrefix 0.0 5.0 0.01 5.0'"); Assert.assertEquals("", r.getMeterType()); //invalid meter types returned as empty string JUnitAppender.assertWarnMessageStartingWith("Meter Type 'X' is not valid type in message 'c BadMeterType 0.3 X NoPrefix 0.0 5.0 0.01 5.0'"); Assert.assertEquals(jmri.Meter.Unit.NoPrefix, r.getMeterUnit()); } // Test named and unnamed current replies @Test public void testNamedCurrentReply() { DCCppReply l = DCCppReply.parseDCCppReply("a MAIN 0"); Assert.assertTrue(l.isCurrentReply()); Assert.assertTrue(l.isNamedCurrentReply()); Assert.assertEquals('a', l.getOpCodeChar()); Assert.assertEquals("0", l.getCurrentString()); l = DCCppReply.parseDCCppReply("a MAIN 100"); Assert.assertTrue(l.isCurrentReply()); Assert.assertTrue(l.isNamedCurrentReply()); Assert.assertEquals('a', l.getOpCodeChar()); Assert.assertEquals("100", l.getCurrentString()); l = DCCppReply.parseDCCppReply("aMAIN0"); Assert.assertTrue(l.isCurrentReply()); Assert.assertTrue(l.isNamedCurrentReply()); Assert.assertEquals('a', l.getOpCodeChar()); Assert.assertEquals("0", l.getCurrentString()); l = DCCppReply.parseDCCppReply("aMAIN41"); Assert.assertTrue(l.isCurrentReply()); Assert.assertTrue(l.isNamedCurrentReply()); Assert.assertEquals('a', l.getOpCodeChar()); Assert.assertEquals("41", l.getCurrentString()); l = DCCppReply.parseDCCppReply("a MAIN 410"); Assert.assertTrue(l.isCurrentReply()); Assert.assertTrue(l.isNamedCurrentReply()); Assert.assertEquals('a', l.getOpCodeChar()); Assert.assertEquals("410", l.getCurrentString()); l = DCCppReply.parseDCCppReply("a41"); Assert.assertTrue(l.isCurrentReply()); Assert.assertFalse(l.isNamedCurrentReply()); Assert.assertEquals('a', l.getOpCodeChar()); Assert.assertEquals("41", l.getCurrentString()); l = DCCppReply.parseDCCppReply("a 41"); Assert.assertTrue(l.isCurrentReply()); Assert.assertFalse(l.isNamedCurrentReply()); Assert.assertEquals('a', l.getOpCodeChar()); Assert.assertEquals("41", l.getCurrentString()); l = DCCppReply.parseDCCppReply("a 1023 512 XYZ 512"); //should ignore undefined values Assert.assertTrue(l.isCurrentReply()); Assert.assertFalse(l.isNamedCurrentReply()); Assert.assertEquals('a', l.getOpCodeChar()); Assert.assertEquals("1023", l.getCurrentString()); l = DCCppReply.parseDCCppReply("a PROG 1024 512 512 512"); //should ignore undefined values Assert.assertTrue(l.isCurrentReply()); Assert.assertTrue(l.isNamedCurrentReply()); Assert.assertEquals('a', l.getOpCodeChar()); Assert.assertEquals("1024", l.getCurrentString()); } @Test public void testStatusReplies() { DCCppReply r = DCCppReply.parseDCCppReply( "iDCC-EX V-3.0.0 / FireBoxMK1 / FIREBOX_MK1 / G-9db6d36"); Assert.assertTrue(r.isStatusReply()); Assert.assertTrue(r.matches(DCCppConstants.STATUS_REPLY_DCCEX_REGEX)); Assert.assertEquals("3.0.0", r.getVersion()); Assert.assertEquals("9db6d36", r.getBuildString()); Assert.assertEquals("DCC-EX", r.getStationType()); r = DCCppReply.parseDCCppReply( "iDCC-EX V-5.4.4 / ESP32 / EXCSB1 G-c389fe9"); Assert.assertTrue(r.isStatusReply()); Assert.assertTrue(r.matches(DCCppConstants.STATUS_REPLY_DCCEX_REGEX)); Assert.assertEquals("5.4.4", r.getVersion()); Assert.assertEquals("c389fe9", r.getBuildString()); Assert.assertEquals("DCC-EX", r.getStationType()); r = DCCppReply.parseDCCppReply( "iDCC-EX V-5.0.0 / UNO / IoTT WiThServer 1.0.4 / STANDARD_MOTOR_SHIELD G-3bddf4d"); Assert.assertTrue(r.isStatusReply()); Assert.assertTrue(r.matches(DCCppConstants.STATUS_REPLY_DCCEX_REGEX)); Assert.assertEquals("5.0.0", r.getVersion()); Assert.assertEquals("3bddf4d", r.getBuildString()); Assert.assertEquals("DCC-EX", r.getStationType()); r = DCCppReply.parseDCCppReply( "iDCC++ BASE STATION FOR ARDUINO MEGA / ARDUINO MOTOR SHIELD: BUILD 23 Feb 2015 09:23:57"); Assert.assertTrue(r.isStatusReply()); Assert.assertTrue(r.matches(DCCppConstants.STATUS_REPLY_REGEX)); Assert.assertEquals("0.0.0", r.getVersion()); Assert.assertEquals("23 Feb 2015 09:23:57", r.getBuildString()); Assert.assertEquals("DCC++ BASE STATION FOR ARDUINO MEGA / ARDUINO MOTOR SHIELD", r.getStationType()); r = DCCppReply.parseDCCppReply( "iDCC++ BASE STATION FOR ARDUINO MEGA / ARDUINO MOTOR SHIELD: V-1.2.1+ / Dec 22 2020 20:59:52"); Assert.assertTrue(r.isStatusReply()); Assert.assertEquals("1.2.1", r.getVersion()); Assert.assertEquals("Dec 22 2020 20:59:52", r.getBuildString()); Assert.assertEquals("DCC++ BASE STATION FOR ARDUINO MEGA / ARDUINO MOTOR SHIELD", r.getStationType()); } @Test public void testVariousReplies() { //Turnout replies DCCppReply r = DCCppReply.parseDCCppReply("H 23 24 2 0"); Assert.assertTrue(r.isTurnoutDefReply()); Assert.assertTrue(r.isTurnoutReply()); Assert.assertEquals(23, r.getTurnoutDefNumInt()); Assert.assertEquals(24, r.getTurnoutDefAddrInt()); Assert.assertEquals(2, r.getTurnoutDefSubAddrInt()); r = DCCppReply.parseDCCppReply("H 23 0"); Assert.assertTrue(r.isTurnoutReply()); Assert.assertFalse(r.isTurnoutDefReply()); Assert.assertEquals("CLOSED", r.getTOStateString()); Assert.assertEquals("23", r.getTOIDString()); Assert.assertEquals(23, r.getTOIDInt()); Assert.assertFalse(r.getTOIsThrown()); Assert.assertTrue(r.getTOIsClosed()); r = DCCppReply.parseDCCppReply("H 23 1"); Assert.assertEquals("THROWN", r.getTOStateString()); Assert.assertTrue(r.getTOIsThrown()); Assert.assertFalse(r.getTOIsClosed()); //RosterID replies r = DCCppReply.parseDCCppReply("jR 1 2 3 4"); Assert.assertTrue(r.isRosterIDsReply()); r = DCCppReply.parseDCCppReply("jR 123 \"desc\" \"fkeys go here\""); Assert.assertTrue(r.isRosterIDReply()); //AutomationID replies r = DCCppReply.parseDCCppReply("jA 4 3 2 1"); Assert.assertTrue(r.isAutomationIDsReply()); r = DCCppReply.parseDCCppReply("jA 456 R \"description\""); Assert.assertTrue(r.isAutomationIDReply()); r = DCCppReply.parseDCCppReply("jB 123 3"); Assert.assertTrue(r.isAutomationStateReply()); r = DCCppReply.parseDCCppReply("jB 123 \"description\""); Assert.assertTrue(r.isAutomationCaptionReply()); r = DCCppReply.parseDCCppReply("jB -123 3"); Assert.assertTrue(r.isAutomationStateReply()); r = DCCppReply.parseDCCppReply("jB -123 \"description\""); Assert.assertTrue(r.isAutomationCaptionReply()); r = DCCppReply.parseDCCppReply("jB 123 X"); Assert.assertFalse(r.isAutomationStateReply()); r = DCCppReply.parseDCCppReply("jB 123 1 \"description\""); Assert.assertFalse(r.isAutomationCaptionReply()); //max Num Slots r = DCCppReply.parseDCCppReply("# 50"); Assert.assertTrue(r.isMaxNumSlotsReply()); //DIAG message r = DCCppReply.parseDCCppReply("* this is a test diagnostic message 12345 *"); Assert.assertTrue(r.isDiagReply()); r = DCCppReply.parseDCCppReply("* this is not, missing trailing asterisk "); Assert.assertFalse(r.isDiagReply()); //Sensor replies r = DCCppReply.parseDCCppReply("Q 22 33 0"); Assert.assertTrue(r.isSensorReply()); Assert.assertTrue(r.isSensorDefReply()); Assert.assertEquals("22", r.getSensorDefNumString()); Assert.assertEquals(22, r.getSensorDefNumInt()); Assert.assertEquals(33, r.getSensorDefPinInt()); Assert.assertFalse(r.getSensorDefPullupBool()); r = DCCppReply.parseDCCppReply("Q 22 33 1"); Assert.assertTrue(r.getSensorDefPullupBool()); r = DCCppReply.parseDCCppReply("Q 123"); Assert.assertTrue(r.isSensorReply()); Assert.assertFalse(r.isSensorDefReply()); Assert.assertEquals(123, r.getSensorNumInt()); Assert.assertEquals("Active", r.getSensorStateString()); Assert.assertTrue(r.getSensorIsActive()); r = DCCppReply.parseDCCppReply("q 124"); Assert.assertTrue(r.isSensorReply()); Assert.assertFalse(r.isSensorDefReply()); Assert.assertEquals(124, r.getSensorNumInt()); Assert.assertTrue(r.getSensorIsInactive()); //Output replies r = DCCppReply.parseDCCppReply("Y 123 44 111 1"); Assert.assertTrue(r.isOutputDefReply()); Assert.assertEquals("123", r.getOutputNumString()); Assert.assertEquals(123, r.getOutputNumInt()); Assert.assertEquals(44, r.getOutputListPinInt()); Assert.assertEquals(111, r.getOutputListIFlagInt()); Assert.assertEquals(1, r.getOutputListStateInt()); //EEPROM reply r = DCCppReply.parseDCCppReply("e 12 34 56"); Assert.assertTrue(r.isWriteEepromReply()); //Throttle Command replies r = DCCppReply.parseDCCppReply("jT 123 456 789"); Assert.assertTrue(r.isTurnoutIDsReply()); Assert.assertFalse(r.isTurnoutIDReply()); Assert.assertEquals(789, (int) r.getTurnoutIDList().get(2)); Assert.assertEquals(3, r.getTurnoutIDList().size()); Assert.assertEquals("Monitor string", "Turnout IDs:[123, 456, 789]", r.toMonitorString()); r = DCCppReply.parseDCCppReply("jT 123 C \"turnout description\""); Assert.assertTrue(r.isTurnoutIDReply()); Assert.assertFalse(r.isTurnoutIDsReply()); Assert.assertEquals(123, r.getTOIDInt()); Assert.assertEquals("C", r.getTurnoutStateString()); Assert.assertEquals("turnout description", r.getTurnoutDescString()); Assert.assertEquals("Monitor string", "Turnout ID:123 State:C Desc:'turnout description'", r.toMonitorString()); r = DCCppReply.parseDCCppReply("jT 456 T \"\""); Assert.assertEquals("T", r.getTurnoutStateString()); Assert.assertEquals("", r.getTurnoutDescString()); Assert.assertEquals("Monitor string", "Turnout ID:456 State:T Desc:''", r.toMonitorString()); r = DCCppReply.parseDCCppReply("jT"); Assert.assertTrue(r.isTurnoutIDsReply()); Assert.assertEquals(0, r.getTurnoutIDList().size()); Assert.assertEquals("Monitor string", "Turnout IDs:[]", r.toMonitorString()); r = DCCppReply.parseDCCppReply("jR"); Assert.assertTrue(r.isRosterIDsReply()); Assert.assertEquals(0, r.getRosterIDList().size()); Assert.assertEquals("Monitor string", "RosterIDs:[]", r.toMonitorString()); r = DCCppReply.parseDCCppReply("jR 123 456 789"); Assert.assertTrue(r.isRosterIDsReply()); Assert.assertFalse(r.isRosterIDReply()); Assert.assertEquals(789, (int) r.getRosterIDList().get(2)); Assert.assertEquals(3, r.getRosterIDList().size()); Assert.assertEquals("Monitor string", "RosterIDs:[123, 456, 789]", r.toMonitorString()); r = DCCppReply.parseDCCppReply("jA"); Assert.assertTrue(r.isAutomationIDsReply()); Assert.assertEquals(0, r.getAutomationIDList().size()); Assert.assertEquals("Monitor string", "AutomationIDs:[]", r.toMonitorString()); r = DCCppReply.parseDCCppReply("jA 123 456 789"); Assert.assertTrue(r.isAutomationIDsReply()); Assert.assertFalse(r.isAutomationIDReply()); Assert.assertEquals(789, (int) r.getAutomationIDList().get(2)); Assert.assertEquals(3, r.getAutomationIDList().size()); Assert.assertEquals("Monitor string", "AutomationIDs:[123, 456, 789]", r.toMonitorString()); r = DCCppReply.parseDCCppReply("jG 123 456 789"); Assert.assertTrue(r.isCurrentMaxesReply()); Assert.assertFalse(r.isCurrentValuesReply()); Assert.assertEquals(789, (int) r.getCurrentMaxesList().get(2)); Assert.assertEquals(3, r.getCurrentMaxesList().size()); Assert.assertEquals("Monitor string", "CurrentMaxes:[123, 456, 789]", r.toMonitorString()); r = DCCppReply.parseDCCppReply("jI 123 456 789"); Assert.assertTrue(r.isCurrentValuesReply()); Assert.assertFalse(r.isCurrentMaxesReply()); Assert.assertEquals(789, (int) r.getCurrentValuesList().get(2)); Assert.assertEquals(3, r.getCurrentValuesList().size()); Assert.assertEquals("Monitor string", "CurrentValues:[123, 456, 789]", r.toMonitorString()); r = DCCppReply.parseDCCppReply("jI -1 -1"); Assert.assertTrue(r.isCurrentValuesReply()); Assert.assertEquals(-1, (int) r.getCurrentValuesList().get(0)); Assert.assertEquals(-1, (int) r.getCurrentValuesList().get(1)); Assert.assertEquals(2, r.getCurrentValuesList().size()); Assert.assertEquals("Monitor string", "CurrentValues:[-1, -1]", r.toMonitorString()); r = DCCppReply.parseDCCppReply("jC 222 4"); //time and rate Assert.assertTrue(r.isClockReply()); Assert.assertEquals(222, r.getClockMinutesInt()); Assert.assertEquals(4, r.getClockRateInt()); Assert.assertEquals("Monitor string", "FastClock Reply: 03:42, Rate:4", r.toMonitorString()); r = DCCppReply.parseDCCppReply("jC 333"); //just time Assert.assertTrue(r.isClockReply()); Assert.assertEquals(333, r.getClockMinutesInt()); Assert.assertEquals("Monitor string", "FastClock Reply: 05:33", r.toMonitorString()); //verify that bad syntax fails r = DCCppReply.parseDCCppReply("jT 123 456 789 xx"); Assert.assertFalse(r.isTurnoutIDsReply()); r = DCCppReply.parseDCCppReply("jT 123 X \"turnout description\""); Assert.assertFalse(r.isTurnoutIDReply()); r = DCCppReply.parseDCCppReply("jR 123 456 789 notint"); Assert.assertFalse(r.isRosterIDsReply()); r = DCCppReply.parseDCCppReply("jR 123 noquotes \"\\F1\\F2\\F3\\\""); Assert.assertFalse(r.isRosterIDReply()); r = DCCppReply.parseDCCppReply("jA 123 456 789 notint"); Assert.assertFalse(r.isAutomationIDsReply()); r = DCCppReply.parseDCCppReply("jA 123 toolong \"gooddescription\""); Assert.assertFalse(r.isAutomationIDReply()); r = DCCppReply.parseDCCppReply("jG 4998 4998 notint"); Assert.assertFalse(r.isCurrentMaxesReply()); r = DCCppReply.parseDCCppReply("jI 123 456 notint"); Assert.assertFalse(r.isCurrentValuesReply()); r = DCCppReply.parseDCCppReply("jC 222 4 xx"); //time and rate Assert.assertFalse(r.isClockReply()); r = DCCppReply.parseDCCppReply("jC x222 4 xx"); //time and rate Assert.assertFalse(r.isClockReply()); //TrackManager r = DCCppReply.parseDCCppReply("= B PROG 123"); Assert.assertTrue(r.isTrackManagerReply()); Assert.assertEquals(r.getTrackManagerLetter(), 'B'); Assert.assertEquals(r.getTrackManagerMode(), "PROG"); Assert.assertEquals("Monitor string", "TrackManager Letter:B Mode:PROG", r.toMonitorString()); //LCD message r = DCCppReply.parseDCCppReply("@ 0 12 \"this is a test lcd message 12345\""); Assert.assertTrue(r.isLCDTextReply()); Assert.assertEquals("this is a test lcd message 12345", r.getLCDTextString()); Assert.assertEquals(0, r.getLCDDisplayNumInt()); Assert.assertEquals(12, r.getLCDLineNumInt()); r = DCCppReply.parseDCCppReply("@ 12 \"this is not, missing display#\""); Assert.assertFalse(r.isLCDTextReply()); r = DCCppReply.parseDCCppReply("@ 0 4 \"123 456.789.001 test initial digits\""); Assert.assertTrue(r.isLCDTextReply()); Assert.assertEquals("123 456.789.001 test initial digits", r.getLCDTextString()); Assert.assertEquals(0, r.getLCDDisplayNumInt()); Assert.assertEquals(4, r.getLCDLineNumInt()); r = DCCppReply.parseDCCppReply("@ 0 4 test without quotes"); Assert.assertFalse(r.isLCDTextReply()); r = DCCppReply.parseDCCppReply("@ 0 4 \" test leading and trailing spaces \""); Assert.assertTrue(r.isLCDTextReply()); Assert.assertEquals(" test leading and trailing spaces ", r.getLCDTextString()); } @Test public void testMonitorStringCurrentReply() { DCCppReply l = DCCppReply.parseDCCppReply("a MAIN 0"); Assert.assertEquals("Named Current Monitor string", "Current: 0 / 1024", l.toMonitorString()); l = DCCppReply.parseDCCppReply("a 41"); Assert.assertEquals("Current Monitor string", "Current: 41 / 1024", l.toMonitorString()); } @Test public void testMonitorStringMeterReply() { DCCppReply l = DCCppReply.parseDCCppReply("c PROGVolts 18.2 V Percent 9.0 24.0 0.1 19"); Assert.assertEquals("Meter reply: name PROGVolts, value 18.20, type V, unit Percent, min 9.00, max 24.00, resolution 0.10, warn 19.00", l.toMonitorString()); Assert.assertTrue( l.isMeterReply()); Assert.assertTrue( l.isMeterTypeVolt()); Assert.assertFalse(l.isMeterTypeCurrent()); l = DCCppReply.parseDCCppReply("c MAINCurrent 0.3 C Kilo 0.0 5.0 0.01 4"); Assert.assertEquals("Meter reply: name MAINCurrent, value 0.30, type C, unit Kilo, min 0.00, max 5.00, resolution 0.01, warn 4.00", l.toMonitorString()); Assert.assertTrue( l.isMeterReply()); Assert.assertTrue( l.isMeterTypeCurrent()); Assert.assertFalse(l.isMeterTypeVolt()); } @Test public void testMonitorStringDiagReply() { DCCppReply l = DCCppReply.parseDCCppReply("* This is a test *"); Assert.assertEquals("Monitor string", "DIAG: This is a test ", l.toMonitorString()); l = DCCppReply.parseDCCppReply("*This is a test with a \nnewline*"); Assert.assertEquals("Monitor string", "DIAG: This is a test with a \nnewline", l.toMonitorString()); l = DCCppReply.parseDCCppReply("**"); Assert.assertEquals("Monitor string", "DIAG: ", l.toMonitorString()); l = DCCppReply.parseDCCppReply("*****"); Assert.assertEquals("Monitor string", "DIAG: ***", l.toMonitorString()); } @Test public void testMaxNumSlotsReply() { DCCppReply l = DCCppReply.parseDCCppReply("# 47"); Assert.assertEquals("Monitor string", "Number of slots reply: 47", l.toMonitorString()); } @Test public void testMonitorStringTurnoutReply() { DCCppReply l = DCCppReply.parseDCCppReply("H 1234 0"); Assert.assertEquals("Monitor string", "Turnout Reply: ID: 1234, Dir: CLOSED", l.toMonitorString()); Assert.assertFalse(l.getTOIsThrown()); Assert.assertTrue(l.getTOIsClosed()); l = DCCppReply.parseDCCppReply("H 1234 1"); Assert.assertEquals("Monitor string", "Turnout Reply: ID: 1234, Dir: THROWN", l.toMonitorString()); Assert.assertTrue(l.getTOIsThrown()); Assert.assertFalse(l.getTOIsClosed()); } @Test public void testTurnoutDefReplies() { DCCppReply l = DCCppReply.parseDCCppReply("H 23 DCC 5 0 1"); Assert.assertEquals("Monitor string", "Turnout Def DCC Reply: ID:23, Address:5, Index:0, DCC Address:17, Dir:THROWN", l.toMonitorString()); Assert.assertTrue(l.getTOIsThrown()); Assert.assertFalse(l.getTOIsClosed()); l = DCCppReply.parseDCCppReply("H 24 SERVO 100 410 205 2 1"); Assert.assertTrue(l.getTOIsThrown()); Assert.assertEquals("Monitor string", "Turnout Def SERVO Reply: ID:24, Pin:100, ThrownPos:410, ClosedPos:205, Profile:2, Dir:THROWN", l.toMonitorString()); l = DCCppReply.parseDCCppReply("H 1124 SERVO 100 410 205 2 0"); Assert.assertEquals("Monitor string", "Turnout Def SERVO Reply: ID:1124, Pin:100, ThrownPos:410, ClosedPos:205, Profile:2, Dir:CLOSED", l.toMonitorString()); Assert.assertTrue(l.getTOIsClosed()); l = DCCppReply.parseDCCppReply("H 12345 VPIN 50 1"); Assert.assertEquals("Monitor string", "Turnout Def VPIN Reply: ID:12345, Pin:50, Dir:THROWN", l.toMonitorString()); Assert.assertTrue(l.getTOIsThrown()); l = DCCppReply.parseDCCppReply("H 12345 VPIN 150 0"); Assert.assertEquals("Monitor string", "Turnout Def VPIN Reply: ID:12345, Pin:150, Dir:CLOSED", l.toMonitorString()); Assert.assertTrue(l.getTOIsClosed()); l = DCCppReply.parseDCCppReply("H 30000 LCN 0"); Assert.assertEquals("Monitor string", "Turnout Def LCN Reply: ID:30000, Dir:CLOSED", l.toMonitorString()); Assert.assertTrue(l.getTOIsClosed()); l = DCCppReply.parseDCCppReply("H 30001 LCN 1"); Assert.assertEquals("Monitor string", "Turnout Def LCN Reply: ID:30001, Dir:THROWN", l.toMonitorString()); Assert.assertTrue(l.getTOIsThrown()); l = DCCppReply.parseDCCppReply("H 12345 VPIN 150 0 ignore unexpected values at the end"); Assert.assertEquals("Monitor string", "Turnout Def VPIN Reply: ID:12345, Pin:150, Dir:CLOSED", l.toMonitorString()); Assert.assertTrue(l.getTOIsClosed()); } @Test public void testTurnoutDefProperties() { DCCppReply l = DCCppReply.parseDCCppReply("H 23 DCC 5 0 1"); Assert.assertEquals("Type:DCC,ID:23,Address:5,Index:0,DCC Address:17", l.getPropertiesAsString()); l = DCCppReply.parseDCCppReply("H 24 SERVO 100 410 205 2 1"); Assert.assertEquals("Type:SERVO,ID:24,Pin:100,ThrownPos:410,ClosedPos:205,Profile:2", l.getPropertiesAsString()); l = DCCppReply.parseDCCppReply("H 1124 SERVO 100 410 205 2 0"); Assert.assertEquals("Type:SERVO,ID:1124,Pin:100,ThrownPos:410,ClosedPos:205,Profile:2", l.getPropertiesAsString()); l = DCCppReply.parseDCCppReply("H 12345 VPIN 50 1"); Assert.assertEquals("Type:VPIN,ID:12345,Pin:50", l.getPropertiesAsString()); l = DCCppReply.parseDCCppReply("H 12345 VPIN 150 0"); Assert.assertEquals("Type:VPIN,ID:12345,Pin:150", l.getPropertiesAsString()); l = DCCppReply.parseDCCppReply("H 30000 LCN 0"); Assert.assertEquals("Type:LCN,ID:30000", l.getPropertiesAsString()); l = DCCppReply.parseDCCppReply("H 30001 LCN 1"); Assert.assertEquals("Type:LCN,ID:30001", l.getPropertiesAsString()); l = DCCppReply.parseDCCppReply("H 12345 VPIN 150 0 ignore unexpected values at the end"); Assert.assertEquals("Type:VPIN,ID:12345,Pin:150", l.getPropertiesAsString()); } @Test public void testOutputProperties() { DCCppReply r = DCCppReply.parseDCCppReply("Y 181 181 1 0"); LinkedHashMap p = r.getProperties(); Assert.assertEquals(4, p.size()); Assert.assertEquals("OUTPUT", p.get("Type")); Assert.assertEquals(181, p.get("ID")); Assert.assertEquals(181, p.get("Pin")); Assert.assertEquals(1, p.get("IFlag")); Assert.assertEquals("Type:OUTPUT,ID:181,Pin:181,IFlag:1", r.getPropertiesAsString()); } @Test public void testSensorProperties() { DCCppReply r = DCCppReply.parseDCCppReply("Q 111 222 0"); LinkedHashMap p = r.getProperties(); Assert.assertEquals(4, p.size()); Assert.assertEquals("SENSOR", p.get("Type")); Assert.assertEquals(111, p.get("ID")); Assert.assertEquals(222, p.get("Pin")); Assert.assertFalse((boolean) p.get("Pullup")); Assert.assertEquals("Type:SENSOR,ID:111,Pin:222,Pullup:false", r.getPropertiesAsString()); r = DCCppReply.parseDCCppReply("Q 111 222 1"); p = r.getProperties(); Assert.assertTrue((boolean) p.get("Pullup")); } @Test public void testTurnoutProperties() { DCCppReply r = DCCppReply.parseDCCppReply("H 23 DCC 5 0 1"); LinkedHashMap p = r.getProperties(); Assert.assertEquals(5, p.size()); Assert.assertEquals(23, p.get("ID")); Assert.assertEquals("DCC", p.get("Type")); Assert.assertEquals(5, p.get("Address")); Assert.assertEquals(0, p.get("Index")); Assert.assertEquals(17, p.get("DCC Address")); r = DCCppReply.parseDCCppReply("H 1124 SERVO 100 410 205 2 0"); p = r.getProperties(); Assert.assertEquals(6, p.size()); Assert.assertEquals(1124, p.get("ID")); Assert.assertEquals("SERVO", p.get("Type")); Assert.assertEquals(100, p.get("Pin")); Assert.assertEquals(410, p.get("ThrownPos")); Assert.assertEquals(205, p.get("ClosedPos")); Assert.assertEquals(2, p.get("Profile")); r = DCCppReply.parseDCCppReply("H 12345 VPIN 150 0"); p = r.getProperties(); Assert.assertEquals(3, p.size()); Assert.assertEquals(12345, p.get("ID")); Assert.assertEquals("VPIN", p.get("Type")); Assert.assertEquals(150, p.get("Pin")); r = DCCppReply.parseDCCppReply("H 30000 LCN 0"); p = r.getProperties(); Assert.assertEquals(2, p.size()); Assert.assertEquals(30000, p.get("ID")); Assert.assertEquals("LCN", p.get("Type")); } @Test public void testMonitorStringOutputPinReply() { DCCppReply l = DCCppReply.parseDCCppReply("Y 1234 0"); Assert.assertEquals("Monitor string", "Output Command Reply: Number: 1234, State: LOW", l.toMonitorString()); } @Test public void testMonitorStringSensorStatusReply() { DCCppReply l = DCCppReply.parseDCCppReply("Q 1234"); Assert.assertEquals("Monitor string", "Sensor Reply (Active): Number: 1234, State: ACTIVE", l.toMonitorString()); l = DCCppReply.parseDCCppReply("q 1234"); Assert.assertEquals("Monitor string", "Sensor Reply (Inactive): Number: 1234, State: INACTIVE", l.toMonitorString()); } @Test public void testMonitorStringCVWriteByteReply() { DCCppReply l = DCCppReply.parseDCCppReply("r 1234|4321|5 123"); Assert.assertEquals("Monitor string", "Program Reply: CallbackNum:1234, Sub:4321, CV:5, Value:123", l.toMonitorString()); l = DCCppReply.parseDCCppReply("r 5 123"); // Assert.assertEquals("Monitor string", "Program Reply: CV:5, Value:123", l.toMonitorString()); l = DCCppReply.parseDCCppReply("r 3 -1"); // Assert.assertEquals("Monitor string", "Program Reply: CV:3, Value:-1", l.toMonitorString()); } @Test public void testMonitorStringLocoIdReply() { DCCppReply l = DCCppReply.parseDCCppReply("r 456"); // Assert.assertEquals("Monitor string", "Program LocoId Reply: LocoId:456", l.toMonitorString()); l = DCCppReply.parseDCCppReply("r -1"); // (-1 for error) Assert.assertEquals("Monitor string", "Program LocoId Reply: LocoId:-1", l.toMonitorString()); } @Test public void testMonitorStringVerifyReply() { DCCppReply l = DCCppReply.parseDCCppReply("v 78 99"); // Assert.assertEquals("Monitor string", "Prog Verify Reply: CV: 78, Value: 99", l.toMonitorString()); l = DCCppReply.parseDCCppReply("v 90 -1"); // Assert.assertEquals("Monitor string", "Prog Verify Reply: CV: 90, Value: -1", l.toMonitorString()); } @Test public void testMonitorStringBitWriteReply() { DCCppReply l = DCCppReply.parseDCCppReply("r 1234|4321|5 3 1"); Assert.assertEquals("Monitor string", "Program Bit Reply: CallbackNum:1234, Sub:4321, CV:5, Bit:3, Value:1", l.toMonitorString()); l = DCCppReply.parseDCCppReply("r 5 3 1"); // Assert.assertEquals("Monitor string", "Program Bit Reply: CV:5, Bit:3, Value:1", l.toMonitorString()); } @Test public void testMonitorStringPowerReply() { DCCppReply l = DCCppReply.parseDCCppReply("p0"); Assert.assertEquals("Monitor string", "Power Status: OFF", l.toMonitorString()); l = DCCppReply.parseDCCppReply("p1"); Assert.assertEquals("Monitor string", "Power Status: ON", l.toMonitorString()); l = DCCppReply.parseDCCppReply("p 0"); Assert.assertEquals("Monitor string", "Power Status: OFF", l.toMonitorString()); l = DCCppReply.parseDCCppReply("p 1"); Assert.assertEquals("Monitor string", "Power Status: ON", l.toMonitorString()); } @Test public void testMonitorStringThrottleCommandsReply() { DCCppReply l = DCCppReply.parseDCCppReply("jT 3456 C \"turnout desc\""); Assert.assertEquals("Monitor string", "Turnout ID:3456 State:C Desc:'turnout desc'", l.toMonitorString()); l = DCCppReply.parseDCCppReply("jT 111 222 3456"); Assert.assertEquals("Monitor string", "Turnout IDs:[111, 222, 3456]", l.toMonitorString()); l = DCCppReply.parseDCCppReply("jT"); //no turnouts defined Assert.assertEquals("Monitor string", "Turnout IDs:[]", l.toMonitorString()); l = DCCppReply.parseDCCppReply("jT 3456 C \"\""); //no description defined Assert.assertEquals("Monitor string", "Turnout ID:3456 State:C Desc:''", l.toMonitorString()); } @Test public void testTurnoutIDListValidation() { // zero is out-of-range and filtered DCCppReply r = DCCppReply.parseDCCppReply("jT 0 123"); ArrayList ids = r.getTurnoutIDList(); Assert.assertEquals(1, ids.size()); Assert.assertEquals(123, (int) ids.get(0)); JUnitAppender.assertWarnMessage("Ignoring out-of-range turnout ID 0 in jT response (buffer overflow?)"); // ID above MAX_TURNOUT_ADDRESS is filtered r = DCCppReply.parseDCCppReply("jT 123 32768"); ids = r.getTurnoutIDList(); Assert.assertEquals(1, ids.size()); Assert.assertEquals(123, (int) ids.get(0)); JUnitAppender.assertWarnMessage("Ignoring out-of-range turnout ID 32768 in jT response (buffer overflow?)"); } @Test public void testAutomationReplyProperties() { DCCppReply r; r = DCCppReply.parseDCCppReply("jA 42 R \"Station Loop\""); Assert.assertTrue(r.isAutomationIDReply()); Assert.assertEquals(42, r.getAutomationIDInt()); Assert.assertEquals("42", r.getAutomationIDString()); Assert.assertEquals("R", r.getAutomationTypeString()); Assert.assertEquals("Station Loop", r.getAutomationDescString()); r = DCCppReply.parseDCCppReply("jA 7 A \"Yard Switcher\""); Assert.assertTrue(r.isAutomationIDReply()); Assert.assertEquals(7, r.getAutomationIDInt()); Assert.assertEquals("A", r.getAutomationTypeString()); Assert.assertEquals("Yard Switcher", r.getAutomationDescString()); r = DCCppReply.parseDCCppReply("jA -5 R \"Reverse Loop\""); Assert.assertTrue(r.isAutomationIDReply()); Assert.assertEquals(-5, r.getAutomationIDInt()); r = DCCppReply.parseDCCppReply("jB 42 2"); Assert.assertTrue(r.isAutomationStateReply()); Assert.assertEquals(42, r.getAutomationIDInt()); Assert.assertEquals("2", r.getAutomationStateString()); r = DCCppReply.parseDCCppReply("jB 42 \"Platform 1\""); Assert.assertTrue(r.isAutomationCaptionReply()); Assert.assertEquals(42, r.getAutomationIDInt()); Assert.assertEquals("Platform 1", r.getAutomationCaptionString()); } @BeforeEach @Override public void setUp() { JUnitUtil.setUp(); m = msg = new DCCppReply(); } @Override @AfterEach public void tearDown() { m = msg = null; JUnitUtil.tearDown(); } }