blob: 3c3c2b3ddb84b1b88548ff6e8f650055afd65050 [file] [log] [blame]
/*
* Copyright 2015 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.core.interop;
import static jsinterop.annotations.JsPackage.GLOBAL;
import com.google.gwt.core.interop.MyExportedClass.InnerClass;
import com.google.gwt.junit.client.GWTTestCase;
import jsinterop.annotations.JsMethod;
import jsinterop.annotations.JsProperty;
import jsinterop.annotations.JsType;
/**
* Tests presence and naming of exported classes, fields, and methods.
*/
public class JsExportTest extends GWTTestCase {
@Override
public String getModuleName() {
return "com.google.gwt.core.Interop";
}
@Override
public void gwtSetUp() throws Exception {
setupGlobal();
}
// $global always points to scope of exports
private native void setupGlobal() /*-{
$global = window.goog && window.goog.global || $wnd;
$wnd.$global = $global;
}-*/;
private native boolean isClosureFormattedOutputEnabled() /*-{
return !!(window.goog && window.goog.global);
}-*/;
public void testMethodExport() {
myClassExportsMethodCallMe1();
assertTrue(MyClassExportsMethod.calledFromCallMe1);
myClassExportsMethodCallMe2();
assertTrue(MyClassExportsMethod.calledFromCallMe2);
myClassExportsMethodCallMe3();
assertTrue(MyClassExportsMethod.calledFromCallMe3);
myClassExportsMethodCallMe4();
assertTrue(MyClassExportsMethod.calledFromCallMe4);
myClassExportsMethodCallMe5();
assertTrue(MyClassExportsMethod.calledFromCallMe5);
}
@JsMethod(namespace = "$global", name = "exported")
private static native void myClassExportsMethodCallMe1();
@JsMethod(namespace = "$global.exportNamespace", name = "exported")
private static native void myClassExportsMethodCallMe2();
@JsMethod(namespace = "$global.exportNamespace", name = "callMe3")
private static native void myClassExportsMethodCallMe3();
@JsMethod(namespace = "$global.woo.MyClassExportsMethod", name = "exported")
private static native void myClassExportsMethodCallMe4();
@JsMethod(namespace = "$global.woo.MyClassExportsMethod", name = "callMe5")
private static native void myClassExportsMethodCallMe5();
public void testMethodExportWithLong() {
NativeMyJsTypeThatUsesLongType obj = new NativeMyJsTypeThatUsesLongType();
assertEquals(42.0, obj.addLong(40.0, 2.0));
assertEquals(82.0, NativeMyJsTypeThatUsesLongType.addLongStatic(80.0, 2.0));
}
/**
* Native interface to type MyJsTypeThatUsesLongType which has been exported to a particular
* namespaces.
*/
@JsType(isNative = true, namespace = "$global.woo", name = "MyJsTypeThatUsesLongType")
private static class NativeMyJsTypeThatUsesLongType {
public native double addLong(double a, double b);
public static native double addLongStatic(double a, double b);
}
public void testMethodExport_notReferencedFromJava() {
// Exported by MyClassExportsMethodWithoutReference which is not referenced by Java. This
// ensures that we correctly collect root types.
assertEquals(42, onlyCalledFromJs());
}
@JsMethod(
namespace = "$global.woo.MyClassExportsMethodWithoutReference", name = "onlyCalledFromJs")
private static native int onlyCalledFromJs();
public void testClinit() {
new NativeMyClassExportsMethodWithClinit();
assertEquals(23, MyClassExportsMethodWithClinit.magicNumber);
}
/**
* Native interface to type MyClassExportsMethodWithClinit which has been exported to a particular
* namespaces.
*/
@JsType(isNative = true, namespace = "$global.woo", name = "MyClassExportsMethodWithClinit")
private static class NativeMyClassExportsMethodWithClinit { }
public void testClinit_staticField() {
assertNotNull(getStaticInitializerStaticFieldExported1());
assertNotNull(getStaticInitializerStaticFieldExported2());
assertNotNull(getStaticInitializerStaticFieldInterfaceStatic());
}
@JsProperty(namespace = "$global.woo.StaticInitializerStaticField", name = "EXPORTED_1")
private static native Object getStaticInitializerStaticFieldExported1();
@JsProperty(namespace = "$global.woo.StaticInitializerStaticField", name = "EXPORTED_2")
private static native Object getStaticInitializerStaticFieldExported2();
@JsProperty(
namespace = "$global.woo.StaticInitializerStaticField.InterfaceWithField", name = "STATIC")
private static native Object getStaticInitializerStaticFieldInterfaceStatic();
public void testClinit_staticMethod() {
assertNotNull(getStaticInitializerStaticMethod());
}
@JsMethod(
namespace = "$global.woo.StaticInitializerStaticMethod", name = "getInstance")
private static native int getStaticInitializerStaticMethod();
public void testClinit_virtualMethod() {
assertNotNull(new NativeStaticInitializerVirtualMethod().getInstance());
}
/**
* Native interface to type StaticInitializerVirtualMethod which has been exported to a particular
* namespaces.
*/
@JsType(isNative = true, namespace = "$global.woo", name = "StaticInitializerVirtualMethod")
private static class NativeStaticInitializerVirtualMethod {
public native Object getInstance();
}
@JsType(namespace = "bar.foo.baz")
class MyExportedClassCorrectNamespace {
public MyExportedClassCorrectNamespace() { }
}
public void testExportClass_correctNamespace() {
assertNull(getBarMyExportedClassCorrectNamespace());
assertNull(getBarFooMyExportedClassCorrectNamespace());
assertTrue(getBarFooBazMyExportedClassCorrectNamespace() instanceof NativeFunction);
Object o = new NativeMyExportedClassCorrectNamespace();
assertNotNull(o);
assertTrue(o instanceof MyExportedClassCorrectNamespace);
}
@JsProperty(namespace = "$global.bar", name = "MyExportedClassCorrectNamespace")
private static native Object getBarMyExportedClassCorrectNamespace();
@JsProperty(namespace = "$global.bar.foo", name = "MyExportedClassCorrectNamespace")
private static native Object getBarFooMyExportedClassCorrectNamespace();
@JsProperty(namespace = "$global.bar.foo.baz", name = "MyExportedClassCorrectNamespace")
private static native Object getBarFooBazMyExportedClassCorrectNamespace();
@JsType(isNative = true, namespace = GLOBAL, name = "Function")
private static class NativeFunction { }
@JsType(
isNative = true, namespace = "$global.bar.foo.baz", name = "MyExportedClassCorrectNamespace")
private static class NativeMyExportedClassCorrectNamespace { }
public void testExportClass_implicitConstructor() {
Object o = new NativeMyExportedClassWithImplicitConstructor();
assertNotNull(o);
assertTrue(o instanceof MyExportedClassWithImplicitConstructor);
}
@JsType(
isNative = true, namespace = "$global.woo", name = "MyExportedClassWithImplicitConstructor")
private static class NativeMyExportedClassWithImplicitConstructor { }
public void testExportConstructors() {
MyClassExportsConstructor nativeMyClassExportsConstructor =
(MyClassExportsConstructor) (Object) new NativeMyClassExportsConstructor(2);
assertEquals(4, nativeMyClassExportsConstructor.foo());
assertEquals(2, new MyClassExportsConstructor().foo());
}
@JsType(
isNative = true, namespace = "$global.woo", name = "MyClassExportsConstructor")
private static class NativeMyClassExportsConstructor {
public NativeMyClassExportsConstructor(@SuppressWarnings("unused") int a) { }
}
public void testGetJsConstructor() {
if (isClosureFormattedOutputEnabled()) {
return; // Closure formatted output doesn't support jsConstructor.
}
Object constructorFn = getJsConstructor(MyClassExportsConstructor.class);
assertSame(getMyClassExportsConstructor(), constructorFn);
assertSame(MyClassExportsConstructor.class, getClass(constructorFn));
assertNull(getJsConstructor(Object.class));
assertNull(getJsConstructor(String.class));
}
@JsProperty(namespace = "$global.woo", name = "MyClassExportsConstructor")
private static native Object getMyClassExportsConstructor();
private static native Object getJsConstructor(Class<?> clazz) /*-{
return clazz.@Class::jsConstructor;
}-*/;
private static native Class<?> getClass(Object ctor) /*-{
return ctor.prototype.@Object::___clazz;
}-*/;
public void testExportedField() {
assertEquals(100, MyExportedClass.EXPORTED_1);
assertEquals(100, getExportedField());
setExportedField(1000);
assertEquals(100, MyExportedClass.EXPORTED_1);
assertEquals(1000, getExportedField());
}
@JsProperty(namespace = "$global.woo.MyExportedClass", name = "EXPORTED_1")
private static native int getExportedField();
@JsProperty(namespace = "$global.woo.MyExportedClass", name = "EXPORTED_1")
private static native void setExportedField(int value);
public void testExportedMethod() {
assertEquals(200, MyExportedClass.foo());
assertEquals(200, callExportedMethod());
setExportedMethod(getReplacementExportedMethod());
assertEquals(200, MyExportedClass.foo());
assertEquals(1000, callExportedMethod());
}
@JsMethod(
namespace = "$global.woo.MyExportedClass", name = "foo")
private static native int callExportedMethod();
@JsProperty(
namespace = "$global.woo.MyExportedClass", name = "foo")
private static native void setExportedMethod(Object object);
@JsProperty(
namespace = "$global.woo.MyExportedClass", name = "replacementFoo")
private static native Object getReplacementExportedMethod();
public void testExportedFieldRefInExportedMethod() {
assertEquals(5, MyExportedClass.bar(0, 0));
assertEquals(5, callExportedFieldByExportedMethod(0, 0));
setExportedField2(myExportedClassNewInnerClass(10));
assertEquals(10, getExportedField2());
assertEquals(7, MyExportedClass.bar(1, 1));
assertEquals(7, callExportedFieldByExportedMethod(1, 1));
}
@JsMethod(namespace = "$global.woo.MyExportedClass", name = "bar")
private static native int callExportedFieldByExportedMethod(int a, int b);
@JsProperty(namespace = "$global.woo.MyExportedClass", name = "EXPORTED_2")
private static native void setExportedField2(InnerClass a);
@JsMethod(namespace = "$global.woo.MyExportedClass", name = "newInnerClass")
private static native InnerClass myExportedClassNewInnerClass(int a);
@JsProperty(namespace = "$global.woo.MyExportedClass.EXPORTED_2", name = "field")
private static native int getExportedField2();
public void testNoExport() {
assertNull(getNotExportedMethod1());
assertNull(getNotExportedMethod2());
assertNull(getNotExported1());
assertNull(getNotExported2());
assertNull(getNotExported3());
assertNull(getNotExported4());
assertNull(getNotExported5());
}
@JsProperty(namespace = "$global.woo.StaticInitializerStaticMethod", name = "notExported_1")
private static native Object getNotExportedMethod1();
@JsProperty(namespace = "$global.woo.StaticInitializerStaticMethod", name = "notExported_2")
private static native Object getNotExportedMethod2();
@JsProperty(namespace = "$global.woo.StaticInitializerStaticField", name = "NOT_EXPORTED_1")
private static native Object getNotExported1();
@JsProperty(namespace = "$global.woo.StaticInitializerStaticField", name = "NOT_EXPORTED_2")
private static native Object getNotExported2();
@JsProperty(namespace = "$global.woo.StaticInitializerStaticField", name = "NOT_EXPORTED_3")
private static native Object getNotExported3();
@JsProperty(namespace = "$global.woo.StaticInitializerStaticField", name = "NOT_EXPORTED_4")
private static native Object getNotExported4();
@JsProperty(namespace = "$global.woo.StaticInitializerStaticField", name = "NOT_EXPORTED_5")
private static native Object getNotExported5();
public static void testInheritClassNamespace() {
assertEquals(42, getBAR());
}
@JsProperty(namespace = "$global.foo.MyExportedClassWithNamespace", name = "BAR")
private static native int getBAR();
public static void testInheritClassNamespace_empty() {
assertEquals(82, getDAN());
assertNotNull(new NativeMyClassWithEmptyNamespace());
}
@JsProperty(namespace = "$global.MyClassWithEmptyNamespace", name = "DAN")
private static native int getDAN();
@JsType(isNative = true, namespace = "$global", name = "MyClassWithEmptyNamespace")
private static class NativeMyClassWithEmptyNamespace { }
public static void testInheritClassNamespace_withName() {
assertEquals(42, getBooBAR());
}
@JsProperty(namespace = "$global.foo.boo", name = "BAR")
private static native int getBooBAR();
public static void testInheritClassNamespace_noExport() {
assertEquals(99, getBAZ());
}
@JsProperty(namespace = "$global.foobaz.MyClassWithNamespace", name = "BAZ")
private static native int getBAZ();
public static void testInheritClassNamespace_nested() {
assertEquals(99, getLOO());
assertNotNull(new BlooInner());
}
@JsProperty(namespace = "$global.woo.Bloo.Inner", name = "LOO")
private static native int getLOO();
@JsType(isNative = true, namespace = "$global.woo.Bloo", name = "Inner")
private static class BlooInner { }
public static void testInheritClassNamespace_nestedNoExport() {
assertEquals(999, getWOOZ());
assertNotNull(new NativeInnerWithNamespace());
}
@JsProperty(namespace = "$global.zoo.InnerWithNamespace", name = "WOOZ")
private static native int getWOOZ();
@JsType(isNative = true, namespace = "$global.zoo", name = "InnerWithNamespace")
private static class NativeInnerWithNamespace { }
public void testInheritPackageNamespace() {
assertEquals(1001, getWOO());
}
@JsProperty(namespace = "$global.woo.MyExportedClassWithPackageNamespace", name = "WOO")
private static native int getWOO();
public void testInheritPackageNamespace_nestedClass() {
assertEquals(99, getNestedWOO());
assertNotNull(new NativeMyClassWithNestedExportedClassInner());
}
@JsProperty(namespace = "$global.woo.MyClassWithNestedExportedClass.Inner", name = "WOO")
private static native int getNestedWOO();
@JsType(isNative = true, namespace = "$global.woo.MyClassWithNestedExportedClass", name = "Inner")
private static class NativeMyClassWithNestedExportedClassInner { }
public void testInheritPackageNamespace_nestedEnum() {
assertNotNull(getNestedEnum());
}
@JsProperty(namespace = "$global.woo.MyClassWithNestedExportedClass.InnerEnum", name = "AA")
private static native Object getNestedEnum();
public void testInheritPackageNamespace_subpackage() {
assertNull(getNestedSubpackage());
assertNotNull(getNestedSubpackageCorrect());
}
@JsProperty(namespace = "$global.woo", name = "subpackage")
private static native Object getNestedSubpackage();
@JsProperty(
namespace = "$global.com.google.gwt.core.interop.subpackage",
name = "MyNestedExportedClassSansPackageNamespace")
private static native Object getNestedSubpackageCorrect();
public void testEnum_enumerations() {
assertNotNull(getEnumerationTEST1());
assertNotNull(getEnumerationTEST2());
}
@JsProperty(namespace = "$global.woo.MyExportedEnum", name = "TEST1")
private static native Object getEnumerationTEST1();
@JsProperty(namespace = "$global.woo.MyExportedEnum", name = "TEST2")
private static native Object getEnumerationTEST2();
public void testEnum_exportedMethods() {
assertNotNull(getPublicStaticMethodInEnum());
assertNotNull(getValuesMethodInEnum());
assertNotNull(getValueOfMethodInEnum());
}
@JsProperty(namespace = "$global.woo.MyExportedEnum", name = "publicStaticMethod")
private static native Object getPublicStaticMethodInEnum();
@JsProperty(namespace = "$global.woo.MyExportedEnum", name = "values")
private static native Object getValuesMethodInEnum();
@JsProperty(namespace = "$global.woo.MyExportedEnum", name = "valueOf")
private static native Object getValueOfMethodInEnum();
public void testEnum_exportedFields() {
assertEquals(1, getPublicStaticFinalFieldInEnum());
// explicitly marked @JsType() fields must be final
// but ones that are in a @JsType()ed class don't need to be final
assertEquals(2, getPublicStaticFieldInEnum());
}
@JsProperty(namespace = "$global.woo.MyExportedEnum", name = "publicStaticFinalField")
private static native int getPublicStaticFinalFieldInEnum();
@JsProperty(namespace = "$global.woo.MyExportedEnum", name = "publicStaticField")
private static native int getPublicStaticFieldInEnum();
public void testEnum_notExported() {
assertNull(myExportedEnumPublicFinalField());
assertNull(myExportedEnumPrivateStaticFinalField());
assertNull(myExportedEnumProtectedStaticFinalField());
assertNull(myExportedEnumDefaultStaticFinalField());
assertNull(myExportedEnumPublicMethod());
assertNull(myExportedEnumProtectedStaticMethod());
assertNull(myExportedEnumPrivateStaticMethod());
assertNull(myExportedEnumDefaultStaticMethod());
}
@JsProperty(namespace = "$global.woo.MyExportedEnum", name = "publicFinalField")
private static native Object myExportedEnumPublicFinalField();
@JsProperty(namespace = "$global.woo.MyExportedEnum", name = "privateStaticFinalField")
private static native Object myExportedEnumPrivateStaticFinalField();
@JsProperty(namespace = "$global.woo.MyExportedEnum", name = "protectedStaticFinalField")
private static native Object myExportedEnumProtectedStaticFinalField();
@JsProperty(namespace = "$global.woo.MyExportedEnum", name = "defaultStaticFinalField")
private static native Object myExportedEnumDefaultStaticFinalField();
@JsProperty(namespace = "$global.woo.MyExportedEnum", name = "publicMethod")
private static native Object myExportedEnumPublicMethod();
@JsProperty(namespace = "$global.woo.MyExportedEnum", name = "protectedStaticMethod")
private static native Object myExportedEnumProtectedStaticMethod();
@JsProperty(namespace = "$global.woo.MyExportedEnum", name = "privateStaticMethod")
private static native Object myExportedEnumPrivateStaticMethod();
@JsProperty(namespace = "$global.woo.MyExportedEnum", name = "defaultStaticMethod")
private static native Object myExportedEnumDefaultStaticMethod();
public void testEnum_subclassEnumerations() {
assertNotNull(getEnumerationA());
assertNotNull(getEnumerationB());
assertNotNull(getEnumerationC());
}
@JsProperty(namespace = "$global.woo.MyEnumWithSubclassGen", name = "A")
private static native Object getEnumerationA();
@JsProperty(namespace = "$global.woo.MyEnumWithSubclassGen", name = "B")
private static native Object getEnumerationB();
@JsProperty(namespace = "$global.woo.MyEnumWithSubclassGen", name = "C")
private static native Object getEnumerationC();
public void testEnum_subclassMethodCallFromExportedEnumerations() {
assertEquals(100, callPublicMethodFromEnumerationA());
assertEquals(200, callPublicMethodFromEnumerationB());
assertEquals(1, callPublicMethodFromEnumerationC());
}
@JsMethod(namespace = "$global.woo.MyEnumWithSubclassGen.A", name = "foo")
private static native int callPublicMethodFromEnumerationA();
@JsMethod(namespace = "$global.woo.MyEnumWithSubclassGen.B", name = "foo")
private static native int callPublicMethodFromEnumerationB();
@JsMethod(namespace = "$global.woo.MyEnumWithSubclassGen.C", name = "foo")
private static native int callPublicMethodFromEnumerationC();
}