/* * Copyright 2011 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.apt; import com.google.gwt.dev.util.Util; import com.google.web.bindery.requestfactory.gwt.client.RequestFactoryPolymorphicTest; import com.google.web.bindery.requestfactory.shared.LoggingRequest; import com.google.web.bindery.requestfactory.shared.SimpleRequestFactory; import com.google.web.bindery.requestfactory.shared.TestRequestFactory; import com.google.web.bindery.requestfactory.shared.impl.FindRequest; import junit.framework.TestCase; import java.io.File; import java.io.IOException; import java.io.StringWriter; import java.net.URI; import java.net.URISyntaxException; import java.net.URL; import java.util.ArrayList; import java.util.Arrays; import java.util.List; import java.util.TreeSet; import javax.tools.Diagnostic; import javax.tools.DiagnosticCollector; import javax.tools.JavaCompiler; import javax.tools.JavaCompiler.CompilationTask; import javax.tools.JavaFileManager; import javax.tools.JavaFileObject; import javax.tools.SimpleJavaFileObject; import javax.tools.ToolProvider; /** * Integration test of {@link RfValidator} using the Java6 tools API to invoke * the Java compiler. This test requires that the gwt-user source is available * on the classpath. */ public class RfValidatorTest extends TestCase { /** * Provides access to a source file from the classpath. */ private static class UriJavaFileObject extends SimpleJavaFileObject { public static UriJavaFileObject create(Class<?> toLoad) { try { String path = toLoad.getName().replace('.', '/') + ".java"; /* * SimpleJavaFileObject does not like the URI's created from jar URLs * since their path does not start with a leading forward-slash. The * choice of "classpath" as the scheme is arbitrary and meaningless. */ URI fakeLocation = new URI("classpath:/" + path); return new UriJavaFileObject(fakeLocation, Thread.currentThread().getContextClassLoader() .getResource(path)); } catch (URISyntaxException e) { throw new RuntimeException(e); } } private final URL contents; public UriJavaFileObject(URI fakeLocation, URL contents) throws URISyntaxException { super(fakeLocation, JavaFileObject.Kind.SOURCE); this.contents = contents; } @Override public CharSequence getCharContent(boolean ignored) throws IOException { return Util.readStreamAsString(contents.openStream()); } } /** * Smoke test to ensure that appropriate errors and warnings are emitted. */ public void testErrorsAndWarnings() throws IOException { testGeneratedMessages(EntityProxyCheckDomainMapping.class); testGeneratedMessages(EntityProxyMismatchedFind.class); testGeneratedMessages(EntityProxyMissingDomainLocatorMethods.class); testGeneratedMessages(EntityProxyMissingDomainType.class); testGeneratedMessages(MyRequestContext.class); testGeneratedMessages(MyRequestFactory.class); testGeneratedMessages(RequestContextMissingDomainType.class); testGeneratedMessages(RequestContextUsingUnmappedProxy.class, EntityProxyMissingDomainType.class); testGeneratedMessages(RequestContextWithMismatchedBoxes.class); testGeneratedMessages(RequestContextWithMismatchedInstance.class); } /** * The target classes for this method don't contain any {@code @Expect} * annotations, so this test will verify that they are error- and * warning-free. */ public void testTestClasses() throws IOException { testGeneratedMessages(RequestFactoryPolymorphicTest.class); testGeneratedMessages(FindRequest.class); testGeneratedMessages(LoggingRequest.class); testGeneratedMessages(SimpleRequestFactory.class); testGeneratedMessages(TestRequestFactory.class); } /** * The target classes for this method don't contain any {@code @Expect} * annotations, so this test will verify that they are error- and * warning-free. * * @throws IOException */ public void testTestClassesClientOnly() throws IOException { testGeneratedMessages(true, RequestFactoryPolymorphicTest.class); testGeneratedMessages(true, FindRequest.class); testGeneratedMessages(true, LoggingRequest.class); testGeneratedMessages(true, SimpleRequestFactory.class); testGeneratedMessages(true, TestRequestFactory.class); } private void assertEquals(TreeSet<Diagnostic<? extends JavaFileObject>> expected, TreeSet<Diagnostic<? extends JavaFileObject>> actual) { List<Diagnostic<?>> unmatched = new ArrayList<Diagnostic<?>>(); // Remove actual elements from expect, saving any unexpected elements for (Diagnostic<? extends JavaFileObject> d : actual) { if (!expected.remove(d)) { unmatched.add(d); } } assertTrue("Did not see expected errors: " + expected + "\n\nLeftovers :" + unmatched, expected .isEmpty()); assertTrue("Unexpected errors: " + unmatched, unmatched.isEmpty()); } private void testGeneratedMessages(Class<?>... classes) throws IOException { testGeneratedMessages(false, classes); } /** * Run the annotation processor over one or more classes and verify that the * appropriate messages are generated. */ private void testGeneratedMessages(boolean clientOnly, Class<?>... classes) throws IOException { JavaCompiler compiler = ToolProvider.getSystemJavaCompiler(); if (compiler == null) { // This test is being run without a full JDK return; } // Don't spray files in random locations File tempFile = File.createTempFile(RfValidatorTest.class.getSimpleName(), ".jar"); tempFile.deleteOnExit(); JavaFileManager fileManager = new ValidationTool.JarOrDirectoryOutputFileManager(tempFile, compiler .getStandardFileManager(null, null, null)); List<JavaFileObject> files = new ArrayList<JavaFileObject>(classes.length); for (Class<?> clazz : classes) { JavaFileObject obj = UriJavaFileObject.create(clazz); files.add(obj); } StringWriter errorWriter = new StringWriter(); RfValidator rfValidator = new RfValidator(); rfValidator.setForceErrors(true); rfValidator.setClientOnly(clientOnly); DiagnosticCollector<JavaFileObject> expectedCollector = new DiagnosticCollector<JavaFileObject>(); CompilationTask expectedTask = compiler.getTask(errorWriter, fileManager, expectedCollector, Arrays.asList("-proc:only"), null, files); expectedTask.setProcessors(Arrays.asList(new ExpectCollector())); expectedTask.call(); DiagnosticCollector<JavaFileObject> actualCollector = new DiagnosticCollector<JavaFileObject>(); CompilationTask actualTask = compiler.getTask(errorWriter, fileManager, actualCollector, Arrays.asList("-proc:only"), null, files); actualTask.setProcessors(Arrays.asList(rfValidator)); actualTask.call(); TreeSet<Diagnostic<? extends JavaFileObject>> expected = new TreeSet<Diagnostic<? extends JavaFileObject>>(new DiagnosticComparator()); expected.addAll(expectedCollector.getDiagnostics()); TreeSet<Diagnostic<? extends JavaFileObject>> actual = new TreeSet<Diagnostic<? extends JavaFileObject>>(new DiagnosticComparator()); actual.addAll(actualCollector.getDiagnostics()); assertEquals(expected, actual); } }