mirror of
https://github.com/hneemann/Digital.git
synced 2025-09-22 11:55:15 -04:00
Allows to set the simulator to a certain line in the a test result.
This commit is contained in:
parent
34f305d3e3
commit
7c086d8796
@ -140,10 +140,20 @@ public class ValueTable extends Observable implements Iterable<TestRow> {
|
||||
* @return the value stored at the given position
|
||||
*/
|
||||
public Value getTableValue(int rowIndex, int columnIndex) {
|
||||
return getTableRow(rowIndex).getValue(columnIndex);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a table row
|
||||
*
|
||||
* @param rowIndex the index of the table row
|
||||
* @return the table row
|
||||
*/
|
||||
public TestRow getTableRow(int rowIndex) {
|
||||
if (tableRowIndex == null)
|
||||
return values.get(rowIndex).getValue(columnIndex);
|
||||
return values.get(rowIndex);
|
||||
else
|
||||
return values.get(tableRowIndex.get(rowIndex)).getValue(columnIndex);
|
||||
return values.get(tableRowIndex.get(rowIndex));
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -6,6 +6,7 @@
|
||||
package de.neemann.digital.data;
|
||||
|
||||
import de.neemann.digital.core.Observer;
|
||||
import de.neemann.digital.testing.parser.TestRow;
|
||||
|
||||
import javax.swing.*;
|
||||
import javax.swing.event.TableModelEvent;
|
||||
@ -20,7 +21,7 @@ import java.util.ArrayList;
|
||||
public class ValueTableModel implements TableModel, Observer {
|
||||
|
||||
private final ValueTable values;
|
||||
private ArrayList<TableModelListener> listeners;
|
||||
private final ArrayList<TableModelListener> listeners;
|
||||
|
||||
/**
|
||||
* Creates a new table model
|
||||
@ -99,4 +100,14 @@ public class ValueTableModel implements TableModel, Observer {
|
||||
l.tableChanged(tme);
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a table row
|
||||
*
|
||||
* @param row the number of the table row
|
||||
* @return the table row
|
||||
*/
|
||||
public TestRow getRow(int row) {
|
||||
return values.getTableRow(row);
|
||||
}
|
||||
}
|
||||
|
@ -1137,7 +1137,7 @@ public final class Main extends JFrame implements ClosingWindowListener.ConfirmS
|
||||
.setVisible(true);
|
||||
|
||||
ensureModelIsStopped();
|
||||
} catch (NodeException | ElementNotFoundException | PinException | TestingDataException | RuntimeException e1) {
|
||||
} catch (TestingDataException | RuntimeException e1) {
|
||||
showError(Lang.get("msg_runningTestError"), e1);
|
||||
}
|
||||
}
|
||||
@ -1589,6 +1589,26 @@ public final class Main extends JFrame implements ClosingWindowListener.ConfirmS
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Starts the simulation and allows to advance the model to a certain state.
|
||||
*
|
||||
* @param advanceSimulator needs to be implemented to advance the model
|
||||
*/
|
||||
public void startSimulation(AdvanceSimulator advanceSimulator) {
|
||||
SwingUtilities.invokeLater(() -> {
|
||||
runModelState.enter(false, null);
|
||||
SwingUtilities.invokeLater(() -> {
|
||||
if (model != null && model.isRunning()) {
|
||||
try {
|
||||
advanceSimulator.advance(Main.this);
|
||||
circuitComponent.graphicHasChanged();
|
||||
} catch (Exception e) {
|
||||
showError("Message", e);
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public void hasChanged() {
|
||||
@ -2113,4 +2133,17 @@ public final class Main extends JFrame implements ClosingWindowListener.ConfirmS
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Allows to start the simulation and advance the model to a certain state.
|
||||
*/
|
||||
public interface AdvanceSimulator {
|
||||
/**
|
||||
* Advances the model to a certain state
|
||||
*
|
||||
* @param main main
|
||||
* @throws Exception Exception
|
||||
*/
|
||||
void advance(Main main) throws Exception;
|
||||
}
|
||||
}
|
||||
|
@ -6,19 +6,19 @@
|
||||
package de.neemann.digital.gui.components.testing;
|
||||
|
||||
import de.neemann.digital.core.ErrorDetector;
|
||||
import de.neemann.digital.core.NodeException;
|
||||
import de.neemann.digital.data.Value;
|
||||
import de.neemann.digital.data.ValueTable;
|
||||
import de.neemann.digital.data.ValueTableModel;
|
||||
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.gui.Main;
|
||||
import de.neemann.digital.gui.SaveAsHelper;
|
||||
import de.neemann.digital.gui.components.data.GraphDialog;
|
||||
import de.neemann.digital.lang.Lang;
|
||||
import de.neemann.digital.testing.TestCaseDescription;
|
||||
import de.neemann.digital.testing.TestExecutor;
|
||||
import de.neemann.digital.testing.TestingDataException;
|
||||
import de.neemann.digital.testing.parser.TestRow;
|
||||
import de.neemann.gui.IconCreator;
|
||||
import de.neemann.gui.LineBreaker;
|
||||
import de.neemann.gui.MyFileChooser;
|
||||
@ -29,6 +29,8 @@ import javax.swing.filechooser.FileNameExtensionFilter;
|
||||
import javax.swing.table.DefaultTableCellRenderer;
|
||||
import java.awt.*;
|
||||
import java.awt.event.ActionEvent;
|
||||
import java.awt.event.MouseAdapter;
|
||||
import java.awt.event.MouseEvent;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
|
||||
@ -50,7 +52,7 @@ public class ValueTableDialog extends JDialog {
|
||||
private static final Icon ICON_GRAPH = IconCreator.create("measurement-graph.png");
|
||||
|
||||
|
||||
private final ArrayList<ValueTable> resultTableData;
|
||||
private final ArrayList<ValueTableHolder> resultTableData;
|
||||
private final JTabbedPane tp;
|
||||
private final Window owner;
|
||||
private final ToolTipAction asGraph;
|
||||
@ -80,7 +82,7 @@ public class ValueTableDialog extends JDialog {
|
||||
JFileChooser fileChooser = new MyFileChooser();
|
||||
fileChooser.setFileFilter(new FileNameExtensionFilter("Comma Separated Values", "csv"));
|
||||
new SaveAsHelper(ValueTableDialog.this, fileChooser, "csv")
|
||||
.checkOverwrite(resultTableData.get(tab)::saveCSV);
|
||||
.checkOverwrite(resultTableData.get(tab).valueTable::saveCSV);
|
||||
}
|
||||
}.setToolTip(Lang.get("menu_saveData_tt")).createJMenuItem());
|
||||
|
||||
@ -90,7 +92,7 @@ public class ValueTableDialog extends JDialog {
|
||||
public void actionPerformed(ActionEvent actionEvent) {
|
||||
int tab = tp.getSelectedIndex();
|
||||
if (tab < 0) tab = 0;
|
||||
new GraphDialog(ValueTableDialog.this, Lang.get("win_testdata_N", tp.getTitleAt(tab)), resultTableData.get(tab))
|
||||
new GraphDialog(ValueTableDialog.this, Lang.get("win_testdata_N", tp.getTitleAt(tab)), resultTableData.get(tab).valueTable)
|
||||
.disableTable()
|
||||
.setVisible(true);
|
||||
}
|
||||
@ -113,12 +115,9 @@ public class ValueTableDialog extends JDialog {
|
||||
* @param circuit the circuit
|
||||
* @param library the library to use
|
||||
* @return this for chained calls
|
||||
* @throws NodeException NodeException
|
||||
* @throws TestingDataException DataException
|
||||
* @throws PinException PinException
|
||||
* @throws ElementNotFoundException ElementNotFoundException
|
||||
* @throws TestingDataException DataException
|
||||
*/
|
||||
public ValueTableDialog addTestResult(java.util.List<Circuit.TestCase> tsl, Circuit circuit, ElementLibrary library) throws TestingDataException, ElementNotFoundException, PinException, NodeException {
|
||||
public ValueTableDialog addTestResult(java.util.List<Circuit.TestCase> tsl, Circuit circuit, ElementLibrary library) throws TestingDataException {
|
||||
Collections.sort(tsl);
|
||||
int i = 0;
|
||||
int errorTabIndex = -1;
|
||||
@ -142,10 +141,11 @@ public class ValueTableDialog extends JDialog {
|
||||
if (testResult.toManyResults())
|
||||
tabName += " " + Lang.get("msg_test_missingLines");
|
||||
|
||||
tp.addTab(tabName, tabIcon, new JScrollPane(createTable(testResult.getValueTable())));
|
||||
ValueTableHolder vth = new ValueTableHolder(testResult.getValueTable(), ts.getTestCaseDescription());
|
||||
tp.addTab(tabName, tabIcon, new JScrollPane(createTable(vth)));
|
||||
if (testResult.toManyResults())
|
||||
tp.setToolTipTextAt(i, new LineBreaker().toHTML().breakLines(Lang.get("msg_test_missingLines_tt")));
|
||||
resultTableData.add(testResult.getValueTable());
|
||||
resultTableData.add(vth);
|
||||
i++;
|
||||
errorDetector.check();
|
||||
} catch (Exception e) {
|
||||
@ -168,18 +168,32 @@ public class ValueTableDialog extends JDialog {
|
||||
* @return this for chained calls
|
||||
*/
|
||||
public ValueTableDialog addValueTable(String name, ValueTable valueTable) {
|
||||
tp.addTab(name, new JScrollPane(createTable(valueTable)));
|
||||
resultTableData.add(valueTable);
|
||||
tp.addTab(name, new JScrollPane(createTable(new ValueTableHolder(valueTable))));
|
||||
resultTableData.add(new ValueTableHolder(valueTable));
|
||||
|
||||
pack();
|
||||
setLocationRelativeTo(owner);
|
||||
return this;
|
||||
}
|
||||
|
||||
private JTable createTable(ValueTable valueTable) {
|
||||
JTable table = new JTable(new ValueTableModel(valueTable));
|
||||
private JTable createTable(ValueTableHolder valueTableHolder) {
|
||||
ValueTableModel vtm = new ValueTableModel(valueTableHolder.valueTable);
|
||||
JTable table = new JTable(vtm);
|
||||
table.setDefaultRenderer(Value.class, new ValueRenderer());
|
||||
table.setDefaultRenderer(Integer.class, new NumberRenderer());
|
||||
table.addMouseListener(new MouseAdapter() {
|
||||
@Override
|
||||
public void mouseClicked(MouseEvent e) {
|
||||
int r = table.getSelectedRow();
|
||||
if (r > 0 && r < vtm.getRowCount() && valueTableHolder.testCaseDescription != null) {
|
||||
TestRow row = vtm.getRow(r);
|
||||
if (owner instanceof Main) {
|
||||
Main main = (Main) owner;
|
||||
main.startSimulation(m -> new TestExecutor(valueTableHolder.testCaseDescription, m.getModel()).executeTo(row.getRow()));
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
final Font font = table.getFont();
|
||||
table.setRowHeight(font.getSize() * 6 / 5);
|
||||
return table;
|
||||
@ -233,4 +247,18 @@ public class ValueTableDialog extends JDialog {
|
||||
}
|
||||
}
|
||||
|
||||
private static final class ValueTableHolder {
|
||||
private final ValueTable valueTable;
|
||||
private final TestCaseDescription testCaseDescription;
|
||||
|
||||
private ValueTableHolder(ValueTable valueTable) {
|
||||
this.valueTable = valueTable;
|
||||
testCaseDescription = null;
|
||||
}
|
||||
|
||||
private ValueTableHolder(ValueTable valueTable, TestCaseDescription testCaseDescription) {
|
||||
this.valueTable = valueTable;
|
||||
this.testCaseDescription = testCaseDescription;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -37,6 +37,7 @@ public class TestExecutor {
|
||||
private boolean errorOccurred;
|
||||
private int failedCount;
|
||||
private int passedCount;
|
||||
private int rowCount;
|
||||
private boolean toManyResults = false;
|
||||
private ArrayList<TestSignal> inputs;
|
||||
private ArrayList<TestSignal> outputs;
|
||||
@ -85,15 +86,51 @@ public class TestExecutor {
|
||||
lines = testCase.getLines();
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the model to the given row.
|
||||
*
|
||||
* @param row the row to advance the model to
|
||||
* @throws TestingDataException DataException
|
||||
* @throws ParserException ParserException
|
||||
*/
|
||||
public void executeTo(int row) throws TestingDataException, ParserException {
|
||||
execute(new LineListener() {
|
||||
private int r = row;
|
||||
|
||||
@Override
|
||||
public void add(TestRow testRow) {
|
||||
Value[] values = testRow.getValues();
|
||||
Value[] res = new Value[values.length];
|
||||
|
||||
if (r >= 0) {
|
||||
advanceModel(model, testRow, values, res);
|
||||
r--;
|
||||
}
|
||||
}
|
||||
}, false);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates the result by comparing the testing vector with the given model
|
||||
*
|
||||
* @return the result of the test execution
|
||||
* @throws TestingDataException DataException
|
||||
* @throws NodeException NodeException
|
||||
* @throws ParserException ParserException
|
||||
*/
|
||||
public TestExecutor.Result execute() throws TestingDataException, NodeException, ParserException {
|
||||
public TestExecutor.Result execute() throws TestingDataException, ParserException {
|
||||
return execute(values -> checkRow(model, values), true);
|
||||
}
|
||||
|
||||
/**
|
||||
* Executes the test and sends all the test lines to the {@link LineListener} provided.
|
||||
*
|
||||
* @param lineListener the line listener to use
|
||||
* @param closeModel if true the model is closed
|
||||
* @return the result of the test execution
|
||||
* @throws TestingDataException DataException
|
||||
* @throws ParserException ParserException
|
||||
*/
|
||||
private TestExecutor.Result execute(LineListener lineListener, boolean closeModel) throws TestingDataException, ParserException {
|
||||
try {
|
||||
HashSet<String> usedSignals = new HashSet<>();
|
||||
inputs = new ArrayList<>();
|
||||
@ -160,11 +197,12 @@ public class TestExecutor {
|
||||
errorOccurred = true;
|
||||
}, ModelEventType.ERROR_OCCURRED);
|
||||
|
||||
lines.emitLines(new LineListenerResolveDontCare(values -> checkRow(model, values), inputs), context);
|
||||
lines.emitLines(new LineListenerResolveDontCare(lineListener, inputs), context);
|
||||
|
||||
return new Result();
|
||||
} finally {
|
||||
model.close();
|
||||
if (closeModel)
|
||||
model.close();
|
||||
}
|
||||
}
|
||||
|
||||
@ -178,6 +216,30 @@ public class TestExecutor {
|
||||
Value[] values = testRow.getValues();
|
||||
Value[] res = new Value[values.length];
|
||||
|
||||
advanceModel(model, testRow, values, res);
|
||||
|
||||
boolean ok = true;
|
||||
for (TestSignal out : outputs) {
|
||||
MatchedValue matchedValue = new MatchedValue(values[out.index], out.value);
|
||||
res[out.index] = matchedValue;
|
||||
if (!matchedValue.isPassed())
|
||||
ok = false;
|
||||
}
|
||||
|
||||
if (ok)
|
||||
passedCount++;
|
||||
else
|
||||
failedCount++;
|
||||
|
||||
if (visibleRows < (ok ? MAX_RESULTS : ERR_RESULTS)) {
|
||||
visibleRows++;
|
||||
results.add(new TestRow(res, testRow.getDescription()).setRow(rowCount));
|
||||
rowCount++;
|
||||
} else
|
||||
toManyResults = true;
|
||||
}
|
||||
|
||||
private void advanceModel(Model model, TestRow testRow, Value[] values, Value[] res) {
|
||||
boolean clockIsUsed = false;
|
||||
// set all values except the clocks
|
||||
for (TestSignal in : inputs) {
|
||||
@ -219,25 +281,6 @@ public class TestExecutor {
|
||||
errorOccurred = true;
|
||||
throw e;
|
||||
}
|
||||
|
||||
boolean ok = true;
|
||||
for (TestSignal out : outputs) {
|
||||
MatchedValue matchedValue = new MatchedValue(values[out.index], out.value);
|
||||
res[out.index] = matchedValue;
|
||||
if (!matchedValue.isPassed())
|
||||
ok = false;
|
||||
}
|
||||
|
||||
if (ok)
|
||||
passedCount++;
|
||||
else
|
||||
failedCount++;
|
||||
|
||||
if (visibleRows < (ok ? MAX_RESULTS : ERR_RESULTS)) {
|
||||
visibleRows++;
|
||||
results.add(new TestRow(res, testRow.getDescription()));
|
||||
} else
|
||||
toManyResults = true;
|
||||
}
|
||||
|
||||
private void addClockRow(int cols, String description) {
|
||||
|
@ -13,6 +13,7 @@ import de.neemann.digital.data.Value;
|
||||
public class TestRow {
|
||||
private final Value[] values;
|
||||
private final String description;
|
||||
private int rowCount;
|
||||
|
||||
/**
|
||||
* Creates a new instance
|
||||
@ -58,4 +59,22 @@ public class TestRow {
|
||||
public String getDescription() {
|
||||
return description;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the row number
|
||||
*
|
||||
* @param rowCount the number to set
|
||||
* @return this for chained calls
|
||||
*/
|
||||
public TestRow setRow(int rowCount) {
|
||||
this.rowCount = rowCount;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the row number of this row
|
||||
*/
|
||||
public int getRow() {
|
||||
return rowCount;
|
||||
}
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user