Skip to content

Commit

Permalink
Add tests for @JsExport and @jstype on Enum type.
Browse files Browse the repository at this point in the history
Change-Id: Iace8a165d4679f22918822a575e713024075a2c7
  • Loading branch information
Ye Wang committed Feb 19, 2015
1 parent ffeca5d commit b2f480c
Show file tree
Hide file tree
Showing 8 changed files with 342 additions and 26 deletions.
15 changes: 13 additions & 2 deletions dev/core/src/com/google/gwt/dev/javac/JSORestrictionsChecker.java
Expand Up @@ -69,6 +69,8 @@ public class JSORestrictionsChecker {
"@JsExport and @JsNoExport is not allowed at the same time.";
public static final String ERR_JSPROPERTY_ONLY_BEAN_OR_FLUENT_STYLE_NAMING =
"@JsProperty is only allowed on JavaBean-style or fluent-style named methods";
public static final String ERR_JSEXPORT_ON_ENUMERATION =
"@JsExport is not allowed on individual enumerations";
public static final String ERR_MUST_EXTEND_MAGIC_PROTOTYPE_CLASS =
"Classes implementing @JsType with a prototype must extend that interface's Prototype class";
public static final String ERR_CLASS_EXTENDS_MAGIC_PROTOTYPE_BUT_NO_PROTOTYPE_ATTRIBUTE =
Expand Down Expand Up @@ -178,7 +180,7 @@ public void endVisit(ConstructorDeclaration meth, ClassScope scope) {

@Override
public void endVisit(FieldDeclaration field, MethodScope scope) {
checkJsExport(field.binding);
checkJsExport(field);

if (!isJso()) {
return;
Expand Down Expand Up @@ -275,8 +277,12 @@ private void checkJsExport(MethodBinding mb) {
}
}

private void checkJsExport(FieldBinding fb) {
private void checkJsExport(FieldDeclaration fd) {
FieldBinding fb = fd.binding;
if (JdtUtil.getAnnotation(fb, JsInteropUtil.JSEXPORT_CLASS) != null) {
if (isEnumConstant(fd)) {
errorOn(fb, ERR_JSEXPORT_ON_ENUMERATION);
}
if (!areAllEnclosingClassesPublic() || !fb.isStatic() || !fb.isFinal() || !fb.isPublic()) {
errorOn(fb, ERR_JSEXPORT_ONLY_CTORS_STATIC_METHODS_AND_STATIC_FINAL_FIELDS);
}
Expand All @@ -286,6 +292,11 @@ private void checkJsExport(FieldBinding fb) {
}
}

private boolean isEnumConstant(FieldDeclaration fd) {
return (fd.initialization != null && fd.initialization instanceof AllocationExpression
&& ((AllocationExpression) fd.initialization).enumConstant != null);
}

private void checkJsProperty(MethodBinding mb, boolean allowed) {
AnnotationBinding jsProperty = JdtUtil.getAnnotation(mb, JsInteropUtil.JSPROPERTY_CLASS);
if (jsProperty != null) {
Expand Down
18 changes: 18 additions & 0 deletions dev/core/test/com/google/gwt/dev/javac/JSORestrictionsTest.java
Expand Up @@ -415,6 +415,24 @@ public void testJsExportOnInterface() {
shouldGenerateNoError(goodCode);
}

public void testJsExportOnEnum() {
StringBuilder goodCode = new StringBuilder();
goodCode.append("import com.google.gwt.core.client.js.JsExport;\n");
goodCode.append("@JsExport enum Buggy { TEST1, TEST2;}");

shouldGenerateNoError(goodCode);
}

public void testJsExportNotOnEnumeration() {
StringBuilder buggyCode = new StringBuilder();
buggyCode.append("import com.google.gwt.core.client.js.JsExport;\n");
buggyCode.append("public enum Buggy {\n");
buggyCode.append(" @JsExport TEST1, TEST2;\n;");
buggyCode.append("}");

shouldGenerateError(buggyCode, "Line 3: " + JSORestrictionsChecker.ERR_JSEXPORT_ON_ENUMERATION);
}

public void testJsExportNotOnNonPublicClass() {
StringBuilder buggyCode = new StringBuilder();
buggyCode.append("import com.google.gwt.core.client.js.JsExport;\n");
Expand Down
95 changes: 94 additions & 1 deletion user/test/com/google/gwt/core/client/interop/JsExportTest.java
Expand Up @@ -103,7 +103,8 @@ private native Object getNotExportedFields() /*-{
return $wnd.woo.StaticInitializerStaticField.NOT_EXPORTED_1
|| $wnd.woo.StaticInitializerStaticField.NOT_EXPORTED_2
|| $wnd.woo.StaticInitializerStaticField.NOT_EXPORTED_3
|| $wnd.woo.StaticInitializerStaticField.NOT_EXPORTED_4;
|| $wnd.woo.StaticInitializerStaticField.NOT_EXPORTED_4
|| $wnd.woo.StaticInitializerStaticField.NOT_EXPORTED_5;
}-*/;

private native Object getNotExportedMethods() /*-{
Expand Down Expand Up @@ -135,4 +136,96 @@ public void testNestedEnum() {
private static native String getEnumNameViaJs(MyClassWithNestedEnum.NestedEnum ref) /*-{
return ref.name2();
}-*/;

public void testEnum_enumerations() {
assertNotNull(getEnumerationTEST1());
assertNotNull(getEnumerationTEST2());
}

private static native Object getEnumerationTEST1() /*-{
return $wnd.woo.MyEnumWithJsExport.TEST1;
}-*/;

private static native Object getEnumerationTEST2() /*-{
return $wnd.woo.MyEnumWithJsExport.TEST2;
}-*/;

public void testEnum_exportedMethods() {
assertNotNull(getPublicStaticMethodInEnum());
}

private static native Object getPublicStaticMethodInEnum() /*-{
return $wnd.woo.MyEnumWithJsExport.publicStaticMethod();
}-*/;

public void testEnum_exportedFields() {
assertEquals(1, getPublicStaticFinalFieldInEnum());

// explicitly marked @JsExport fields must be final
// but ones that are in a @JsExported class don't need to be final
assertEquals(2, getPublicStaticFieldInEnum());
}

private static native int getPublicStaticFinalFieldInEnum() /*-{
return $wnd.woo.MyEnumWithJsExport.publicStaticFinalField;
}-*/;

private static native int getPublicStaticFieldInEnum() /*-{
return $wnd.woo.MyEnumWithJsExport.publicStaticField;
}-*/;

public void testEnum_notExported() {
assertNull(getNotExportedFieldsInEnum());
assertNull(getNotExportedMethodsInEnum());
}

private native Object getNotExportedFieldsInEnum() /*-{
return $wnd.woo.MyEnumWithJsExport.publicFinalField
|| $wnd.woo.MyEnumWithJsExport.privateStaticFinalField
|| $wnd.woo.MyEnumWithJsExport.protectedStaticFinalField
|| $wnd.woo.MyEnumWithJsExport.defaultStaticFinalField;
}-*/;

private native Object getNotExportedMethodsInEnum() /*-{
return $wnd.woo.MyEnumWithJsExport.publicMethod
|| $wnd.woo.MyEnumWithJsExport.protectedStaticMethod
|| $wnd.woo.MyEnumWithJsExport.privateStaticMethod
|| $wnd.woo.MyEnumWithJsExport.defaultStaticMethod;
}-*/;

public void testEnum_subclassEnumerations() {
assertNotNull(getEnumerationA());
assertNotNull(getEnumerationB());
assertNotNull(getEnumerationC());
}

private static native Object getEnumerationA() /*-{
return $wnd.woo.MyEnumWithSubclassGen.A;
}-*/;

private static native Object getEnumerationB() /*-{
return $wnd.woo.MyEnumWithSubclassGen.B;
}-*/;

private static native Object getEnumerationC() /*-{
return $wnd.woo.MyEnumWithSubclassGen.C;
}-*/;

public void testEnum_subclassMethodCallFromExportedEnumerations() {
assertEquals(100, callPublicMethodFromEnumerationA());
assertEquals(200, callPublicMethodFromEnumerationB());
assertEquals(1, callPublicMethodFromEnumerationC());
}

private static native int callPublicMethodFromEnumerationA() /*-{
return $wnd.woo.MyEnumWithSubclassGen.A.foo();
}-*/;

private static native int callPublicMethodFromEnumerationB() /*-{
return $wnd.woo.MyEnumWithSubclassGen.B.foo();
}-*/;

private static native int callPublicMethodFromEnumerationC() /*-{
return $wnd.woo.MyEnumWithSubclassGen.C.foo();
}-*/;
}
71 changes: 48 additions & 23 deletions user/test/com/google/gwt/core/client/interop/JsTypeTest.java
Expand Up @@ -80,38 +80,24 @@ public void testVirtualUpRefs() {
public void testConcreteJsTypeAccess() {
ConcreteJsType concreteJsType = new ConcreteJsType();

assertTrue(hasField(concreteJsType, "publicMethod"));
assertTrue(hasField(concreteJsType, "publicField"));

assertFalse(hasField(concreteJsType, "publicStaticMethod"));
assertFalse(hasField(concreteJsType, "privateMethod"));
assertFalse(hasField(concreteJsType, "protectedMethod"));
assertFalse(hasField(concreteJsType, "packageMethod"));
assertFalse(hasField(concreteJsType, "publicStaticField"));
assertFalse(hasField(concreteJsType, "privateField"));
assertFalse(hasField(concreteJsType, "protectedField"));
assertFalse(hasField(concreteJsType, "packageField"));
testJsTypeHasFields(concreteJsType, "publicMethod", "publicField");
testJsTypeHasNoFields(concreteJsType, "publicStaticMethod", "privateMethod", "protectedMethod",
"packageMethod", "publicStaticField", "privateField", "protectedField", "packageField");
}

public void testConcreteJsTypeSubclassAccess() {
ConcreteJsType concreteJsType = new ConcreteJsType();
ConcreteJsTypeSubclass concreteJsTypeSubclass = new ConcreteJsTypeSubclass();

// A subclass of a JsType is not itself a JsType.
assertFalse(hasField(concreteJsTypeSubclass, "publicSubclassMethod"));
assertFalse(hasField(concreteJsTypeSubclass, "publicSubclassField"));
assertFalse(hasField(concreteJsTypeSubclass, "publicStaticSubclassMethod"));
assertFalse(hasField(concreteJsTypeSubclass, "privateSubclassMethod"));
assertFalse(hasField(concreteJsTypeSubclass, "protectedSubclassMethod"));
assertFalse(hasField(concreteJsTypeSubclass, "packageSubclassMethod"));
assertFalse(hasField(concreteJsTypeSubclass, "publicStaticSubclassField"));
assertFalse(hasField(concreteJsTypeSubclass, "privateSubclassField"));
assertFalse(hasField(concreteJsTypeSubclass, "protectedSubclassField"));
assertFalse(hasField(concreteJsTypeSubclass, "packageSubclassField"));
testJsTypeHasNoFields(concreteJsTypeSubclass, "publicSubclassMethod", "publicSubclassField",
"publicStaticSubclassMethod", "privateSubclassMethod", "protectedSubclassMethod",
"packageSubclassMethod", "publicStaticSubclassField", "privateSubclassField",
"protectedSubclassField", "packageSubclassField");

// But if it overrides an exported method then the overriding method will be exported.
assertTrue(hasField(concreteJsType, "publicMethod"));
assertTrue(hasField(concreteJsTypeSubclass, "publicMethod"));
testJsTypeHasFields(concreteJsType, "publicMethod");
testJsTypeHasFields(concreteJsTypeSubclass, "publicMethod");
assertFalse(
areSameFunction(concreteJsType, "publicMethod", concreteJsTypeSubclass, "publicMethod"));
assertFalse(callIntFunction(concreteJsType, "publicMethod")
Expand Down Expand Up @@ -208,6 +194,24 @@ public void testInstanceOfWithNameSpace() {
assertFalse(obj2 instanceof MyNamespacedJsInterface);
}

public void testEnumeration() {
assertEquals(2, callPublicMethodFromEnumeration(MyEnumWithJsType.TEST1));
assertEquals(3, callPublicMethodFromEnumeration(MyEnumWithJsType.TEST2));
}

public void testEnumJsTypeAccess() {
testJsTypeHasFields(MyEnumWithJsType.TEST2, "publicMethod", "publicField");
testJsTypeHasNoFields(MyEnumWithJsType.TEST2, "publicStaticMethod", "privateMethod",
"protectedMethod", "packageMethod", "publicStaticField", "privateField", "protectedField",
"packageField");
}

public void testEnumSubclassEnumeration() {
assertEquals(100, callPublicMethodFromEnumerationSubclass(MyEnumWithSubclassGen.A));
assertEquals(200, callPublicMethodFromEnumerationSubclass(MyEnumWithSubclassGen.B));
assertEquals(1, callPublicMethodFromEnumerationSubclass(MyEnumWithSubclassGen.C));
}

private static native boolean alwaysTrue() /*-{
return !!$wnd;
}-*/;
Expand Down Expand Up @@ -252,4 +256,25 @@ private static native boolean isIE8() /*-{
private static native boolean isFirefox40OrEarlier() /*-{
return @com.google.gwt.dom.client.DOMImplMozilla::isGecko2OrBefore()();
}-*/;

private static native int callPublicMethodFromEnumeration(MyEnumWithJsType enumeration) /*-{
return enumeration.idxAddOne();
}-*/;

private static native int callPublicMethodFromEnumerationSubclass(
MyEnumWithSubclassGen enumeration) /*-{
return enumeration.foo();
}-*/;

private static void testJsTypeHasFields(Object obj, String... fields) {
for (String field : fields) {
assertTrue("Field '" + field + "' should be exported", hasField(obj, field));
}
}

private static void testJsTypeHasNoFields(Object obj, String... fields) {
for (String field : fields) {
assertFalse("Field '" + field + "' should not be exported", hasField(obj, field));
}
}
}
@@ -0,0 +1,60 @@
/*
* 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.client.interop;

import com.google.gwt.core.client.js.JsExport;

/**
* This enum is annotated as @JsExport.
*/
@JsExport
public enum MyEnumWithJsExport {
TEST1, TEST2;

public static int publicStaticMethod() {
return 0;
}

public static final int publicStaticFinalField = 1;

// explicitly marked @JsExport fields must be final
// but ones that are in a @JsExported class don't need to be final
public static int publicStaticField = 2;

public final int publicFinalField = 3;

private static final int privateStaticFinalField = 4;

protected static final int protectedStaticFinalField = 5;

static final int defaultStaticFinalField = 6;

public int publicMethod() {
return 0;
}

protected static int protectedStaticMethod() {
return 0;
}

static int defaultStaticMethod() {
return 0;
}

private static int privateStaticMethod() {
return 0;
}
}
61 changes: 61 additions & 0 deletions user/test/com/google/gwt/core/client/interop/MyEnumWithJsType.java
@@ -0,0 +1,61 @@
/*
* 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.client.interop;

import com.google.gwt.core.client.js.JsType;

/**
* This enum is annotated as a @JsType.
*/
@JsType
public enum MyEnumWithJsType {
TEST1(1), TEST2(2);

public int idx;
MyEnumWithJsType(int a) {
this.idx = a;
}

public int idxAddOne() {
return idx + 1;
}

public int publicMethod() {
return 10;
}

public static void publicStaticMethod() {
}

private void privateMethod() {
}

protected void protectedMethod() {
}

void packageMethod() {
}

public int publicField = 10;

public static int publicStaticField = 10;

private int privateField = 10;

protected int protectedField = 10;

int packageField = 10;
}

0 comments on commit b2f480c

Please sign in to comment.