Restores various unit tests of the UiBinder code generator.
Review by fabbott
git-svn-id: https://google-web-toolkit.googlecode.com/svn/trunk@6305 8db76d5a-ed1c-0410-87a9-c151d255dfc7
diff --git a/eclipse/user/.classpath b/eclipse/user/.classpath
index 37be02a..1b04495 100644
--- a/eclipse/user/.classpath
+++ b/eclipse/user/.classpath
@@ -24,6 +24,10 @@
<classpathentry kind="var" path="GWT_TOOLS/lib/xerces/xerces-2_9_1/xml-apis.jar" />
<classpathentry kind="var" path="GWT_TOOLS/lib/w3c/sac/sac-1.3.jar"/>
<classpathentry kind="var" path="GWT_TOOLS/lib/w3c/flute/flute-1.3.jar"/>
+ <classpathentry kind="var" path="GWT_TOOLS/lib/cglib/cglib-2.2.jar"/>
+ <classpathentry kind="var" path="GWT_TOOLS/lib/easymock/easymock.jar"/>
+ <classpathentry kind="var" path="GWT_TOOLS/lib/easymock/easymockclassextension.jar"/>
+ <classpathentry kind="var" path="GWT_TOOLS/lib/objectweb/asm-3.1.jar"/>
<classpathentry combineaccessrules="false" kind="src" path="/gwt-dev-windows"/>
<classpathentry kind="output" path="bin"/>
</classpath>
diff --git a/user/build.xml b/user/build.xml
index 4db7d74..ab92084 100755
--- a/user/build.xml
+++ b/user/build.xml
@@ -34,6 +34,10 @@
<pathelement location="${gwt.build}/out/dev/core/bin-test" />
<pathelement location="test-super" />
<pathelement location="test_i18n_${gwt.i18n.test.InnerClassChar}" />
+ <pathelement location="${gwt.tools.lib}/cglib/cglib-2.2.jar"/>
+ <pathelement location="${gwt.tools.lib}/easymock/easymock.jar"/>
+ <pathelement location="${gwt.tools.lib}/easymock/easymockclassextension.jar"/>
+ <pathelement location="${gwt.tools.lib}/objectweb/asm-3.1.jar"/>
</path>
<!-- Platform shouldn't matter here, just picking one -->
@@ -75,6 +79,10 @@
<pathelement location="${gwt.tools.lib}/tomcat/servlet-api-2.5.jar" />
<pathelement location="${gwt.tools.lib}/junit/junit-3.8.1.jar" />
<pathelement location="${gwt.tools.lib}/selenium/selenium-java-client-driver.jar" />
+ <pathelement location="${gwt.tools.lib}/cglib/cglib-2.2.jar"/>
+ <pathelement location="${gwt.tools.lib}/easymock/easymock.jar"/>
+ <pathelement location="${gwt.tools.lib}/easymock/easymockclassextension.jar"/>
+ <pathelement location="${gwt.tools.lib}/objectweb/asm-3.1.jar"/>
<pathelement location="${gwt.dev.jar}" />
</classpath>
</gwt.javac>
diff --git a/user/src/com/google/gwt/uibinder/rebind/MortalLogger.java b/user/src/com/google/gwt/uibinder/rebind/MortalLogger.java
index 80964ad..d0c77d2 100644
--- a/user/src/com/google/gwt/uibinder/rebind/MortalLogger.java
+++ b/user/src/com/google/gwt/uibinder/rebind/MortalLogger.java
@@ -26,7 +26,7 @@
public class MortalLogger {
private final TreeLogger logger;
- MortalLogger(TreeLogger logger) {
+ public MortalLogger(TreeLogger logger) {
this.logger = logger;
}
diff --git a/user/test/com/google/gwt/uibinder/UiBinderJreSuite.java b/user/test/com/google/gwt/uibinder/UiBinderJreSuite.java
new file mode 100644
index 0000000..20b033b
--- /dev/null
+++ b/user/test/com/google/gwt/uibinder/UiBinderJreSuite.java
@@ -0,0 +1,52 @@
+/*
+ * 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;
+
+import com.google.gwt.uibinder.rebind.GwtResourceEntityResolverTest;
+import com.google.gwt.uibinder.rebind.HandlerEvaluatorTest;
+import com.google.gwt.uibinder.rebind.TokenatorTest;
+import com.google.gwt.uibinder.rebind.XMLElementTest;
+import com.google.gwt.uibinder.rebind.model.OwnerClassTest;
+import com.google.gwt.uibinder.rebind.model.OwnerFieldClassTest;
+import com.google.gwt.uibinder.rebind.model.OwnerFieldTest;
+
+import junit.framework.Test;
+import junit.framework.TestSuite;
+
+/**
+ * Suite of UiBinder tests that require the JRE
+ */
+public class UiBinderJreSuite {
+ public static Test suite() {
+ TestSuite suite = new TestSuite("UiBinder tests that require the JRE");
+
+ // rebind
+ suite.addTestSuite(GwtResourceEntityResolverTest.class);
+ suite.addTestSuite(HandlerEvaluatorTest.class);
+ suite.addTestSuite(TokenatorTest.class);
+ suite.addTestSuite(XMLElementTest.class);
+
+ // model
+ suite.addTestSuite(OwnerClassTest.class);
+ suite.addTestSuite(OwnerFieldClassTest.class);
+ suite.addTestSuite(OwnerFieldTest.class);
+
+ return suite;
+ }
+
+ private UiBinderJreSuite() {
+ }
+}
diff --git a/user/test/com/google/gwt/uibinder/rebind/HandlerEvaluatorTest.java b/user/test/com/google/gwt/uibinder/rebind/HandlerEvaluatorTest.java
new file mode 100644
index 0000000..f8680be
--- /dev/null
+++ b/user/test/com/google/gwt/uibinder/rebind/HandlerEvaluatorTest.java
@@ -0,0 +1,85 @@
+/*
+ * 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;
+
+import com.google.gwt.core.ext.typeinfo.JClassType;
+import com.google.gwt.core.ext.typeinfo.TypeOracle;
+import com.google.gwt.dev.shell.log.TreeItemLogger;
+import com.google.gwt.event.shared.EventHandler;
+import com.google.gwt.event.shared.HandlerRegistration;
+import com.google.gwt.uibinder.rebind.model.OwnerClass;
+
+import junit.framework.TestCase;
+
+import org.easymock.classextension.EasyMock;
+import org.easymock.classextension.IMocksControl;
+
+import java.io.PrintWriter;
+import java.io.StringWriter;
+
+/**
+ * Tests the HandlerEvaluator.
+ *
+ */
+public class HandlerEvaluatorTest extends TestCase {
+
+ HandlerEvaluator evaluator;
+
+ // Defines the mock control.
+ private IMocksControl mockControl;
+
+ private OwnerClass ownerType;
+ private MortalLogger logger;
+ private TypeOracle oracle;
+
+ @Override
+ protected void setUp() throws Exception {
+ super.setUp();
+
+ logger = new MortalLogger(new TreeItemLogger());
+
+ // Creates all needed mocks.
+ mockControl = EasyMock.createControl();
+ ownerType = mockControl.createMock(OwnerClass.class);
+ oracle = mockControl.createMock(TypeOracle.class);
+
+ // TODO(hermes): sucks I know!!!! This class shouldn't be using EasyMock
+ // but for now that's the easiest way of creating new instances of
+ // TypeOracle, TreeLogger, etc. Again, I must check a better way of
+ // injecting TypeOracle, TreeLogger and JClassType.
+
+ JClassType handlerRegistrationJClass = mockControl.createMock(JClassType.class);
+ EasyMock.expect(oracle.findType(HandlerRegistration.class.getName())).andReturn(
+ handlerRegistrationJClass);
+
+ JClassType eventHandlerJClass = mockControl.createMock(JClassType.class);
+ EasyMock.expect(oracle.findType(EventHandler.class.getName())).andReturn(
+ eventHandlerJClass);
+
+ mockControl.replay();
+ evaluator = new HandlerEvaluator(ownerType, logger, oracle);
+ mockControl.verify();
+ mockControl.reset();
+ }
+
+ public void testWriteAddHandler() throws Exception {
+ StringWriter sw = new StringWriter();
+ evaluator.writeAddHandler(new IndentedWriter(new PrintWriter(sw)),
+ "handler1", "addClickHandler", "label1");
+
+ assertEquals("label1.addClickHandler(handler1);", sw.toString().trim());
+ }
+}
diff --git a/user/test/com/google/gwt/uibinder/rebind/JClassTypeAdapter.java b/user/test/com/google/gwt/uibinder/rebind/JClassTypeAdapter.java
new file mode 100644
index 0000000..4d73cdb
--- /dev/null
+++ b/user/test/com/google/gwt/uibinder/rebind/JClassTypeAdapter.java
@@ -0,0 +1,496 @@
+/*
+ * 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;
+
+import com.google.gwt.core.ext.typeinfo.HasAnnotations;
+import com.google.gwt.core.ext.typeinfo.HasTypeParameters;
+import com.google.gwt.core.ext.typeinfo.JAbstractMethod;
+import com.google.gwt.core.ext.typeinfo.JClassType;
+import com.google.gwt.core.ext.typeinfo.JConstructor;
+import com.google.gwt.core.ext.typeinfo.JField;
+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 static org.easymock.EasyMock.expect;
+import static org.easymock.EasyMock.isA;
+
+import org.easymock.IAnswer;
+import org.easymock.classextension.EasyMock;
+
+import java.lang.annotation.Annotation;
+import java.lang.reflect.AnnotatedElement;
+import java.lang.reflect.Constructor;
+import java.lang.reflect.Field;
+import java.lang.reflect.GenericDeclaration;
+import java.lang.reflect.Member;
+import java.lang.reflect.Method;
+import java.lang.reflect.Modifier;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * Creates stub adapters for GWT reflection using EasyMock.
+ * This takes in a real java reflection class and returns a JClassType which
+ * forwards all its method calls to the equivalent java reflection methods.
+ * <p>
+ * Most reflections are done lazily (only when the method is actually called),
+ * specially those which potentially require mocking a new class / method /
+ * field / parameter / constructor / etc.
+ * <p>
+ * The support for the typeinfo API is still incomplete, and in fact will
+ * always be in some way since Java doesn't support all the reflections that
+ * GWT's typeinfo does.
+ * <p>
+ * TODO: With a bit of generalization, this class should make its way
+ * to core/src/com/google/gwt/junit
+ *
+ * To make it public we need to...
+ * <ol>
+ * <li>implement the missing parts and TODOs (e.g. generics)
+ * <li>add tests to it (even though it's a testing utility, it does need
+ * tests, specially for cases like inner and anonymous classes, generic
+ * parameters, etc.)
+ * <li>decide what to do with the parts of JType reflection that java doesn't
+ * have an equivalent for - e.g. parameter names. This may involve making a
+ * slightly more complex API to inject those values.
+ * </ol>
+ */
+public class JClassTypeAdapter {
+
+ private final Map<Class<?>, JClassType> adaptedClasses =
+ new HashMap<Class<?>, JClassType>();
+ private final List<Object> allMocks = new ArrayList<Object>();
+
+ public void verifyAll() {
+ EasyMock.verify(allMocks.toArray());
+ }
+
+ /**
+ * Creates a mock GWT class type for the given Java class.
+ *
+ * @param clazz the java class
+ * @return the gwt class
+ */
+ public JClassType adaptJavaClass(final Class<?> clazz) {
+ if (clazz.isPrimitive()) {
+ throw new RuntimeException(
+ "Only classes can be passed to adaptJavaClass");
+ }
+
+ // First try the cache (also avoids infinite recursion if a type references
+ // itself).
+ JClassType type = adaptedClasses.get(clazz);
+ if (type != null) {
+ return type;
+ }
+
+ // Create and put in the cache
+ type = createMock(JClassType.class);
+ final JClassType finalType = type;
+ adaptedClasses.put(clazz, type);
+
+ // Adds behaviour for annotations and generics
+ addAnnotationBehaviour(clazz, type);
+
+ // TODO(rdamazio): Add generics behaviour
+
+ // Add behaviour for getting methods
+ expect(type.getMethods()).andStubAnswer(new IAnswer<JMethod[]>() {
+ public JMethod[] answer() throws Throwable {
+ // TODO(rdamazio): Check behaviour for parent methods
+ Method[] realMethods = clazz.getDeclaredMethods();
+ JMethod[] methods = new JMethod[realMethods.length];
+ for (int i = 0; i < realMethods.length; i++) {
+ methods[i] = adaptMethod(realMethods[i], finalType);
+ }
+ return methods;
+ }
+ });
+
+ // Add behaviour for getting constructors
+ expect(type.getConstructors()).andStubAnswer(new IAnswer<JConstructor[]>() {
+ public JConstructor[] answer() throws Throwable {
+ Constructor<?>[] realConstructors = clazz.getDeclaredConstructors();
+ JConstructor[] constructors = new JConstructor[realConstructors.length];
+ for (int i = 0; i < realConstructors.length; i++) {
+ constructors[i] = adaptConstructor(realConstructors[i], finalType);
+ }
+ return constructors;
+ }
+ });
+
+ // Add behaviour for getting fields
+ expect(type.getFields()).andStubAnswer(new IAnswer<JField[]>() {
+ public JField[] answer() throws Throwable {
+ Field[] realFields = clazz.getDeclaredFields();
+ JField[] fields = new JField[realFields.length];
+ for (int i = 0; i < realFields.length; i++) {
+ fields[i] = adaptField(realFields[i], finalType);
+ }
+ return fields;
+ }
+ });
+
+ // Add behaviour for getting names
+ expect(type.getName()).andStubReturn(clazz.getName());
+ expect(type.getQualifiedSourceName()).andStubReturn(
+ clazz.getCanonicalName());
+ expect(type.getSimpleSourceName()).andStubReturn(clazz.getSimpleName());
+
+ // Add modifier behaviour
+ int modifiers = clazz.getModifiers();
+ expect(type.isAbstract()).andStubReturn(Modifier.isAbstract(modifiers));
+ expect(type.isFinal()).andStubReturn(Modifier.isFinal(modifiers));
+ expect(type.isPublic()).andStubReturn(Modifier.isPublic(modifiers));
+ expect(type.isProtected()).andStubReturn(Modifier.isProtected(modifiers));
+ expect(type.isPrivate()).andStubReturn(Modifier.isPrivate(modifiers));
+
+ // Add conversion behaviours
+ expect(type.isArray()).andStubReturn(null);
+ expect(type.isEnum()).andStubReturn(null);
+ expect(type.isPrimitive()).andStubReturn(null);
+ expect(type.isClassOrInterface()).andStubReturn(type);
+ if (clazz.isInterface()) {
+ expect(type.isClass()).andStubReturn(null);
+ expect(type.isInterface()).andStubReturn(type);
+ } else {
+ expect(type.isClass()).andStubReturn(type);
+ expect(type.isInterface()).andStubReturn(null);
+ }
+ expect(type.getEnclosingType()).andStubAnswer(new IAnswer<JClassType>() {
+ public JClassType answer() throws Throwable {
+ Class<?> enclosingClass = clazz.getEnclosingClass();
+ if (enclosingClass == null) {
+ return null;
+ }
+
+ return adaptJavaClass(enclosingClass);
+ }
+ });
+ expect(type.getSuperclass()).andStubAnswer(new IAnswer<JClassType>() {
+ public JClassType answer() throws Throwable {
+ Class<?> superclass = clazz.getSuperclass();
+ if (superclass == null) {
+ return null;
+ }
+
+ return adaptJavaClass(superclass);
+ }
+ });
+
+ // TODO(rdamazio): Mock out other methods as needed
+ // TODO(rdamazio): Figure out what to do with reflections that GWT allows
+ // but Java doesn't
+
+ EasyMock.replay(type);
+ return type;
+ }
+
+ /**
+ * Creates a mock GWT field for the given Java field.
+ *
+ * @param realField the java field
+ * @param enclosingType the GWT enclosing type
+ * @return the GWT field
+ */
+ public JField adaptField(final Field realField, JClassType enclosingType) {
+ JField field = createMock(JField.class);
+
+ addAnnotationBehaviour(realField, field);
+
+ expect(field.getType()).andStubAnswer(new IAnswer<JType>() {
+ public JType answer() throws Throwable {
+ return adaptType(realField.getType());
+ }
+ });
+
+ expect(field.getEnclosingType()).andStubReturn(enclosingType);
+ expect(field.getName()).andStubReturn(realField.getName());
+
+ EasyMock.replay(field);
+ return field;
+ }
+
+ /**
+ * Creates a mock GWT constructor for the given java constructor.
+ *
+ * @param realConstructor the java constructor
+ * @param enclosingType the type to which the constructor belongs
+ * @return the GWT constructor
+ */
+ private JConstructor adaptConstructor(final Constructor<?> realConstructor,
+ JClassType enclosingType) {
+ final JConstructor constructor = createMock(JConstructor.class);
+
+ addCommonAbstractMethodBehaviour(realConstructor, constructor,
+ enclosingType);
+ addAnnotationBehaviour(realConstructor, constructor);
+
+ // Parameters
+ expect(constructor.getParameters()).andStubAnswer(
+ new IAnswer<JParameter[]>() {
+ public JParameter[] answer() throws Throwable {
+ return adaptParameters(realConstructor.getParameterTypes(),
+ realConstructor.getParameterAnnotations(), constructor);
+ }
+ });
+
+ // Thrown exceptions
+ expect(constructor.getThrows()).andStubAnswer(
+ new IAnswer<JType[]>() {
+ public JType[] answer() throws Throwable {
+ Class<?>[] realThrows = realConstructor.getExceptionTypes();
+ JType[] gwtThrows = new JType[realThrows.length];
+ for (int i = 0; i < realThrows.length; i++) {
+ gwtThrows[i] = adaptType(realThrows[i]);
+ }
+ return gwtThrows;
+ }
+ });
+
+ EasyMock.replay(constructor);
+ return constructor;
+ }
+
+ /**
+ * Creates a mock GWT method for the given java method.
+ *
+ * @param realMethod the java method
+ * @param enclosingType the type to which the method belongs
+ * @return the GWT method
+ */
+ private JMethod adaptMethod(final Method realMethod,
+ JClassType enclosingType) {
+ // TODO(rdamazio): ensure a single instance per method per class
+ final JMethod method = createMock(JMethod.class);
+
+ addCommonAbstractMethodBehaviour(realMethod, method, enclosingType);
+ addAnnotationBehaviour(realMethod, method);
+ addGenericsBehaviour(realMethod, method);
+
+ expect(method.isStatic()).andStubReturn(
+ Modifier.isStatic(realMethod.getModifiers()));
+
+ // Return type
+ expect(method.getReturnType()).andStubAnswer(new IAnswer<JType>() {
+ public JType answer() throws Throwable {
+ return adaptType(realMethod.getReturnType());
+ }
+ });
+
+ // Parameters
+ expect(method.getParameters()).andStubAnswer(new IAnswer<JParameter[]>() {
+ public JParameter[] answer() throws Throwable {
+ return adaptParameters(realMethod.getParameterTypes(),
+ realMethod.getParameterAnnotations(), method);
+ }
+ });
+
+ // Thrown exceptions
+ expect(method.getThrows()).andStubAnswer(new IAnswer<JType[]>() {
+ public JType[] answer() throws Throwable {
+ Class<?>[] realThrows = realMethod.getExceptionTypes();
+ JType[] gwtThrows = new JType[realThrows.length];
+ for (int i = 0; i < realThrows.length; i++) {
+ gwtThrows[i] = adaptType(realThrows[i]);
+ }
+ return gwtThrows;
+ }
+ });
+
+ EasyMock.replay(method);
+ return method;
+ }
+
+ /**
+ * Creates an array of mock GWT parameters for the given array of java
+ * parameters.
+ *
+ * @param parameterTypes the types of the parameters
+ * @param parameterAnnotations the list of annotations for each parameter
+ * @param method the method or constructor to which the parameters belong
+ * @return an array of GWT parameters
+ */
+ @SuppressWarnings("unchecked")
+ protected JParameter[] adaptParameters(Class<?>[] parameterTypes,
+ Annotation[][] parameterAnnotations, JAbstractMethod method) {
+ JParameter[] parameters = new JParameter[parameterTypes.length];
+ for (int i = 0; i < parameterTypes.length; i++) {
+ final Class<?> realParameterType = parameterTypes[i];
+ JParameter parameter = createMock(JParameter.class);
+ parameters[i] = parameter;
+
+ // TODO(rdamazio): getName() has no plain java equivalent.
+ // Perhaps compiling with -g:vars ?
+
+ expect(parameter.getEnclosingMethod()).andStubReturn(method);
+ expect(parameter.getType()).andStubAnswer(new IAnswer<JType>() {
+ public JType answer() throws Throwable {
+ return adaptType(realParameterType);
+ }
+ });
+
+ // Add annotation behaviour
+ final Annotation[] annotations = parameterAnnotations[i];
+
+ expect(parameter.isAnnotationPresent(isA(Class.class))).andStubAnswer(
+ new IAnswer<Boolean>() {
+ public Boolean answer() throws Throwable {
+ Class<? extends Annotation> annotationClass =
+ (Class<? extends Annotation>)
+ EasyMock.getCurrentArguments()[0];
+ for (Annotation annotation : annotations) {
+ if (annotation.equals(annotationClass)) {
+ return true;
+ }
+ }
+ return false;
+ }
+ });
+
+ expect(parameter.getAnnotation(isA(Class.class))).andStubAnswer(
+ new IAnswer<Annotation>() {
+ public Annotation answer() throws Throwable {
+ Class<? extends Annotation> annotationClass =
+ (Class<? extends Annotation>)
+ EasyMock.getCurrentArguments()[0];
+ for (Annotation annotation : annotations) {
+ if (annotation.equals(annotationClass)) {
+ return annotation;
+ }
+ }
+ return null;
+ }
+ });
+
+ EasyMock.replay(parameter);
+ }
+
+ return parameters;
+ }
+
+ /**
+ * Creates a GWT mock type for the given java type.
+ * The type can be a class or a primitive type.
+ *
+ * @param type the java type
+ * @return the GWT type
+ */
+ private JType adaptType(Class<?> type) {
+ if (!type.isPrimitive()) {
+ return adaptJavaClass(type);
+ } else {
+ return adaptPrimitiveType(type);
+ }
+ }
+
+ /**
+ * Returns the GWT primitive type for the given java primitive type.
+ *
+ * @param type the java primitive type
+ * @return the GWT primitive equivalent
+ */
+ private JType adaptPrimitiveType(Class<?> type) {
+ if (boolean.class.equals(type)) { return JPrimitiveType.BOOLEAN; }
+ if (int.class.equals(type)) { return JPrimitiveType.INT; }
+ if (char.class.equals(type)) { return JPrimitiveType.CHAR; }
+ if (byte.class.equals(type)) { return JPrimitiveType.BYTE; }
+ if (long.class.equals(type)) { return JPrimitiveType.LONG; }
+ if (short.class.equals(type)) { return JPrimitiveType.SHORT; }
+ if (float.class.equals(type)) { return JPrimitiveType.FLOAT; }
+ if (double.class.equals(type)) { return JPrimitiveType.DOUBLE; }
+ if (void.class.equals(type)) { return JPrimitiveType.VOID; }
+
+ throw new IllegalArgumentException(
+ "Invalid primitive type: " + type.getName());
+ }
+
+ /**
+ * Adds expectations common to all method types (methods and constructors).
+ *
+ * @param realMember the java method
+ * @param member the mock GWT method
+ * @param enclosingType the type to which the method belongs
+ */
+ private void addCommonAbstractMethodBehaviour(Member realMember,
+ JAbstractMethod member, JClassType enclosingType) {
+ // Attributes
+ int modifiers = realMember.getModifiers();
+ expect(member.isPublic()).andStubReturn(Modifier.isPublic(modifiers));
+ expect(member.isProtected()).andStubReturn(Modifier.isProtected(modifiers));
+ expect(member.isPrivate()).andStubReturn(Modifier.isPrivate(modifiers));
+ expect(member.getName()).andStubReturn(realMember.getName());
+ expect(member.getEnclosingType()).andStubReturn(enclosingType);
+ }
+
+ /**
+ * Adds expectations for getting annotations from elements (methods, classes,
+ * parameters, etc.).
+ *
+ * @param realElement the java element which contains annotations
+ * @param element the mock GWT element which contains annotations
+ */
+ @SuppressWarnings("unchecked")
+ private void addAnnotationBehaviour(final AnnotatedElement realElement,
+ final HasAnnotations element) {
+ expect(element.isAnnotationPresent(isA(Class.class))).andStubAnswer(
+ new IAnswer<Boolean>() {
+ public Boolean answer() throws Throwable {
+ Class<? extends Annotation> annotationClass =
+ (Class<? extends Annotation>) EasyMock.getCurrentArguments()[0];
+ return realElement.isAnnotationPresent(annotationClass);
+ }
+ });
+
+ expect(element.getAnnotation(isA(Class.class))).andStubAnswer(
+ new IAnswer<Annotation>() {
+ public Annotation answer() throws Throwable {
+ Class<? extends Annotation> annotationClass =
+ (Class<? extends Annotation>) EasyMock.getCurrentArguments()[0];
+ return realElement.getAnnotation(annotationClass);
+ }
+ });
+ }
+
+ /**
+ * Adds expectations for getting generics types.
+ *
+ * @param realGeneric the java generic declaration
+ * @param generic the mock GWT generic declaration
+ */
+ private void addGenericsBehaviour(final GenericDeclaration realGeneric,
+ final HasTypeParameters generic) {
+ // TODO(rdamazio): Implement when necessary
+ }
+
+ /**
+ * Creates a mock of the given class and adds it to the {@link #allMocks}
+ * member list.
+ *
+ * @param <T> the type of the mock
+ * @param clazz the class of the mock
+ * @return the mock
+ */
+ private <T> T createMock(Class<T> clazz) {
+ T mock = EasyMock.createMock(clazz);
+ allMocks.add(mock);
+ return mock;
+ }
+}
diff --git a/user/test/com/google/gwt/uibinder/rebind/model/OwnerClassTest.java b/user/test/com/google/gwt/uibinder/rebind/model/OwnerClassTest.java
new file mode 100644
index 0000000..24cc2e6
--- /dev/null
+++ b/user/test/com/google/gwt/uibinder/rebind/model/OwnerClassTest.java
@@ -0,0 +1,403 @@
+/*
+ * 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.JMethod;
+import com.google.gwt.core.ext.typeinfo.JParameter;
+import com.google.gwt.dev.shell.log.TreeItemLogger;
+import com.google.gwt.event.dom.client.ClickEvent;
+import com.google.gwt.event.dom.client.MouseOverEvent;
+import com.google.gwt.uibinder.client.UiFactory;
+import com.google.gwt.uibinder.client.UiField;
+import com.google.gwt.uibinder.client.UiHandler;
+import com.google.gwt.uibinder.rebind.JClassTypeAdapter;
+import com.google.gwt.uibinder.rebind.MortalLogger;
+import com.google.gwt.user.client.ui.Button;
+import com.google.gwt.user.client.ui.Label;
+
+import junit.framework.TestCase;
+
+import java.util.Collection;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+
+/**
+ * Tests for the owner class descriptor.
+ */
+public class OwnerClassTest extends TestCase {
+
+ private JClassTypeAdapter gwtTypeAdapter;
+ private MortalLogger logger;
+
+ @Override
+ protected void setUp() throws Exception {
+ super.setUp();
+
+ logger = new MortalLogger(new TreeItemLogger());
+ gwtTypeAdapter = new JClassTypeAdapter();
+ }
+
+ /**
+ * Empty uibinder class for sanity checking.
+ */
+ private static class EmptyOwnerClass { }
+
+ public void testOwnerClass_empty() throws Exception {
+ JClassType ownerType = gwtTypeAdapter.adaptJavaClass(EmptyOwnerClass.class);
+ JClassType labelType = gwtTypeAdapter.adaptJavaClass(Label.class);
+ OwnerClass ownerClass = new OwnerClass(ownerType, logger);
+
+ assertNull(ownerClass.getUiFactoryMethod(labelType));
+ assertNull(ownerClass.getUiField("fieldName"));
+ assertNull(ownerClass.getUiFieldForType(labelType));
+ assertTrue(ownerClass.getUiFields().isEmpty());
+ assertTrue(ownerClass.getUiHandlers().isEmpty());
+
+ gwtTypeAdapter.verifyAll();
+ }
+
+ /**
+ * Uibinder class for testing of {@link UiFactory}.
+ */
+ private static class UiFactoryClass {
+ @UiFactory
+ Label createLabel() {
+ throw new UnsupportedOperationException("Should never be called");
+ }
+ }
+
+ public void testOwnerClass_uiFactory() throws Exception {
+ JClassType ownerType = gwtTypeAdapter.adaptJavaClass(UiFactoryClass.class);
+ JClassType labelType = gwtTypeAdapter.adaptJavaClass(Label.class);
+ OwnerClass ownerClass = new OwnerClass(ownerType, logger);
+
+ JMethod uiFactoryMethod = ownerClass.getUiFactoryMethod(labelType);
+ assertNotNull(uiFactoryMethod);
+ assertEquals("createLabel", uiFactoryMethod.getName());
+ assertEquals(labelType, uiFactoryMethod.getReturnType());
+ JParameter[] parameters = uiFactoryMethod.getParameters();
+ assertNotNull(parameters);
+ assertEquals(0, parameters.length);
+
+ gwtTypeAdapter.verifyAll();
+ }
+
+ /**
+ * Uibinder class for testing bad usage of {@link UiFactory}.
+ */
+ private static class BadUiFactoryClass {
+ @UiFactory
+ int thisShouldntWork() {
+ throw new UnsupportedOperationException("Should never be called");
+ }
+ }
+
+ public void testOwnerClass_uiFactoryBadType() {
+ JClassType ownerType = gwtTypeAdapter.adaptJavaClass(BadUiFactoryClass.class);
+ try {
+ new OwnerClass(ownerType, logger);
+ fail("Expected exception not thrown.");
+ } catch (UnableToCompleteException utce) {
+ // Expected
+ }
+
+ gwtTypeAdapter.verifyAll();
+ }
+
+ /**
+ * Uibinder class for testing bad usage of {@link UiFactory}.
+ */
+ private static class DuplicateUiFactoryClass {
+ @UiFactory
+ Label labelFactory1() {
+ throw new UnsupportedOperationException("Should never be called");
+ }
+
+ @UiFactory
+ Label labelFactory2() {
+ throw new UnsupportedOperationException("Should never be called");
+ }
+ }
+
+ public void testOwnerClass_uiFactoryDuplicateType() {
+ JClassType ownerType = gwtTypeAdapter.adaptJavaClass(DuplicateUiFactoryClass.class);
+ try {
+ new OwnerClass(ownerType, logger);
+ fail("Expected exception not thrown.");
+ } catch (UnableToCompleteException utce) {
+ // Expected
+ }
+
+ gwtTypeAdapter.verifyAll();
+ }
+
+ /**
+ * Uibinder class for testing of {@link UiField}.
+ */
+ private static class UiFieldsClass {
+ @UiField
+ Label label1;
+
+ @UiField(provided = true)
+ Button button1;
+ }
+
+ public void testOwnerClass_uiFields() throws Exception {
+ JClassType ownerType = gwtTypeAdapter.adaptJavaClass(UiFieldsClass.class);
+ JClassType labelType = gwtTypeAdapter.adaptJavaClass(Label.class);
+ JClassType buttonType = gwtTypeAdapter.adaptJavaClass(Button.class);
+ OwnerClass ownerClass = new OwnerClass(ownerType, logger);
+
+ OwnerField labelField = ownerClass.getUiField("label1");
+ OwnerField labelField2 = ownerClass.getUiFieldForType(labelType);
+ assertNotNull(labelField);
+ assertNotNull(labelField2);
+ assertEquals(labelField, labelField2);
+ assertFalse(labelField.isProvided());
+ assertEquals(labelType, labelField.getType().getRawType());
+ assertEquals("label1", labelField.getName());
+
+ OwnerField buttonField = ownerClass.getUiField("button1");
+ OwnerField buttonField2 = ownerClass.getUiFieldForType(buttonType);
+ assertNotNull(buttonField);
+ assertNotNull(buttonField2);
+ assertEquals(buttonField, buttonField2);
+ assertTrue(buttonField.isProvided());
+ assertEquals(buttonType, buttonField.getType().getRawType());
+ assertEquals("button1", buttonField.getName());
+
+ Collection<OwnerField> uiFields = ownerClass.getUiFields();
+ Set<OwnerField> uiFieldSet = new HashSet<OwnerField>(uiFields);
+ Set<OwnerField> expectedFieldSet = new HashSet<OwnerField>();
+ expectedFieldSet.add(labelField);
+ expectedFieldSet.add(buttonField);
+ assertEquals(expectedFieldSet, uiFieldSet);
+
+ gwtTypeAdapter.verifyAll();
+ }
+
+ /**
+ * Uibinder class for testing bad usage of {@link UiField}.
+ */
+ private static class BadUiFieldsClass {
+ @UiField
+ int thisShouldntWork;
+ }
+
+ public void testOwnerClass_uiFieldsBadType() {
+ JClassType ownerType = gwtTypeAdapter.adaptJavaClass(BadUiFieldsClass.class);
+ try {
+ new OwnerClass(ownerType, logger);
+ fail("Expected exception not thrown.");
+ } catch (UnableToCompleteException utce) {
+ // Expected
+ }
+
+ gwtTypeAdapter.verifyAll();
+ }
+
+ /**
+ * Uibinder class for testing of {@link UiHandler}.
+ */
+ private static class UiHandlersClass {
+ @UiHandler("myField")
+ void onMyFieldClicked(ClickEvent ev) {
+ throw new UnsupportedOperationException("Should never be called");
+ }
+
+ @UiHandler({"myField", "myOtherField"})
+ void onMouseOver(MouseOverEvent ev) {
+ throw new UnsupportedOperationException("Should never be called");
+ }
+ }
+
+ public void testOwnerClass_uiHandlers() throws Exception {
+ JClassType ownerType = gwtTypeAdapter.adaptJavaClass(UiHandlersClass.class);
+ OwnerClass ownerClass = new OwnerClass(ownerType, logger);
+
+ // Assert the two expected handlers are there
+ List<JMethod> uiHandlers = ownerClass.getUiHandlers();
+ assertEquals(2, uiHandlers.size());
+ JMethod clickMethod = null,
+ mouseOverMethod = null;
+
+ // Don't care about ordering
+ for (JMethod method : uiHandlers) {
+ if (method.getName().equals("onMyFieldClicked")) {
+ clickMethod = method;
+ } else if (method.getName().equals("onMouseOver")) {
+ mouseOverMethod = method;
+ }
+ }
+
+ assertNotNull(clickMethod);
+ assertNotNull(mouseOverMethod);
+
+ // Check the click handler
+ JClassType clickEventType = gwtTypeAdapter.adaptJavaClass(ClickEvent.class);
+ JParameter[] clickParams = clickMethod.getParameters();
+ assertEquals(1, clickParams.length);
+ assertEquals(clickEventType, clickParams[0].getType());
+ assertTrue(clickMethod.isAnnotationPresent(UiHandler.class));
+ UiHandler clickAnnotation = clickMethod.getAnnotation(UiHandler.class);
+ String[] clickFields = clickAnnotation.value();
+ assertEquals(1, clickFields.length);
+ assertEquals("myField", clickFields[0]);
+
+ // Check the mouse over handler
+ JClassType mouseOverEventType = gwtTypeAdapter.adaptJavaClass(MouseOverEvent.class);
+ JParameter[] mouseOverParams = mouseOverMethod.getParameters();
+ assertEquals(1, mouseOverParams.length);
+ assertEquals(mouseOverEventType, mouseOverParams[0].getType());
+ assertTrue(mouseOverMethod.isAnnotationPresent(UiHandler.class));
+ UiHandler mouseOverAnnotation = mouseOverMethod.getAnnotation(UiHandler.class);
+ String[] mouseOverFields = mouseOverAnnotation.value();
+ assertEquals(2, mouseOverFields.length);
+ assertEquals("myField", mouseOverFields[0]);
+ assertEquals("myOtherField", mouseOverFields[1]);
+
+ gwtTypeAdapter.verifyAll();
+ }
+
+ /**
+ * Parent class for testing inheritance of owner classes.
+ */
+ private static class ParentUiBinderClass {
+ @UiField
+ Label label1;
+
+ @UiFactory
+ Label createLabel() {
+ throw new UnsupportedOperationException("Should never be called");
+ }
+
+ @UiHandler("label1")
+ void onLabelMouseOver(MouseOverEvent ev) {
+ throw new UnsupportedOperationException("Should never be called");
+ }
+ }
+
+ /**
+ * Child class for testing inheritance of owner classes.
+ */
+ private static class ChildUiBinderClass extends ParentUiBinderClass {
+ @UiField(provided = true)
+ Button button1;
+
+ @UiFactory
+ Button createButton() {
+ throw new UnsupportedOperationException("Should never be called");
+ }
+
+ @UiHandler("button1")
+ void onButtonClicked(ClickEvent ev) {
+ throw new UnsupportedOperationException("Should never be called");
+ }
+ }
+
+ public void testOwnerClass_withParent() throws Exception {
+ JClassType ownerType =
+ gwtTypeAdapter.adaptJavaClass(ChildUiBinderClass.class);
+ JClassType labelType = gwtTypeAdapter.adaptJavaClass(Label.class);
+ JClassType buttonType = gwtTypeAdapter.adaptJavaClass(Button.class);
+ OwnerClass ownerClass = new OwnerClass(ownerType, logger);
+
+ // Test fields
+ OwnerField labelField = ownerClass.getUiField("label1");
+ OwnerField labelField2 = ownerClass.getUiFieldForType(labelType);
+ assertNotNull(labelField);
+ assertNotNull(labelField2);
+ assertEquals(labelField, labelField2);
+ assertFalse(labelField.isProvided());
+ assertEquals(labelType, labelField.getType().getRawType());
+ assertEquals("label1", labelField.getName());
+
+ OwnerField buttonField = ownerClass.getUiField("button1");
+ OwnerField buttonField2 = ownerClass.getUiFieldForType(buttonType);
+ assertNotNull(buttonField);
+ assertNotNull(buttonField2);
+ assertEquals(buttonField, buttonField2);
+ assertTrue(buttonField.isProvided());
+ assertEquals(buttonType, buttonField.getType().getRawType());
+ assertEquals("button1", buttonField.getName());
+
+ Collection<OwnerField> uiFields = ownerClass.getUiFields();
+ Set<OwnerField> uiFieldSet = new HashSet<OwnerField>(uiFields);
+ Set<OwnerField> expectedFieldSet = new HashSet<OwnerField>();
+ expectedFieldSet.add(labelField);
+ expectedFieldSet.add(buttonField);
+ assertEquals(expectedFieldSet, uiFieldSet);
+
+ // Test factories
+ JMethod labelFactoryMethod = ownerClass.getUiFactoryMethod(labelType);
+ assertNotNull(labelFactoryMethod);
+ assertEquals("createLabel", labelFactoryMethod.getName());
+ assertEquals(labelType, labelFactoryMethod.getReturnType());
+ JParameter[] labelParams = labelFactoryMethod.getParameters();
+ assertNotNull(labelParams);
+ assertEquals(0, labelParams.length);
+
+ JMethod buttonFactoryMethod = ownerClass.getUiFactoryMethod(labelType);
+ assertNotNull(buttonFactoryMethod);
+ assertEquals("createLabel", buttonFactoryMethod.getName());
+ assertEquals(labelType, buttonFactoryMethod.getReturnType());
+ JParameter[] buttonParams = buttonFactoryMethod.getParameters();
+ assertNotNull(buttonParams);
+ assertEquals(0, buttonParams.length);
+
+ // Test handlers
+ List<JMethod> uiHandlers = ownerClass.getUiHandlers();
+ assertEquals(2, uiHandlers.size());
+ JMethod clickMethod = null,
+ mouseOverMethod = null;
+
+ for (JMethod method : uiHandlers) {
+ if (method.getName().equals("onButtonClicked")) {
+ clickMethod = method;
+ } else if (method.getName().equals("onLabelMouseOver")) {
+ mouseOverMethod = method;
+ }
+ }
+
+ assertNotNull(clickMethod);
+ assertNotNull(mouseOverMethod);
+
+ JClassType clickEventType = gwtTypeAdapter.adaptJavaClass(ClickEvent.class);
+ JParameter[] clickParams = clickMethod.getParameters();
+ assertEquals(1, clickParams.length);
+ assertEquals(clickEventType, clickParams[0].getType());
+ assertTrue(clickMethod.isAnnotationPresent(UiHandler.class));
+ UiHandler clickAnnotation = clickMethod.getAnnotation(UiHandler.class);
+ String[] clickFields = clickAnnotation.value();
+ assertEquals(1, clickFields.length);
+ assertEquals("button1", clickFields[0]);
+
+ JClassType mouseOverEventType = gwtTypeAdapter.adaptJavaClass(MouseOverEvent.class);
+ JParameter[] mouseOverParams = mouseOverMethod.getParameters();
+ assertEquals(1, mouseOverParams.length);
+ assertEquals(mouseOverEventType, mouseOverParams[0].getType());
+ assertTrue(mouseOverMethod.isAnnotationPresent(UiHandler.class));
+ UiHandler mouseOverAnnotation = mouseOverMethod.getAnnotation(UiHandler.class);
+ String[] mouseOverFields = mouseOverAnnotation.value();
+ assertEquals(1, mouseOverFields.length);
+ assertEquals("label1", mouseOverFields[0]);
+
+ gwtTypeAdapter.verifyAll();
+ }
+}
diff --git a/user/test/com/google/gwt/uibinder/rebind/model/OwnerFieldClassTest.java b/user/test/com/google/gwt/uibinder/rebind/model/OwnerFieldClassTest.java
new file mode 100644
index 0000000..8de43d2
--- /dev/null
+++ b/user/test/com/google/gwt/uibinder/rebind/model/OwnerFieldClassTest.java
@@ -0,0 +1,355 @@
+/*
+ * 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.shell.log.TreeItemLogger;
+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.user.client.ui.Label;
+
+import junit.framework.TestCase;
+
+/**
+ * Tests for descriptors of potential owner field classes.
+ */
+public class OwnerFieldClassTest extends TestCase {
+
+ private JClassTypeAdapter gwtTypeAdapter;
+ private MortalLogger logger;
+
+ @Override
+ protected void setUp() throws Exception {
+ super.setUp();
+
+ logger = new MortalLogger(new TreeItemLogger());
+ 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, logger);
+
+ // 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, logger));
+
+ gwtTypeAdapter.verifyAll();
+ }
+
+ /**
+ * Class with lots of setters for testing.
+ */
+ 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 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, logger);
+ 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, logger);
+ 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.
+ */
+ 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, logger);
+ 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 UiConstructor}-annotated constructor.
+ */
+ 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, logger);
+ 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}.
+ */
+ 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, logger);
+ 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());
+ }
+ }
+}
diff --git a/user/test/com/google/gwt/uibinder/rebind/model/OwnerFieldTest.java b/user/test/com/google/gwt/uibinder/rebind/model/OwnerFieldTest.java
new file mode 100644
index 0000000..b1d5a86
--- /dev/null
+++ b/user/test/com/google/gwt/uibinder/rebind/model/OwnerFieldTest.java
@@ -0,0 +1,107 @@
+/*
+ * 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.JField;
+import com.google.gwt.dev.shell.log.TreeItemLogger;
+import com.google.gwt.uibinder.client.UiField;
+import com.google.gwt.uibinder.rebind.JClassTypeAdapter;
+import com.google.gwt.uibinder.rebind.MortalLogger;
+import com.google.gwt.user.client.ui.Button;
+import com.google.gwt.user.client.ui.Label;
+
+import junit.framework.TestCase;
+
+/**
+ * Tests for the owner field descriptor.
+ */
+public class OwnerFieldTest extends TestCase {
+
+ private JClassTypeAdapter gwtTypeAdapter;
+ private JClassType ownerType;
+ private MortalLogger logger;
+
+ @Override
+ protected void setUp() throws Exception {
+ super.setUp();
+
+ logger = new MortalLogger(new TreeItemLogger());
+ gwtTypeAdapter = new JClassTypeAdapter();
+ ownerType = gwtTypeAdapter.adaptJavaClass(this.getClass());
+ }
+
+ // Fields for testing
+
+ @UiField
+ Label someField;
+
+ @UiField(provided = true)
+ Button providedField;
+
+ @UiField
+ int badTypeField;
+
+ Label nonAnnotatedField;
+
+ public void testOwnerField() throws Exception {
+ JClassType labelType = gwtTypeAdapter.adaptJavaClass(Label.class);
+ JClassType buttonType = gwtTypeAdapter.adaptJavaClass(Button.class);
+
+ JField someGwtField = gwtTypeAdapter.adaptField(
+ this.getClass().getDeclaredField("someField"), ownerType);
+ OwnerField someOwnerField = new OwnerField(someGwtField, logger);
+ assertEquals("someField", someOwnerField.getName());
+ assertEquals(labelType, someOwnerField.getType().getRawType());
+ assertFalse(someOwnerField.isProvided());
+
+ JField providedGwtField = gwtTypeAdapter.adaptField(
+ this.getClass().getDeclaredField("providedField"), ownerType);
+ OwnerField providedOwnerField = new OwnerField(providedGwtField, logger);
+ assertEquals("providedField", providedOwnerField.getName());
+ assertEquals(buttonType, providedOwnerField.getType().getRawType());
+ assertTrue(providedOwnerField.isProvided());
+
+ gwtTypeAdapter.verifyAll();
+ }
+
+ public void testOwnerField_badFieldType() throws Exception {
+ JField someGwtField = gwtTypeAdapter.adaptField(
+ this.getClass().getDeclaredField("badTypeField"), ownerType);
+ try {
+ new OwnerField(someGwtField, logger);
+ fail("Expected exception not thrown.");
+ } catch (UnableToCompleteException utce) {
+ // Expected
+ }
+
+ gwtTypeAdapter.verifyAll();
+ }
+
+ public void testOwnerField_missingAnnotation() throws Exception {
+ JField someGwtField = gwtTypeAdapter.adaptField(
+ this.getClass().getDeclaredField("nonAnnotatedField"), ownerType);
+ try {
+ new OwnerField(someGwtField, logger);
+ fail("Expected exception not thrown.");
+ } catch (UnableToCompleteException utce) {
+ // Expected
+ }
+
+ gwtTypeAdapter.verifyAll();
+ }
+}