package targetast;

import de.dhbwstuttgart.environment.ByteArrayClassLoader;
import org.junit.BeforeClass;
import org.junit.Test;

import java.lang.reflect.Method;
import java.nio.file.Path;
import java.util.Vector;

import static org.junit.Assert.assertEquals;

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

    @BeforeClass
    public static void setUpBeforeClass() throws Exception {
        var classLoader = new ByteArrayClassLoader();

        var classes = TestCodegen.generateClassFiles(classLoader, "Inherit.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(m.invoke(instanceOfClassAA, 5), "AA");
        Method main = classToTest.getDeclaredMethod("main", classToTestAA, Integer.class);
        assertEquals(main.invoke(instanceOfClass, instanceOfClassAA, 5), "AA");
    }

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

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

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

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

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

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

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