package me.tomassetti.turin.compiler.context;
import com.github.javaparser.ast.body.ModifierSet;
import me.tomassetti.turin.classloading.ClassFileDefinition;
import me.tomassetti.turin.classloading.TurinClassLoader;
import me.tomassetti.turin.compiler.AbstractCompilerTest;
import me.tomassetti.turin.compiler.Compiler;
import me.tomassetti.turin.parser.Parser;
import me.tomassetti.turin.parser.ast.TurinFile;
import org.junit.Test;
import turin.context.Context;
import java.io.IOException;
import java.lang.reflect.InvocationTargetException;
import java.util.List;
import java.util.Optional;
import static org.junit.Assert.*;
public class ContextCompilationTest extends AbstractCompilerTest {
@Test
public void aContextClassIsGeneratedForEachContextDefinition() throws IOException {
TurinFile turinFile = new Parser().parse(this.getClass().getResourceAsStream("/context/context_definition.to"));
// generate bytecode
Compiler.Options options = new Compiler.Options();
Compiler instance = new Compiler(getResolverFor(turinFile), options);
List<ClassFileDefinition> classDefinitions = instance.compile(turinFile, new MyErrorCollector());
assertEquals(2, classDefinitions.size());
assertEquals("a.Context_a", classDefinitions.get(0).getName());
assertEquals("a.Context_b", classDefinitions.get(1).getName());
TurinClassLoader classLoader = new TurinClassLoader();
Class contextA = classLoader.addClass(classDefinitions.get(0));
Class contextB = classLoader.addClass(classDefinitions.get(1));
assertEquals(Context.class.getCanonicalName(), contextA.getSuperclass().getCanonicalName());
assertEquals(Context.class.getCanonicalName(), contextB.getSuperclass().getCanonicalName());
}
@Test
public void aContextClassHasAStaticFieldNamedInstance() throws IOException, NoSuchFieldException, IllegalAccessException {
TurinFile turinFile = new Parser().parse(this.getClass().getResourceAsStream("/context/context_definition.to"));
// generate bytecode
Compiler.Options options = new Compiler.Options();
Compiler instance = new Compiler(getResolverFor(turinFile), options);
List<ClassFileDefinition> classDefinitions = instance.compile(turinFile, new MyErrorCollector());
assertEquals(2, classDefinitions.size());
TurinClassLoader classLoader = new TurinClassLoader();
Class contextA = classLoader.addClass(classDefinitions.get(0));
Class contextB = classLoader.addClass(classDefinitions.get(1));
assertEquals(contextA, contextA.getField("INSTANCE").getType());
assertTrue(ModifierSet.isStatic(contextA.getField("INSTANCE").getModifiers()));
assertTrue(ModifierSet.isPublic(contextA.getField("INSTANCE").getModifiers()));
assertTrue(ModifierSet.isFinal(contextA.getField("INSTANCE").getModifiers()));
assertEquals(contextB, contextB.getField("INSTANCE").getType());
assertTrue(ModifierSet.isStatic(contextB.getField("INSTANCE").getModifiers()));
assertTrue(ModifierSet.isPublic(contextB.getField("INSTANCE").getModifiers()));
assertTrue(ModifierSet.isFinal(contextB.getField("INSTANCE").getModifiers()));
assertNotNull(contextA.getField("INSTANCE").get(null));
assertNotNull(contextB.getField("INSTANCE").get(null));
}
@Test
public void contextUsage() throws IOException, NoSuchFieldException, NoSuchMethodException, InvocationTargetException, IllegalAccessException {
TurinFile turinFile = new Parser().parse(this.getClass().getResourceAsStream("/context/context_usage.to"));
// generate bytecode
Compiler.Options options = new Compiler.Options();
Compiler instance = new Compiler(getResolverFor(turinFile), options);
List<ClassFileDefinition> classDefinitions = instance.compile(turinFile, new MyErrorCollector());
assertEquals(3, classDefinitions.size());
TurinClassLoader classLoader = new TurinClassLoader();
Class contextClass = classLoader.addClass(classDefinitions.get(0));
assertEquals("a.Context_worldName", contextClass.getCanonicalName());
Class worldNameInCtxClass = classLoader.addClass(classDefinitions.get(1));
assertEquals("a.Function_worldNameInCtx", worldNameInCtxClass.getCanonicalName());
saveClassFile(classDefinitions.get(1), "ctx");
saveClassFile(classDefinitions.get(2), "ctx");
Class worldNameNoCtxClass = classLoader.addClass(classDefinitions.get(2));
assertEquals("a.Function_worldNameNoCtx", worldNameNoCtxClass.getCanonicalName());
assertEquals(Optional.of("Earth"), worldNameInCtxClass.getMethod("invoke", new Class[]{}).invoke(null));
assertEquals(Optional.empty(), worldNameNoCtxClass.getMethod("invoke", new Class[]{}).invoke(null));
}
}