/*******************************************************************************
* This file is part of logisim-evolution.
*
* logisim-evolution is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* logisim-evolution is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with logisim-evolution. If not, see <http://www.gnu.org/licenses/>.
*
* Original code by Carl Burch (http://www.cburch.com), 2011.
* Subsequent modifications by :
* + Haute École Spécialisée Bernoise
* http://www.bfh.ch
* + Haute École du paysage, d'ingénierie et d'architecture de Genève
* http://hepia.hesge.ch/
* + Haute École d'Ingénierie et de Gestion du Canton de Vaud
* http://www.heig-vd.ch/
* The project is currently maintained by :
* + REDS Institute - HEIG-VD
* Yverdon-les-Bains, Switzerland
* http://reds.heig-vd.ch
*******************************************************************************/
/**
* Code taken from Cornell's version of Logisim:
* http://www.cs.cornell.edu/courses/cs3410/2015sp/
*/
package com.cburch.logisim.gui.test;
import com.cburch.logisim.circuit.Circuit;
import com.cburch.logisim.circuit.CircuitEvent;
import com.cburch.logisim.circuit.CircuitListener;
import com.cburch.logisim.circuit.CircuitState;
import com.cburch.logisim.comp.Component;
import com.cburch.logisim.data.FailException;
import com.cburch.logisim.data.TestException;
import com.cburch.logisim.data.TestVector;
import com.cburch.logisim.instance.Instance;
import com.cburch.logisim.instance.InstanceState;
import com.cburch.logisim.instance.StdAttr;
import com.cburch.logisim.proj.Project;
import com.cburch.logisim.std.wiring.Pin;
import com.cburch.logisim.util.StringUtil;
public class TestThread extends Thread implements CircuitListener {
// used only for automated testing via command line arguments
public static int doTestVector(Project proj, Circuit circuit,
String vectorname) {
System.out.println(StringUtil.format(Strings.get("testLoadingVector"),
vectorname));
TestVector vec;
try {
vec = new TestVector(vectorname);
} catch (Exception e) {
System.err.println(StringUtil.format(
Strings.get("testLoadingFailed"), e.getMessage()));
return -1;
}
TestThread tester;
try {
tester = new TestThread(proj, circuit, vec);
} catch (TestException e) {
System.err.println(StringUtil.format(
Strings.get("testSetupFailed"), e.getMessage()));
return -1;
}
System.out.println(StringUtil.format(Strings.get("testRunning"),
Integer.toString(vec.data.size())));
int numPass = 0, numFail = 0;
for (int i = 0; i < vec.data.size(); i++) {
try {
System.out.print((i + 1) + " \r");
tester.test(i);
numPass++;
} catch (FailException e) {
System.out.println();
System.err.println(StringUtil.format(Strings.get("testFailed"),
Integer.toString(i + 1)));
for (; e != null; e = e.getMore())
System.out.println(" " + e.getMessage());
numFail++;
continue;
} catch (TestException e) {
System.out.println();
System.err.println(StringUtil.format(Strings.get("testFailed"),
Integer.toString(i + 1) + " " + e.getMessage()));
numFail++;
continue;
}
}
System.out.println();
System.out.println(StringUtil.format(Strings.get("testResults"),
Integer.toString(numPass), Integer.toString(numFail)));
return 0;
}
private Instance[] pin;
private Project project;
private Circuit circuit;
private TestVector vector;
private Model model;
private boolean canceled = false, paused = false;
public TestThread(Model model) throws TestException {
this.model = model;
this.project = model.getProject();
this.circuit = model.getCircuit();
this.vector = model.getVector();
matchPins();
model.getCircuit().addCircuitListener(this);
}
// used only for automated testing via command line arguments
private TestThread(Project proj, Circuit circuit, TestVector vec)
throws TestException {
this.project = proj;
this.circuit = circuit;
this.vector = vec;
matchPins();
}
public void cancel() {
canceled = true;
}
public void circuitChanged(CircuitEvent event) {
int action = event.getAction();
if (action == CircuitEvent.ACTION_SET_NAME)
return;
else
model.clearResults();
}
void matchPins() throws TestException {
int n = vector.columnName.length;
pin = new Instance[n];
CircuitState state = new CircuitState(this.project, this.circuit);
for (int i = 0; i < n; i++) {
String columnName = vector.columnName[i];
for (Component comp : circuit.getNonWires()) {
if (!(comp.getFactory() instanceof Pin))
continue;
Instance inst = Instance.getInstanceFor(comp);
InstanceState pinState = state.getInstanceState(comp);
String label = pinState.getAttributeValue(StdAttr.LABEL);
if (label == null || !label.equals(columnName))
continue;
if (Pin.FACTORY.getWidth(inst).getWidth() != vector.columnWidth[i]
.getWidth())
throw new TestException("test vector column '" + columnName
+ "' has width " + vector.columnWidth[i]
+ ", but pin has width "
+ Pin.FACTORY.getWidth(inst));
pin[i] = inst;
break;
}
if (pin[i] == null)
throw new TestException("test vector column '" + columnName
+ "' has no matching pin");
}
}
public void run() {
try {
for (int i = 0; i < vector.data.size() && !canceled; i++) {
while (paused) {
if (canceled)
return;
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
}
}
try {
test(i);
canceled = canceled || !model.setResult(vector, i, null);
} catch (TestException e) {
canceled = canceled || !model.setResult(vector, i, e);
}
Thread.yield();
}
} finally {
model.stop();
}
}
public void setPaused(boolean paused) {
this.paused = paused;
}
private void test(int idx) throws TestException {
circuit.doTestVector(project, pin, vector.data.get(idx));
}
}