From b2c0c985142a91ac6c3ff8896540d67e225bfea8 Mon Sep 17 00:00:00 2001 From: hneemann Date: Sun, 20 Oct 2019 09:43:25 +0200 Subject: [PATCH 1/2] adds a helper to create unit tests, see #363 --- .../neemann/digital/testing/UnitTester.java | 94 +++++++++++++++++++ .../digital/integration/UnitTestTest.java | 42 +++++++++ 2 files changed, 136 insertions(+) create mode 100644 src/main/java/de/neemann/digital/testing/UnitTester.java create mode 100644 src/test/java/de/neemann/digital/integration/UnitTestTest.java diff --git a/src/main/java/de/neemann/digital/testing/UnitTester.java b/src/main/java/de/neemann/digital/testing/UnitTester.java new file mode 100644 index 000000000..99ad38cf8 --- /dev/null +++ b/src/main/java/de/neemann/digital/testing/UnitTester.java @@ -0,0 +1,94 @@ +/* + * Copyright (c) 2019 Helmut Neemann. + * Use of this source code is governed by the GPL v3 license + * that can be found in the LICENSE file. + */ +package de.neemann.digital.testing; + +import de.neemann.digital.core.Model; +import de.neemann.digital.core.Node; +import de.neemann.digital.core.NodeException; +import de.neemann.digital.core.memory.DataField; +import de.neemann.digital.core.memory.ProgramMemory; +import de.neemann.digital.core.memory.RAMInterface; +import de.neemann.digital.draw.elements.Circuit; +import de.neemann.digital.draw.elements.PinException; +import de.neemann.digital.draw.library.ElementLibrary; +import de.neemann.digital.draw.library.ElementNotFoundException; +import de.neemann.digital.draw.model.ModelCreator; +import de.neemann.digital.draw.shapes.ShapeFactory; + +import java.io.File; +import java.io.IOException; +import java.util.List; + +public class UnitTester { + private final ShapeFactory sf; + private final ElementLibrary library; + private final Model model; + private boolean initCalled = false; + + public UnitTester(File file) throws IOException, ElementNotFoundException, PinException, NodeException { + library = new ElementLibrary(); + library.setRootFilePath(file.getParentFile()); + sf = new ShapeFactory(library); + Circuit circuit = Circuit.loadCircuit(file, sf); + model = new ModelCreator(circuit, library).createModel(false); + } + + public UnitTester writeDataTo(MemoryFilter filter, DataField data) throws TestException { + getMemory(filter).setProgramMemory(data); + return this; + } + + public ProgramMemory getMemory(MemoryFilter filter) throws TestException { + Node node = getNode(n -> n instanceof ProgramMemory && filter.accept((ProgramMemory) n)); + return (ProgramMemory) node; + } + + public RAMInterface getRAM() throws TestException { + return getRAM(pm -> true); + } + + public RAMInterface getRAM(MemoryFilter filter) throws TestException { + Node node = getNode(n -> n instanceof RAMInterface && filter.accept((RAMInterface) n)); + return (RAMInterface) node; + } + + public Node getNode(Model.NodeFilter filter) throws TestException { + List list = model.findNode(filter); + if (list.size() == 0) + throw new TestException("no node found"); + else if (list.size() > 1) + throw new TestException("multiple nodes found"); + else { + return list.get(0); + } + } + + public UnitTester runToBreak() throws TestException, NodeException { + if (!model.isRunToBreakAllowed()) + throw new TestException("model has no break or no clock element"); + + getModel().runToBreak(); + return this; + } + + public Model getModel() throws NodeException { + if (!initCalled) { + model.init(); + initCalled = true; + } + return model; + } + + public static class TestException extends Exception { + private TestException(String message) { + super(message); + } + } + + public interface MemoryFilter { + boolean accept(ProgramMemory pm); + } +} diff --git a/src/test/java/de/neemann/digital/integration/UnitTestTest.java b/src/test/java/de/neemann/digital/integration/UnitTestTest.java new file mode 100644 index 000000000..3d4b6a60a --- /dev/null +++ b/src/test/java/de/neemann/digital/integration/UnitTestTest.java @@ -0,0 +1,42 @@ +/* + * Copyright (c) 2019 Helmut Neemann. + * Use of this source code is governed by the GPL v3 license + * that can be found in the LICENSE file. + */ +package de.neemann.digital.integration; + +import de.neemann.digital.core.memory.*; +import de.neemann.digital.core.memory.importer.Importer; +import de.neemann.digital.testing.UnitTester; +import junit.framework.TestCase; + +import java.io.File; + +public class UnitTestTest extends TestCase { + + public void testProcessor() throws Exception { + // the file containing the processor + File processor = new File(Resources.getRoot(), + "../../main/dig/processor/Processor.dig"); + + // the hex file containing the program + File hexFile = new File(Resources.getRoot(), + "programs/fibonacci.hex"); + + // import the hex file + DataField program = Importer.read(hexFile, 16); + + // run the program + RAMInterface ram = new UnitTester(processor) // load processor + .writeDataTo(pm -> pm instanceof ROM && pm.getDataBits() == 16, program) + // write program to the 16-Bit rom + .runToBreak() // run program to break point + .getRAM(v -> v instanceof RAMDualPort); // get the data ram of processor + + // get the content of the data ram + DataField ramContent = ram.getMemory(); + + // check if address 0 contains the value 610 ( the fifteenth Fibonacci number ) + assertEquals(610, ramContent.getDataWord(0)); + } +} From 8c5cd3fb0ec4e91f9469269e70c253648fb14217 Mon Sep 17 00:00:00 2001 From: hneemann Date: Tue, 22 Oct 2019 21:57:24 +0200 Subject: [PATCH 2/2] adds some comments, see #363 --- .../neemann/digital/testing/UnitTester.java | 89 +++++++++++++++++-- 1 file changed, 83 insertions(+), 6 deletions(-) diff --git a/src/main/java/de/neemann/digital/testing/UnitTester.java b/src/main/java/de/neemann/digital/testing/UnitTester.java index 99ad38cf8..47e94a92b 100644 --- a/src/main/java/de/neemann/digital/testing/UnitTester.java +++ b/src/main/java/de/neemann/digital/testing/UnitTester.java @@ -22,39 +22,93 @@ import java.io.File; import java.io.IOException; import java.util.List; +/** + * Helper to test circuits + */ public class UnitTester { - private final ShapeFactory sf; - private final ElementLibrary library; private final Model model; private boolean initCalled = false; + /** + * Creates a new instanve + * + * @param file the file to load + * @throws IOException IOException + * @throws ElementNotFoundException ElementNotFoundException + * @throws PinException PinException + * @throws NodeException NodeException + */ public UnitTester(File file) throws IOException, ElementNotFoundException, PinException, NodeException { - library = new ElementLibrary(); + ElementLibrary library = new ElementLibrary(); library.setRootFilePath(file.getParentFile()); - sf = new ShapeFactory(library); - Circuit circuit = Circuit.loadCircuit(file, sf); + initLibrary(library); + ShapeFactory shapeFactory = new ShapeFactory(library); + Circuit circuit = Circuit.loadCircuit(file, shapeFactory); model = new ModelCreator(circuit, library).createModel(false); } + /** + * Overload this method if you have to modify the library. + * + * @param library the used library + */ + protected void initLibrary(ElementLibrary library) { + } + + /** + * Writed data to a memory component + * + * @param filter the filter to identify the memory component + * @param data the data to write + * @return this for chained calls + * @throws TestException TestException + */ public UnitTester writeDataTo(MemoryFilter filter, DataField data) throws TestException { getMemory(filter).setProgramMemory(data); return this; } + /** + * Reruts the memory idetified by the filter + * + * @param filter the filter to identify the memory component + * @return the memory component + * @throws TestException TestException + */ public ProgramMemory getMemory(MemoryFilter filter) throws TestException { Node node = getNode(n -> n instanceof ProgramMemory && filter.accept((ProgramMemory) n)); return (ProgramMemory) node; } + /** + * Used to get the RAM if there is only on in the circuit + * + * @return the RSM component + * @throws TestException TestException + */ public RAMInterface getRAM() throws TestException { return getRAM(pm -> true); } + /** + * Used to get a RAM component from the circuit + * + * @param filter the filter to identify the memory component + * @return the memory component + * @throws TestException TestException + */ public RAMInterface getRAM(MemoryFilter filter) throws TestException { Node node = getNode(n -> n instanceof RAMInterface && filter.accept((RAMInterface) n)); return (RAMInterface) node; } + /** + * Used to find a specific node in the circuit. + * + * @param filter the filter io identify the node. + * @return the node + * @throws TestException TestException + */ public Node getNode(Model.NodeFilter filter) throws TestException { List list = model.findNode(filter); if (list.size() == 0) @@ -66,6 +120,13 @@ public class UnitTester { } } + /** + * Runs the simulation until a break signal is detected + * + * @return this for chained calls + * @throws TestException TestException + * @throws NodeException NodeException + */ public UnitTester runToBreak() throws TestException, NodeException { if (!model.isRunToBreakAllowed()) throw new TestException("model has no break or no clock element"); @@ -74,6 +135,10 @@ public class UnitTester { return this; } + /** + * @return the model + * @throws NodeException NodeException + */ public Model getModel() throws NodeException { if (!initCalled) { model.init(); @@ -82,13 +147,25 @@ public class UnitTester { return model; } - public static class TestException extends Exception { + /** + * Exception according to this test + */ + public static final class TestException extends Exception { private TestException(String message) { super(message); } } + /** + * Filter to identify a memory component. + */ public interface MemoryFilter { + /** + * Used to identify the component + * + * @param pm the memory component + * @return true if this component is to use + */ boolean accept(ProgramMemory pm); } }