
de.tsl2.nano.autotest.creator.AutoTestGenerator Maven / Gradle / Ivy
package de.tsl2.nano.autotest.creator;
import static de.tsl2.nano.autotest.creator.AFunctionCaller.def;
import static de.tsl2.nano.autotest.creator.AutoTest.CLEAN;
import static de.tsl2.nano.autotest.creator.AutoTest.DONTTEST;
import static de.tsl2.nano.autotest.creator.AutoTest.DUPLICATION;
import static de.tsl2.nano.autotest.creator.AutoTest.FAST_CLASSSCAN;
import static de.tsl2.nano.autotest.creator.AutoTest.FILENAME;
import static de.tsl2.nano.autotest.creator.AutoTest.FILTER;
import static de.tsl2.nano.autotest.creator.AutoTest.FILTER_COMPLEXTYPES;
import static de.tsl2.nano.autotest.creator.AutoTest.FILTER_ERROR_TYPES;
import static de.tsl2.nano.autotest.creator.AutoTest.FILTER_EXCLUDE;
import static de.tsl2.nano.autotest.creator.AutoTest.FILTER_FAILING;
import static de.tsl2.nano.autotest.creator.AutoTest.FILTER_NONINSTANCEABLES;
import static de.tsl2.nano.autotest.creator.AutoTest.FILTER_NULLRESULTS;
import static de.tsl2.nano.autotest.creator.AutoTest.FILTER_SINGELTONS;
import static de.tsl2.nano.autotest.creator.AutoTest.FILTER_TEST;
import static de.tsl2.nano.autotest.creator.AutoTest.FILTER_UNSUCCESSFUL;
import static de.tsl2.nano.autotest.creator.AutoTest.FILTER_VOID_PARAMETER;
import static de.tsl2.nano.autotest.creator.AutoTest.FILTER_VOID_RETURN;
import static de.tsl2.nano.autotest.creator.AutoTest.MODIFIER;
import static de.tsl2.nano.autotest.creator.AutoTest.PARALLEL;
import static de.tsl2.nano.autotest.creator.AutoTest.PRECHECK_TWICE;
import static de.tsl2.nano.autotest.creator.AutoTest.TESTNEVERFAIL;
import java.io.BufferedWriter;
import java.io.File;
import java.io.IOException;
import java.lang.annotation.Annotation;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.Date;
import java.util.LinkedHashSet;
import java.util.LinkedList;
import java.util.List;
import java.util.Scanner;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.atomic.AtomicReference;
import de.tsl2.nano.core.IPreferences;
import de.tsl2.nano.core.ManagedException;
import de.tsl2.nano.core.cls.BeanClass;
import de.tsl2.nano.core.cls.ClassFinder;
import de.tsl2.nano.core.cls.PrimitiveUtil;
import de.tsl2.nano.core.exception.ExceptionHandler;
import de.tsl2.nano.core.execution.ProgressBar;
import de.tsl2.nano.core.log.LogFactory;
import de.tsl2.nano.core.util.ByteUtil;
import de.tsl2.nano.core.util.ConcurrentUtil;
import de.tsl2.nano.core.util.DateUtil;
import de.tsl2.nano.core.util.FileUtil;
import de.tsl2.nano.core.util.FormatUtil;
import de.tsl2.nano.core.util.NumberUtil;
import de.tsl2.nano.core.util.ObjectUtil;
import de.tsl2.nano.core.util.StringUtil;
import de.tsl2.nano.core.util.Util;
/**
* generates and prints {@link Expectations} annotations on all methods, fitting
* the given class and method filter.
*
* these methods will be run with randomized parameter values. the results will
* be used to fill the {@link Expect} values of the {@link Expectations}
* annoation.
*
* so, the generated {@link Expectations} contain values to specify the code
* implementation as is!
*
* works only on methods with simple parameter and return types.
* if the method returns null, no expectations will be created
*
* @author ts
*/
public class AutoTestGenerator {
private static final String REGEX_UNMATCH = "XXXXXXXX";
static String fileName = def(FILENAME, "generated/generated-autotests-");
int methods_loaded = 0;
int count = 0;
int fails = 0;
int nullresults = 0;
int load_method_error = 0;
int load_unsuccessful = 0;
int filter_typeconversions = 0;
int filter_errors = 0;
int filter_unsuccessful = 0;
int filter_nullresults = 0;
int filter_complextypes = 0;
private Statistics statistics = new Statistics();
private AtomicReference filteredFunctionWriter = new AtomicReference();
private ExceptionHandler uncaughtExceptionHandler = new ExceptionHandler();
static ProgressBar progress;
private AFunctionCaller maxDurationFct, maxMemUsageFct;
private long start;
public static void main(String[] args) {
if (args.length == 0) {
log("Please provide a comma-separated list of full classnames to be loaded!");
return;
}
String[] clsNames = args[0].split("\\s*,\\s*");
Arrays.stream(clsNames).forEach(c -> ClassFinder.getClassesInPackage(BeanClass.load(c).getPackage().getName(), null));
new AutoTestGenerator().createExpectationTesters();
}
private void printStartParameters() {
Util.trY( () -> FileUtil.writeBytes((IPreferences.printInfo(AutoTest.class)).getBytes(), getTimedFileName() + "statistics.txt", false), false);
}
public String getTimedFileName() {
return fileName + DateUtil.getShortTimestamp(start) + "-";
}
@SuppressWarnings("rawtypes")
public Collection extends AFunctionTester> createExpectationTesters() {
if (def(DONTTEST, false)) {
log("\n##############################################");
log(" donttest=true ==> Leaving AutoTestGenerator!");
log("##############################################");
return new LinkedList<>();
}
start = System.currentTimeMillis();
def("timefilename", getTimedFileName()); //provide timed file name for other instances
int duplication = def(DUPLICATION, 10);
Collection testers = Collections.synchronizedList(new LinkedList<>());
try {
printStartParameters();
FileUtil.delete(fileName + "initialization-error.txt");
prepareFilteredWriter();
List methods;
if (def(FAST_CLASSSCAN, true))
methods = ClassFinder.self().findMethods(def(FILTER, ""), def(MODIFIER, -1), null);
else
methods = ClassFinder.self().find(def(FILTER, ""), Method.class, def(MODIFIER, -1), null);
FileUtil.writeBytes(("\nmatching methods in classpath: " + methods.size()).getBytes(), getTimedFileName() + "statistics.txt", true);
filterExcludes(methods);
filterTestClasses(methods);
filterSingeltons(methods);
filterNonInstanceable(methods);
FileUtil.writeBytes(("\nfiltered methods : " + methods.size()).getBytes(), getTimedFileName() + "statistics.txt", true);
progress = new ProgressBar(methods.size() * duplication);
ArrayList dupList = NumberUtil.numbers(duplication);
Util.stream(dupList, def(PARALLEL, false)).forEach( i ->
{
Thread.currentThread().setUncaughtExceptionHandler(uncaughtExceptionHandler );
if (!getFile(i).exists() || def(CLEAN, false)) {
generateExpectations(i, methods);
}
});
Util.stream(dupList, def(PARALLEL, false)).forEach( i ->
{
Thread.currentThread().setUncaughtExceptionHandler(uncaughtExceptionHandler );
if (getFile(i).exists() || count > 0)
testers.addAll(readExpectations(i));
});
if (def(FILTER_UNSUCCESSFUL, true))
load_unsuccessful = FunctionCheck.filterFailingTest(testers, fileName);
return testers;
} catch (Throwable e) {
Util.trY( () -> ManagedException.writeError(e, fileName + "initialization-error.txt"), false);
ConcurrentUtil.sleep(3000);
log("JUNIT TEST PARAMETERS FAILING:");
e.printStackTrace();
ManagedException.forward(e);
return null;
} finally {
if (statistics.statuss.isEmpty()) // -> no generation but only reading
testers.forEach( t -> statistics.add(t));
printStatistics(duplication +1, testers, statistics.getInfo(22));
if (filteredFunctionWriter.get() != null) {
Util.trY(() -> filteredFunctionWriter.get().close(), false);
filteredFunctionWriter.set(null); // to avoid access with additional flush on parallel use
}
if (uncaughtExceptionHandler.hasExceptions()) {
Util.trY( () -> FileUtil.writeBytes(uncaughtExceptionHandler.toString().getBytes(), getTimedFileName() + "uncaught-exceptions.txt", false), false);
// throw new IllegalStateException(uncaughtExceptionHandler.toString());
}
if (progress != null)
progress.setFinished();
}
}
private void prepareFilteredWriter() throws IOException {
if (!getFile(0).exists() || def(CLEAN, false))
FileUtil.delete(fileName + "filtered.txt");
filteredFunctionWriter.set(FileUtil.getBAWriter(fileName + "filtered.txt"));
}
private static void filterExcludes(List methods) {
methods.removeIf(m -> m.toGenericString().matches(def(FILTER_EXCLUDE, REGEX_UNMATCH)));
}
private static void filterTestClasses(List methods) {
methods.removeIf(m -> m.getDeclaringClass().getName().matches(def(FILTER_TEST, ".*(Test|IT)")));
}
private static void filterSingeltons(List methods) {
if (def(FILTER_SINGELTONS, true))
methods.removeIf(m -> BeanClass.getBeanClass(m.getDeclaringClass()).isSingleton());
}
private static void filterNonInstanceable(List methods) {
if (def(FILTER_NONINSTANCEABLES, true))
methods.removeIf(m -> !Util.isInstanceable((m.getDeclaringClass())));
}
private static boolean filterErrorType(Throwable e) {
return ManagedException.getRootCause(e).toString().matches(def(FILTER_ERROR_TYPES, REGEX_UNMATCH));
}
void generateExpectations(int iteration, List methods) {
LogFactory.setPrintToConsole(false);
String p = "\n" + StringUtil.fixString(79, '~') + "\n";
try (BufferedWriter writer = FileUtil.getBAWriter(getFile(iteration).getPath())) {
count = 0;
methods_loaded = methods.size();
log(p + "calling " + methods.size() + " methods to create expectations -> " + getFile(iteration) + p);
AtomicReference refWriter = new AtomicReference<>(writer);
Util.stream(methods, def(PARALLEL, false)).forEach(m -> writeExpectation(new AFunctionCaller(iteration, m), refWriter));
} catch (IOException e1) {
ManagedException.forward(e1);
} finally {
if (filteredFunctionWriter != null)
Util.trY( () ->filteredFunctionWriter.get().flush(), false);
ConcurrentUtil.sleep(200);
if (count > 0)
log(new String(FileUtil.getFileBytes(getFile(iteration).getPath(), null)));
log(p + count + " expectations written into '" + getFile(iteration) + p);
}
}
File getFile(int iteration) {
return FileUtil.userDirFile(fileName + iteration + ".txt");
}
private void writeExpectation(AFunctionCaller f, AtomicReference writer) {
Thread.currentThread().setUncaughtExceptionHandler(uncaughtExceptionHandler );
try {
log("writeExpectation", progress);
String then = null;
try {
if (f.source.isSynthetic() || f.source.isBridge() || f.source.getName().startsWith("$")) // -> e.g. $jacocoInit() -> javaagent code enhancing
f.status = Status.FUNC_SYNTHETIC;
if (def(FILTER_VOID_PARAMETER, false) && f.source.getParameterCount() == 0 && Modifier.isStatic(f.source.getModifiers()))
f.status = Status.FUNC_WITHOUT_INPUT;
else if (def(FILTER_VOID_RETURN, false) && void.class.isAssignableFrom(f.source.getReturnType()))
f.status = Status.FUNC_WITHOUT_OUTPUT;
else if (def(FILTER_COMPLEXTYPES, false) && !FunctionCheck.hasSimpleTypes(f))
f.status = Status.FUNC_COMPLEX_INPUT;
if (f.status.isRefused()) {
writeFilteredFunctionCall(f);
filter_complextypes++;
return;
}
f.runWithTimeout();
} catch (Exception | AssertionError e) {
if (f.status.in(StatusTyp.NEW) || f.status.isFatal() || def(FILTER_FAILING, false) || filterErrorType(e)) {
writeFilteredFunctionCall(f);
filter_errors++;
return;
}
fails++;
then = "fail(" + AFunctionTester.getErrorMsg(e) + ")";
}
if (then == null) {
if (f.getResult() == null) {
if (def(FILTER_NULLRESULTS, false)) {
filter_nullresults++;
writeFilteredFunctionCall(f);
return;
} else {
then = "null";
}
}
}
if (f.getResult() != null && !FunctionCheck.checkTypeConversion(f.getResult())) {
writeFilteredFunctionCall(f);
filter_typeconversions++;
return;
}
String expect = ExpectationCreator.createExpectationString(f, then);
if (expect == null) {
writeFilteredFunctionCall(f);
filter_typeconversions++;
return;
}
Status testStatus;
if (def(FILTER_UNSUCCESSFUL, true) && (testStatus = FunctionCheck.checkTestSuccessful(f, expect)) != null) {
f.status = testStatus;
writeFilteredFunctionCall("STATUS: " + f.status + expect);
filter_unsuccessful++;
return;
}
count++;
maxDurationFct = maxDurationFct == null || maxDurationFct.duration < f.duration ? f : maxDurationFct;
maxMemUsageFct = maxMemUsageFct == null || maxMemUsageFct.memusage < f.memusage ? f : maxMemUsageFct;
Util.trY(() -> writer.get().append(expect));
} finally {
statistics.add(f);
}
}
private void writeFilteredFunctionCall(AFunctionCaller f) {
writeFilteredFunctionCall(f.toString() + "\n");
}
private void writeFilteredFunctionCall(String call) {
Util.trY(() -> filteredFunctionWriter.get().append(call), false);
}
public Collection readExpectations(int iteration) {
return readExpectations(iteration, getFile(iteration));
}
Collection readExpectations(int iteration, File file) {
log("\nREADING " + count + " EXPECTATIONS FROM " + file.getPath() + "...\n");
LinkedHashSet expTesters = new LinkedHashSet<>();
Scanner sc = Util.trY( () ->new Scanner(file));
ProgressBar progress = new ProgressBar((int) (count > 0 ? count : file.length() / 450));
Expectations exp = null;
Method method = null;
while (sc.hasNextLine()) {
String l = sc.nextLine();
if (exp == null && !l.startsWith("@") )
continue;
if (exp == null) {
exp = ExpectationCreator.createExpectationFromLine(l);
} else {
if (l.matches("\\w+.*\\(.*\\)")) {
method = ExpectationCreator.extractMethod(l);
progress.increase(method != null ? " " + method.getDeclaringClass().getSimpleName() + "." + method.getName() : " ...");
if (method != null)
expTesters.add(new ExpectationFunctionTester(iteration, method, exp));
else
load_method_error++;
} else {
load_method_error++;
log("ERROR: method-format for " + exp + " -> " + l + "\n");
}
exp = null;
}
}
log("\nEXPECTATION READING ON ITERATION " + iteration + " FINSIHED!\n");
return expTesters;
}
private static void log(Object obj) {
log(obj, null);
}
private static void log(Object obj, ProgressBar progress) {
if (progress == null)
AFunctionCaller.log(obj + "\n");
else
// synchronized (progress) {
progress.increase(" " + obj.toString());
// }
}
private void printStatistics(int iterations, Collection testers, String groupByState) {
String p = "\n" + StringUtil.fixString(79, '=') + "\n";
Integer dup = def(DUPLICATION, 10);
String s = AutoTestGenerator.class.getSimpleName() + " created " + count + " expectations in file pattern: '" + fileName + "...'"
+ "\n\tend time : " + DateUtil.getFormattedDateTime(new Date()) + "\tduration: " + DateUtil.getFormattedTime(System.currentTimeMillis() - start)
+ "\n\ttestneverfail : " + def(TESTNEVERFAIL, false)
+ "\n\tclassfinder cls/mthds : " + ClassFinder.self().getLoadedClassCount() + " / " + ClassFinder.self().getLoadedMethodCount()
+ "\n\tmethods loaded : " + methods_loaded + "\t(rate: " + methods_loaded / (float)ClassFinder.self().getLoadedMethodCount() + ")"
+ "\n\tduplications : " + dup + "\t(methods loaded * duplications: " + methods_loaded * dup + ")"
+ "\nGENERATION PROCESS:"
+ "\n\tcreated with fail : " + fails
+ "\n\tcreated with null : " + nullresults
+ "\n\tcreated totally : " + count
+ "\n\tfiltered type error : " + filter_typeconversions
+ "\n\tfiltered complex types: " + filter_complextypes
+ "\n\tfiltered errors : " + filter_errors
+ "\n\tfiltered nulls : " + filter_nullresults
+ "\n\tmax duration : " + (maxDurationFct != null ? maxDurationFct.duration + " msec\t\t<- " + maxDurationFct.cloneIndex + ":" + maxDurationFct.getFunctionDescription() : "")
+ "\n\tmax mem usage : " + (maxMemUsageFct != null ? ByteUtil.amount(maxMemUsageFct.memusage) + "\t\t\t<- " + maxMemUsageFct.cloneIndex + ":" + maxMemUsageFct.getFunctionDescription() : "")
+ groupByState
+ "\nLOADING PROCESS:"
+ "\n\tfiltered unsuccessful : " + filter_unsuccessful
+ "\n\tload errors : " + load_method_error
+ "\n\tloaded unsuccessful : " + load_unsuccessful
+ "\n\ttotally loaded : " + testers.size() + " (load-rate: " + (testers.size() / (float)dup) / (float)methods_loaded + ", total-rate: "
+ (testers.size() / dup) / (float)ClassFinder.self().getLoadedMethodCount() + ")"
;
AFunctionTester.log(p + s +p);
FileUtil.writeBytes((p + s + p).getBytes(), getTimedFileName() + "statistics.txt", true);
}
}
class Statistics {
Collection statuss = Collections.synchronizedCollection(new LinkedList<>());
public void add(AFunctionCaller fc) { statuss.add(fc.status);}
public String getInfo(int keyWidth) {
int[] count = new int[StatusTyp.values().length];
statuss.forEach(s -> ++count[s.typ.ordinal()]);
final StringBuilder buf = new StringBuilder("\n\tGENERATED FUNCTION TESTERS GROUPED BY STATE:");
for (int i = 0; i < count.length; i++) {
buf.append("\n\t\t" + StringUtil.fixString(StatusTyp.values()[i], keyWidth) + ": " + count[i]);
}
buf.append("\n\t\t" + StringUtil.fixString("<<< TOTALLY >>>", keyWidth) + ": " + statuss.size());
return buf.toString();
}
}
class ExpectationCreator {
private static final String PREF_WHEN = "@" + Expectations.class.getSimpleName() + "({@" + Expect.class.getSimpleName() + "( when = {";
private static final String PREF_THEN = "then = \"";
private static final String PREF_CONSTRUCT = "construct = \"";
private static final String PREF_CONSTRUCT_TYPES = "constructTypes = \"";
static String createExpectationString(AFunctionCaller f, String then) {
try {
if ((then == null || then.equals("null")) && void.class.isAssignableFrom(f.source.getReturnType())) {
if (f.getParameter().length > 0 && f.getParameter()[0] != null)
then = asString(f.getParameter()[0]); // see ExpectationTester.getResultIndex()
}
then = (then != null || f.getResult() == null ? then : asString(f.getResult()));
String expect = "\n@" + Expectations.class.getSimpleName() + "({@" + Expect.class.getSimpleName()
+ "( when = " + Util.toJson(f.getParameter())
+ " then = \"" + then + "\""
+ (f.construction != null && f.construction.parameter != null ?
" constructTypes = " + Util.toJson(f.getConstruction().constructor.getParameterTypes())
+ " construct = " + Util.toJson(f.getConstruction().parameter) : "")
+ "})\n"
+ f.source + "\n\n";
expect = expect.replace("]}", "}");
return expect;
} catch (Exception e) {
f.status = new Status(StatusTyp.STORE_ERROR, null, e);
return null;
}
}
private static String asString(Object obj) {
return AFunctionTester.convertMultilineString(ObjectUtil.isSingleValueType(obj.getClass()) ? FormatUtil.format(obj) : Util.toJson(obj));
}
static Expectations createExpectationFromLine(String l) {
String when[], then, construct[];
when = extractArray(l, PREF_WHEN);
then = StringUtil.substring(l, PREF_THEN, "\"", 0, true);
then = then != null && then.startsWith("{") ? StringUtil.substring(l, PREF_THEN, "}\"", 0, true) : then;
Class[] constructTypes = loadClasses(extractArray(l, PREF_CONSTRUCT_TYPES));
construct = extractArray(l, PREF_CONSTRUCT);
return ExpectationCreator.createExpectation(when, then, constructTypes, construct);
}
private static Class[] loadClasses(String[] typenames) {
if (typenames == null)
return null;
Class[] types = new Class[typenames.length];
for (int i = 0; i < typenames.length; i++) {
types[i] = BeanClass.load(typenames[i]);
}
return types;
}
private static String[] extractArray(String l, String prefix) {
String arr[] = null, all;
all = StringUtil.substring(l, prefix, "} ", 0, true);
if (!Util.isEmpty(all)) {
String obj;
do { // ugly, but the json from MapUtil creates some additional \" that we use to distinguish inner maps and arrays
obj = StringUtil.substring(all, ",\"{\"", "}", true, true);
if (obj != null) {
String obj1 = obj.replaceAll("\"", "");
all = all.replace("\"" + obj, obj1);
}
} while(obj != null);
arr = all.split("\",\"");
for (int i = 0; i < arr.length; i++) {
arr[i] = arr[i].replaceAll("\"", "");
}
}
return arr;
}
static ExpectationsImpl createExpectation(String[] when, String then, Class[] constructTypes, String[] construct) {
return new ExpectationsImpl(new ExpectImpl(-1, null, when, StringUtil.toString(then), -1, constructTypes, construct));
}
@SuppressWarnings("unchecked")
static Method extractMethod(String m) {
String name = StringUtil.substring(m, " ", "(", false);
name = StringUtil.substring(name, " ", "(", true);
String methodName = StringUtil.substring(name, ".", null, true);
String clsName = StringUtil.substring(name, null, "." + methodName);
String pars = StringUtil.substring(m, "(", ")");
try {
return BeanClass.load(clsName).getDeclaredMethod(methodName, Util.isEmpty(pars) ? new Class[0] : createParameterTypes(pars.split("[,]")));
} catch (Exception e) {
AFunctionTester.log(e.toString() + "\n");
return null;
}
}
@SuppressWarnings("rawtypes")
static Class[] createParameterTypes(String[] pars) {
Class[] types = new Class[pars.length];
for (int i = 0; i < types.length; i++) {
types[i] = pars[i].contains("[]")
? BeanClass.loadArrayClass(pars[i])
: pars[i].contains(".")
? BeanClass.load(pars[i])
: PrimitiveUtil.getPrimitiveClass(pars[i]);
}
return types;
}
}
class FunctionCheck {
static Status checkTestSuccessful(AFunctionCaller t, String expect) {
ExpectationFunctionTester tester = null;
try {
tester = new ExpectationFunctionTester(t.cloneIndex, t.source, ExpectationCreator.createExpectationFromLine(expect));
tester.testMe();
if (def(PRECHECK_TWICE, true))
tester.testMe(); //do it twice, sometimes a value changes the first time. would be better to do the initial run() twice!
t.status = tester.status;
return null;
} catch (Exception | AssertionError e) {
return tester != null ? tester.status : new Status(StatusTyp.TEST_FAILED, null, e);
}
}
static boolean checkTypeConversion(Object result) {
try {
String strResult = FormatUtil.format(result);
Object recreatedResult = null;
recreatedResult = ObjectUtil.wrap(strResult, result.getClass());
return AFunctionTester.best(result).equals(AFunctionTester.best(recreatedResult));
} catch (Throwable e) { //catch Throwable as it is possible that something like OutOfMemoryError occur
return false;
}
}
static boolean hasSimpleTypes(AFunctionCaller f) {
if (!isSimpleType(f.source.getReturnType()))
return false;
return Arrays.stream(f.source.getParameterTypes()).allMatch(t -> isSimpleType(t));
}
static boolean isSimpleType(Class> t) {
return ObjectUtil.isStandardType(t) && ObjectUtil.isSingleValueType(t);
}
@SuppressWarnings("rawtypes")
static int filterFailingTest(Collection testers, String filePrefix) {
Collection failing = Collections.synchronizedCollection(new LinkedList<>());
int size = testers.size();
try ( BufferedWriter removedFunctionWriter = FileUtil.getBAWriter(filePrefix + "removed-functions.txt")) {
AtomicReference refWriter = new AtomicReference<>(removedFunctionWriter);
Util.stream(testers, def(PARALLEL, false)).forEach( t -> {
try {
t.testMe();
} catch (Throwable e) {
failing.add(t);
Util.trY( () -> refWriter.get().append(t.getID() + "\n"), false);
}
});
testers.removeAll(failing);
if (testers.size() != size-failing.size())
throw new IllegalStateException("failing testers were not removed from list - check your equals()!");
} catch (IOException e1) {
ManagedException.forward(e1);
}
return failing.size();
}
}
// TODO: replace this implementation by using the AdapterProxy
class ExpectationsImpl implements Expectations {
private Expect[] value;
public ExpectationsImpl(Expect... value) {
this.value = value;
}
@Override
public Class extends Annotation> annotationType() {
return Expectations.class;
}
@Override
public Expect[] value() {
return value;
}
@Override
public String toString() {
return Util.toJson(this);
}
}
class ExpectImpl implements Expect {
private int parIndex;
private String whenPar;
private String[] when;
private String then;
private int resultIndex;
private String[] construct;
private Class[] constructTypes;
@SuppressWarnings("rawtypes")
public ExpectImpl(int parIndex, String whenPar, String[] when, String then, int resultIndex, Class[] constructTypes, String[] construct) {
super();
this.parIndex = parIndex;
this.whenPar = whenPar;
this.when = when;
this.then = then;
this.resultIndex = resultIndex;
this.constructTypes = constructTypes;
this.construct = construct;
}
@Override
public Class extends Annotation> annotationType() {
return Expect.class;
}
@Override
public int parIndex() {
return parIndex;
}
@Override
public String whenPar() {
return whenPar;
}
@Override
public String[] when() {
return when;
}
@Override
public String then() {
return then;
}
@Override
public int resultIndex() {
return resultIndex;
}
@Override
public Class[] constructTypes() {
return constructTypes;
}
@Override
public String[] construct() {
return construct;
}
@Override
public String toString() {
return Util.toJson(this);
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy