Skip to content

Commit

Permalink
refactoring of input don't care handling
Browse files Browse the repository at this point in the history
  • Loading branch information
hneemann committed Apr 19, 2017
1 parent 311793d commit 4d92a55
Show file tree
Hide file tree
Showing 5 changed files with 129 additions and 157 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -73,7 +74,12 @@ public TestResultDialog(JFrame owner, ArrayList<TestSet> 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)
Expand Down
Original file line number Diff line number Diff line change
@@ -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<TestResult.TestSignal> inputs;

/**
* Create a new instance
*
* @param parent the parent listener
* @param inputs the input test signals
*/
public LineListenerResolveDontCare(LineListener parent, ArrayList<TestResult.TestSignal> inputs) {
this.parent = parent;
this.inputs = inputs;
}

@Override
public void add(Value[] rowWithDontCare) {
ArrayList<Integer> 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);
}
}
}
}
221 changes: 64 additions & 157 deletions src/main/java/de/neemann/digital/testing/TestResult.java
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand All @@ -31,6 +29,8 @@ public class TestResult {
private boolean allPassed;
private Exception exception;
private boolean toManyResults = false;
private ArrayList<TestSignal> inputs;
private ArrayList<TestSignal> outputs;

/**
* Creates a new testing result
Expand All @@ -56,7 +56,7 @@ public TestResult create(Model model) throws TestingDataException, NodeException
allPassed = true;
HashSet<String> usedSignals = new HashSet<>();

ArrayList<TestSignal> inputs = new ArrayList<>();
inputs = new ArrayList<>();
for (Signal s : model.getInputs()) {
final int index = getIndexOf(s.getName());
if (index >= 0) {
Expand All @@ -72,7 +72,7 @@ public TestResult create(Model model) throws TestingDataException, NodeException
}
}

ArrayList<TestSignal> outputs = new ArrayList<>();
outputs = new ArrayList<>();
for (Signal s : model.getOutputs()) {
final int index = getIndexOf(s.getName());
if (index >= 0) {
Expand All @@ -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) {
Expand All @@ -163,20 +107,59 @@ public TestResult create(Model model) throws TestingDataException, NodeException
return this;
}

private Iterable<Value[]> resolveDontCares(ArrayList<TestSignal> inputs, Value[] rowWithDontCare) {
ArrayList<Integer> 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;
}

/**
Expand All @@ -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;
}

Expand Down Expand Up @@ -244,99 +227,23 @@ 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;

TestSignal(int index, ObservableValue value) {
this.index = index;
this.value = value;
}
}

private static class SingleItemIterator<T> implements Iterable<T> {
private final T value;

SingleItemIterator(T value) {
this.value = value;
}

@Override
public Iterator<T> iterator() {
return new SingleItemIterable<>(value);
}
}

private static class SingleItemIterable<T> implements Iterator<T> {
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<Value[]> {
private final ArrayList<Integer> dcIndex;
private final Value[] rowWithDontCare;

VariantsIterator(ArrayList<Integer> dcIndex, Value[] rowWithDontCare) {
this.dcIndex = dcIndex;
this.rowWithDontCare = rowWithDontCare;
}

@Override
public Iterator<Value[]> 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<Value[]> {
private final ArrayList<Integer> dcIndex;
private final Value[] row;
private final int count;
private int n;

VariantsIterable(ArrayList<Integer> 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;
}
}

Expand Down
4 changes: 4 additions & 0 deletions src/main/resources/lang/lang_de.xml
Original file line number Diff line number Diff line change
Expand Up @@ -768,6 +768,10 @@ Die Icons stammen aus dem Tango Desktop Project.</string>
<string name="msg_testResult">Testergebnis</string>
<string name="msg_test_N_Passed">{0}: ok</string>
<string name="msg_test_N_Failed">{0}: Fehler</string>
<string name="msg_test_missingLines">(Zu viele Einträge!)</string>
<string name="msg_test_missingLines_tt">Es wurden alle Testfälle ausgeführt, aber nicht alle Ergebnisse werden angezeigt.
Die Bewertung des Testergebnises ist dennoch korrekt!</string>

<string name="msg_testExp_N0_found_N1">E: {0} / F: {1}</string>
<string name="msg_creatingHelp">Fehler bei der Erzeugung der Hilfe!</string>
<string name="msg_clipboardContainsNoImportableData">In der Zwischenablage befinden sich keine importierbaren Daten!</string>
Expand Down
3 changes: 3 additions & 0 deletions src/main/resources/lang/lang_en.xml
Original file line number Diff line number Diff line change
Expand Up @@ -770,6 +770,9 @@ The icons are taken from the Tango Desktop Project.</string>
<string name="msg_fileIsNotUnique">The file name is not unique!</string>
<string name="msg_fileNotImportedYet">The file has not yet been imported.</string>
<string name="msg_fileExists">The file {0} already exists! Do you want to overwrite the file?</string>
<string name="msg_test_missingLines">(To many entries!)</string>
<string name="msg_test_missingLines_tt">All test cases are executed, but not all results are shown.
The evaluation of the test result is nevertheless correct!</string>

<string name="ok">Ok</string>
<string name="rot_0">0°</string>
Expand Down

0 comments on commit 4d92a55

Please sign in to comment.