package net.teamio.blockunit;

import net.teamio.taam.content.piping.MachinePipeTest;
import net.teamio.taam.content.piping.MachineTankTest;
import net.teamio.taam.piping.PipeEndFluidHandlerTest;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;

import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.List;

/**
 * Base framework for the in-game unit testing.
 * Test classes that are registered are instantiated & all methods annotated with {@link TestMethod} are executed.
 * Test methods have to be either parameterless, in which case only exception-free execution is tested;
 * or have one parameter of the type {@link TestingHarness} for performing test assertions.
 * <p>
 * Created by oliver on 2017-07-03.
 */
public class Framework {

	public static final Logger LOGGER = LogManager.getLogger("net.teamio.blockunit");

	private static List<Class<?>> tests = new ArrayList<Class<?>>(20);

	public static void runTests() {
		registerTests();

		LOGGER.info("Running tests...");

		int classCount = 0;
		int classCountSuccessful = 0;
		int methodCount = 0;
		int methodCountSuccessful = 0;

		for (Class<?> cls : tests) {
			classCount++;
			LOGGER.info("Test class " + cls.getName());
			Object instance;
			try {
				instance = cls.newInstance();
			} catch (InstantiationException e) {
				e.printStackTrace();
				continue;
			} catch (IllegalAccessException e) {
				e.printStackTrace();
				continue;
			}

			boolean didAnyFail = false;

			Method[] methods = cls.getMethods();
			for (Method m : methods) {
				if (m.isAnnotationPresent(TestMethod.class)) {
					methodCount++;
					try {
						LOGGER.info("Running test method " + m.getName());
						runTest(instance, m);
						LOGGER.info("Test case successful");
						methodCountSuccessful++;
					} catch (Exception e) {
						LOGGER.error("Test failed horribly", e);
						didAnyFail = true;
					}
				}
			}
			if (!didAnyFail) {
				classCountSuccessful++;
			}
		}
		LOGGER.info("Tests complete. {}/{} tests successful - {}/{} total methods successful", classCountSuccessful, classCount, methodCountSuccessful, methodCount);
	}

	public static void runTest(Object instance, Method m) {
		Class<?>[] params = m.getParameterTypes();
		if (params.length == 0) {
			// "Just check for failure or not"
			try {
				m.invoke(instance);
			} catch (IllegalAccessException e) {
				throw new RuntimeException("Error accessing test method " + m.getName(), e);
			} catch (InvocationTargetException e) {
				Throwable te = e.getTargetException();
				if (te instanceof TestAssertionException) {
					LOGGER.error("Test assertion failed", te);
				} else {
					LOGGER.error("Test failed with exception", te);
				}
			}
		} else if (params.length == 1) {
			if (params[0] != TestingHarness.class) {
				// Umm.. did you read the documentation?
				LOGGER.error("Incorrect parameters for test method " + m.getName());
				return;
			}
			// Detailed testing with test harness
			try {
				m.invoke(instance, new TestingHarness());
			} catch (IllegalAccessException e) {
				LOGGER.error("Error accessing test method " + m.getName(), e);
			} catch (InvocationTargetException e) {
				Throwable te = e.getTargetException();
				if (te instanceof TestAssertionException) {
					LOGGER.error("Test assertion failed", te);
				} else {
					LOGGER.error("Test failed with exception", te);
				}
			}
		} else {
			// Umm.. did you read the documentation?
			LOGGER.error("Incorrect parameters for test method " + m.getName());
		}
	}

	public static void registerTestClass(Class cls) {
		tests.add(cls);
	}

	public static void registerTests() {
		tests.clear();
		//TODO: This should not be in the Framework class
		registerTestClass(PipeEndFluidHandlerTest.class);
		registerTestClass(MachineTankTest.class);
		registerTestClass(MachinePipeTest.class);
	}
}

@@ -1769,16 +1769,20 @@
 ;%0A%09%09%09%09%09%09
+if (
 runTest(
@@ -1793,24 +1793,27 @@
 ance, m)
-;
+) %7B
 %0A%09%09%09%09%09%09
+%09
 LOGGER.i
@@ -1843,24 +1843,25 @@
 ul%22);%0A%09%09%09%09%09%09
+%09
 methodCountS
@@ -1869,24 +1869,73 @@
 ccessful++;%0A
+%09%09%09%09%09%09%7D else %7B%0A%09%09%09%09%09%09%09didAnyFail = true;%0A%09%09%09%09%09%09%7D%0A
 %09%09%09%09%09%7D catch
@@ -2271,36 +2271,39 @@
 %0A%09public static 
-void
+boolean
  runTest(Object 
@@ -2464,24 +2464,41 @@
 (instance);%0A
+%09%09%09%09return true;%0A
 %09%09%09%7D catch (
@@ -3072,16 +3072,22 @@
 %09%09return
+ false
 ;%0A%09%09%09%7D%0A%09
@@ -3181,16 +3181,33 @@
 ess());%0A
+%09%09%09%09return true;%0A
 %09%09%09%7D cat
@@ -3691,20 +3691,36 @@
 ame());%0A
-
 %09%09%7D%0A
+%09%09return false;%0A
 %09%7D%0A%0A%09pub

Fix test failure detection