package targetast;

import de.dhbwstuttgart.core.ConsoleInterface;
import de.dhbwstuttgart.util.Logger;
import org.junit.jupiter.api.BeforeAll;
import org.junit.jupiter.api.Test;

import java.lang.reflect.Method;
import java.util.Vector;

import static org.junit.jupiter.api.Assertions.assertEquals;

public class InheritTest {
    private static Class<?> classToTest, classToTestAA, classToTestBB, classToTestCC, classToTestDD;
    private static Object instanceOfClass, instanceOfClassAA, instanceOfClassBB, instanceOfClassCC, instanceOfClassDD;

    @BeforeAll
    public static void setUpBeforeClass() throws Exception {
        var classLoader = TestCodegen.createClassLoader();

        var classes = TestCodegen.generateClassFiles(classLoader, "Inherit.jav", "AA.jav", "BB.jav", "CC.jav", "DD.jav");
        classToTest = classes.get("Inherit");
        classToTestAA = classes.get("AA");
        classToTestBB = classes.get("BB");
        classToTestCC = classes.get("CC");
        classToTestDD = classes.get("DD");

        instanceOfClass   = classToTest.getDeclaredConstructor().newInstance();
        instanceOfClassAA = classToTestAA.getDeclaredConstructor().newInstance();
        instanceOfClassBB = classToTestBB.getDeclaredConstructor().newInstance();
        instanceOfClassCC = classToTestCC.getDeclaredConstructor().newInstance();
        instanceOfClassDD = classToTestDD.getDeclaredConstructor().newInstance();
    }

    @Test
    public void testmainAA() throws Exception {
        Method m = classToTestAA.getDeclaredMethod("m", Integer.class);
        assertEquals("AA", m.invoke(instanceOfClassAA, 5));
        Method main = classToTest.getDeclaredMethod("main", classToTestAA, Integer.class);
        assertEquals("AA", main.invoke(instanceOfClass, instanceOfClassAA, 5));
    }

    @Test
    public void testmainBB() throws Exception {
        Method m = classToTestAA.getDeclaredMethod("m", Integer.class);
        assertEquals("AA", m.invoke(instanceOfClassBB, 5));
        Method main = classToTest.getDeclaredMethod("main", classToTestAA, Integer.class);
        assertEquals("AA", main.invoke(instanceOfClass, instanceOfClassBB, 5));
    }

    @Test
    public void testmainCC() throws Exception {
        Method m = classToTestCC.getDeclaredMethod("m", Integer.class);
        assertEquals("CC", m.invoke(instanceOfClassCC, 5));
        Method main = classToTest.getDeclaredMethod("main", classToTestCC, Integer.class);
        assertEquals("CC", main.invoke(instanceOfClass, instanceOfClassCC, 5));
    }

    @Test
    public void testmainDD() throws Exception {
        Method m = classToTestCC.getDeclaredMethod("m", Integer.class);
        assertEquals("CC", m.invoke(instanceOfClassDD, 5));
        Method main = classToTest.getDeclaredMethod("main", classToTestCC, Integer.class);
        assertEquals("CC", main.invoke(instanceOfClass, instanceOfClassDD, 5));
    }

    @Test
    public void testmainVectorAA() throws Exception {
        Method m = classToTestAA.getDeclaredMethod("m", Integer.class);
        assertEquals("AA", m.invoke(instanceOfClassAA, 5));
        Vector v = new Vector<>();
        v.add(instanceOfClassAA);
        Method main = classToTest.getDeclaredMethod("main", Vector.class, Integer.class);
        assertEquals("AA", main.invoke(instanceOfClass, v, 5));
    }

    @Test
    public void testmainVectorBB() throws Exception {
        Method m = classToTestAA.getDeclaredMethod("m", Integer.class);
        assertEquals("AA", m.invoke(instanceOfClassBB, 5));
        Vector v = new Vector<>();
        v.add(instanceOfClassBB);
        Method main = classToTest.getDeclaredMethod("main", Vector.class, Integer.class);
        assertEquals("AA", main.invoke(instanceOfClass, v, 5));
    }

    @Test
    public void testmainVectorCC() throws Exception {
        Method m = classToTestCC.getDeclaredMethod("m", Integer.class);
        assertEquals("CC", m.invoke(instanceOfClassCC, 5));
        Vector v = new Vector<>();
        v.add(instanceOfClassCC);
        Method main = classToTest.getDeclaredMethod("main", Vector.class, Integer.class);
        assertEquals("CC", main.invoke(instanceOfClass, v, 5));
    }

    @Test
    public void testmainVectorDD() throws Exception {
        Method m = classToTestCC.getDeclaredMethod("m", Integer.class);
        assertEquals("CC", m.invoke(instanceOfClassDD, 5));
        Vector v = new Vector<>();
        v.add(instanceOfClassDD);
        Method main = classToTest.getDeclaredMethod("main", Vector.class, Integer.class);
        assertEquals("CC", main.invoke(instanceOfClass, v, 5));
    }
}
