blob: 2ee67903717fcf53fbd87d6b836ada1ca1ff7d8b [file] [log] [blame]
/*
* Copyright 2009 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.uibinder.rebind.model;
import com.google.gwt.core.ext.UnableToCompleteException;
import com.google.gwt.core.ext.typeinfo.JClassType;
import com.google.gwt.core.ext.typeinfo.JConstructor;
import com.google.gwt.core.ext.typeinfo.JMethod;
import com.google.gwt.core.ext.typeinfo.JParameter;
import com.google.gwt.core.ext.typeinfo.JPrimitiveType;
import com.google.gwt.core.ext.typeinfo.JType;
import com.google.gwt.dev.util.Pair;
import com.google.gwt.uibinder.client.UiChild;
import com.google.gwt.uibinder.client.UiConstructor;
import com.google.gwt.uibinder.rebind.JClassTypeAdapter;
import com.google.gwt.uibinder.rebind.MortalLogger;
import com.google.gwt.uibinder.rebind.UiBinderContext;
import com.google.gwt.user.client.ui.Label;
import junit.framework.TestCase;
import java.util.Map;
/**
* Tests for descriptors of potential owner field classes.
*/
public class OwnerFieldClassTest extends TestCase {
private JClassTypeAdapter gwtTypeAdapter;
private UiBinderContext uiBinderCtx;
@Override
protected void setUp() throws Exception {
super.setUp();
uiBinderCtx = new UiBinderContext();
gwtTypeAdapter = new JClassTypeAdapter();
}
public void testOwnerFieldClass() throws Exception {
// Get the JType for a Label
JClassType labelType = gwtTypeAdapter.adaptJavaClass(Label.class);
// Now get its field class model
OwnerFieldClass fieldClass = OwnerFieldClass.getFieldClass(labelType,
MortalLogger.NULL, uiBinderCtx);
// Check the class model properties
assertEquals(labelType, fieldClass.getRawType());
assertNull(fieldClass.getUiConstructor());
JMethod setter = fieldClass.getSetter("visible");
assertMethod(setter, "setVisible", JPrimitiveType.BOOLEAN);
// Check that the same instance of the model is returned if asked again
assertSame(fieldClass, OwnerFieldClass.getFieldClass(labelType,
MortalLogger.NULL, uiBinderCtx));
gwtTypeAdapter.verifyAll();
}
/**
* Class with lots of setters for testing.
*/
@SuppressWarnings("unused")
// We know these methods are unused
private static class SettersTestClass {
// No ambiguity in these setters
public void setBlaBla(int x) {
throw new UnsupportedOperationException("Should never get called");
}
public void setBlaBle(String x) {
throw new UnsupportedOperationException("Should never get called");
}
// To be used in subclass test
public void setBlaBla2(int x) {
throw new UnsupportedOperationException("Should never get called");
}
public void setBlaBle2(String x) {
throw new UnsupportedOperationException("Should never get called");
}
public void setBli2(int x) {
throw new UnsupportedOperationException("Should never get called");
}
public void setBli2(double x) {
throw new UnsupportedOperationException("Should never get called");
}
// Ambiguous, String parameter should win
public void setBle(int y) {
throw new UnsupportedOperationException("Should never get called");
}
public void setBle(String y) {
throw new UnsupportedOperationException("Should never get called");
}
// Ambiguous with no winner
public void setBli(int y) {
throw new UnsupportedOperationException("Should never get called");
}
public void setBli(double y) {
throw new UnsupportedOperationException("Should never get called");
}
// Not considered setters
void setNothing(int x) {
throw new UnsupportedOperationException("Should never get called");
}
public void set() {
}
public int setNothing2(String x) {
throw new UnsupportedOperationException("Should never get called");
}
public void notASetter(String x) {
throw new UnsupportedOperationException("Should never get called");
}
public static void setStatic(String x) {
throw new UnsupportedOperationException("Should never get called");
}
}
public void testOwnerFieldClass_setters() throws Exception {
JClassType settersType = gwtTypeAdapter.adaptJavaClass(SettersTestClass.class);
JClassType stringType = gwtTypeAdapter.adaptJavaClass(String.class);
OwnerFieldClass settersClass = OwnerFieldClass.getFieldClass(settersType,
MortalLogger.NULL, uiBinderCtx);
assertEquals(settersType, settersClass.getRawType());
assertNull(settersClass.getUiConstructor());
JMethod blaBlaSetter = settersClass.getSetter("blaBla");
assertMethod(blaBlaSetter, "setBlaBla", JPrimitiveType.INT);
JMethod blaBleSetter = settersClass.getSetter("blaBle");
assertMethod(blaBleSetter, "setBlaBle", stringType);
assertNull(settersClass.getSetter("nothing"));
assertNull(settersClass.getSetter("nothing2"));
assertNull(settersClass.getSetter("notASetter"));
assertNull(settersClass.getSetter("aSetter"));
assertNull(settersClass.getSetter("static"));
gwtTypeAdapter.verifyAll();
}
public void testOwnerFieldClass_ambiguousSetters() throws Exception {
JClassType settersType = gwtTypeAdapter.adaptJavaClass(SettersTestClass.class);
JClassType stringType = gwtTypeAdapter.adaptJavaClass(String.class);
OwnerFieldClass settersClass = OwnerFieldClass.getFieldClass(settersType,
MortalLogger.NULL, uiBinderCtx);
assertEquals(settersType, settersClass.getRawType());
JMethod bleSetter = settersClass.getSetter("ble");
assertMethod(bleSetter, "setBle", stringType);
try {
settersClass.getSetter("bli");
fail("Expected exception not thrown");
} catch (UnableToCompleteException utce) {
// Expected
}
gwtTypeAdapter.verifyAll();
}
/**
* Class with overridden setters for testing.
*/
@SuppressWarnings("unused")
// We know these methods are unused
private static class OverriddenSettersTestClass extends SettersTestClass {
// Simple override of parent method
@Override
public void setBlaBla(int x) {
throw new UnsupportedOperationException("Should never get called");
}
// setBlaBle is not overridden
// Subclass adds ambiguity, String from this class wins
public void setBlaBla2(String x) {
throw new UnsupportedOperationException("Should never get called");
}
// Subclass adds ambiguity, String from superclass wins
public void setBlaBle2(int x) {
throw new UnsupportedOperationException("Should never get called");
}
// setBle had settled ambiguity, this shouldn't change it
public void setBle(double x) {
throw new UnsupportedOperationException("Should never get called");
}
// setBli2 ambiguous in superclass only
// setBlo us ambiguous here only
public void setBlo(int x) {
throw new UnsupportedOperationException("Should never get called");
}
public void setBlo(double x) {
throw new UnsupportedOperationException("Should never get called");
}
// Solves superclass ambiguity
public void setBli(String y) {
throw new UnsupportedOperationException("Should never get called");
}
}
public void testOwnerFieldClass_overriddenSetters() throws Exception {
JClassType settersType = gwtTypeAdapter.adaptJavaClass(OverriddenSettersTestClass.class);
JClassType stringType = gwtTypeAdapter.adaptJavaClass(String.class);
OwnerFieldClass settersClass = OwnerFieldClass.getFieldClass(settersType,
MortalLogger.NULL, uiBinderCtx);
assertEquals(settersType, settersClass.getRawType());
// setBlaBla is not ambiguous, though overridden
JMethod blaBlaSetter = settersClass.getSetter("blaBla");
assertMethod(blaBlaSetter, "setBlaBla", JPrimitiveType.INT);
// setBlaBle is not overridden, works from superclass
JMethod blaBleSetter = settersClass.getSetter("blaBle");
assertMethod(blaBleSetter, "setBlaBle", stringType);
// setBlaBla2 is not ambiguous, subclass String wins
JMethod blaBla2Setter = settersClass.getSetter("blaBla2");
assertMethod(blaBla2Setter, "setBlaBla2", stringType);
// setBlaBle2 is not ambiguous, superclass String wins
JMethod blaBle2Setter = settersClass.getSetter("blaBle2");
assertMethod(blaBle2Setter, "setBlaBle2", stringType);
// setBle is disambiguated and overridden
JMethod bleSetter = settersClass.getSetter("ble");
assertMethod(bleSetter, "setBle", stringType);
// setBli was ambiguous in the superclass, subclass String settles it
JMethod bliSetter = settersClass.getSetter("bli");
assertMethod(bliSetter, "setBli", stringType);
// setBli2 is ambiguous in the superclass
try {
settersClass.getSetter("bli2");
fail("Expected exception not thrown");
} catch (UnableToCompleteException utce) {
// Expected
}
// setBlo is ambiguous in the subclass
try {
settersClass.getSetter("blo");
fail("Expected exception not thrown");
} catch (UnableToCompleteException utce) {
// Expected
}
// Ignored superclass setters are still ignored
assertNull(settersClass.getSetter("nothing"));
assertNull(settersClass.getSetter("nothing2"));
assertNull(settersClass.getSetter("notASetter"));
assertNull(settersClass.getSetter("aSetter"));
assertNull(settersClass.getSetter("static"));
gwtTypeAdapter.verifyAll();
}
/**
* Class with a {@link UiChild}-annotated methods.
*/
@SuppressWarnings("unused")
// We know these methods are unused
private static class UiChildClass {
public UiChildClass() {
throw new UnsupportedOperationException("Should never get called");
}
@UiChild
void addChild(Object child) {
throw new UnsupportedOperationException("Should never get called");
}
@UiChild(tagname = "second", limit = 4)
void doesNotStartWithAdd(Object child) {
throw new UnsupportedOperationException("Should never get called");
}
}
public void testOwnerFieldClass_withUiChildren() throws Exception {
JClassType parentType = gwtTypeAdapter.adaptJavaClass(UiChildClass.class);
OwnerFieldClass parentClass = OwnerFieldClass.getFieldClass(parentType,
MortalLogger.NULL, uiBinderCtx);
assertEquals(parentType, parentClass.getRawType());
Map<String, Pair<JMethod, Integer>> childMethods = parentClass.getUiChildMethods();
assertNotNull(childMethods);
assertEquals(2, childMethods.size());
Pair<JMethod, Integer> childPair = childMethods.get("child");
assertEquals("addChild", childPair.left.getName());
assertEquals(Integer.valueOf(-1), childPair.right);
Pair<JMethod, Integer> secondPair = childMethods.get("second");
assertEquals("doesNotStartWithAdd", secondPair.left.getName());
assertEquals(Integer.valueOf(4), secondPair.right);
gwtTypeAdapter.verifyAll();
}
public void testOwnerFieldClass_withNoUiChildren() throws Exception {
JClassType parentType = gwtTypeAdapter.adaptJavaClass(Object.class);
OwnerFieldClass parentClass = OwnerFieldClass.getFieldClass(parentType,
MortalLogger.NULL, uiBinderCtx);
assertEquals(parentType, parentClass.getRawType());
Map<String, Pair<JMethod, Integer>> childMethods = parentClass.getUiChildMethods();
assertNotNull(childMethods);
assertEquals(0, childMethods.size());
gwtTypeAdapter.verifyAll();
}
/**
* Class with a {@link UiChild}-annotated methods.
*/
@SuppressWarnings("unused")
// We know these methods are unused
private static class UiChildWithPoorMethodNames {
public UiChildWithPoorMethodNames() {
throw new UnsupportedOperationException("Should never get called");
}
@UiChild
void poorlyNamedMethodWithoutTag(Object child) {
throw new UnsupportedOperationException("Should never get called");
}
}
public void testOwnerFieldClass_withBadlyNamedMethod() {
JClassType parentType = gwtTypeAdapter.adaptJavaClass(UiChildWithPoorMethodNames.class);
try {
OwnerFieldClass parentClass = OwnerFieldClass.getFieldClass(parentType,
MortalLogger.NULL, uiBinderCtx);
fail("Class should error because @UiChild method has invalid name (and no tag specified).");
} catch (UnableToCompleteException expected) {
gwtTypeAdapter.verifyAll();
}
}
/**
* Class with a {@link UiConstructor}-annotated constructor.
*/
@SuppressWarnings("unused")
// We know these methods are unused
private static class UiConstructorClass {
@UiConstructor
public UiConstructorClass(boolean visible) {
throw new UnsupportedOperationException("Should never get called");
}
}
public void testOwnerFieldClass_withUiConstructor() throws Exception {
JClassType constructorsType = gwtTypeAdapter.adaptJavaClass(UiConstructorClass.class);
OwnerFieldClass constructorsClass = OwnerFieldClass.getFieldClass(
constructorsType, MortalLogger.NULL, uiBinderCtx);
assertEquals(constructorsType, constructorsClass.getRawType());
JConstructor constructor = constructorsClass.getUiConstructor();
assertNotNull(constructor);
assertEquals(constructorsType, constructor.getEnclosingType());
JParameter[] parameters = constructor.getParameters();
assertEquals(1, parameters.length);
assertEquals(JPrimitiveType.BOOLEAN, parameters[0].getType());
gwtTypeAdapter.verifyAll();
}
/**
* Class with (disallowed) multiple constructors annotated with
* {@link UiConstructor}.
*/
@SuppressWarnings("unused")
// We know these methods are unused
private static class MultiUiConstructorsClass {
@UiConstructor
public MultiUiConstructorsClass(boolean visible) {
throw new UnsupportedOperationException("Should never get called");
}
@UiConstructor
public MultiUiConstructorsClass(String size) {
throw new UnsupportedOperationException("Should never get called");
}
}
public void testOwnerFieldClass_withMultipleUiConstructors() throws Exception {
JClassType constructorsType = gwtTypeAdapter.adaptJavaClass(MultiUiConstructorsClass.class);
try {
OwnerFieldClass.getFieldClass(constructorsType, MortalLogger.NULL,
uiBinderCtx);
fail("Expected exception not thrown");
} catch (UnableToCompleteException utce) {
// Expected
}
}
/**
* Asserts that the given method has the proper name and parameters.
*
* @param method the actual method
* @param methodName the expected method name
* @param parameterTypes the expected parameter types
*/
private void assertMethod(JMethod method, String methodName,
JType... parameterTypes) {
assertNotNull(method);
assertEquals(methodName, method.getName());
JParameter[] parameters = method.getParameters();
assertEquals(parameterTypes.length, parameters.length);
for (int i = 0; i < parameters.length; i++) {
assertEquals("Parameter " + i + " of method " + methodName
+ " mismatch. Expected" + parameterTypes[i].getSimpleSourceName()
+ "; actual: " + parameters[i].getType().getSimpleSourceName(),
parameterTypes[i], parameters[i].getType());
}
}
}