package jmri.jmrit; import static org.junit.jupiter.api.Assertions.assertDoesNotThrow; import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertNotNull; import static org.junit.jupiter.api.Assertions.assertNull; import static org.junit.jupiter.api.Assertions.assertThrowsExactly; import static org.junit.jupiter.api.Assertions.assertTrue; import static org.junit.jupiter.api.Assertions.fail; import java.io.File; import java.io.FileNotFoundException; import java.io.IOException; import jmri.util.FileUtil; import jmri.util.JUnitAppender; import org.junit.jupiter.api.*; /** * Test simple functioning of MemoryContents * * @author Bob Jacobsen Copyright (C) 2008 * @suthor B. Milhaupt Copyright (C) 2014 */ public class MemoryContentsTest { @Test public void testReadNormalFile() { MemoryContents m = new MemoryContents(); log.debug("Begin of testReadNormalFile"); String fileName = "java/test/jmri/jmrit/MemoryContentsTestFiles/TestFiles/MemoryContentsTestFile.hex"; assertDoesNotThrow( () -> m.readHex(new File(fileName))); assertEquals(864, m.nextContent(500), "content restarts"); } @Test public void testReadSegmentsTestFile() { MemoryContents m = new MemoryContents(); log.debug("Begin of testReadSegmentsTestFile"); String fileName = "java/test/jmri/jmrit/MemoryContentsTestFiles/TestFiles/MemoryContentsTestFile_extSegRecords.hex"; assertDoesNotThrow( () -> m.readHex(new File(fileName))); verifyMemoryData(0x00000, 0x01, m); verifyMemoryData(0x00001, 0x02, m); verifyMemoryData(0x00002, -1, m); verifyMemoryData(0x00003, -1, m); verifyMemoryData(0x0FFFF, -1, m); verifyMemoryData(0x10000, 0x03, m); verifyMemoryData(0x10001, 0x04, m); verifyMemoryData(0x10002, -1, m); verifyMemoryData(0x10003, -1, m); verifyMemoryData(0x1FFFF, -1, m); verifyMemoryData(0x20000, 0x05, m); verifyMemoryData(0x20001, 0x06, m); verifyMemoryData(0x20002, -1, m); verifyMemoryData(0x20003, -1, m); verifyMemoryData(0x2FFFF, -1, m); verifyMemoryData(0x30000, 0x07, m); verifyMemoryData(0x30001, 0x08, m); verifyMemoryData(0x30002, -1, m); verifyMemoryData(0x30003, -1, m); verifyMemoryData(0x3FFFF, -1, m); verifyMemoryData(0x9FFFF, -1, m); JUnitAppender.assertErrorMessage("Error in getLocation(0x9ffff): accessed uninitialized page 9"); verifyMemoryData(0xA0000, 0xa0, m); verifyMemoryData(0xA0001, 0xa1, m); verifyMemoryData(0xA0002, -1, m); verifyMemoryData(0xA0003, -1, m); } @Test public void testReadNormal24BitAddressFile() { MemoryContents m = new MemoryContents(); log.debug("Begin of testReadNormal24BitAddressFile"); String filename1 = "java/test/jmri/jmrit/MemoryContentsTestFiles/TestFiles/MemoryContentsTestFile_24bit.hex"; assertDoesNotThrow( () -> m.readHex(new File(filename1))); verifyMemoryData(0x10000, 0x54, m); verifyMemoryData(0x10001, 0x32, m); verifyMemoryData(0x20001, 0xBE, m); verifyMemoryData(0x20002, 0xEF, m); // Write a copy of the MemoryContents to a new file // File path for this file generated by the testcase is modeled after // the temp file used in jmri.jmrix.rps.PackageFileTest.java String tempDirectoryName = "temp"; if (!(new File(tempDirectoryName).isDirectory())) { // create the temp directory if it does not exist FileUtil.createDirectory(tempDirectoryName); } String filename = tempDirectoryName + File.separator + "MemoryContentsTestOutputFile.hex"; File memoryContentsTestWrite_24AddrFile = new File(filename); if (memoryContentsTestWrite_24AddrFile.exists()) { boolean deleted = assertDoesNotThrow( () -> memoryContentsTestWrite_24AddrFile.delete(), "Exception while trying to delete the existing file " + filename + " before creating a new copy of the file.\n Exception reported: " ); assertTrue(deleted); // return; } m.setAddressFormat(MemoryContents.LoadOffsetFieldType.ADDRESSFIELDSIZE24BITS); m.addKeyValueComment("Harrumph", "TRUE"); try (java.io.FileWriter writer = new java.io.FileWriter(memoryContentsTestWrite_24AddrFile)) { m.writeHex(writer, true, 16); } catch (IOException e) { fail("I/O exception attempting to write a .hex file ", e); } catch (MemoryContents.MemoryFileAddressingFormatException e) { fail("Memory Addressing format exception attempting to write .hex file", e); } // make sure the new file is in 24-bit address format m.setAddressFormat(MemoryContents.LoadOffsetFieldType.ADDRESSFIELDSIZE24BITS); MemoryContents n = new MemoryContents(); assertDoesNotThrow( () -> n.readHex(new File(filename))); // attempt to delete the file if debug logging is not enabled. if (log.isDebugEnabled()) { log.debug("Path to written hex file is: {}", filename); } else { assertTrue(memoryContentsTestWrite_24AddrFile.delete()); } assertEquals(864, n.nextContent(500), () -> "NextContent didn't reply as expected for nextContent(500) - " + "expected 864, got " + m.nextContent(500) + "."); // Code here uses manual validity checks (the "if" statements) below // instead of Assert.assertEquals because of unexplainable lack of // failure in some forced failing cases. verifyMemoryData(0x00, 0xa8, n); verifyMemoryData(0x01, 0x29, n); if (m.locationInUse(0x02)) { verifyMemoryData(0x02, -1, n); } if (m.locationInUse(0x03)) { verifyMemoryData(0x03, -1, n); } if (m.locationInUse(0x04)) { verifyMemoryData(0x04, -1, n); } if (m.locationInUse(0x05)) { verifyMemoryData(0x05, -1, n); } if (m.locationInUse(0x06)) { verifyMemoryData(0x06, -1, n); } if (m.locationInUse(0x07)) { verifyMemoryData(0x07, -1, n); } verifyMemoryData(0xA0, 0x0B, n); verifyMemoryData(0xA1, 0x16, n); verifyMemoryData(0x400E, 0x5c, n); verifyMemoryData(0x400F, 0x09, n); verifyMemoryData(0x4010, 0xFF, n); verifyMemoryData(0x4011, 0x3F, n); } @Test public void testReadFileCksumError() { MemoryContents m = new MemoryContents(); log.debug("Begin of testReadFileCksumError"); String fileName = "java/test/jmri/jmrit/MemoryContentsTestFiles/TestFiles/MemoryContentsTestFile_cksumErr.hex"; MemoryContents.MemoryFileChecksumException e = assertThrowsExactly(MemoryContents.MemoryFileChecksumException.class, () -> m.readHex(new File(fileName)), "Checksum Exception was expected"); assertNotNull(e); JUnitAppender.assertErrorMessage( "Record checksum error in line 29 - computed checksum = 0x1f, expected checksum = 0x1e."); } @Test public void testReadFileRecordTypeError() { MemoryContents m = new MemoryContents(); log.debug("Begin of testReadFileRecordTypeError"); String fileName = "java/test/jmri/jmrit/MemoryContentsTestFiles/TestFiles/MemoryContentsTestFile_recordTypeError.hex"; MemoryContents.MemoryFileUnknownRecordType e = assertThrowsExactly(MemoryContents.MemoryFileUnknownRecordType.class, () -> m.readHex(new File(fileName)), "Record Type Exception was expected"); assertNotNull(e); JUnitAppender.assertErrorMessage( "Unknown RECTYP 0x3 was found in line 16. Aborting file read."); } @Test public void testReadFileRecordLengthError() { MemoryContents m = new MemoryContents(); log.debug("Begin of testReadFileRecordLengthError"); String fileName = "java/test/jmri/jmrit/MemoryContentsTestFiles/TestFiles/MemoryContentsTestFile_recordLenError.hex"; MemoryContents.MemoryFileRecordLengthException e = assertThrowsExactly(MemoryContents.MemoryFileRecordLengthException.class, () -> m.readHex(new File(fileName)), "Record Length Exception was expected"); assertNotNull(e); JUnitAppender.assertErrorMessage( "Data record line length is incorrect for inferred addressing type and for data count field in line 10"); if (!(m.extractValueOfKey("KeyName2").matches("ValueInfo99"))) { fail("Expect to retrieve 'ValueInfo99' as value of key KeyName2, but got '" + m.extractValueOfKey("KeyName2") + "' instead."); } assertNull(m.extractValueOfKey("non-existent_Key")); assertNull(m.extractValueOfKey("fictitiousKeyName"), "Failed to return for non-existant key name 'fictitiousKeyName'."); } @Test public void testReadFileFileNotFound() { MemoryContents m = new MemoryContents(); log.debug("Begin of testReadFileFileNotFound"); String fileName = "java/test/jmri/jmrit/MemoryContentsTestFiles/TestFiles/MemoryContentsTestFile_file_doesnt_exist.hex"; FileNotFoundException e = assertThrowsExactly(FileNotFoundException.class, () -> m.readHex(new File(fileName)), "File-not-found Exception was expected"); assertNotNull(e); // make sure that key/value from previous test is gone now. assertNull( m.extractValueOfKey(m.extractValueOfKey("KeyName2")), "old key/value disappears"); assertEquals(-1, m.nextContent(500), "old data disappears"); } @Test public void testReadFileMalformedLine() { MemoryContents m = new MemoryContents(); log.debug("Begin of testReadFileMalformedLine"); String fileName = "java/test/jmri/jmrit/MemoryContentsTestFiles/TestFiles/MemoryContentsTestFile_malformed_line.hex"; MemoryContents.MemoryFileRecordLengthException e = assertThrowsExactly(MemoryContents.MemoryFileRecordLengthException.class, () -> m.readHex(new File(fileName)), "Record Content Length exception expected"); assertNotNull(e); JUnitAppender.assertErrorMessage( "Data record line length is incorrect for inferred addressing type and for data count field in line 7"); } @Test public void testReadFileNoEOFRecordFile() { MemoryContents m = new MemoryContents(); log.debug("Begin of testReadFileNoEOFRecordFile"); String fileName = "java/test/jmri/jmrit/MemoryContentsTestFiles/TestFiles/MemoryContentsTestFile_noEOFRecord.hex"; MemoryContents.MemoryFileNoEOFRecordException e = assertThrowsExactly(MemoryContents.MemoryFileNoEOFRecordException.class, () -> m.readHex(new File(fileName)), "No EOF Record exception expected"); assertNotNull(e); JUnitAppender.assertErrorMessage( "No EOF Record found in file - aborting."); } @Test public void testReadFileNoContentFile() { MemoryContents m = new MemoryContents(); log.debug("Begin of testReadFileNoContentFile"); String fileName = "java/test/jmri/jmrit/MemoryContentsTestFiles/TestFiles/MemoryContentsTestFile_no_data_records.dmf"; MemoryContents.MemoryFileNoDataRecordsException e = assertThrowsExactly(MemoryContents.MemoryFileNoDataRecordsException.class, () -> m.readHex(new File(fileName)), "'No records found' exception expected"); assertNotNull(e); JUnitAppender.assertErrorMessage( "No Data Records found in file - aborting."); } @Test public void testReadFile16bitContentFile() { MemoryContents m = new MemoryContents(); log.debug("Begin of testReadFile16bitContentFile"); String fileName = "java/test/jmri/jmrit/MemoryContentsTestFiles/TestFiles/MemoryContentsTestFile_16bit.hex"; assertDoesNotThrow( () -> m.readHex(new File(fileName))); } @Test public void testReadFileRecordType02BadFile() { MemoryContents m = new MemoryContents(); log.debug("Begin of testReadFileRecordType02BadFile"); String fileName = "java/test/jmri/jmrit/MemoryContentsTestFiles/TestFiles/MemoryContentsTestFile_RecType02bad.hex"; MemoryContents.MemoryFileAddressingRangeException e = assertThrowsExactly(MemoryContents.MemoryFileAddressingRangeException.class, () -> m.readHex(new File(fileName)), "'Addressing range' exception expected"); assertNotNull(e); JUnitAppender.assertErrorMessage( "Unsupported Extended Segment Address Record data value 0x1000 in line 3"); } @Test public void testReadFileRecordType02BadFile2() { MemoryContents m = new MemoryContents(); log.debug("Begin of testReadFileRecordType02BadFile2"); String fileName = "java/test/jmri/jmrit/MemoryContentsTestFiles/TestFiles/MemoryContentsTestFile_RecType02bad_2.hex"; MemoryContents.MemoryFileAddressingRangeException e = assertThrowsExactly(MemoryContents.MemoryFileAddressingRangeException.class, () -> m.readHex(new File(fileName)), "'Addressing range' exception expected"); assertNotNull(e); JUnitAppender.assertErrorMessage( "Unsupported Extended Segment Address Record data value 0x1000 in line 2"); } @Test public void testReadFileHighSegments() { MemoryContents m = new MemoryContents(); log.debug("Begin of testReadFileHighSegments"); String fileName = "java/test/jmri/jmrit/MemoryContentsTestFiles/TestFiles/MemoryContentsTestFile_24bitHighSegs.hex"; assertDoesNotThrow( () -> m.readHex(new File(fileName))); verifyMemoryData(0xFFFFFF, 0x7B, m); if (m.locationInUse(0xFFFFFE)) { verifyMemoryData(0xFFFFFE, -1, m); } if (m.locationInUse(0x0)) { verifyMemoryData(0x0, -1, m); } verifyMemoryData(0xF000FF, 0xD0, m); verifyMemoryData(0xFF0000, 0x9A, m); verifyMemoryData(0xD000FF, 0x12, m); verifyMemoryData(0xD00100, 0x34, m); } @Test public void testReadFilePageCross() { MemoryContents m = new MemoryContents(); log.debug("Begin of testReadFilePageCross"); String fileName = "java/test/jmri/jmrit/MemoryContentsTestFiles/TestFiles/MemoryContentsTestFile_16bit_pagecross.hex"; MemoryContents.MemoryFileAddressingRangeException e = assertThrowsExactly(MemoryContents.MemoryFileAddressingRangeException.class, () -> m.readHex(new File(fileName)), "Address Range exception was expected"); assertNotNull(e); JUnitAppender.assertErrorMessage( "Data crosses boundary which could lead to mis-interpretation. Aborting read at line :02FFFF000102FD"); if (m.locationInUse(0x00FFFF)) { verifyMemoryData(0x00FFFF, -1, m); } if (m.locationInUse(0x00FFFE)) { verifyMemoryData(0x00FFFE, -1, m); } if (m.locationInUse(0x00FF00)) { verifyMemoryData(0x00FF00, -1, m); } if (m.locationInUse(0x00FF01)) { verifyMemoryData(0x00FF01, -1, m); } if (m.locationInUse(0x00FF02)) { verifyMemoryData(0x00FF02, -1, m); } if (m.locationInUse(0x00FF03)) { verifyMemoryData(0x00FF03, -1, m); } if (m.locationInUse(0x010000)) { verifyMemoryData(0x010000, -1, m); } if (m.locationInUse(0x010001)) { verifyMemoryData(0x010001, -1, m); } if (m.locationInUse(0x010002)) { verifyMemoryData(0x010002, -1, m); } if (m.locationInUse(0x010003)) { verifyMemoryData(0x010003, -1, m); } } @Test public void testReadFile24bitPageCross() { MemoryContents m = new MemoryContents(); log.debug("Begin of testReadFile24bitPageCross"); String fileName = "java/test/jmri/jmrit/MemoryContentsTestFiles/TestFiles/MemoryContentsTestFile_24bit_pagecross.hex"; MemoryContents.MemoryFileAddressingRangeException e = assertThrowsExactly(MemoryContents.MemoryFileAddressingRangeException.class, () -> m.readHex(new File(fileName)), "Address Range exception was expected"); assertNotNull(e); JUnitAppender.assertErrorMessage( "Data crosses boundary which could lead to mis-interpretation. Aborting read at line :0201FFFF000709EF"); if (m.locationInUse(0x01FFFF)) { verifyMemoryData(0x01FFFF, -1, m); } if (m.locationInUse(0x01FFFE)) { verifyMemoryData(0x01FFFE, -1, m); } if (m.locationInUse(0x020000)) { verifyMemoryData(0x020000, -1, m); } if (m.locationInUse(0x020001)) { verifyMemoryData(0x020001, -1, m); } if (m.locationInUse(0x020002)) { verifyMemoryData(0x020002, -1, m); } if (m.locationInUse(0x020003)) { verifyMemoryData(0x020003, -1, m); } if (m.locationInUse(0x010000)) { verifyMemoryData(0x010000, -1, m); } if (m.locationInUse(0x010001)) { verifyMemoryData(0x010001, -1, m); } if (m.locationInUse(0x010002)) { verifyMemoryData(0x010002, -1, m); } if (m.locationInUse(0x010003)) { verifyMemoryData(0x010003, -1, m); } } private void verifyMemoryData(int address, int expect, MemoryContents mc) { int reported = mc.getLocation(address); assertEquals(expect, reported, () -> "Verify that address 0x" + Integer.toHexString(address) + " has correct value: expected 0x" + Integer.toHexString(expect) + ", got 0x" + Integer.toHexString(reported)); } @BeforeEach public void setUp() { jmri.util.JUnitUtil.setUp(); } @AfterEach public void tearDown() { jmri.util.JUnitUtil.tearDown(); } private static final org.slf4j.Logger log = org.slf4j.LoggerFactory.getLogger(MemoryContentsTest.class); }