blob: f85282ceddee7dabf2c40d8ddf10a87cd2883678 [file] [log] [blame]
/*
* Copyright 2008 Google Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not
* use this file except in compliance with the License. You may obtain a copy of
* the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations under
* the License.
*/
package com.google.gwt.tools.apichecker;
import com.google.gwt.core.ext.UnableToCompleteException;
import com.google.gwt.core.ext.typeinfo.JAbstractMethod;
import com.google.gwt.dev.javac.testing.impl.StaticJavaResource;
import com.google.gwt.dev.resource.Resource;
import com.google.gwt.dev.util.log.AbstractTreeLogger;
import com.google.gwt.dev.util.log.PrintWriterTreeLogger;
import junit.framework.TestCase;
import java.util.Arrays;
import java.util.HashSet;
import java.util.Set;
/**
* Test {@link ApiContainer}.
*/
public class ApiContainerTest extends TestCase {
class TestA {
public TestA(String args) {
}
protected TestA(TestA a) {
}
public String valueOf(Object o) {
return "a";
}
public String valueOf(String s) {
return "";
}
}
class TestB extends TestA {
public TestB(TestA a) {
super(a);
}
public void main(String args[]) {
TestA x1 = new TestA("test");
x1.valueOf("ab");
TestB x2 = new TestB(x1);
new TestB(x2);
}
}
public static StaticJavaResource[] getScuArray() {
return new StaticJavaResource[] {
new StaticJavaResource("test.apicontainer.ApiClass", getSourceForApiClass()),
new StaticJavaResource("test.apicontainer.NonApiClass", getSourceForNonApiClass()),
new StaticJavaResource("test.nonapipackage.TestClass", getSourceForTestClass()),
new StaticJavaResource("java.lang.Object", getSourceForObject()),
new StaticJavaResource("test.apicontainer.OneMoreApiClass", getSourceForOneMoreApiClass()),
new StaticJavaResource("java.newpackage.Test", getSourceForTest()),};
}
private static JAbstractMethod getMethodByName(String name, ApiClass apiClass) {
return (apiClass.getApiMethodsByName(name, ApiClass.MethodType.METHOD).toArray(
new ApiAbstractMethod[0])[0]).getMethod();
}
private static String getSourceForApiClass() {
StringBuffer sb = new StringBuffer();
sb.append("package test.apicontainer;\n");
sb.append("public class ApiClass extends NonApiClass {\n");
sb.append("\tpublic void apiMethod() { };\n");
sb.append("\tpublic java.lang.Object checkParametersAndReturnTypes(ApiClass a) { return this; };\n");
sb.append("\tpublic final java.lang.Object checkParametersAndReturnTypesFinalVersion(ApiClass a) { return this; };\n");
sb.append("};\n");
return sb.toString();
}
private static String getSourceForNonApiClass() {
StringBuffer sb = new StringBuffer();
sb.append("package test.apicontainer;\n");
sb.append("class NonApiClass extends java.lang.Object {\n");
sb.append("\tpublic void methodInNonApiClass(NonApiClass a) { };\n");
sb.append("\tpublic int fieldInNonApiClass = 3;\n");
sb.append("\tprotected class ApiClassInNonApiClass {\n");
sb.append("\tprotected ApiClassInNonApiClass() { }\n");
sb.append("\t}\n");
sb.append("\tprotected final class AnotherApiClassInNonApiClass {\n");
sb.append("\tprivate AnotherApiClassInNonApiClass() { }\n");
sb.append("\t}\n");
sb.append("}\n");
return sb.toString();
}
private static String getSourceForObject() {
StringBuffer sb = new StringBuffer();
sb.append("package java.lang;\n");
sb.append("public class Object {\n");
sb.append("\tpublic void apiMethod() { }\n");
sb.append("\tprivate void internalMethod() { }\n");
sb.append("\tprotected native long protectedMethod();\n");
sb.append("\tprotected void checkOverloadedAndOverridableDetection(java.lang.Object b) { }\n");
sb.append("\tprotected final void checkOverloadedMethodAccounted(java.lang.Object b) { }\n");
sb.append("\tpublic int apiField = 0;\n");
sb.append("\tprotected transient int apiFieldWillBeMissing = 1;\n");
sb.append("\tprivate int internalField = 0;\n");
sb.append("\tprotected int protectedField=2;\n");
sb.append("}\n");
return sb.toString();
}
private static String getSourceForOneMoreApiClass() {
StringBuffer sb = new StringBuffer();
sb.append("package test.apicontainer;\n");
sb.append("public class OneMoreApiClass extends java.lang.Object {\n");
sb.append("\tprotected final void checkOverloadedMethodAccounted(test.apicontainer.OneMoreApiClass b) { }\n");
sb.append("\tpublic void testUncheckedExceptions () { }\n");
sb.append("};\n");
return sb.toString();
}
private static String getSourceForTest() {
StringBuffer sb = new StringBuffer();
sb.append("package java.newpackage;\n");
sb.append("public class Test { }\n");
return sb.toString();
}
private static String getSourceForTestClass() {
StringBuffer sb = new StringBuffer();
sb.append("package test.nonapipackage;\n");
sb.append("class TestClass extends java.lang.Object {\n");
sb.append("\tpublic void method() { }\n");
sb.append("}\n");
return sb.toString();
}
ApiContainer apiCheck = null;
AbstractTreeLogger logger = new PrintWriterTreeLogger();
/**
* Class hierarchy. public java.lang.Object -- test.apicontainer.NonApiClass
* (encloses ApiClassInNonApiClass and AnotherApiClassInNonApiClass) -- public
* test.apicontainer.ApiClass -- test.nonapipackage.TestClass
*/
@Override
public void setUp() throws UnableToCompleteException {
logger.setMaxDetail(com.google.gwt.core.ext.TreeLogger.ERROR);
apiCheck =
new ApiContainer("ApiContainerTest", new HashSet<Resource>(Arrays.asList(getScuArray())),
new HashSet<String>(), logger);
}
/*
* Test if ApiContainer correctly creates an ApiContainer (for example, avoids
* an infinite loop) when a nested class extends an outer class.
*/
public void testApiContainerLoop() throws UnableToCompleteException {
StringBuffer sb = new StringBuffer();
sb.append("package java.lang;\n");
sb.append("public class Object {\n");
sb.append("\tpublic static class Foo extends Object{\n");
sb.append("\t}\n");
sb.append("}\n");
sb.append("class Temp {\n");
sb.append("}");
ApiContainer apiCheckLoop =
new ApiContainer("ApiClassTest", new HashSet<Resource>(Arrays
.asList(new StaticJavaResource[] {new StaticJavaResource("java.lang.Object", sb
.toString())})), new HashSet<String>(), logger);
ApiPackage javaLangPackage = apiCheckLoop.getApiPackage("java.lang");
assertNotNull(javaLangPackage);
assertNotNull(javaLangPackage.getApiClass("java.lang.Object"));
assertEquals(2, javaLangPackage.getApiClassNames().size());
}
public void testEverything() {
checkApiClass();
checkApiMembers();
checkApiPackages();
}
/**
* Check if apiClasses are determined correctly. Check if inner classes are
* classified correctly as api classes.
*/
void checkApiClass() {
ApiPackage package1 = apiCheck.getApiPackage("java.lang");
ApiPackage package2 = apiCheck.getApiPackage("test.apicontainer");
assertNotNull(package1);
assertNotNull(package2);
assertNull(package2.getApiClass("test.apicontainer.NonApiClass"));
assertNotNull(package1.getApiClass("java.lang.Object"));
assertNotNull(package2.getApiClass("test.apicontainer.ApiClass"));
assertNotNull(package2.getApiClass("test.apicontainer.NonApiClass.ApiClassInNonApiClass"));
assertNotNull(package2
.getApiClass("test.apicontainer.NonApiClass.AnotherApiClassInNonApiClass"));
assertEquals(1, package1.getApiClassNames().size());
assertEquals(4, package2.getApiClassNames().size());
}
/**
* Since constructors and methods use the same code, check methods in most
* cases. Also need to check apiFields.
*
* For methods, check if: (a) inherited methods are identified correctly as
* apiMethods, (b) method overloading is done correctly
*
*/
void checkApiMembers() {
ApiClass object = apiCheck.getApiPackage("java.lang").getApiClass("java.lang.Object");
ApiClass apiClass =
apiCheck.getApiPackage("test.apicontainer").getApiClass("test.apicontainer.ApiClass");
ApiClass innerClass =
apiCheck.getApiPackage("test.apicontainer").getApiClass(
"test.apicontainer.NonApiClass.ApiClassInNonApiClass");
ApiClass oneMoreApiClass =
apiCheck.getApiPackage("test.apicontainer")
.getApiClass("test.apicontainer.OneMoreApiClass");
// constructors
assertEquals(1, innerClass.getApiMemberNames(ApiClass.MethodType.CONSTRUCTOR).size());
// fields
assertEquals(3, object.getApiFieldNames().size());
assertEquals(4, apiClass.getApiFieldNames().size());
assertEquals(3, oneMoreApiClass.getApiFieldNames().size());
// methods
assertEquals(4, object.getApiMemberNames(ApiClass.MethodType.METHOD).size());
assertEquals(7, apiClass.getApiMemberNames(ApiClass.MethodType.METHOD).size());
// the method definition lowest in the class hierarchy is kept
assertNotSame(getMethodByName("apiMethod0", apiClass), getMethodByName("apiMethod0", object));
assertEquals(getMethodByName("protectedMethod0", apiClass), getMethodByName("protectedMethod0",
object));
assertNotNull(getMethodByName("methodInNonApiClass1", apiClass));
assertEquals(5, oneMoreApiClass.getApiMemberNames(ApiClass.MethodType.METHOD).size());
Set<String> methodNames =
new HashSet<String>(Arrays.asList(new String[] {"checkOverloadedAndOverridableDetection1"}));
assertEquals(1, oneMoreApiClass.getApiMembersBySet(methodNames, ApiClass.MethodType.METHOD)
.size());
// checkOverloadedMethodAccounted should appear twice.
methodNames =
new HashSet<String>(Arrays.asList(new String[] {"checkOverloadedMethodAccounted1"}));
assertEquals(2, oneMoreApiClass.getApiMembersBySet(methodNames, ApiClass.MethodType.METHOD)
.size());
}
/**
* Test if apiPackages are identified correctly.
*/
void checkApiPackages() {
assertNotNull(apiCheck.getApiPackage("java.lang"));
assertNotNull(apiCheck.getApiPackage("test.apicontainer"));
assertEquals(3, apiCheck.getApiPackageNames().size());
}
}