/* * Copyright (C) 2015 Red Hat, Inc. and/or its affiliates. * * 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 org.jboss.errai.processor; /* * Copyright 2012 JBoss 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. */ import static org.junit.Assert.*; import java.io.IOException; import java.util.Arrays; import java.util.HashSet; import java.util.List; import java.util.Set; import javax.annotation.processing.AbstractProcessor; import javax.tools.Diagnostic; import javax.tools.Diagnostic.Kind; import javax.tools.DiagnosticCollector; import javax.tools.JavaCompiler; import javax.tools.JavaCompiler.CompilationTask; import javax.tools.JavaFileObject; import javax.tools.StandardJavaFileManager; import javax.tools.ToolProvider; /** * Base class for Errai annotation checker tests. * <p> * This code is based on a corresponding class from the UberFire test suite. */ public abstract class AbstractProcessorTest { /** * Warning messages that don't count against {@link #assertSuccessfulCompilation(List)}. */ private final Set<String> ignorableWarnings = new HashSet<>( Arrays.asList( "bootstrap class path not set in conjunction with -source 1.6", "Implicitly compiled files were not subject to annotation processing.")); /** * Compile a unit of source code with the specified annotation processor * * @param annotationProcessor * the annotation processor that should participate in the * compilation * @param compilationUnit * path to a classpath resource, eg * "org/jboss/errai/processor/testcase/TemplatedNotExtendingComposite.java" */ public List<Diagnostic<? extends JavaFileObject>> compile(final String compilationUnit) { final DiagnosticCollector<JavaFileObject> diagnosticListener = new DiagnosticCollector<>(); try { final JavaCompiler compiler = ToolProvider.getSystemJavaCompiler(); final StandardJavaFileManager fileManager = compiler.getStandardFileManager(diagnosticListener, null, null); // Convert compilation unit to file path and add to items to compile final String path = this.getClass().getResource("/" + compilationUnit).getPath(); final Iterable<? extends JavaFileObject> compilationUnits = fileManager.getJavaFileObjects(path); // Compile with provided annotation processor final CompilationTask task = compiler .getTask(null, fileManager, diagnosticListener, Arrays.asList("-source", "1.8", "-target", "1.8"), null, compilationUnits); task.setProcessors(Arrays.asList(getProcessorUnderTest())); task.call(); fileManager.close(); } catch (final IOException ioe) { fail(ioe.getMessage()); } return diagnosticListener.getDiagnostics(); } /** * Checks that there are no unignorable errors or warnings in the given list of diagnostics. */ public void assertSuccessfulCompilation(final List<Diagnostic<? extends JavaFileObject>> diagnostics) { final StringBuilder sb = new StringBuilder(100); nextMessage: for (final Diagnostic<? extends JavaFileObject> msg : diagnostics) { for (final String ignorableWarning : ignorableWarnings) { if (msg.getMessage(null).contains(ignorableWarning)) { continue nextMessage; } } sb.append(msg.getKind()) .append(" ") .append(msg.getLineNumber()) .append(":") .append(msg.getColumnNumber()) .append(": ") .append(msg.getMessage(null)) .append("\n"); } if (sb.length() > 0) { fail("Expected no warnings or errors; got:\n" + sb); } } /** * Assert that compilation failed * * @param diagnostics */ public void assertFailedCompilation(final List<Diagnostic<? extends JavaFileObject>> diagnostics) { assertTrue(hasErrors(diagnostics)); } private boolean hasErrors(final List<Diagnostic<? extends JavaFileObject>> diagnostics) { for (final Diagnostic<? extends JavaFileObject> diagnostic : diagnostics) { if (diagnostic.getKind().equals(Kind.ERROR)) { return true; } } return false; } /** * Assert that the given error message is contained in the compilation * diagnostics. * * @param diagnostics * the list of diagnostic messages from the compiler. Must not be null. * @param kind * the kind of message to search for, or null to search messages of * any kind. * @param line * the line number that must be attached to the message, or * {@link Diagnostic#NOPOS} if line number is not important. * @param col * the column number that must be attached to the message, or * {@link Diagnostic#NOPOS} if column number is not important. * @param message * the message to search for. If any otherwise matching message in * the given list contains this string, the assertion passes. Must not be null. */ public void assertCompilationMessage(final List<Diagnostic<? extends JavaFileObject>> diagnostics, final Kind kind, final long line, final long col, final String message) { final StringBuilder sb = new StringBuilder(100); for (final Diagnostic<? extends JavaFileObject> msg : diagnostics) { sb.append(msg.getKind()) .append(" ") .append(msg.getLineNumber()) .append(":") .append(msg.getColumnNumber()) .append(": ") .append(msg.getMessage(null)) .append("\n"); if ( (kind == null || msg.getKind().equals(kind)) && (line == Diagnostic.NOPOS || msg.getLineNumber() == line) && (col == Diagnostic.NOPOS || msg.getColumnNumber() == col) && msg.getMessage(null).contains(message)) { return; } } fail("Compiler diagnostics did not contain " + kind + " message " + line + ":" + col + ": " + message + "\n" + "Dump of all " + diagnostics.size() + " actual messages:\n" + sb); } /** * Returns the annotation processor being tested by the current test. This * processor should be created with a GenerationCompleteCallback that will * capture the output of the processor so it can be examined by test * assertions. */ protected abstract AbstractProcessor getProcessorUnderTest(); }