| /* |
| * 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()); |
| } |
| } |
| } |