| /* |
| * Copyright 2010 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.web.bindery.requestfactory.gwt.rebind.model; |
| |
| import com.google.web.bindery.autobean.shared.Splittable; |
| import com.google.gwt.core.ext.TreeLogger; |
| import com.google.gwt.core.ext.UnableToCompleteException; |
| import com.google.gwt.dev.javac.CompilationState; |
| import com.google.gwt.dev.javac.CompilationStateBuilder; |
| import com.google.gwt.dev.javac.testing.impl.JavaResourceBase; |
| import com.google.gwt.dev.javac.testing.impl.MockJavaResource; |
| import com.google.gwt.dev.resource.Resource; |
| import com.google.gwt.dev.util.UnitTestTreeLogger; |
| import com.google.gwt.dev.util.Util; |
| import com.google.gwt.dev.util.log.PrintWriterTreeLogger; |
| import com.google.web.bindery.requestfactory.server.TestContextImpl; |
| import com.google.web.bindery.requestfactory.shared.EntityProxy; |
| import com.google.web.bindery.requestfactory.shared.InstanceRequest; |
| import com.google.web.bindery.requestfactory.shared.Locator; |
| import com.google.web.bindery.requestfactory.shared.ProxyFor; |
| import com.google.web.bindery.requestfactory.shared.Receiver; |
| import com.google.web.bindery.requestfactory.shared.Request; |
| import com.google.web.bindery.requestfactory.shared.RequestContext; |
| import com.google.web.bindery.requestfactory.shared.RequestFactory; |
| import com.google.web.bindery.requestfactory.shared.Service; |
| import com.google.web.bindery.requestfactory.shared.ServiceLocator; |
| import com.google.web.bindery.requestfactory.shared.ValueProxy; |
| |
| import junit.framework.TestCase; |
| |
| import java.io.InputStream; |
| import java.io.PrintWriter; |
| import java.util.Arrays; |
| import java.util.HashSet; |
| import java.util.List; |
| import java.util.Set; |
| import java.util.SortedSet; |
| |
| /** |
| * Test case for |
| * {@link com.google.web.bindery.requestfactory.gwt.rebind.model.RequestFactoryModel} that |
| * uses mock CompilationStates. |
| */ |
| public class RequestFactoryModelTest extends TestCase { |
| |
| /** |
| * Constructs an empty interface representation of a type. |
| */ |
| private static class EmptyMockJavaResource extends MockJavaResource { |
| |
| private final StringBuilder code = new StringBuilder(); |
| |
| public EmptyMockJavaResource(Class<?> clazz) { |
| super(clazz.getName()); |
| |
| code.append("package ").append(clazz.getPackage().getName()).append(";\n"); |
| code.append("public interface ").append(clazz.getSimpleName()); |
| |
| int numParams = clazz.getTypeParameters().length; |
| if (numParams != 0) { |
| code.append("<"); |
| for (int i = 0; i < numParams; i++) { |
| if (i != 0) { |
| code.append(","); |
| } |
| code.append("T").append(i); |
| } |
| code.append(">"); |
| } |
| |
| code.append("{}\n"); |
| } |
| |
| @Override |
| public CharSequence getContent() { |
| return code; |
| } |
| } |
| |
| /** |
| * Loads the actual source of a type. This should be used only for types |
| * directly tested by this test. Note that use of this class requires your |
| * source files to be on your classpath. |
| */ |
| private static class RealJavaResource extends MockJavaResource { |
| |
| public RealJavaResource(Class<?> clazz) { |
| super(clazz.getName()); |
| } |
| |
| @Override |
| public CharSequence getContent() { |
| String resourceName = getTypeName().replace('.', '/') + ".java"; |
| InputStream stream = Thread.currentThread().getContextClassLoader().getResourceAsStream( |
| resourceName); |
| assertNotNull("Could not open " + resourceName, stream); |
| return Util.readStreamAsString(stream); |
| } |
| } |
| |
| private static TreeLogger createCompileLogger() { |
| PrintWriterTreeLogger logger = new PrintWriterTreeLogger(new PrintWriter( |
| System.err, true)); |
| logger.setMaxDetail(TreeLogger.ERROR); |
| return logger; |
| } |
| |
| private TreeLogger logger; |
| |
| @Override |
| public void setUp() throws Exception { |
| super.setUp(); |
| logger = createCompileLogger(); |
| } |
| |
| public void testBadCollectionType() { |
| testModelWithMethodDecl( |
| "Request<SortedSet<Integer>> badReturnType();", |
| "Requests that return collections may be declared with java.util.List or java.util.Set only"); |
| } |
| |
| public void testBadCollectionTypeNotParameterized() { |
| testModelWithMethodDecl("Request<SortedSet> badReturnType();", |
| "Requests that return collections of List or Set must be parameterized"); |
| } |
| |
| public void testBadReturnType() { |
| testModelWithMethodDecl("Request<Iterable> badReturnType();", |
| "Invalid Request parameterization java.lang.Iterable"); |
| } |
| |
| public void testDuplicateBooleanGetters() { |
| testModelWithMethodDecl("Request<t.ProxyWithRepeatedGetters> method();", |
| "Duplicate accessors for property foo: getFoo() and isFoo()"); |
| } |
| |
| public void testMissingProxyFor() { |
| testModelWithMethodDeclArgs("Request<TestProxy> okMethodProxy();", |
| TestContextImpl.class.getName(), null, |
| "The t.TestProxy type does not have a @ProxyFor, " |
| + "@ProxyForName, or @JsonRpcProxy annotation"); |
| } |
| |
| public void testMissingService() { |
| testModelWithMethodDeclArgs("Request<String> okMethod();", null, |
| TestContextImpl.class.getName(), |
| "RequestContext subtype t.TestContext is missing a " |
| + "@Service or @JsonRpcService annotation"); |
| } |
| |
| public void testModelWithMethodDecl(final String clientMethodDecls, |
| String... expected) { |
| testModelWithMethodDeclArgs(clientMethodDecls, |
| TestContextImpl.class.getName(), TestContextImpl.class.getName(), |
| expected); |
| } |
| |
| public void testModelWithMethodDeclArgs(final String clientMethodDecls, |
| final String serviceClass, String proxyClass, String... expected) { |
| Set<Resource> javaResources = getJavaResources(proxyClass); |
| javaResources.add(new MockJavaResource("t.TestRequestFactory") { |
| @Override |
| public CharSequence getContent() { |
| StringBuilder code = new StringBuilder(); |
| code.append("package t;\n"); |
| code.append("import " + RequestFactory.class.getName() + ";\n"); |
| code.append("interface TestRequestFactory extends RequestFactory {\n"); |
| code.append("TestContext testContext();"); |
| code.append("}"); |
| return code; |
| } |
| }); |
| javaResources.add(new MockJavaResource("t.TestContext") { |
| @Override |
| public CharSequence getContent() { |
| StringBuilder code = new StringBuilder(); |
| code.append("package t;\n"); |
| code.append("import " + Request.class.getName() + ";\n"); |
| code.append("import " + InstanceRequest.class.getName() + ";\n"); |
| |
| code.append("import " + RequestContext.class.getName() + ";\n"); |
| code.append("import " + SortedSet.class.getName() + ";\n"); |
| code.append("import " + List.class.getName() + ";\n"); |
| code.append("import " + Set.class.getName() + ";\n"); |
| code.append("import " + Service.class.getName() + ";\n"); |
| code.append("import " + TestContextImpl.class.getName() + ";\n"); |
| |
| if (serviceClass != null) { |
| code.append("@Service(" + serviceClass + ".class)"); |
| } |
| code.append("interface TestContext extends RequestContext {\n"); |
| code.append(clientMethodDecls); |
| code.append("}"); |
| return code; |
| } |
| }); |
| |
| CompilationState state = CompilationStateBuilder.buildFrom(logger, |
| javaResources); |
| |
| UnitTestTreeLogger.Builder builder = new UnitTestTreeLogger.Builder(); |
| builder.setLowestLogLevel(TreeLogger.ERROR); |
| for (String expectedMsg : expected) { |
| builder.expectError(expectedMsg, null); |
| } |
| builder.expectError(RequestFactoryModel.poisonedMessage(), null); |
| UnitTestTreeLogger testLogger = builder.createLogger(); |
| try { |
| new RequestFactoryModel(testLogger, state.getTypeOracle().findType( |
| "t.TestRequestFactory")); |
| fail("Should have complained"); |
| } catch (UnableToCompleteException e) { |
| } |
| testLogger.assertCorrectLogEntries(); |
| } |
| |
| private Set<Resource> getJavaResources(final String proxyClass) { |
| MockJavaResource[] javaFiles = {new MockJavaResource("t.AddressProxy") { |
| @Override |
| public CharSequence getContent() { |
| StringBuilder code = new StringBuilder(); |
| code.append("package t;\n"); |
| code.append("import " + ProxyFor.class.getName() + ";\n"); |
| code.append("import " + EntityProxy.class.getName() + ";\n"); |
| if (proxyClass != null) { |
| code.append("@ProxyFor(" + proxyClass + ".class)"); |
| } |
| code.append("interface TestProxy extends EntityProxy {\n"); |
| code.append("}"); |
| System.out.println(code); |
| return code; |
| } |
| }, new MockJavaResource("t.ProxyWithRepeatedGetters") { |
| @Override |
| public CharSequence getContent() { |
| StringBuilder code = new StringBuilder(); |
| code.append("package t;\n"); |
| code.append("import " + ProxyFor.class.getName() + ";\n"); |
| code.append("import " + EntityProxy.class.getName() + ";\n"); |
| if (proxyClass != null) { |
| code.append("@ProxyFor(" + proxyClass + ".class)"); |
| } |
| code.append("interface ProxyWithRepeatedGetters extends EntityProxy {\n"); |
| code.append(" boolean getFoo();"); |
| code.append(" boolean isFoo();"); |
| code.append("}"); |
| return code; |
| } |
| }, new MockJavaResource("java.util.List") { |
| // Tests a Driver interface that extends more than RFED |
| @Override |
| public CharSequence getContent() { |
| StringBuilder code = new StringBuilder(); |
| code.append("package java.util;\n"); |
| code.append("public interface List<T> extends Collection<T> {\n"); |
| code.append("}"); |
| return code; |
| } |
| }, new MockJavaResource("java.util.Set") { |
| // Tests a Driver interface that extends more than RFED |
| @Override |
| public CharSequence getContent() { |
| StringBuilder code = new StringBuilder(); |
| code.append("package java.util;\n"); |
| code.append("public interface Set<T> extends Collection<T> {\n"); |
| code.append("}"); |
| return code; |
| } |
| }, new MockJavaResource("java.util.SortedSet") { |
| // Tests a Driver interface that extends more than RFED |
| @Override |
| public CharSequence getContent() { |
| StringBuilder code = new StringBuilder(); |
| code.append("package java.util;\n"); |
| code.append("public interface SortedSet<T> extends Set<T> {\n"); |
| code.append("}"); |
| return code; |
| } |
| }}; |
| |
| Set<Resource> toReturn = new HashSet<Resource>(Arrays.asList(javaFiles)); |
| |
| toReturn.addAll(Arrays.asList(new Resource[] { |
| new EmptyMockJavaResource(Iterable.class), |
| new EmptyMockJavaResource(EntityProxy.class), |
| new EmptyMockJavaResource(InstanceRequest.class), |
| new EmptyMockJavaResource(Locator.class), |
| new EmptyMockJavaResource(RequestFactory.class), |
| new EmptyMockJavaResource(Receiver.class), |
| new EmptyMockJavaResource(ServiceLocator.class), |
| new EmptyMockJavaResource(Splittable.class), |
| new EmptyMockJavaResource(ValueProxy.class), |
| |
| new RealJavaResource(Request.class), |
| new RealJavaResource(Service.class), |
| new RealJavaResource(ProxyFor.class), |
| new EmptyMockJavaResource(RequestContext.class),})); |
| toReturn.addAll(Arrays.asList(JavaResourceBase.getStandardResources())); |
| return toReturn; |
| } |
| } |