From 4d92a55cbb77e1bed6464a3818a6665abf503e8d Mon Sep 17 00:00:00 2001 From: hneemann Date: Wed, 19 Apr 2017 19:51:27 +0200 Subject: [PATCH] refactoring of input don't care handling --- .../components/testing/TestResultDialog.java | 6 + .../testing/LineListenerResolveDontCare.java | 52 +++++ .../neemann/digital/testing/TestResult.java | 221 +++++------------- src/main/resources/lang/lang_de.xml | 4 + src/main/resources/lang/lang_en.xml | 3 + 5 files changed, 129 insertions(+), 157 deletions(-) create mode 100644 src/main/java/de/neemann/digital/testing/LineListenerResolveDontCare.java diff --git a/src/main/java/de/neemann/digital/gui/components/testing/TestResultDialog.java b/src/main/java/de/neemann/digital/gui/components/testing/TestResultDialog.java index 88ee5a89e..447ef1a59 100644 --- a/src/main/java/de/neemann/digital/gui/components/testing/TestResultDialog.java +++ b/src/main/java/de/neemann/digital/gui/components/testing/TestResultDialog.java @@ -11,6 +11,7 @@ import de.neemann.digital.testing.*; import de.neemann.gui.ErrorMessage; import de.neemann.gui.IconCreator; +import de.neemann.gui.StringUtils; import javax.swing.*; import javax.swing.table.DefaultTableCellRenderer; @@ -73,7 +74,12 @@ public TestResultDialog(JFrame owner, ArrayList tsl, Circuit circuit, E tabIcon = ICON_FAILED; errorTabIndex = i; } + if (tr.toManyResults()) + tabName += " " + Lang.get("msg_test_missingLines"); + tp.addTab(tabName, tabIcon, new JScrollPane(table)); + if (tr.toManyResults()) + tp.setToolTipTextAt(i, StringUtils.textToHTML(Lang.get("msg_test_missingLines_tt"))); i++; } if (errorTabIndex >= 0) diff --git a/src/main/java/de/neemann/digital/testing/LineListenerResolveDontCare.java b/src/main/java/de/neemann/digital/testing/LineListenerResolveDontCare.java new file mode 100644 index 000000000..68a2b4deb --- /dev/null +++ b/src/main/java/de/neemann/digital/testing/LineListenerResolveDontCare.java @@ -0,0 +1,52 @@ +package de.neemann.digital.testing; + +import de.neemann.digital.testing.parser.LineListener; + +import java.util.ArrayList; + +/** + * Resolves don't cares in the inputs list + * Created by hneemann on 19.04.17. + */ +public class LineListenerResolveDontCare implements LineListener { + + private final LineListener parent; + private final ArrayList inputs; + + /** + * Create a new instance + * + * @param parent the parent listener + * @param inputs the input test signals + */ + public LineListenerResolveDontCare(LineListener parent, ArrayList inputs) { + this.parent = parent; + this.inputs = inputs; + } + + @Override + public void add(Value[] rowWithDontCare) { + ArrayList dcIndex = null; + for (TestResult.TestSignal in : inputs) { + if (rowWithDontCare[in.getIndex()].getType() == Value.Type.DONTCARE) { + if (dcIndex == null) + dcIndex = new ArrayList<>(); + dcIndex.add(in.getIndex()); + } + } + if (dcIndex == null) + parent.add(rowWithDontCare); + else { + int count = 1 << dcIndex.size(); + for (int n = 0; n < count; n++) { + int mask = 1; + for (int in : dcIndex) { + boolean val = (n & mask) != 0; + rowWithDontCare[in] = new Value(val ? 1 : 0); + mask *= 2; + } + parent.add(rowWithDontCare); + } + } + } +} diff --git a/src/main/java/de/neemann/digital/testing/TestResult.java b/src/main/java/de/neemann/digital/testing/TestResult.java index 3c361b4df..7c41fef55 100644 --- a/src/main/java/de/neemann/digital/testing/TestResult.java +++ b/src/main/java/de/neemann/digital/testing/TestResult.java @@ -12,8 +12,6 @@ import java.util.ArrayList; import java.util.HashSet; -import java.util.Iterator; -import java.util.NoSuchElementException; /** * Stores the test results created by a single {@link TestData} instance. @@ -31,6 +29,8 @@ public class TestResult { private boolean allPassed; private Exception exception; private boolean toManyResults = false; + private ArrayList inputs; + private ArrayList outputs; /** * Creates a new testing result @@ -56,7 +56,7 @@ public TestResult create(Model model) throws TestingDataException, NodeException allPassed = true; HashSet usedSignals = new HashSet<>(); - ArrayList inputs = new ArrayList<>(); + inputs = new ArrayList<>(); for (Signal s : model.getInputs()) { final int index = getIndexOf(s.getName()); if (index >= 0) { @@ -72,7 +72,7 @@ public TestResult create(Model model) throws TestingDataException, NodeException } } - ArrayList outputs = new ArrayList<>(); + outputs = new ArrayList<>(); for (Signal s : model.getOutputs()) { final int index = getIndexOf(s.getName()); if (index >= 0) { @@ -94,63 +94,7 @@ public TestResult create(Model model) throws TestingDataException, NodeException model.init(); try { - lines.emitLines(rowWithDontCare -> { - for (Value[] row : resolveDontCares(inputs, rowWithDontCare)) { - - Value[] res = new Value[row.length]; - - boolean clockIsUsed = false; - // set all values except the clocks - for (TestSignal in : inputs) { - if (row[in.index].getType() != Value.Type.CLOCK) { - row[in.index].copyTo(in.value); - } else { - clockIsUsed = true; - } - res[in.index] = row[in.index]; - } - - try { - if (clockIsUsed) { // a clock signal is used - model.doStep(); // propagate all except clock - - // set clock - for (TestSignal in : inputs) - if (row[in.index].getType() == Value.Type.CLOCK) - row[in.index].copyTo(in.value); - - // propagate clock change - model.doStep(); - - // restore clock - for (TestSignal in : inputs) // invert the clock values - if (row[in.index].getType() == Value.Type.CLOCK) - in.value.setBool(!in.value.getBool()); - } - - model.doStep(); - } catch (NodeException | RuntimeException e) { - exception = e; - allPassed = false; - throw new RuntimeException(e); - } - - boolean ok = true; - for (TestSignal out : outputs) { - MatchedValue matchedValue = new MatchedValue(row[out.index], out.value); - res[out.index] = matchedValue; - if (!matchedValue.isPassed()) { - allPassed = false; - ok = false; - } - } - - if (results.size() < (ok ? MAX_RESULTS : ERR_RESULTS)) - results.add(res); - else - toManyResults = true; - } - }, new Context()); + lines.emitLines(new LineListenerResolveDontCare(values -> checkRow(model, values), inputs), new Context()); } catch (ParserException e) { throw new TestingDataException(e); } catch (RuntimeException e) { @@ -163,20 +107,59 @@ public TestResult create(Model model) throws TestingDataException, NodeException return this; } - private Iterable resolveDontCares(ArrayList inputs, Value[] rowWithDontCare) { - ArrayList dcIndex = null; + private void checkRow(Model model, Value[] row) { + Value[] res = new Value[row.length]; + + boolean clockIsUsed = false; + // set all values except the clocks for (TestSignal in : inputs) { - if (rowWithDontCare[in.index].getType() == Value.Type.DONTCARE) { - if (dcIndex == null) - dcIndex = new ArrayList<>(); - dcIndex.add(in.index); + if (row[in.index].getType() != Value.Type.CLOCK) { + row[in.index].copyTo(in.value); + } else { + clockIsUsed = true; } + res[in.index] = row[in.index]; } - if (dcIndex == null) - return new SingleItemIterator<>(rowWithDontCare); - else { - return new VariantsIterator(dcIndex, rowWithDontCare); + + try { + if (clockIsUsed) { // a clock signal is used + model.doStep(); // propagate all except clock + + // set clock + for (TestSignal in : inputs) + if (row[in.index].getType() == Value.Type.CLOCK) + row[in.index].copyTo(in.value); + + // propagate clock change + model.doStep(); + + // restore clock + for (TestSignal in : inputs) // invert the clock values + if (row[in.index].getType() == Value.Type.CLOCK) + in.value.setBool(!in.value.getBool()); + } + + model.doStep(); + } catch (NodeException | RuntimeException e) { + exception = e; + allPassed = false; + throw new RuntimeException(e); + } + + boolean ok = true; + for (TestSignal out : outputs) { + MatchedValue matchedValue = new MatchedValue(row[out.index], out.value); + res[out.index] = matchedValue; + if (!matchedValue.isPassed()) { + allPassed = false; + ok = false; + } } + + if (results.size() < (ok ? MAX_RESULTS : ERR_RESULTS)) + results.add(res); + else + toManyResults = true; } /** @@ -193,7 +176,7 @@ public boolean allPassed() { * * @return true if there are missing items in the results list. */ - public boolean isToManyResults() { + public boolean toManyResults() { return toManyResults; } @@ -244,7 +227,10 @@ public Value getResultValue(int rowIndex, int columnIndex) { return results.get(rowIndex)[columnIndex]; } - private static class TestSignal { + /** + * A test signal + */ + public static class TestSignal { private final int index; private final ObservableValue value; @@ -252,91 +238,12 @@ private static class TestSignal { this.index = index; this.value = value; } - } - - private static class SingleItemIterator implements Iterable { - private final T value; - SingleItemIterator(T value) { - this.value = value; - } - - @Override - public Iterator iterator() { - return new SingleItemIterable<>(value); - } - } - - private static class SingleItemIterable implements Iterator { - private T value; - - SingleItemIterable(T value) { - this.value = value; - } - - @Override - public boolean hasNext() { - return value != null; - } - - @Override - public T next() { - if (value == null) - throw new NoSuchElementException(); - T r = value; - value = null; - return r; - } - } - - private static class VariantsIterator implements Iterable { - private final ArrayList dcIndex; - private final Value[] rowWithDontCare; - - VariantsIterator(ArrayList dcIndex, Value[] rowWithDontCare) { - this.dcIndex = dcIndex; - this.rowWithDontCare = rowWithDontCare; - } - - @Override - public Iterator iterator() { - Value[] copy = new Value[rowWithDontCare.length]; - for (int i = 0; i < copy.length; i++) - copy[i] = new Value(rowWithDontCare[i]); - return new VariantsIterable(dcIndex, copy); - } - } - - private static class VariantsIterable implements Iterator { - private final ArrayList dcIndex; - private final Value[] row; - private final int count; - private int n; - - VariantsIterable(ArrayList dcIndex, Value[] row) { - this.dcIndex = dcIndex; - this.row = row; - count = 1 << dcIndex.size(); - n = 0; - } - - @Override - public boolean hasNext() { - return n < count; - } - - @Override - public Value[] next() { - if (n >= count) - throw new NoSuchElementException(); - int mask = 1; - for (int in : dcIndex) { - boolean val = (n & mask) != 0; - row[in] = new Value(val ? 1 : 0); - mask *= 2; - } - n++; - return row; + /** + * @return the index of this value + */ + public int getIndex() { + return index; } } diff --git a/src/main/resources/lang/lang_de.xml b/src/main/resources/lang/lang_de.xml index dd1314a09..585d1743a 100644 --- a/src/main/resources/lang/lang_de.xml +++ b/src/main/resources/lang/lang_de.xml @@ -768,6 +768,10 @@ Die Icons stammen aus dem Tango Desktop Project. Testergebnis {0}: ok {0}: Fehler + (Zu viele Einträge!) + Es wurden alle Testfälle ausgeführt, aber nicht alle Ergebnisse werden angezeigt. + Die Bewertung des Testergebnises ist dennoch korrekt! + E: {0} / F: {1} Fehler bei der Erzeugung der Hilfe! In der Zwischenablage befinden sich keine importierbaren Daten! diff --git a/src/main/resources/lang/lang_en.xml b/src/main/resources/lang/lang_en.xml index e59a76a50..1093cc037 100644 --- a/src/main/resources/lang/lang_en.xml +++ b/src/main/resources/lang/lang_en.xml @@ -770,6 +770,9 @@ The icons are taken from the Tango Desktop Project. The file name is not unique! The file has not yet been imported. The file {0} already exists! Do you want to overwrite the file? + (To many entries!) + All test cases are executed, but not all results are shown. + The evaluation of the test result is nevertheless correct! Ok