/*
* Copyright (C) 2013 RoboVM AB
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/gpl-2.0.html>.
*/
package org.robovm.compiler;
import static org.junit.Assert.*;
import org.junit.Before;
import org.junit.Test;
import org.robovm.compiler.VTable.Entry;
import soot.Scene;
import soot.SootClass;
import soot.options.Options;
/**
* Tests {@link VTable}.
*/
public class VTableTest {
@Before
public void initializeSoot() {
soot.G.reset();
Options.v().set_output_format(Options.output_format_jimple);
Options.v().set_include_all(true);
Options.v().set_print_tags_in_output(true);
Options.v().set_allow_phantom_refs(true);
Options.v().set_soot_classpath(System.getProperty("sun.boot.class.path") +
":" + System.getProperty("java.class.path"));
Scene.v().loadNecessaryClasses();
}
private SootClass getSootClass(String name) {
return Scene.v().loadClassAndSupport(name);
}
@Test
public void testObject() {
SootClass sc = getSootClass("java.lang.Object");
VTable.Cache cache = new VTable.Cache();
VTable vtable = cache.get(sc);
assertEquals(11, vtable.size());
assertNotNull(vtable.findEntry("toString", "()Ljava/lang/String;"));
}
@Test
public void testA() {
SootClass sc = getSootClass("org.robovm.compiler.a.A");
VTable.Cache cache = new VTable.Cache();
VTable vtable = cache.get(sc);
assertEquals(14, vtable.size());
Entry toStringEntry = vtable.findEntry("toString", "()Ljava/lang/String;");
assertEquals(sc.getName(), toStringEntry.getDeclaringClass());
Entry superToStringEntry = cache.get(getSootClass("java.lang.Object")).findEntry("toString", "()Ljava/lang/String;");
assertEquals(superToStringEntry.getIndex(), toStringEntry.getIndex());
assertNotSame(toStringEntry, superToStringEntry);
Entry equalsEntry = vtable.findEntry("equals", "(Ljava/lang/Object;)Z");
assertEquals(sc.getName(), equalsEntry.getDeclaringClass());
Entry superEqualsEntry = cache.get(getSootClass("java.lang.Object")).findEntry("equals", "(Ljava/lang/Object;)Z");
assertEquals(superEqualsEntry.getIndex(), equalsEntry.getIndex());
assertNotSame(superEqualsEntry, equalsEntry);
Entry cloneEntry = vtable.findEntry("clone", "()Ljava/lang/Object;");
assertEquals("java.lang.Object", cloneEntry.getDeclaringClass());
Entry superCloneEntry = cache.get(getSootClass("java.lang.Object")).findEntry("clone", "()Ljava/lang/Object;");
assertSame(superCloneEntry, cloneEntry);
assertNull(vtable.findEntry("foo", "()V"));
Entry fooEntry = vtable.findEntry("org.robovm.compiler.a", "foo", "()V");
assertEquals(sc.getName(), fooEntry.getDeclaringClass());
assertEquals(11, fooEntry.getIndex());
}
@Test
public void testB() {
SootClass scJLO = getSootClass("java.lang.Object");
SootClass scA = getSootClass("org.robovm.compiler.a.A");
SootClass scB = getSootClass("org.robovm.compiler.b.B");
VTable.Cache cache = new VTable.Cache();
VTable vtableJLO = cache.get(scJLO);
VTable vtableA = cache.get(scA);
VTable vtableB = cache.get(scB);
assertEquals(16, vtableB.size());
Entry toStringEntry = vtableB.findEntry("toString", "()Ljava/lang/String;");
assertEquals(scA.getName(), toStringEntry.getDeclaringClass());
Entry superToStringEntry = vtableA.findEntry("toString", "()Ljava/lang/String;");
assertSame(toStringEntry, superToStringEntry);
Entry equalsEntry = vtableB.findEntry("equals", "(Ljava/lang/Object;)Z");
assertEquals(scA.getName(), equalsEntry.getDeclaringClass());
Entry superEqualsEntry = vtableA.findEntry("equals", "(Ljava/lang/Object;)Z");
assertSame(superEqualsEntry, equalsEntry);
Entry cloneEntry = vtableB.findEntry("clone", "()Ljava/lang/Object;");
assertEquals(scJLO.getName(), cloneEntry.getDeclaringClass());
Entry superCloneEntry = vtableJLO.findEntry("clone", "()Ljava/lang/Object;");
assertSame(superCloneEntry, cloneEntry);
Entry fooInAEntry = vtableB.findEntry("org.robovm.compiler.a", "foo", "()V");
assertEquals(scA.getName(), fooInAEntry.getDeclaringClass());
assertEquals(11, fooInAEntry.getIndex());
Entry fooInBEntry = vtableB.findEntry("org.robovm.compiler.b", "foo", "()V");
assertEquals(scB.getName(), fooInBEntry.getDeclaringClass());
assertEquals(14, fooInBEntry.getIndex());
assertNotSame(fooInAEntry, fooInBEntry);
Entry fooIVEntry = vtableB.findEntry("foo", "(I)V");
assertEquals(scB.getName(), fooIVEntry.getDeclaringClass());
Entry superFooIVEntry = vtableA.findEntry("foo", "(I)V");
assertEquals(superFooIVEntry.getIndex(), fooIVEntry.getIndex());
assertNotSame(superFooIVEntry, fooIVEntry);
Entry barInAEntry = vtableB.findEntry("org.robovm.compiler.a", "bar", "()V");
assertEquals(scA.getName(), barInAEntry.getDeclaringClass());
assertEquals(12, barInAEntry.getIndex());
Entry barInBEntry = vtableB.findEntry("org.robovm.compiler.b", "bar", "()V");
assertEquals(scB.getName(), barInBEntry.getDeclaringClass());
assertEquals(15, barInBEntry.getIndex());
assertNotSame(barInAEntry, barInBEntry);
}
@Test
public void testC() {
SootClass scA = getSootClass("org.robovm.compiler.a.A");
SootClass scC = getSootClass("org.robovm.compiler.a.C");
VTable.Cache cache = new VTable.Cache();
VTable vtableA = cache.get(scA);
VTable vtableC = cache.get(scC);
assertEquals(14, vtableC.size());
Entry fooEntry = vtableC.findEntry("org.robovm.compiler.a", "foo", "()V");
assertEquals(scC.getName(), fooEntry.getDeclaringClass());
Entry superFooEntry = vtableA.findEntry("org.robovm.compiler.a", "foo", "()V");
assertEquals(superFooEntry.getIndex(), fooEntry.getIndex());
assertNotSame(superFooEntry, fooEntry);
Entry barEntry = vtableC.findEntry("org.robovm.compiler.a", "bar", "()V");
assertEquals(scA.getName(), barEntry.getDeclaringClass());
Entry superBarEntry = vtableA.findEntry("org.robovm.compiler.a", "bar", "()V");
assertSame(superBarEntry, barEntry);
}
@Test
public void testD() {
SootClass scA = getSootClass("org.robovm.compiler.a.A");
SootClass scB = getSootClass("org.robovm.compiler.b.B");
SootClass scD = getSootClass("org.robovm.compiler.b.D");
VTable.Cache cache = new VTable.Cache();
VTable vtableB = cache.get(scB);
VTable vtableD = cache.get(scD);
assertEquals(vtableB.size(), vtableD.size());
Entry barInAEntry = vtableD.findEntry("org.robovm.compiler.a", "bar", "()V");
assertEquals(scA.getName(), barInAEntry.getDeclaringClass());
assertEquals(12, barInAEntry.getIndex());
Entry barInDEntry = vtableD.findEntry("org.robovm.compiler.b", "bar", "()V");
assertEquals(scD.getName(), barInDEntry.getDeclaringClass());
assertEquals(15, barInDEntry.getIndex());
assertNotSame(barInAEntry, barInDEntry);
Entry barInBEntry = vtableD.findEntry("org.robovm.compiler.b", "bar", "()V");
assertSame(barInBEntry, barInDEntry);
}
@Test
public void testEmpty() {
SootClass scJLO = getSootClass("java.lang.Object");
SootClass scEmpty = getSootClass("org.robovm.compiler.a.Empty");
VTable.Cache cache = new VTable.Cache();
VTable vtableJLO = cache.get(scJLO);
VTable vtableEmpty = cache.get(scEmpty);
assertArrayEquals(vtableJLO.getEntries(), vtableEmpty.getEntries());
}
}