blob: 709272ac456c75f5c9c181480f499d70d0259a35 [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2008 - 2017 Walter Harley and others
*
* This program and the accompanying materials
* are made available under the terms of the Eclipse Public License 2.0
* which accompanies this distribution, and is available at
* https://www.eclipse.org/legal/epl-2.0/
*
* SPDX-License-Identifier: EPL-2.0
*
* Contributors:
* eclipse@cafewalter.com - initial API and implementation
* Harry Terkelsen <het@google.com> - Contribution for Bug 437414 - Annotation processing is broken when build is batched
* Fabian Steeg <steeg@hbz-nrw.de> - Pass automatically provided options to Java 6 processors - https://bugs.eclipse.org/341298
* Pierre-Yves B. <pyvesdev@gmail.com> - Contribution for bug 559618 - No compiler warning for import from same package
*******************************************************************************/
package org.eclipse.jdt.apt.pluggable.tests;
import java.util.List;
import org.eclipse.core.resources.IProject;
import org.eclipse.core.runtime.IPath;
import org.eclipse.jdt.apt.core.util.AptConfig;
import org.eclipse.jdt.apt.pluggable.tests.processors.buildertester.Bug341298Processor;
import org.eclipse.jdt.apt.pluggable.tests.processors.buildertester.Bug468893Processor;
import org.eclipse.jdt.apt.pluggable.tests.processors.buildertester.Bug510118Processor;
import org.eclipse.jdt.apt.pluggable.tests.processors.buildertester.BugsProc;
import org.eclipse.jdt.apt.pluggable.tests.processors.buildertester.InheritedAnnoProc;
import org.eclipse.jdt.apt.pluggable.tests.processors.buildertester.TestFinalRoundProc;
import org.eclipse.jdt.core.IJavaProject;
import org.eclipse.jdt.core.tests.builder.Problem;
import org.eclipse.jdt.internal.core.builder.AbstractImageBuilder;
import junit.framework.Test;
import junit.framework.TestSuite;
/**
* Tests covering the IDE's ability to process the correct set of files.
*/
public class BuilderTests extends TestBase
{
public BuilderTests(String name) {
super(name);
}
public static Test suite() {
return new TestSuite(BuilderTests.class);
}
/**
* Verify that a new type generated in the final round does not get
* annotations processed, but does get compiled. The JSR269 spec is somewhat
* vague about whether it should be possible to generate a new type during
* the final round (since the final round does not happen until after a
* round in which no new types are generated); but apparently javac behaves
* this way.
* <p>
* See <a href="http://bugs.eclipse.org/329156">Bug 329156</a> and <a
* href="http://bugs.sun.com/view_bug.do?bug_id=6634138">the corresponding
* bug in javac</a>, which Sun fixed.
*/
public void testFinalRound() throws Throwable {
ProcessorTestStatus.reset();
TestFinalRoundProc.resetNumRounds();
IJavaProject jproj = createJavaProject(_projectName);
disableJava5Factories(jproj);
IProject proj = jproj.getProject();
IPath projPath = proj.getFullPath();
IPath root = projPath.append("src");
// The @FinalRoundTestTrigger processor does not generate any files when it
// first runs; but on its final round it then generates a new Java type
// that is annotated with @FinalRoundTestTrigger.
env.addClass(root, "t", "Foo",
"package t;\n" +
"import org.eclipse.jdt.apt.pluggable.tests.annotations.FinalRoundTestTrigger;\n" +
"@FinalRoundTestTrigger\n" +
"public class Foo {}"
);
AptConfig.setEnabled(jproj, true);
fullBuild();
expectingNoProblems();
// Processor should have run total of two rounds; compiled classes
// should include Foo and FinalRoundGen.
assertEquals(2, TestFinalRoundProc.getNumRounds());
expectingUniqueCompiledClasses(new String[] {"t.Foo", "g.FinalRoundGen"});
}
/**
* Verify that a class whose superclass is annotated with an inherited annotation
* gets treated the same as if the annotation were present on the class itself.
* See <a href="http://bugs.eclipse.org/270754">Bug 270754</a>.
*/
public void disabled_testInheritedAnnotation() throws Throwable {
ProcessorTestStatus.reset();
IJavaProject jproj = createJavaProject(_projectName);
disableJava5Factories(jproj);
IProject proj = jproj.getProject();
IPath projPath = proj.getFullPath();
IPath root = projPath.append("src");
env.addClass(root, "", "Base",
"import org.eclipse.jdt.apt.pluggable.tests.annotations.InheritedTrigger;\n" +
"@InheritedTrigger(0)\n" +
"public class Base {}"
);
// Because Sub extends Base, it should be treated as if it were annotated with InheritedTrigger
env.addClass(root, "", "Sub",
"public class Sub extends Base {\n" +
"}"
);
AptConfig.setEnabled(jproj, true);
fullBuild();
expectingNoProblems();
List<String> elements = InheritedAnnoProc.getProcessedElements();
assertTrue(elements.contains("Base"));
assertTrue(elements.contains("Sub"));
assertTrue("Processor did not run", ProcessorTestStatus.processorRan());
assertEquals("Processor reported errors", ProcessorTestStatus.NO_ERRORS, ProcessorTestStatus.getErrors());
// Modify base class and verify that both base and subclass get processed
InheritedAnnoProc.clearProcessedElements();
env.addClass(root, "", "Base",
"import org.eclipse.jdt.apt.pluggable.tests.annotations.InheritedTrigger;\n" +
"@InheritedTrigger(1)\n" +
"public class Base {}"
);
incrementalBuild();
expectingNoProblems();
elements = InheritedAnnoProc.getProcessedElements();
assertTrue(elements.contains("Base"));
assertTrue(elements.contains("Sub"));
assertTrue("Processor did not run", ProcessorTestStatus.processorRan());
assertEquals("Processor reported errors", ProcessorTestStatus.NO_ERRORS, ProcessorTestStatus.getErrors());
// Modify subclass and verify that it gets processed
InheritedAnnoProc.clearProcessedElements();
env.addClass(root, "", "Sub",
"public class Sub extends Base {\n" +
" // this line is new\n" +
"}"
);
incrementalBuild();
expectingNoProblems();
elements = InheritedAnnoProc.getProcessedElements();
assertTrue(elements.contains("Sub"));
assertTrue("Processor did not run", ProcessorTestStatus.processorRan());
assertEquals("Processor reported errors", ProcessorTestStatus.NO_ERRORS, ProcessorTestStatus.getErrors());
}
/**
* Deleting FooEvent caused the reference to FooEvent in
* FooImpl to appear as a package in one case and as a type in another,
* in turn causing a null binding to be passed to APT.
*
* See <a href="http://bugs.eclipse.org/295948">Bug 295948</a>.
*/
public void testBug295948() throws Throwable {
ProcessorTestStatus.reset();
IJavaProject jproj = createJavaProject(_projectName);
disableJava5Factories(jproj);
IProject proj = jproj.getProject();
IPath projPath = proj.getFullPath();
IPath root = projPath.append("src");
env.addClass(root, "test295948", "FooEvent",
"package test295948;\n" +
"public class FooEvent {\n" +
" public interface Handler {\n" +
" void handle(FooEvent event);\n" +
" }\n" +
"}\n" +
"\n"
);
IPath fooImplClass = env.addClass(root, "test295948", "FooImpl",
"package test295948;\n" +
"public class FooImpl implements FooEvent.Handler {\n" +
" @Override\n" +
" public void handle(FooEvent event) {\n" +
" }\n" +
"}\n"
);
AptConfig.setEnabled(jproj, true);
fullBuild();
expectingNoProblems();
// Delete FooEvent and recompile
proj.findMember("src/test295948/FooEvent.java").delete(false, null);
incrementalBuild();
expectingProblemsFor(fooImplClass,
"Problem : FooEvent cannot be resolved to a type [ resource : </" + _projectName + "/src/test295948/FooImpl.java> range : <108,116> category : <40> severity : <2>]\n" +
"Problem : FooEvent cannot be resolved to a type [ resource : </" + _projectName + "/src/test295948/FooImpl.java> range : <52,60> category : <40> severity : <2>]");
}
// https://bugs.eclipse.org/bugs/show_bug.cgi?id=407841
public void testBug407841() throws Throwable {
int old = org.eclipse.jdt.internal.core.builder.AbstractImageBuilder.MAX_AT_ONCE;
try {
org.eclipse.jdt.internal.core.builder.AbstractImageBuilder.MAX_AT_ONCE =1;
ProcessorTestStatus.reset();
IJavaProject jproj = createJavaProject(_projectName);
disableJava5Factories(jproj);
IProject proj = jproj.getProject();
IdeTestUtils.copyResources(proj, "targets/bug407841", "src/targets/bug407841");
AptConfig.setEnabled(jproj, true);
fullBuild();
expectingNoProblems();
assertEquals("Elements should have been processed", 0, BugsProc.getUnprocessedElements());
assertEquals("Elements should have been processed", 4, BugsProc.getNumRounds());
} finally {
org.eclipse.jdt.internal.core.builder.AbstractImageBuilder.MAX_AT_ONCE = old;
}
}
public void testBug468893() throws Throwable {
ProcessorTestStatus.reset();
IJavaProject jproj = createJavaProject(_projectName);
disableJava5Factories(jproj);
IProject proj = jproj.getProject();
IdeTestUtils.copyResources(proj, "targets/bug468893", "src/targets/bug468893");
AptConfig.setEnabled(jproj, true);
fullBuild();
expectingNoProblems();
assertEquals("Should have been processed over just once", 1, Bug468893Processor.count());
}
// https://bugs.eclipse.org/bugs/show_bug.cgi?id=419769
public void testBug419769() throws Throwable {
try {
ProcessorTestStatus.reset();
IJavaProject jproj = createJavaProject(_projectName);
disableJava5Factories(jproj);
IProject proj = jproj.getProject();
IdeTestUtils.copyResources(proj, "targets/bug419769", "src/targets/bug419769");
AptConfig.setEnabled(jproj, true);
fullBuild();
expectingNoProblems(); // There should be no compiler errors, i.e. except the APT injected ones.
Problem[] problems = env.getProblemsFor(jproj.getProject().getFullPath(), "org.eclipse.jdt.apt.pluggable.core.compileProblem");
StringBuffer buf = new StringBuffer();
for (int i = 0, length = problems.length; i < length; i++) {
Problem problem = problems[i];
buf.append(problem.getMessage());
if (i < length - 1) buf.append('\n');
}
assertEquals("There should be two reported problems",
"Some Error Message.\nYet another Error Message.",
buf.toString());
} finally {
}
}
public void testBug387956() throws Exception {
ProcessorTestStatus.reset();
IJavaProject jproj = createJavaProject(_projectName);
disableJava5Factories(jproj);
IProject proj = jproj.getProject();
IdeTestUtils.copyResources(proj, "targets/bug387956", "src/targets/bug387956");
AptConfig.setEnabled(jproj, true);
fullBuild();
expectingNoProblems();
}
public void testBatchedBuild() throws Throwable {
int old = AbstractImageBuilder.MAX_AT_ONCE;
IJavaProject jproj = createJavaProject(_projectName);
disableJava5Factories(jproj);
IProject proj = jproj.getProject();
IPath projPath = proj.getFullPath();
IPath root = projPath.append("src");
IPath packagePath = root.append("test");
try {
// Force the build to be batched
AbstractImageBuilder.MAX_AT_ONCE = 1;
ProcessorTestStatus.reset();
env.addClass(root, "test", "Foo",
"package test;\n" +
"import org.eclipse.jdt.apt.pluggable.tests.annotations.GenClass6;\n" +
"@GenClass6(name = \"FooGen\", pkg = \"test\")\n" +
"public class Foo {\n" +
" public Bar bar;\n" +
"}");
env.addClass(root, "test", "Bar",
"package test;\n" +
"import org.eclipse.jdt.apt.pluggable.tests.annotations.GenClass6;\n" +
"@GenClass6(name = \"BarGen\", pkg = \"test\")\n" +
"public class Bar {\n" +
" public Foo foo;\n" +
"}");
AptConfig.setEnabled(jproj, true);
fullBuild();
expectingNoProblems();
expectingUniqueCompiledClasses(
new String[] {"test.Foo", "test.Bar", "test.FooGen", "test.BarGen"});
} finally {
AbstractImageBuilder.MAX_AT_ONCE = old;
env.removeClass(packagePath, "Foo");
env.removeClass(packagePath, "Bar");
env.removeClass(packagePath, "FooGen");
env.removeClass(packagePath, "BarGen");
}
}
public void testBug468853() throws Throwable {
int old = AbstractImageBuilder.MAX_AT_ONCE;
IJavaProject jproj = createJavaProject(_projectName);
disableJava5Factories(jproj);
IProject proj = jproj.getProject();
IPath projPath = proj.getFullPath();
IPath root = projPath.append("src");
IPath packagePath = root.append("test");
try {
// Force the build to be batched
AbstractImageBuilder.MAX_AT_ONCE = 2;
ProcessorTestStatus.reset();
env.addClass(root, "test", "Foo",
"package test;\n" +
"import org.eclipse.jdt.apt.pluggable.tests.annotations.GenClass6;\n" +
"import org.eclipse.jdt.apt.pluggable.tests.annotations.Message6;\n" +
"import javax.tools.Diagnostic.Kind;\n" +
"@GenClass6(name = \"FooGen\", pkg = \"test\", rounds = 2)\n" +
"@Message6(text = \"APT message\", value = Kind.ERROR)\n" +
"public class Foo extends FooGen {\n" +
" public Bar bar;\n" +
"}");
env.addClass(root, "test", "Bar",
"package test;\n" +
"public class Bar {\n" +
" public Foo foo;\n" +
"}");
AptConfig.setEnabled(jproj, true);
fullBuild();
expectingNoProblems();
expectingUniqueCompiledClasses(
new String[] {"test.Foo", "test.Bar", "test.FooGen", "test.FooGenGen"});
} finally {
AbstractImageBuilder.MAX_AT_ONCE = old;
env.removeClass(packagePath, "Foo");
env.removeClass(packagePath, "Bar");
env.removeClass(packagePath, "FooGen");
}
}
public void testBug510118() throws Throwable {
ProcessorTestStatus.reset();
IJavaProject jproj = createJavaProject(_projectName);
disableJava5Factories(jproj);
IProject proj = jproj.getProject();
IdeTestUtils.copyResources(proj, "targets/bug510118", "src/targets/bug510118");
AptConfig.setEnabled(jproj, true);
fullBuild();
expectingNoProblems();
assertTrue("Incorrect status received from annotation processor", Bug510118Processor.status());
}
public void testBug341298() throws Throwable {
ProcessorTestStatus.reset();
IJavaProject project = createJavaProject(_projectName);
IPath root = project.getProject().getFullPath().append("src");
env.addClass(root, "test341298", "Annotated",
"package test341298;\n" +
"@Annotation public class Annotated {}"
);
env.addClass(root, "test341298", "Annotation",
"package test341298;\n" +
"public @interface Annotation {}"
);
AptConfig.addProcessorOption(project, "classpath", "%classpath%");
AptConfig.addProcessorOption(project, "sourcepath", "%sourcepath%");
AptConfig.addProcessorOption(project, "phase", "%test341298%");
AptConfig.setEnabled(project, true);
fullBuild();
assertTrue("Processor should be able to compile with passed options", Bug341298Processor.success());
}
public void testBug539663() throws Throwable {
if (!canRunJava9()) {
return;
}
ProcessorTestStatus.reset();
IJavaProject jproj = createJava9Project(_projectName);
disableJava5Factories(jproj);
IProject proj = jproj.getProject();
IPath projPath = proj.getFullPath();
IPath root = projPath.append("src");
IPath packagePath = root.append("test");
try {
env.addClass(root, null, "module-info", "module example {requires annotations;}");
env.addClass(root, "test", "Foo",
"package test;\n" +
"import org.eclipse.jdt.apt.pluggable.tests.annotations.GenClass6;\n" +
"@GenClass6(name = \"ImmutableFoo\", pkg = \"test\")\n" +
"public class Foo {\n" +
" public void f(ImmutableFoo o) { }\n" +
"}");
AptConfig.setEnabled(jproj, true);
fullBuild();
expectingNoProblems();
} finally {
env.removeClass(packagePath, "module-info");
env.removeClass(packagePath, "Foo");
env.removeClass(packagePath, "ImmutableFoo");
}
}
}