/*
* Here comes the text of your license
* Each line should be prefixed with *
*/
package nars.lab.testutils;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.TreeSet;
import nars.NAR;
import nars.entity.Sentence;
import nars.entity.Task;
import nars.io.TextOutput;
import nars.io.Texts;
import nars.operator.Operator.ExecutionResult;
/**
* OutputCondition that watches for a specific String output,
* while collecting similar results (according to Levenshtein text distance).
*
*/
public class OutputContainsCondition extends OutputCondition<Task> {
public List<Task> exact = new ArrayList();
public static class SimilarOutput implements Comparable<SimilarOutput> {
public final String signal;
public final int distance;
public SimilarOutput(String signal, int distance) {
this.signal = signal;
this.distance = distance;
}
@Override
public int hashCode() { return signal.hashCode(); }
@Override
public boolean equals(Object obj) { return signal.equals(((SimilarOutput)obj).signal); }
@Override
public String toString() {
return "similar(" + distance + "): " + signal;
}
@Override
public int compareTo(SimilarOutput o) {
return Integer.compare(distance, o.distance);
}
}
final String containing;
public TreeSet<SimilarOutput> almost = new TreeSet();
final boolean saveSimilar;
int maxSimilars = 5;
/**
*
* @param nar
* @param containing
* @param maxSimilars # of similar results to collect, -1 to disable
*/
public OutputContainsCondition(NAR nar, String containing, int maxSimilars) {
super(nar);
this.containing = containing;
this.maxSimilars = maxSimilars;
this.saveSimilar = maxSimilars != -1;
}
@Override
public String getFalseReason() {
String s = "FAIL: No substring match: " + containing;
if (!almost.isEmpty()) {
for (SimilarOutput cs : getCandidates(5)) {
s += "\n\t" + cs;
}
}
return s;
}
public Collection<SimilarOutput> getCandidates(int max) {
return almost;
}
public boolean cond(Class channel, Object signal) {
if ((channel == OUT.class) || (channel == EXE.class)) {
String o;
if (signal instanceof Task) {
//only compare for Sentence string, faster than TextOutput.getOutputString
//which also does unescaping, etc..
Task t = (Task)signal;
Sentence s = t.sentence;
o = s.toString(nar, false).toString();
if (o.contains(containing)) {
if (saveSimilar) {
exact.add(t);
}
return true;
}
} else {
Task t = null;
if (signal instanceof ExecutionResult)
t = ((ExecutionResult)signal).getTask();
o = TextOutput.getOutputString(channel, signal, false, false, nar).toString();
if (o.contains(containing)) {
if ((saveSimilar) && (t!=null)) {
exact.add(t);
}
return true;
}
}
if (saveSimilar) {
int dist = Texts.levenshteinDistance(o, containing);
if (almost.size() >= maxSimilars) {
SimilarOutput last = almost.last();
if (dist < last.distance) {
almost.remove(last);
almost.add(new SimilarOutput(o, dist));
}
}
else {
almost.add(new SimilarOutput(o, dist));
}
}
}
/*if (channel == ERR.class) {
Assert.assertTrue(signal.toString(), false);
}*/
return false;
}
@Override
public boolean condition(Class channel, Object signal) {
if (succeeded) {
return true;
}
return cond(channel, signal);
}
@Override
public List<Task> getTrueReasons() {
return exact;
}
}