All Downloads are FREE. Search and download functionalities are using the official Maven repository.

de.tsl2.nano.autotest.creator.AFunctionTester Maven / Gradle / Ivy

The newest version!
package de.tsl2.nano.autotest.creator;

import static org.junit.Assert.assertArrayEquals;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;

import java.io.Serializable;
import java.lang.annotation.Annotation;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.Collection;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Set;

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.util.ConcurrentUtil;
import de.tsl2.nano.core.util.FileUtil;
import de.tsl2.nano.core.util.ObjectUtil;
import de.tsl2.nano.core.util.Util;

/**
 * base class to create automated parameterized test through the information of an annotation.
 * 
 * @param  Function Test Annotation
 * 
 * @author ts
 */
@SuppressWarnings("rawtypes")
public abstract class AFunctionTester extends AFunctionCaller  implements Runnable, Cloneable {
	protected transient A def;
	private static final float DELTA_FLOAT = Util.get(PREF_PROPS + "delta.float", 0.0000000001f);
	private static final float DELTA_DOUBLE = Util.get(PREF_PROPS + "delta.double", 0.0000000001f);

	public AFunctionTester(Method source) {
		super(source);
	}

	public AFunctionTester(int iteration, Method source) {
		super(iteration, source);
	}

	public static Collection createRunners(Class testerType, int duplication, String filter) {
		try {
			log("collecting tests for " + testerType.getSimpleName() + ":\n");
			Class type = testerType.getAnnotation(FunctionType.class).value();
			List revFcts = ClassFinder.self().find(filter, Method.class, -1, type);
			Set runners = new LinkedHashSet<>(revFcts.size());
			revFcts.forEach(m -> runners.add(createRunner(testerType, m)));
			duplicate(duplication, runners);
			return runners;
		} catch (Throwable e) {
			ConcurrentUtil.sleep(3000);
			e.printStackTrace();
			ManagedException.forward(e);
			return null;
		}
	}

	protected static AFunctionTester createRunner(Class testerType, Method m) {
		return BeanClass.createInstance(testerType, m);
	}

	private static void duplicate(int duplication, Set runners) {
		log("duplicating " + runners.size() + " runners " + duplication + " times\n");
		ArrayList current = new ArrayList<>(runners);
		ArrayList clones = new ArrayList<>();
		for (int i = 0; i < duplication; i++) {
			clones.clear();
			for (AFunctionTester tester : current) {
				clones.add((AFunctionTester) Util.trY(() -> tester.clone()));
			}
			runners.addAll(clones);
			current.clear();
			current.addAll(clones);
		}
	}

	public static Object best(Object obj) {
		return obj == null || (ObjectUtil.isStandardType(obj) || ObjectUtil.isSingleValueType(obj.getClass())) && ObjectUtil.hasEquals(obj.getClass()) 
				? obj 
				: obj instanceof Serializable && !obj.getClass().isAnonymousClass() && !(obj instanceof StringBuilder) && !(obj instanceof StringBuffer)
					? bytes(obj) 
					: string(obj);
	}

	/** to be overwritten */
	protected void doBetween() {
	}

	public abstract Object getCompareOrigin();
	public abstract Object getCompareResult();
	public abstract Throwable getExpectFail();

	public static String getErrorMsg(Throwable e) {
		Throwable rootCause = ManagedException.getRootCause(e);
		return convertMultilineString(rootCause.toString());
	}
	
	static Object convertOnMultilineString(Object obj) {
		return obj instanceof String ? convertMultilineString(obj.toString()) : obj;
	}

	static String convertMultilineString(String txt) {
		//TODO: at the moment, we read only one line per expectation!
		return txt.replace('\r', ' ').replace('\n', ' ');
	}

	protected int undefToZeroIndex(int index) {
		return index < 0 ? 0 : index;
	}

	public static byte[] bytes(Object obj) {
		return ObjectUtil.serialize(obj);
	}

	public static String string(Object obj) {
		return Util.toJson(obj);
	}

	public static Collection prepareTestParameters(FunctionTester types) {
		Collection runners = new LinkedHashSet<>();
		for (int i = 0; i < types.value().length; i++) {
			runners.addAll(AFunctionTester.createRunners(types.value()[i], def(AutoTest.DUPLICATION, 3), def(AutoTest.FILTER, "")));
		}
		return runners;
	}

	public void testMe() {
		long start = System.currentTimeMillis();
		try {
			runWithTimeout();
			checkFail();
			if (def(AutoTest.FILTER_NULLRESULTS, false))
				assertTrue(getCompareOrigin() != null || getCompareResult() != null);

			Object o1 = best(getCompareOrigin());
			Object o2 = best(getCompareResult());
			if (o1 != null && o1.getClass().isArray())
				assertAnyArrayEquals(o1, o2);
			else {
				assertEquals(toString(), o1, o2);
			}
			status = new Status(StatusTyp.TESTED, (System.currentTimeMillis() - start) / 1000 + " sec", null);
			logd(cloneIndex + ": " + getFunctionDescription() + "\n");
		} catch (Exception | AssertionError e) {
			boolean shouldFailError = false;
			try {
				if (shouldFail(e)) {
					status = new Status(StatusTyp.TESTED, (System.currentTimeMillis() - start) / 1000 + " sec", e);
					return;
				}
			} catch (Exception | AssertionError e1) {
				status = new Status(StatusTyp.TEST_FAILED, e1.toString(), e1);
				shouldFailError = true;
			}
			if (!shouldFailError)
				status = new Status(StatusTyp.TEST_FAILED, e.toString(), e);
			logd(" -> " + status + "\n");
			if (!Util.get(PREF_PROPS + "testneverfail", false)) {
				if (AutoTestGenerator.progress != null && AutoTestGenerator.progress.isFinished())
					Util.trY( () -> FileUtil.writeBytes(("\n\nTEST: " + toString() + "\n" + ManagedException.toString(e)).getBytes(), def("timedfilename", "") + AutoTestGenerator.fileName + "failed-tests.txt", true), false);
				ManagedException.forward(e);
			} else
				logd("ERROR (testneverfail=true): " + status);
		}
	}

	private boolean checkFail() {
		return shouldFail(status.err);
	}
	private boolean shouldFail(Throwable error) {
		Throwable expectedFail;
		String emsg;
		if ((expectedFail = getExpectFail()) != null) {
			/*
			 * on exptected             : "IllegalArgumentException: argument type mismatch"
			 * the end test results with: "IllegalArgumentException: ClassCastException@"
			 *  -> same Callstack, same Problem, but there are diffent MethodAccessor Implementations envolved:
			 *     1. NativeMethodAccessorImpl
			 *     2. GeneratedMethodAccessor1
			 * don't know why, but as the methods are not invoked, the test can/should fail!
			 */
			if (error == null)
				fail("test should fail with:\n\t" + expectedFail + "\nbut has result:\n\t" + getResult());
			else if (!getErrorMsg(error)
					.contains((emsg = getErrorMsg(expectedFail)).substring(0, Math.min(50, emsg.length())))
					&& !getErrorMsg(expectedFail)
							.contains((emsg = getErrorMsg(error)).substring(0, Math.min(50, emsg.length()))))
				fail("test should fail with:\n\t" + expectedFail + " but failed with:\n\t" + error);
			return true;
		}
		return false;
	}

	protected void assertAnyArrayEquals(Object o1, Object o2) {
		if (o1.getClass().getComponentType() == byte.class)
			assertArrayEquals(toString(), (byte[])o1, (byte[])o2);
		else if (o1.getClass().getComponentType() == char.class)
			assertArrayEquals(toString(), (char[])o1, (char[])o2);
		else if (o1.getClass().getComponentType() == short.class)
			assertArrayEquals(toString(), (short[])o1, (short[])o2);
		else if (o1.getClass().getComponentType() == int.class)
			assertArrayEquals(toString(), (int[])o1, (int[])o2);
		else if (o1.getClass().getComponentType() == float.class)
			assertArrayEquals(toString(), (float[])o1, (float[])o2, DELTA_FLOAT);
		else if (o1.getClass().getComponentType() == double.class)
			assertArrayEquals(toString(), (double[])o1, (double[])o2, DELTA_DOUBLE);
		else
			assertArrayEquals(toString(), (Object[])o1, (Object[])o2);
	}
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy