blob: 5f3a6b25c3ec17f3d26e2bb21cc13121e3e1fdd3 [file] [log] [blame]
// Copyright 2006 Google Inc. All Rights Reserved.
package com.google.gwt.dev.jdt.test;
import com.google.gwt.core.ext.TreeLogger;
import com.google.gwt.core.ext.UnableToCompleteException;
import com.google.gwt.core.ext.typeinfo.CompilationUnitProvider;
import com.google.gwt.dev.jdt.ByteCodeCompiler;
import com.google.gwt.dev.jdt.RebindOracle;
import com.google.gwt.dev.jdt.SourceOracle;
import com.google.gwt.dev.jdt.URLCompilationUnitProvider;
import com.google.gwt.dev.util.FileOracle;
import com.google.gwt.dev.util.FileOracleFactory;
import com.google.gwt.dev.util.FileOracleFactory.FileFilter;
import com.google.gwt.dev.util.log.Loggers;
import junit.framework.TestCase;
import java.net.URL;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
public class ByteCodeCompilerTest extends TestCase {
private static class TestByteCodeCompilerHost implements SourceOracle,
RebindOracle {
private abstract class TestCup implements CompilationUnitProvider {
public TestCup(String packageName, String onlyTypeName) {
this(packageName, new String[]{onlyTypeName});
}
public TestCup(String packageName, String[] typeNames) {
this.packageName = packageName;
registerPackage(packageName);
for (int i = 0; i < typeNames.length; i++) {
if (packageName.length() > 0) {
registerType(packageName + "." + typeNames[i], this);
} else {
// In the default package.
//
registerType(typeNames[i], this);
}
}
firstTypeName = typeNames[0];
}
public long getLastModified() throws UnableToCompleteException {
return 0;
}
public String getLocation() {
return "transient source for " + packageName + "." + firstTypeName;
}
public String getPackageName() {
return packageName;
}
public abstract char[] getSource();
public boolean isTransient() {
return true;
}
private final String firstTypeName;
private final String packageName;
}
public TestByteCodeCompilerHost() {
registerPackage(""); // the default package
}
public final CompilationUnitProvider findCompilationUnit(TreeLogger logger,
String typeName) {
return (CompilationUnitProvider) cupsByTypeName.get(typeName);
}
public final boolean isPackage(String possiblePackageName) {
return pkgNames.contains(possiblePackageName);
}
// Override for specific test cases.
//
public String rebind(TreeLogger logger, String typeName)
throws UnableToCompleteException {
return typeName;
}
public final void registerPackage(String packageName) {
String[] packageParts = packageName.split("\\.");
String toRegister = null;
for (int i = 0; i < packageParts.length; i++) {
String part = packageParts[i];
if (toRegister != null) {
toRegister += "." + part;
} else {
toRegister = part;
}
pkgNames.add(toRegister);
}
}
public final void registerType(String typeName, TestCup cup) {
cupsByTypeName.put(typeName, cup);
}
{
pkgNames = new HashSet();
cupsByTypeName = new HashMap();
}
final CompilationUnitProvider CU_AB =
new TestCup("test", new String[]{"A", "A.B"}) {
public char[] getSource() {
StringBuffer sb = new StringBuffer();
sb.append("package test;\n");
sb.append("public class A {\n");
sb.append(" public static class B extends A { }\n");
sb.append("}\n");
return sb.toString().toCharArray();
}
};
final CompilationUnitProvider CU_C =
new TestCup("test", new String[]{"C", "C.Message"}) {
public char[] getSource() {
StringBuffer sb = new StringBuffer();
sb.append("package test;\n");
sb.append("import com.google.gwt.core.client.GWT;\n");
sb.append("public class C {\n");
sb.append(" public static String getMessage() {\n");
sb.append(" return ((Message)GWT.create(Message.class)).f();\n");
sb.append(" }\n");
sb.append(" public static class Message {\n");
sb.append(" public String f() {\n");
sb.append(" return \"C.Message\";\n");
sb.append(" }\n");
sb.append(" }\n");
sb.append("}\n");
return sb.toString().toCharArray();
}
};
final CompilationUnitProvider CU_CLASS = new TestCup("java.lang", "Class") {
public char[] getSource() {
StringBuffer sb = new StringBuffer();
sb.append("package java.lang;\n");
sb.append("public class Class { }\n");
return sb.toString().toCharArray();
}
};
/**
* This one is different because D is not public and it lives in the default
* package.
*/
final CompilationUnitProvider CU_DE =
new TestCup("", new String[]{"D", "D.E"}) {
public char[] getSource() {
StringBuffer sb = new StringBuffer();
sb.append("class D extends test.C.Message {\n");
sb.append(" public static class E extends D {\n");
sb.append(" public String getMessage() {\n");
sb.append(" return \"D.E.Message\";\n");
sb.append(" }\n");
sb.append(" }\n");
sb.append("}\n");
return sb.toString().toCharArray();
}
};
final CompilationUnitProvider CU_GWT =
new TestCup("com.google.gwt.core.client", "GWT") {
public char[] getSource() {
StringBuffer sb = new StringBuffer();
sb.append("package com.google.gwt.core.client;\n");
sb.append("public final class GWT {\n");
sb
.append(" public static Object create(Class classLiteral) { return null; }\n");
sb.append("}\n");
return sb.toString().toCharArray();
}
};
final CompilationUnitProvider CU_MAIN = new TestCup("test", "Main") {
public char[] getSource() {
StringBuffer sb = new StringBuffer();
sb.append("package test;\n");
sb.append("import com.google.gwt.core.client.GWT;\n");
sb.append("public class Main {\n");
sb.append(" public static void main(String[] args) {\n");
sb.append(" A a = (A)GWT.create(A.class);\n");
sb.append(" }\n");
sb.append("}\n");
return sb.toString().toCharArray();
}
};
final TestCup CU_OBJECT = new TestCup("java.lang", "Object") {
public char[] getSource() {
StringBuffer sb = new StringBuffer();
sb.append("package java.lang;\n");
sb.append("public class Object { }\n");
return sb.toString().toCharArray();
}
};
final CompilationUnitProvider CU_STRING =
new TestCup("java.lang", "String") {
public char[] getSource() {
StringBuffer sb = new StringBuffer();
sb.append("package java.lang;\n");
sb.append("public class String { }\n");
return sb.toString().toCharArray();
}
};
private final Map cupsByTypeName;
private final Set pkgNames;
}
public static void main(String[] args) throws UnableToCompleteException {
// Run this to try to put the hurtin' on the compiler.
//
scanAndCompile(Loggers.createOptionalGuiTreeLogger());
}
private static void scanAndCompile(TreeLogger logger)
throws UnableToCompleteException {
FileOracleFactory fof = new FileOracleFactory();
fof.addPackage("", new FileFilter() {
public boolean accept(String string) {
return string.endsWith(".java");
}
});
final FileOracle fo = fof.create(logger);
final SourceOracle host = new SourceOracle() {
public CompilationUnitProvider findCompilationUnit(TreeLogger logger,
String typeName) {
// ONLY LOOK FOR TOP-LEVEL TYPES.
//
CompilationUnitProvider cup =
(CompilationUnitProvider) cups.get(typeName);
if (cup == null) {
String path = typeName.replace('.', '/') + ".java";
URL url = fo.find(path);
if (url != null) {
String pkgName = "";
int len = findLengthOfPackagePart(typeName);
if (len > 0) {
pkgName = typeName.substring(0, len);
}
return new URLCompilationUnitProvider(url, pkgName);
} else {
return null;
}
}
return cup;
}
public boolean isPackage(String possiblePackageName) {
String path = possiblePackageName.replace('.', '/') + "/";
URL url = fo.find(path);
if (url != null) {
return true;
} else {
return false;
}
}
private int findLengthOfPackagePart(String typeName) {
int maxDotIndex = 0;
int i = typeName.indexOf('.');
while (i != -1) {
if (!isPackage(typeName.substring(0, i))) {
break;
} else {
maxDotIndex = i;
i = typeName.indexOf('.', i + 1);
}
}
return maxDotIndex;
}
private Map cups = new HashMap();
};
ByteCodeCompiler cs = new ByteCodeCompiler(host);
String[] allJava = fo.getAllFiles();
for (int i = 0; i < 3; ++i) {
long before = System.currentTimeMillis();
for (int j = 0; j < allJava.length; j++) {
String typeName =
allJava[j].substring(0, allJava[j].length() - 5).replace('/', '.');
cs.getClassBytes(logger, typeName);
}
long after = System.currentTimeMillis();
System.out.println("Iter " + i + " took " + (after - before) + " ms");
}
}
// This one is standalone.
//
public void testJavaLangObject() throws Exception {
ByteCodeCompiler cs = new ByteCodeCompiler(testHost);
assertNotNull(cs.getClassBytes(logger, "java.lang.Object"));
}
// This one requires java.lang.Object.
//
public void testJavaLangString() throws Exception {
ByteCodeCompiler cs = new ByteCodeCompiler(testHost);
assertNotNull(cs.getClassBytes(logger, "java.lang.Object"));
assertNotNull(cs.getClassBytes(logger, "java.lang.String"));
}
// Try deferred binding that takes three compile iterations.
// - In Main, we rebind from A to C
// - In C, we rebind from C to D.E
//
public void testRebindCreateTransitive() throws Exception {
ByteCodeCompiler cs = new ByteCodeCompiler(new TestByteCodeCompilerHost() {
public String rebind(TreeLogger logger, String typeName)
throws com.google.gwt.core.ext.UnableToCompleteException {
if ("test.C.Message".equals(typeName)) {
return "D.E";
} else {
return typeName;
}
}
});
assertNotNull(cs.getClassBytes(logger, "test.C"));
assertNotNull(cs.getClassBytes(logger, "test.C$Message"));
assertNotNull(cs.getClassBytes(logger, "D"));
assertNotNull(cs.getClassBytes(logger, "D$E"));
assertNotNull(cs.getClassBytes(logger, "java.lang.Object"));
assertNotNull(cs.getClassBytes(logger, "java.lang.String"));
assertNotNull(cs.getClassBytes(logger, "java.lang.Class"));
assertNotNull(cs.getClassBytes(logger, "com.google.gwt.core.client.GWT"));
}
// Try deferred binding that works.
//
public void testRebindCreateWithSuccess() throws Exception {
ByteCodeCompiler cs = new ByteCodeCompiler(new TestByteCodeCompilerHost() {
public String rebind(TreeLogger logger, String typeName)
throws com.google.gwt.core.ext.UnableToCompleteException {
if ("test.A".equals(typeName)) {
return "test.A.B";
} else {
return typeName;
}
}
});
assertNotNull(cs.getClassBytes(logger, "java.lang.Object"));
assertNotNull(cs.getClassBytes(logger, "java.lang.String"));
assertNotNull(cs.getClassBytes(logger, "java.lang.Class"));
assertNotNull(cs.getClassBytes(logger, "com.google.gwt.core.client.GWT"));
assertNotNull(cs.getClassBytes(logger, "test.Main"));
assertNotNull(cs.getClassBytes(logger, "test.A"));
assertNotNull(cs.getClassBytes(logger, "test.A$B"));
// Check again for the same class to make sure it's cached.
// (Although you have to run this test with "-Dgwt.useGuiLogger" defined
// to see what it does.)
//
assertNotNull(cs.getClassBytes(logger, "java.lang.Object"));
}
protected void setUp() throws Exception {
logger = Loggers.createOptionalGuiTreeLogger();
testHost = new TestByteCodeCompilerHost();
}
private TreeLogger logger = TreeLogger.NULL;
private TestByteCodeCompilerHost testHost = null;
}