mirror of
https://github.com/hneemann/Digital.git
synced 2025-09-15 07:48:29 -04:00
Refactoring of TestAllDialog
This commit is contained in:
parent
9c781d0731
commit
81e41a973c
@ -5,21 +5,11 @@
|
||||
*/
|
||||
package de.neemann.digital.gui.components.testing;
|
||||
|
||||
import de.neemann.digital.core.Model;
|
||||
import de.neemann.digital.core.NodeException;
|
||||
import de.neemann.digital.draw.elements.Circuit;
|
||||
import de.neemann.digital.draw.elements.PinException;
|
||||
import de.neemann.digital.draw.elements.VisualElement;
|
||||
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 de.neemann.digital.gui.Main;
|
||||
import de.neemann.digital.lang.Lang;
|
||||
import de.neemann.digital.testing.TestCaseDescription;
|
||||
import de.neemann.digital.testing.TestCaseElement;
|
||||
import de.neemann.digital.testing.TestExecutor;
|
||||
import de.neemann.digital.testing.TestingDataException;
|
||||
import de.neemann.digital.testing.FolderTestRunner;
|
||||
|
||||
import javax.swing.*;
|
||||
import javax.swing.event.TableModelEvent;
|
||||
@ -30,10 +20,7 @@ import java.awt.*;
|
||||
import java.awt.event.MouseAdapter;
|
||||
import java.awt.event.MouseEvent;
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Comparator;
|
||||
|
||||
/**
|
||||
* Tests all the files in a given folder
|
||||
@ -41,7 +28,7 @@ import java.util.Comparator;
|
||||
public class TestAllDialog extends JDialog {
|
||||
|
||||
/**
|
||||
* Creates a new dialog
|
||||
* Creates a new dialog and starts the test execution.
|
||||
*
|
||||
* @param frame the parent frame
|
||||
* @param folder the folder to scan
|
||||
@ -50,12 +37,11 @@ public class TestAllDialog extends JDialog {
|
||||
*/
|
||||
public TestAllDialog(Frame frame, File folder, ShapeFactory shapeFactory, ElementLibrary library) {
|
||||
super(frame, Lang.get("msg_testResult"), false);
|
||||
ArrayList<FileToTest> files = new ArrayList<>();
|
||||
scan(folder.getPath().length() + 1, folder, files);
|
||||
FolderTestRunner folderTestRunner = new FolderTestRunner(folder);
|
||||
|
||||
final FileModel tableModel = new FileModel(files);
|
||||
final FileModel tableModel = new FileModel(folderTestRunner.getFiles());
|
||||
JTable table = new JTable(tableModel);
|
||||
table.getColumnModel().getColumn(1).setCellRenderer(new StateRenderer(files));
|
||||
table.getColumnModel().getColumn(1).setCellRenderer(new StateRenderer());
|
||||
getContentPane().add(new JScrollPane(table));
|
||||
pack();
|
||||
setLocationRelativeTo(frame);
|
||||
@ -66,7 +52,7 @@ public class TestAllDialog extends JDialog {
|
||||
if (mouseEvent.getClickCount() == 2) {
|
||||
int row = table.getSelectedRow();
|
||||
if (row >= 0) {
|
||||
File f = files.get(row).file;
|
||||
File f = folderTestRunner.getFiles().get(row).getFile();
|
||||
new Main.MainBuilder()
|
||||
.setParent(frame)
|
||||
.setFileToOpen(f)
|
||||
@ -78,51 +64,18 @@ public class TestAllDialog extends JDialog {
|
||||
}
|
||||
});
|
||||
|
||||
Thread t = new Thread(new TestRunner(files, tableModel, shapeFactory, library));
|
||||
t.setDaemon(true);
|
||||
t.start();
|
||||
folderTestRunner.startTests(
|
||||
(f, row) -> SwingUtilities.invokeLater(() -> tableModel.messageChanged(row)),
|
||||
shapeFactory,
|
||||
library);
|
||||
}
|
||||
|
||||
private void scan(int rootLength, File folder, ArrayList<FileToTest> files) {
|
||||
File[] fileList = folder.listFiles();
|
||||
if (fileList != null) {
|
||||
Arrays.sort(fileList, Comparator.comparing(f -> f.getPath().toLowerCase()));
|
||||
for (File f : fileList)
|
||||
if (f.isDirectory())
|
||||
scan(rootLength, f, files);
|
||||
else if (f.isFile() && f.getName().endsWith(".dig"))
|
||||
files.add(new FileToTest(rootLength, f));
|
||||
}
|
||||
}
|
||||
|
||||
private static final class FileToTest {
|
||||
private enum State {unknown, passed, error, failed}
|
||||
|
||||
private final File file;
|
||||
private final String name;
|
||||
private String message = "-";
|
||||
private State state = State.unknown;
|
||||
|
||||
private FileToTest(int rootLength, File file) {
|
||||
this.file = file;
|
||||
name = file.getPath().substring(rootLength);
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
private void setMessage(String message, State state) {
|
||||
this.message = message;
|
||||
this.state = state;
|
||||
}
|
||||
}
|
||||
|
||||
private final static class FileModel implements TableModel {
|
||||
private final ArrayList<FileToTest> files;
|
||||
private final ArrayList<FolderTestRunner.FileToTest> files;
|
||||
private ArrayList<TableModelListener> listener;
|
||||
|
||||
private FileModel(ArrayList<FileToTest> files) {
|
||||
private FileModel(ArrayList<FolderTestRunner.FileToTest> files) {
|
||||
this.files = files;
|
||||
listener = new ArrayList<>();
|
||||
}
|
||||
@ -159,12 +112,12 @@ public class TestAllDialog extends JDialog {
|
||||
|
||||
@Override
|
||||
public Object getValueAt(int row, int col) {
|
||||
FileToTest file = files.get(row);
|
||||
FolderTestRunner.FileToTest file = files.get(row);
|
||||
switch (col) {
|
||||
case 0:
|
||||
return file.getName();
|
||||
default:
|
||||
return file.message;
|
||||
return file;
|
||||
}
|
||||
}
|
||||
|
||||
@ -189,100 +142,14 @@ public class TestAllDialog extends JDialog {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private static final class TestRunner implements Runnable {
|
||||
private final ArrayList<FileToTest> files;
|
||||
private final FileModel tableModel;
|
||||
private final ShapeFactory shapeFactory;
|
||||
private final ElementLibrary library;
|
||||
|
||||
private TestRunner(ArrayList<FileToTest> files, FileModel tableModel, ShapeFactory shapeFactory, ElementLibrary library) {
|
||||
this.files = files;
|
||||
this.tableModel = tableModel;
|
||||
this.shapeFactory = shapeFactory;
|
||||
this.library = library;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
for (int i = 0; i < files.size(); i++) {
|
||||
FileToTest f = files.get(i);
|
||||
try {
|
||||
Circuit circuit = Circuit.loadCircuit(f.file, shapeFactory);
|
||||
ArrayList<TestCase> testCases = new ArrayList<>();
|
||||
for (VisualElement el : circuit.getElements()) {
|
||||
if (el.equalsDescription(TestCaseElement.TESTCASEDESCRIPTION)) {
|
||||
String label = el.getElementAttributes().getCleanLabel();
|
||||
TestCaseDescription testData = el.getElementAttributes().get(TestCaseElement.TESTDATA);
|
||||
testCases.add(new TestCase(label, testData));
|
||||
}
|
||||
}
|
||||
if (testCases.isEmpty())
|
||||
setMessage(f, i, Lang.get("err_noTestData"), FileToTest.State.unknown);
|
||||
else {
|
||||
Model model = new ModelCreator(circuit, library).createModel(false);
|
||||
StringBuilder sb = new StringBuilder();
|
||||
int rowCount = 0;
|
||||
for (TestCase tc : testCases) {
|
||||
try {
|
||||
TestExecutor te = new TestExecutor(tc.testData).create(model);
|
||||
if (te.allPassed()) {
|
||||
rowCount += te.getResult().getRows();
|
||||
} else {
|
||||
if (sb.length() > 0)
|
||||
sb.append("; ");
|
||||
sb.append(Lang.get("msg_test_N_Failed", tc.label));
|
||||
}
|
||||
} catch (TestingDataException | NodeException e) {
|
||||
if (sb.length() > 0)
|
||||
sb.append("; ");
|
||||
sb.append(tc.label).append(": ").append(e.getMessage());
|
||||
}
|
||||
}
|
||||
if (sb.length() == 0)
|
||||
setMessage(f, i, Lang.get("msg_testPassed_N", rowCount), FileToTest.State.passed);
|
||||
else
|
||||
setMessage(f, i, sb.toString(), FileToTest.State.failed);
|
||||
}
|
||||
|
||||
} catch (IOException | NodeException | ElementNotFoundException | PinException e) {
|
||||
setMessage(f, i, e.getMessage(), FileToTest.State.error);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void setMessage(FileToTest f, int i, String message, FileToTest.State state) {
|
||||
SwingUtilities.invokeLater(() -> {
|
||||
f.setMessage(message, state);
|
||||
tableModel.messageChanged(i);
|
||||
});
|
||||
}
|
||||
|
||||
private final class TestCase {
|
||||
private final String label;
|
||||
private final TestCaseDescription testData;
|
||||
|
||||
private TestCase(String label, TestCaseDescription testData) {
|
||||
this.label = label;
|
||||
this.testData = testData;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private static final class StateRenderer extends DefaultTableCellRenderer {
|
||||
private final ArrayList<FileToTest> files;
|
||||
|
||||
private StateRenderer(ArrayList<FileToTest> files) {
|
||||
this.files = files;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Component getTableCellRendererComponent(JTable jTable, Object o, boolean b, boolean b1, int row, int i1) {
|
||||
final Component tc = super.getTableCellRendererComponent(jTable, o, b, b1, row, i1);
|
||||
final JLabel tc = (JLabel) super.getTableCellRendererComponent(jTable, o, b, b1, row, i1);
|
||||
|
||||
FileToTest f = files.get(row);
|
||||
switch (f.state) {
|
||||
FolderTestRunner.FileToTest f = (FolderTestRunner.FileToTest) o;
|
||||
switch (f.getStatus()) {
|
||||
case error:
|
||||
tc.setBackground(Color.LIGHT_GRAY);
|
||||
break;
|
||||
@ -296,6 +163,7 @@ public class TestAllDialog extends JDialog {
|
||||
tc.setBackground(ValueTableDialog.FAILED_COLOR);
|
||||
break;
|
||||
}
|
||||
tc.setText(f.getMessage());
|
||||
|
||||
return tc;
|
||||
}
|
||||
|
258
src/main/java/de/neemann/digital/testing/FolderTestRunner.java
Normal file
258
src/main/java/de/neemann/digital/testing/FolderTestRunner.java
Normal file
@ -0,0 +1,258 @@
|
||||
/*
|
||||
* Copyright (c) 2018 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.NodeException;
|
||||
import de.neemann.digital.draw.elements.Circuit;
|
||||
import de.neemann.digital.draw.elements.PinException;
|
||||
import de.neemann.digital.draw.elements.VisualElement;
|
||||
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 de.neemann.digital.lang.Lang;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Comparator;
|
||||
|
||||
/**
|
||||
* Runs all tests in al circuits in a folder
|
||||
*/
|
||||
public class FolderTestRunner {
|
||||
private final ArrayList<FileToTest> files;
|
||||
private Thread thread;
|
||||
|
||||
/**
|
||||
* Creates a new instance
|
||||
*
|
||||
* @param folder the folder to scan
|
||||
*/
|
||||
public FolderTestRunner(File folder) {
|
||||
files = new ArrayList<>();
|
||||
scan(folder.getPath().length() + 1, folder);
|
||||
}
|
||||
|
||||
private void scan(int rootLength, File folder) {
|
||||
File[] fileList = folder.listFiles();
|
||||
if (fileList != null) {
|
||||
Arrays.sort(fileList, Comparator.comparing(f -> f.getPath().toLowerCase()));
|
||||
for (File f : fileList)
|
||||
if (f.isDirectory())
|
||||
scan(rootLength, f);
|
||||
else if (f.isFile() && f.getName().endsWith(".dig"))
|
||||
files.add(new FileToTest(rootLength, f));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Starts all the tests.
|
||||
* The test execution is done in a new thread, so this method returns immediately.
|
||||
*
|
||||
* @param fileChangedListener the listsener to notify if a file status changed
|
||||
* @param shapeFactory the shape factory
|
||||
* @param library the element library
|
||||
*/
|
||||
public void startTests(FileChangedListener fileChangedListener, ShapeFactory shapeFactory, ElementLibrary library) {
|
||||
thread = new Thread(new TestRunner(files, fileChangedListener, shapeFactory, library));
|
||||
thread.setDaemon(true);
|
||||
thread.start();
|
||||
}
|
||||
|
||||
/**
|
||||
* Waits until tests are done.
|
||||
*
|
||||
* @throws InterruptedException InterruptedException
|
||||
*/
|
||||
public void waitUntilFinished() throws InterruptedException {
|
||||
thread.join();
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the list of files to test
|
||||
*/
|
||||
public ArrayList<FileToTest> getFiles() {
|
||||
return files;
|
||||
}
|
||||
|
||||
/**
|
||||
* Describes the file to test
|
||||
*/
|
||||
public static final class FileToTest {
|
||||
|
||||
/**
|
||||
* the status of the file
|
||||
*/
|
||||
public enum Status {
|
||||
/**
|
||||
* status unknown
|
||||
*/
|
||||
unknown,
|
||||
/**
|
||||
* all tests have passed
|
||||
*/
|
||||
passed,
|
||||
/**
|
||||
* there was an exception during model building or execution
|
||||
*/
|
||||
error,
|
||||
/**
|
||||
* at least one test has failed
|
||||
*/
|
||||
failed
|
||||
}
|
||||
|
||||
private final File file;
|
||||
private final String name;
|
||||
private String message = "-";
|
||||
private FileToTest.Status status = FileToTest.Status.unknown;
|
||||
private int rowCount;
|
||||
|
||||
|
||||
private FileToTest(int rootLength, File file) {
|
||||
this.file = file;
|
||||
name = file.getPath().substring(rootLength);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the name of this file
|
||||
*/
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
private void setMessage(String message, FileToTest.Status status) {
|
||||
this.message = message;
|
||||
this.status = status;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the message to show
|
||||
*/
|
||||
public String getMessage() {
|
||||
return message;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the status of this file
|
||||
*/
|
||||
public Status getStatus() {
|
||||
return status;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the tested file
|
||||
*/
|
||||
public File getFile() {
|
||||
return file;
|
||||
}
|
||||
|
||||
private void setTestRows(int rowCount) {
|
||||
this.rowCount = rowCount;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the number of test case rows
|
||||
*/
|
||||
public int getRowCount() {
|
||||
return rowCount;
|
||||
}
|
||||
}
|
||||
|
||||
private static final class TestRunner implements Runnable {
|
||||
private final ArrayList<FileToTest> files;
|
||||
private final FileChangedListener fileChangedListener;
|
||||
private final ShapeFactory shapeFactory;
|
||||
private final ElementLibrary library;
|
||||
|
||||
private TestRunner(ArrayList<FileToTest> files, FileChangedListener fileChangedListener, ShapeFactory shapeFactory, ElementLibrary library) {
|
||||
this.files = files;
|
||||
this.fileChangedListener = fileChangedListener;
|
||||
this.shapeFactory = shapeFactory;
|
||||
this.library = library;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
for (int i = 0; i < files.size(); i++) {
|
||||
FileToTest f = files.get(i);
|
||||
try {
|
||||
Circuit circuit = Circuit.loadCircuit(f.file, shapeFactory);
|
||||
ArrayList<TestCase> testCases = new ArrayList<>();
|
||||
for (VisualElement el : circuit.getElements()) {
|
||||
if (el.equalsDescription(TestCaseElement.TESTCASEDESCRIPTION)) {
|
||||
String label = el.getElementAttributes().getCleanLabel();
|
||||
TestCaseDescription testData = el.getElementAttributes().get(TestCaseElement.TESTDATA);
|
||||
testCases.add(new TestCase(label, testData));
|
||||
}
|
||||
}
|
||||
if (testCases.isEmpty())
|
||||
setMessage(f, i, Lang.get("err_noTestData"), FileToTest.Status.unknown);
|
||||
else {
|
||||
Model model = new ModelCreator(circuit, library).createModel(false);
|
||||
StringBuilder sb = new StringBuilder();
|
||||
int rowCount = 0;
|
||||
for (TestCase tc : testCases) {
|
||||
try {
|
||||
TestExecutor te = new TestExecutor(tc.testData).create(model);
|
||||
if (te.allPassed()) {
|
||||
rowCount += te.getResult().getRows();
|
||||
} else {
|
||||
if (sb.length() > 0)
|
||||
sb.append("; ");
|
||||
sb.append(Lang.get("msg_test_N_Failed", tc.label));
|
||||
}
|
||||
} catch (TestingDataException | NodeException e) {
|
||||
if (sb.length() > 0)
|
||||
sb.append("; ");
|
||||
sb.append(tc.label).append(": ").append(e.getMessage());
|
||||
}
|
||||
}
|
||||
if (sb.length() == 0) {
|
||||
f.setTestRows(rowCount);
|
||||
setMessage(f, i, Lang.get("msg_testPassed_N", rowCount), FileToTest.Status.passed);
|
||||
} else
|
||||
setMessage(f, i, sb.toString(), FileToTest.Status.failed);
|
||||
}
|
||||
|
||||
} catch (IOException | NodeException | ElementNotFoundException | PinException e) {
|
||||
setMessage(f, i, e.getMessage(), FileToTest.Status.error);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void setMessage(FileToTest f, int i, String message, FileToTest.Status status) {
|
||||
f.setMessage(message, status);
|
||||
fileChangedListener.messageChanged(f, i);
|
||||
}
|
||||
}
|
||||
|
||||
private static final class TestCase {
|
||||
private final String label;
|
||||
private final TestCaseDescription testData;
|
||||
|
||||
private TestCase(String label, TestCaseDescription testData) {
|
||||
this.label = label;
|
||||
this.testData = testData;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Interface to notify a listener for changes
|
||||
*/
|
||||
public interface FileChangedListener {
|
||||
/**
|
||||
* Called if a file message has changed
|
||||
*
|
||||
* @param f the file changed
|
||||
* @param row the row index
|
||||
*/
|
||||
void messageChanged(FileToTest f, int row);
|
||||
}
|
||||
}
|
@ -0,0 +1,39 @@
|
||||
/*
|
||||
* Copyright (c) 2018 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.draw.library.ElementLibrary;
|
||||
import de.neemann.digital.draw.shapes.ShapeFactory;
|
||||
import de.neemann.digital.integration.Resources;
|
||||
import junit.framework.TestCase;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
|
||||
public class FolderTestRunnerTest extends TestCase {
|
||||
|
||||
private static final int[] ROWS = new int[]{8, 512, 4, 4, 512};
|
||||
|
||||
public void testFolderTest() throws InterruptedException, IOException {
|
||||
File f = new File(Resources.getRoot(), "dig/test/arith");
|
||||
FolderTestRunner ft = new FolderTestRunner(f);
|
||||
assertEquals(5, ft.getFiles().size());
|
||||
|
||||
|
||||
ElementLibrary library = new ElementLibrary();
|
||||
library.setRootFilePath(f.getParentFile());
|
||||
ShapeFactory shapeFactory = new ShapeFactory(library);
|
||||
ft.startTests(
|
||||
(fileToTest, row) -> {
|
||||
assertEquals("row " + row, ROWS[row], fileToTest.getRowCount());
|
||||
assertEquals(FolderTestRunner.FileToTest.Status.passed, fileToTest.getStatus());
|
||||
},
|
||||
shapeFactory,
|
||||
library);
|
||||
|
||||
ft.waitUntilFinished();
|
||||
}
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user