blob: 2690c7ebb8874025143a3dc5eab640209d70652e [file] [log] [blame]
/*
* 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;
}
}