package me.tomassetti.turin.compiler;
import me.tomassetti.turin.classloading.ClassFileDefinition;
import me.tomassetti.turin.classloading.TurinClassLoader;
import me.tomassetti.turin.parser.ast.typeusage.BasicTypeUsageNode;
import me.tomassetti.turin.resolvers.InFileSymbolResolver;
import me.tomassetti.turin.resolvers.jdk.JdkTypeResolver;
import me.tomassetti.turin.parser.ast.NamespaceDefinition;
import me.tomassetti.turin.parser.ast.*;
import me.tomassetti.turin.parser.ast.TurinFile;
import me.tomassetti.turin.parser.ast.properties.PropertyDefinition;
import me.tomassetti.turin.parser.ast.properties.PropertyReference;
import me.tomassetti.turin.parser.ast.typeusage.ReferenceTypeUsageNode;
import org.junit.Test;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.Collections;
import java.util.List;
import java.util.Optional;
import static org.junit.Assert.*;
public class CompilerOnAstTest extends AbstractCompilerTest {
private TurinFile mangaAst() {
// define AST
TurinFile turinFile = new TurinFile();
NamespaceDefinition namespaceDefinition = new NamespaceDefinition("manga");
turinFile.setNameSpace(namespaceDefinition);
ReferenceTypeUsageNode stringType = new ReferenceTypeUsageNode("String");
BasicTypeUsageNode intType = new BasicTypeUsageNode("uint");
PropertyDefinition nameProperty = new PropertyDefinition("name", stringType, Optional.empty(), Optional.empty(), Collections.emptyList());
turinFile.add(nameProperty);
TurinTypeDefinition mangaCharacter = new TurinTypeDefinition("MangaCharacter");
mangaCharacter.setPosition(Position.create(0, 0, 0, 0));
PropertyDefinition ageProperty = new PropertyDefinition("age", intType, Optional.empty(), Optional.empty(), Collections.emptyList());
PropertyReference nameRef = new PropertyReference("name");
mangaCharacter.add(nameRef);
mangaCharacter.add(ageProperty);
turinFile.add(mangaCharacter);
return turinFile;
}
@Test
public void compileAstManga() throws IllegalAccessException, InvocationTargetException, InstantiationException, NoSuchMethodException {
TurinFile turinFile = mangaAst();
// generate bytecode
Compiler instance = new Compiler(new InFileSymbolResolver(JdkTypeResolver.getInstance()), new Compiler.Options());
List<ClassFileDefinition> classFileDefinitions = instance.compile(turinFile, new AbstractCompilerTest.MyErrorCollector());
assertEquals(1, classFileDefinitions.size());
TurinClassLoader turinClassLoader = new TurinClassLoader();
Class mangaCharacterClass = turinClassLoader.addClass(classFileDefinitions.get(0).getName(),
classFileDefinitions.get(0).getBytecode());
assertEquals(1, mangaCharacterClass.getConstructors().length);
Object ranma = mangaCharacterClass.getConstructors()[0].newInstance("Ranma", 16);
Method getName = mangaCharacterClass.getMethod("getName");
assertEquals("Ranma", getName.invoke(ranma));
Method getAge = mangaCharacterClass.getMethod("getAge");
assertEquals(16, getAge.invoke(ranma));
}
@Test
public void compileAstRegistryPerson() throws IllegalAccessException, InvocationTargetException, InstantiationException, NoSuchMethodException {
TurinFile turinFile = ExamplesAst.registryAst();
// generate bytecode
Compiler instance = new Compiler(new InFileSymbolResolver(JdkTypeResolver.getInstance()), new Compiler.Options());
List<ClassFileDefinition> classFileDefinitions = instance.compile(turinFile, new AbstractCompilerTest.MyErrorCollector());
assertEquals(2, classFileDefinitions.size());
assertEquals("registry.Person", classFileDefinitions.get(0).getName());
TurinClassLoader turinClassLoader = new TurinClassLoader();
Class personClass = turinClassLoader.addClass(classFileDefinitions.get(0).getName(),
classFileDefinitions.get(0).getBytecode());
assertEquals(1, personClass.getConstructors().length);
assertEquals(2, personClass.getConstructors()[0].getParameterTypes().length);
Object federico = personClass.getConstructors()[0].newInstance("Federico", "Tomassetti");
Method getFirstName = personClass.getMethod("getFirstName");
assertEquals("Federico", getFirstName.invoke(federico));
Method getLastName = personClass.getMethod("getLastName");
assertEquals("Tomassetti", getLastName.invoke(federico));
}
@Test
public void compileAstRegistryAddress() throws IllegalAccessException, InvocationTargetException, InstantiationException, NoSuchMethodException {
TurinFile turinFile = ExamplesAst.registryAst();
// generate bytecode
Compiler instance = new Compiler(new InFileSymbolResolver(JdkTypeResolver.getInstance()), new Compiler.Options());
List<ClassFileDefinition> classFileDefinitions = instance.compile(turinFile, new AbstractCompilerTest.MyErrorCollector());
assertEquals(2, classFileDefinitions.size());
assertEquals("registry.Address", classFileDefinitions.get(1).getName());
TurinClassLoader turinClassLoader = new TurinClassLoader();
Class addressClass = turinClassLoader.addClass(classFileDefinitions.get(1).getName(),
classFileDefinitions.get(1).getBytecode());
assertEquals(1, addressClass.getConstructors().length);
assertEquals(4, addressClass.getConstructors()[0].getParameterTypes().length);
Object address = addressClass.getConstructors()[0].newInstance("Rue de Seze", 86, "Lyon", 69006);
assertEquals("Rue de Seze", addressClass.getMethod("getStreet").invoke(address));
assertEquals(86, addressClass.getMethod("getNumber").invoke(address));
assertEquals("Lyon", addressClass.getMethod("getCity").invoke(address));
assertEquals(69006, addressClass.getMethod("getZip").invoke(address));
}
@Test
public void compileAstRegistryAddressSetters() throws IllegalAccessException, InvocationTargetException, InstantiationException, NoSuchMethodException {
TurinFile turinFile = ExamplesAst.registryAst();
// generate bytecode
Compiler instance = new Compiler(new InFileSymbolResolver(JdkTypeResolver.getInstance()), new Compiler.Options());
List<ClassFileDefinition> classFileDefinitions = instance.compile(turinFile, new AbstractCompilerTest.MyErrorCollector());
assertEquals(2, classFileDefinitions.size());
assertEquals("registry.Address", classFileDefinitions.get(1).getName());
TurinClassLoader turinClassLoader = new TurinClassLoader();
Class addressClass = turinClassLoader.addClass(classFileDefinitions.get(1).getName(),
classFileDefinitions.get(1).getBytecode());
assertEquals(1, addressClass.getConstructors().length);
assertEquals(4, addressClass.getConstructors()[0].getParameterTypes().length);
Object address = addressClass.getConstructors()[0].newInstance("Rue de Seze", 86, "Lyon", 69006);
addressClass.getMethod("setStreet", String.class).invoke(address, "Piazza Emanuele Filiberto");
addressClass.getMethod("setNumber", int.class).invoke(address, 4);
addressClass.getMethod("setCity", String.class).invoke(address, "Torino");
addressClass.getMethod("setZip", int.class).invoke(address, 10136);
assertEquals("Piazza Emanuele Filiberto", addressClass.getMethod("getStreet").invoke(address));
assertEquals(4, addressClass.getMethod("getNumber").invoke(address));
assertEquals("Torino", addressClass.getMethod("getCity").invoke(address));
assertEquals(10136, addressClass.getMethod("getZip").invoke(address));
}
@Test
public void nullIsNotAcceptedForNameProperty() throws IllegalAccessException, InvocationTargetException, InstantiationException, NoSuchMethodException {
TurinFile turinFile = mangaAst();
// generate bytecode
Compiler instance = new Compiler(new InFileSymbolResolver(JdkTypeResolver.getInstance()), new Compiler.Options());
List<ClassFileDefinition> classFileDefinitions = instance.compile(turinFile, new AbstractCompilerTest.MyErrorCollector());
assertEquals(1, classFileDefinitions.size());
TurinClassLoader turinClassLoader = new TurinClassLoader();
Class mangaCharacterClass = turinClassLoader.addClass(classFileDefinitions.get(0).getName(),
classFileDefinitions.get(0).getBytecode());
assertEquals(1, mangaCharacterClass.getConstructors().length);
try {
Object ranma = mangaCharacterClass.getConstructors()[0].newInstance(null, 16);
fail("exception expected");
} catch (InvocationTargetException e) {
assertTrue(e.getTargetException() instanceof IllegalArgumentException);
assertEquals("name cannot be null", e.getTargetException().getMessage());
}
}
@Test
public void negativeAgeIsNotAcceptedForNameProperty() throws IllegalAccessException, InvocationTargetException, InstantiationException, NoSuchMethodException {
TurinFile turinFile = mangaAst();
// generate bytecode
Compiler instance = new Compiler(new InFileSymbolResolver(JdkTypeResolver.getInstance()), new Compiler.Options());
List<ClassFileDefinition> classFileDefinitions = instance.compile(turinFile, new AbstractCompilerTest.MyErrorCollector());
assertEquals(1, classFileDefinitions.size());
TurinClassLoader turinClassLoader = new TurinClassLoader();
Class mangaCharacterClass = turinClassLoader.addClass(classFileDefinitions.get(0).getName(),
classFileDefinitions.get(0).getBytecode());
assertEquals(1, mangaCharacterClass.getConstructors().length);
try {
Object ranma = mangaCharacterClass.getConstructors()[0].newInstance("Ranma", -16);
fail("exception expected");
} catch (InvocationTargetException e) {
assertTrue(e.getTargetException() instanceof IllegalArgumentException);
assertEquals("age should be positive", e.getTargetException().getMessage());
}
}
@Test
public void equalsIsGeneratedCorrectlyPositiveCase() throws IllegalAccessException, InvocationTargetException, InstantiationException, NoSuchMethodException {
TurinFile turinFile = mangaAst();
// generate bytecode
Compiler instance = new Compiler(new InFileSymbolResolver(JdkTypeResolver.getInstance()), new Compiler.Options());
List<ClassFileDefinition> classFileDefinitions = instance.compile(turinFile, new AbstractCompilerTest.MyErrorCollector());
assertEquals(1, classFileDefinitions.size());
TurinClassLoader turinClassLoader = new TurinClassLoader();
Class mangaCharacterClass = turinClassLoader.addClass(classFileDefinitions.get(0).getName(),
classFileDefinitions.get(0).getBytecode());
assertEquals(1, mangaCharacterClass.getConstructors().length);
Object ranma1 = mangaCharacterClass.getConstructors()[0].newInstance("Ranma", 16);
Object ranma2 = mangaCharacterClass.getConstructors()[0].newInstance("Ranma", 16);
assertTrue(ranma1.equals(ranma2));
assertTrue(ranma2.equals(ranma1));
}
@Test
public void equalsIsGeneratedCorrectlyDifferentName() throws IllegalAccessException, InvocationTargetException, InstantiationException, NoSuchMethodException {
TurinFile turinFile = mangaAst();
// generate bytecode
Compiler instance = new Compiler(new InFileSymbolResolver(JdkTypeResolver.getInstance()), new Compiler.Options());
List<ClassFileDefinition> classFileDefinitions = instance.compile(turinFile, new AbstractCompilerTest.MyErrorCollector());
assertEquals(1, classFileDefinitions.size());
TurinClassLoader turinClassLoader = new TurinClassLoader();
Class mangaCharacterClass = turinClassLoader.addClass(classFileDefinitions.get(0).getName(),
classFileDefinitions.get(0).getBytecode());
assertEquals(1, mangaCharacterClass.getConstructors().length);
Object ranma1 = mangaCharacterClass.getConstructors()[0].newInstance("Ranma", 16);
Object ranma2 = mangaCharacterClass.getConstructors()[0].newInstance("Ranma Saotome", 16);
assertFalse(ranma1.equals(ranma2));
assertFalse(ranma2.equals(ranma1));
}
@Test
public void equalsIsGeneratedCorrectlyDifferentAge() throws IllegalAccessException, InvocationTargetException, InstantiationException, NoSuchMethodException {
TurinFile turinFile = mangaAst();
// generate bytecode
Compiler instance = new Compiler(new InFileSymbolResolver(JdkTypeResolver.getInstance()), new Compiler.Options());
List<ClassFileDefinition> classFileDefinitions = instance.compile(turinFile, new AbstractCompilerTest.MyErrorCollector());
assertEquals(1, classFileDefinitions.size());
TurinClassLoader turinClassLoader = new TurinClassLoader();
Class mangaCharacterClass = turinClassLoader.addClass(classFileDefinitions.get(0).getName(),
classFileDefinitions.get(0).getBytecode());
assertEquals(1, mangaCharacterClass.getConstructors().length);
Object ranma1 = mangaCharacterClass.getConstructors()[0].newInstance("Ranma", 16);
Object ranma2 = mangaCharacterClass.getConstructors()[0].newInstance("Ranma", 18);
assertFalse(ranma1.equals(ranma2));
assertFalse(ranma2.equals(ranma1));
}
@Test
public void equalsIsGeneratedCorrectlyOnOtherClassReturnFalse() throws IllegalAccessException, InvocationTargetException, InstantiationException, NoSuchMethodException {
TurinFile turinFile = mangaAst();
// generate bytecode
Compiler instance = new Compiler(new InFileSymbolResolver(JdkTypeResolver.getInstance()), new Compiler.Options());
List<ClassFileDefinition> classFileDefinitions = instance.compile(turinFile, new AbstractCompilerTest.MyErrorCollector());
assertEquals(1, classFileDefinitions.size());
TurinClassLoader turinClassLoader = new TurinClassLoader();
Class mangaCharacterClass = turinClassLoader.addClass(classFileDefinitions.get(0).getName(),
classFileDefinitions.get(0).getBytecode());
assertEquals(1, mangaCharacterClass.getConstructors().length);
Object ranma1 = mangaCharacterClass.getConstructors()[0].newInstance("Ranma", 16);
Object ranma2 = new String("Ranma");
assertFalse(ranma1.equals(ranma2));
assertFalse(ranma2.equals(ranma1));
}
@Test
public void equalsIsGeneratedCorrectlyOnNullReturnFalse() throws IllegalAccessException, InvocationTargetException, InstantiationException, NoSuchMethodException {
TurinFile turinFile = mangaAst();
// generate bytecode
Compiler instance = new Compiler(new InFileSymbolResolver(JdkTypeResolver.getInstance()), new Compiler.Options());
List<ClassFileDefinition> classFileDefinitions = instance.compile(turinFile, new AbstractCompilerTest.MyErrorCollector());
assertEquals(1, classFileDefinitions.size());
TurinClassLoader turinClassLoader = new TurinClassLoader();
Class mangaCharacterClass = turinClassLoader.addClass(classFileDefinitions.get(0).getName(),
classFileDefinitions.get(0).getBytecode());
assertEquals(1, mangaCharacterClass.getConstructors().length);
Object ranma1 = mangaCharacterClass.getConstructors()[0].newInstance("Ranma", 16);
Object ranma2 = null;
assertFalse(ranma1.equals(ranma2));
}
@Test
public void equalsIsGeneratedCorrectlyIsEqualsToItSelf() throws IllegalAccessException, InvocationTargetException, InstantiationException, NoSuchMethodException {
TurinFile turinFile = mangaAst();
// generate bytecode
Compiler instance = new Compiler(new InFileSymbolResolver(JdkTypeResolver.getInstance()), new Compiler.Options());
List<ClassFileDefinition> classFileDefinitions = instance.compile(turinFile, new AbstractCompilerTest.MyErrorCollector());
assertEquals(1, classFileDefinitions.size());
TurinClassLoader turinClassLoader = new TurinClassLoader();
Class mangaCharacterClass = turinClassLoader.addClass(classFileDefinitions.get(0).getName(),
classFileDefinitions.get(0).getBytecode());
assertEquals(1, mangaCharacterClass.getConstructors().length);
Object ranma1 = mangaCharacterClass.getConstructors()[0].newInstance("Ranma", 16);
Object ranma2 = ranma1;
assertTrue(ranma1.equals(ranma2));
}
@Test
public void hashcodeIsGeneratedCorrectlyPositiveCase() throws IllegalAccessException, InvocationTargetException, InstantiationException, NoSuchMethodException {
TurinFile turinFile = mangaAst();
// generate bytecode
Compiler instance = new Compiler(new InFileSymbolResolver(JdkTypeResolver.getInstance()), new Compiler.Options());
List<ClassFileDefinition> classFileDefinitions = instance.compile(turinFile, new AbstractCompilerTest.MyErrorCollector());
assertEquals(1, classFileDefinitions.size());
TurinClassLoader turinClassLoader = new TurinClassLoader();
Class mangaCharacterClass = turinClassLoader.addClass(classFileDefinitions.get(0).getName(),
classFileDefinitions.get(0).getBytecode());
assertEquals(1, mangaCharacterClass.getConstructors().length);
Object ranma1 = mangaCharacterClass.getConstructors()[0].newInstance("Ranma", 16);
Object ranma2 = mangaCharacterClass.getConstructors()[0].newInstance("Ranma", 16);
assertTrue(ranma1.hashCode() == ranma2.hashCode());
assertTrue(ranma2.hashCode() == ranma1.hashCode());
}
@Test
public void hashcodeIsGeneratedCorrectlyDifferentName() throws IllegalAccessException, InvocationTargetException, InstantiationException, NoSuchMethodException {
TurinFile turinFile = mangaAst();
// generate bytecode
Compiler instance = new Compiler(new InFileSymbolResolver(JdkTypeResolver.getInstance()), new Compiler.Options());
List<ClassFileDefinition> classFileDefinitions = instance.compile(turinFile, new AbstractCompilerTest.MyErrorCollector());
assertEquals(1, classFileDefinitions.size());
TurinClassLoader turinClassLoader = new TurinClassLoader();
Class mangaCharacterClass = turinClassLoader.addClass(classFileDefinitions.get(0).getName(),
classFileDefinitions.get(0).getBytecode());
assertEquals(1, mangaCharacterClass.getConstructors().length);
Object ranma1 = mangaCharacterClass.getConstructors()[0].newInstance("Ranma", 16);
Object ranma2 = mangaCharacterClass.getConstructors()[0].newInstance("Ranma Saotome", 16);
assertFalse(ranma1.hashCode() == ranma2.hashCode());
assertFalse(ranma2.hashCode() == ranma1.hashCode());
}
@Test
public void hashcodeIsGeneratedCorrectlyDifferentAge() throws IllegalAccessException, InvocationTargetException, InstantiationException, NoSuchMethodException {
TurinFile turinFile = mangaAst();
// generate bytecode
Compiler instance = new Compiler(new InFileSymbolResolver(JdkTypeResolver.getInstance()), new Compiler.Options());
List<ClassFileDefinition> classFileDefinitions = instance.compile(turinFile, new AbstractCompilerTest.MyErrorCollector());
assertEquals(1, classFileDefinitions.size());
TurinClassLoader turinClassLoader = new TurinClassLoader();
Class mangaCharacterClass = turinClassLoader.addClass(classFileDefinitions.get(0).getName(),
classFileDefinitions.get(0).getBytecode());
assertEquals(1, mangaCharacterClass.getConstructors().length);
Object ranma1 = mangaCharacterClass.getConstructors()[0].newInstance("Ranma", 16);
Object ranma2 = mangaCharacterClass.getConstructors()[0].newInstance("Ranma", 18);
assertFalse(ranma1.hashCode() == ranma2.hashCode());
assertFalse(ranma2.hashCode() == ranma1.hashCode());
}
}