Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Support alternate JavaCompilers (such as ECJ) in CompilationRule #71

Open
wants to merge 2 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,12 @@
<version>${jsr305.version}</version>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.eclipse.jdt.core.compiler</groupId>
<artifactId>ecj</artifactId>
<version>4.4.2</version>
<scope>test</scope>
</dependency>
</dependencies>
<build>
<plugins>
Expand Down
10 changes: 4 additions & 6 deletions src/main/java/com/google/testing/compile/Compilation.java
Original file line number Diff line number Diff line change
Expand Up @@ -54,9 +54,8 @@ private Compilation() {}
*
* @throws RuntimeException if compilation fails.
*/
static Result compile(Iterable<? extends Processor> processors,
static Result compile(JavaCompiler compiler, Iterable<? extends Processor> processors,
Iterable<String> options, Iterable<? extends JavaFileObject> sources) {
JavaCompiler compiler = ToolProvider.getSystemJavaCompiler();
if (compiler == null) {
throw new IllegalStateException("Java Compiler is not present. "
+ "May be, you need to include tools.jar on your dependency list.");
Expand All @@ -70,7 +69,7 @@ static Result compile(Iterable<? extends Processor> processors,
fileManager,
diagnosticCollector,
ImmutableList.copyOf(options),
ImmutableSet.<String>of(),
null, // explicitly use the default behaviour because Eclipse compiler fails with empty Set
sources);
task.setProcessors(processors);
boolean successful = task.call();
Expand All @@ -82,8 +81,7 @@ static Result compile(Iterable<? extends Processor> processors,
* Parse {@code sources} into {@linkplain CompilationUnitTree compilation units}. This method
* <b>does not</b> compile the sources.
*/
static ParseResult parse(Iterable<? extends JavaFileObject> sources) {
JavaCompiler compiler = ToolProvider.getSystemJavaCompiler();
static ParseResult parse(JavaCompiler compiler, Iterable<? extends JavaFileObject> sources) {
DiagnosticCollector<JavaFileObject> diagnosticCollector =
new DiagnosticCollector<JavaFileObject>();
InMemoryJavaFileManager fileManager = new InMemoryJavaFileManager(
Expand All @@ -93,7 +91,7 @@ static ParseResult parse(Iterable<? extends JavaFileObject> sources) {
fileManager,
diagnosticCollector,
ImmutableSet.<String>of(),
ImmutableSet.<String>of(),
null, // explicitly use the default behaviour because Eclipse compiler fails with empty Set
sources);
try {
Iterable<? extends CompilationUnitTree> parsedCompilationUnits = task.parse();
Expand Down
96 changes: 62 additions & 34 deletions src/main/java/com/google/testing/compile/CompilationRule.java
Original file line number Diff line number Diff line change
Expand Up @@ -17,9 +17,10 @@

import static com.google.common.base.Preconditions.checkState;

import com.google.common.base.Charsets;
import com.google.common.base.Supplier;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableSet;
import com.google.testing.compile.Compilation.Result;

import org.junit.Rule;
import org.junit.rules.TestRule;
Expand All @@ -37,61 +38,88 @@
import javax.lang.model.element.TypeElement;
import javax.lang.model.util.Elements;
import javax.lang.model.util.Types;
import javax.tools.DiagnosticCollector;
import javax.tools.JavaCompiler;
import javax.tools.JavaCompiler.CompilationTask;
import javax.tools.JavaFileManager;
import javax.tools.JavaFileObject;
import javax.tools.ToolProvider;

/**
* A {@link JUnit4} {@link Rule} that executes tests such that a instances of {@link Elements} and
* A {@link JUnit4} {@link Rule} that executes tests such that instances of {@link Elements} and
* {@link Types} are available during execution.
*
* <p>To use this rule in a test, just add the following field: <pre><code>
* {@code @Rule} public CompilationRule compilationRule = new CompilationRule();</code></pre>
*
* <p>This rule uses {@link ToolProvider#getSystemJavaCompiler() javac} by default, but you can
* also pass a supplier of {@link JavaCompiler} to use other compilers, such as Eclipse ECJ.
*
* @author Gregory Kick
*/
public final class CompilationRule implements TestRule {
private final Supplier<JavaCompiler> compilerSupplier;

private Elements elements;
private Types types;

public CompilationRule() {
this(new Supplier<JavaCompiler>() {
@Override
public JavaCompiler get() {
return ToolProvider.getSystemJavaCompiler();
}
});
}

public CompilationRule(Supplier<JavaCompiler> compilerSupplier) {
this.compilerSupplier = compilerSupplier;
}

@Override
public Statement apply(final Statement base, Description description) {
return new Statement() {
@Override public void evaluate() throws Throwable {
final AtomicReference<Throwable> thrown = new AtomicReference<Throwable>();
Result result = Compilation.compile(ImmutableList.of(new AbstractProcessor() {
@Override
public SourceVersion getSupportedSourceVersion() {
return SourceVersion.latest();
}
JavaCompiler compiler = compilerSupplier.get();
DiagnosticCollector<JavaFileObject> diagnosticCollector = new DiagnosticCollector<JavaFileObject>();
JavaFileManager fileManager = compiler.getStandardFileManager(diagnosticCollector, null, Charsets.UTF_8);
CompilationTask task = compiler.getTask(null, fileManager, diagnosticCollector, null,
ImmutableSet.of(CompilationRule.class.getCanonicalName()), null);
task.setProcessors(ImmutableList.of(new AbstractProcessor() {
@Override
public SourceVersion getSupportedSourceVersion() {
return SourceVersion.latest();
}

@Override
public Set<String> getSupportedAnnotationTypes() {
return ImmutableSet.of("*");
}
@Override
public Set<String> getSupportedAnnotationTypes() {
return ImmutableSet.of("*");
}

@Override
public synchronized void init(ProcessingEnvironment processingEnv) {
super.init(processingEnv);
elements = processingEnv.getElementUtils();
types = processingEnv.getTypeUtils();
}
@Override
public synchronized void init(ProcessingEnvironment processingEnv) {
super.init(processingEnv);
elements = processingEnv.getElementUtils();
types = processingEnv.getTypeUtils();
}

@Override
public boolean process(Set<? extends TypeElement> annotations,
RoundEnvironment roundEnv) {
// just run the test on the last round after compilation is over
if (roundEnv.processingOver()) {
try {
base.evaluate();
} catch (Throwable e) {
thrown.set(e);
@Override
public boolean process(Set<? extends TypeElement> annotations,
RoundEnvironment roundEnv) {
// just run the test on the last round after compilation is over
if (roundEnv.processingOver()) {
try {
base.evaluate();
} catch (Throwable e) {
thrown.set(e);
}
}
return false;
}
}
return false;
}
}),
ImmutableSet.<String>of(),
// just compile _something_
ImmutableList.of(JavaFileObjects.forSourceLines("Dummy", "final class Dummy {}")));
checkState(result.successful(), result);
}));
boolean successful = task.call();
checkState(successful);
Throwable t = thrown.get();
if (t != null) {
throw t;
Expand Down
25 changes: 19 additions & 6 deletions src/main/java/com/google/testing/compile/JavaSourcesSubject.java
Original file line number Diff line number Diff line change
Expand Up @@ -48,8 +48,10 @@
import javax.tools.Diagnostic;
import javax.tools.Diagnostic.Kind;
import javax.tools.FileObject;
import javax.tools.JavaCompiler;
import javax.tools.JavaFileManager;
import javax.tools.JavaFileObject;
import javax.tools.ToolProvider;

/**
* A <a href="https://github.com/truth0/truth">Truth</a> {@link Subject} that evaluates the result
Expand All @@ -60,12 +62,19 @@
@SuppressWarnings("restriction") // Sun APIs usage intended
public final class JavaSourcesSubject
extends Subject<JavaSourcesSubject, Iterable<? extends JavaFileObject>>
implements CompileTester, ProcessedCompileTesterFactory {
implements ProcessedCompileTesterFactory {
private final List<String> options = new ArrayList<String>(Arrays.asList("-Xlint"));
private JavaCompiler compiler = ToolProvider.getSystemJavaCompiler();

JavaSourcesSubject(FailureStrategy failureStrategy, Iterable<? extends JavaFileObject> subject) {
super(failureStrategy, subject);
}

@Override
public JavaSourcesSubject withCompiler(JavaCompiler javaCompiler) {
this.compiler = javaCompiler;
return this;
}

@Override
public JavaSourcesSubject withCompilerOptions(Iterable<String> options) {
Expand Down Expand Up @@ -161,7 +170,7 @@ private String reportFilesGenerated(Compilation.Result result) {

@Override
public void parsesAs(JavaFileObject first, JavaFileObject... rest) {
Compilation.ParseResult actualResult = Compilation.parse(getSubject());
Compilation.ParseResult actualResult = Compilation.parse(compiler, getSubject());
ImmutableList<Diagnostic<? extends JavaFileObject>> errors =
actualResult.diagnosticsByKind().get(Kind.ERROR);
if (!errors.isEmpty()) {
Expand All @@ -172,7 +181,7 @@ public void parsesAs(JavaFileObject first, JavaFileObject... rest) {
}
failureStrategy.fail(message.toString());
}
final Compilation.ParseResult expectedResult = Compilation.parse(Lists.asList(first, rest));
final Compilation.ParseResult expectedResult = Compilation.parse(compiler, Lists.asList(first, rest));
final FluentIterable<? extends CompilationUnitTree> actualTrees = FluentIterable.from(
actualResult.compilationUnits());
final FluentIterable<? extends CompilationUnitTree> expectedTrees = FluentIterable.from(
Expand Down Expand Up @@ -295,7 +304,7 @@ public CleanCompilationClause compilesWithoutWarnings() {

private Compilation.Result successfulCompilationResult() {
Compilation.Result result =
Compilation.compile(processors, options, getSubject());
Compilation.compile(compiler, processors, options, getSubject());
if (!result.successful()) {
ImmutableList<Diagnostic<? extends JavaFileObject>> errors =
result.diagnosticsByKind().get(Kind.ERROR);
Expand All @@ -313,7 +322,7 @@ private Compilation.Result successfulCompilationResult() {

@Override
public UnsuccessfulCompilationClause failsToCompile() {
Result result = Compilation.compile(processors, options, getSubject());
Result result = Compilation.compile(compiler, processors, options, getSubject());
if (result.successful()) {
String message = Joiner.on('\n').join(
"Compilation was expected to fail, but contained no errors.",
Expand Down Expand Up @@ -748,14 +757,18 @@ public static JavaSourcesSubject assertThat(JavaFileObject... javaFileObjects) {

public static final class SingleSourceAdapter
extends Subject<SingleSourceAdapter, JavaFileObject>
implements CompileTester, ProcessedCompileTesterFactory {
implements ProcessedCompileTesterFactory {
private final JavaSourcesSubject delegate;

SingleSourceAdapter(FailureStrategy failureStrategy, JavaFileObject subject) {
super(failureStrategy, subject);
this.delegate =
new JavaSourcesSubject(failureStrategy, ImmutableList.of(subject));
}

public JavaSourcesSubject withCompiler(JavaCompiler javaCompiler) {
return this.delegate.withCompiler(javaCompiler);
}

@Override
public JavaSourcesSubject withCompilerOptions(Iterable<String> options) {
Expand Down
8 changes: 5 additions & 3 deletions src/main/java/com/google/testing/compile/MoreTrees.java
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@
import java.util.Arrays;

import javax.annotation.Nullable;
import javax.tools.ToolProvider;

/**
* A class containing methods which are useful for gaining access to {@code Tree} instances from
Expand All @@ -52,8 +53,8 @@ static CompilationUnitTree parseLinesToTree(String... source) {

/** Parses the source given into a {@link CompilationUnitTree}. */
static CompilationUnitTree parseLinesToTree(Iterable<String> source) {
Iterable<? extends CompilationUnitTree> parseResults = Compilation.parse(ImmutableList.of(
JavaFileObjects.forSourceLines("", source))).compilationUnits();
Iterable<? extends CompilationUnitTree> parseResults = Compilation.parse(ToolProvider.getSystemJavaCompiler(),
ImmutableList.of(JavaFileObjects.forSourceLines("", source))).compilationUnits();
return Iterables.getOnlyElement(parseResults);
}

Expand All @@ -64,7 +65,8 @@ static Compilation.ParseResult parseLines(String... source) {

/** Parses the source given and produces a {@link Compilation.ParseResult}. */
static Compilation.ParseResult parseLines(Iterable<String> source) {
return Compilation.parse(ImmutableList.of(JavaFileObjects.forSourceLines("", source)));
return Compilation.parse(ToolProvider.getSystemJavaCompiler(),
ImmutableList.of(JavaFileObjects.forSourceLines("", source)));
}

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,14 +17,19 @@

import javax.annotation.CheckReturnValue;
import javax.annotation.processing.Processor;
import javax.tools.JavaCompiler;

/**
* Creates {@link CompileTester} instances that test compilation with provided {@link Processor}
* instances.
*
* @author Gregory Kick
*/
public interface ProcessedCompileTesterFactory {
public interface ProcessedCompileTesterFactory extends CompileTester{

/** Specify compiler (Javac, Eclipse ECJ, ...) **/
@CheckReturnValue
ProcessedCompileTesterFactory withCompiler(JavaCompiler var1);

/**
* Adds options that will be passed to the compiler. {@code -Xlint} is the first option, by
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
package com.google.testing.compile;

import javax.tools.JavaCompiler;

import org.eclipse.jdt.internal.compiler.tool.EclipseCompiler;
import org.junit.runner.RunWith;
import org.junit.runners.JUnit4;

import com.google.common.base.Supplier;

@RunWith(JUnit4.class)
public class EclipseCompilationRuleTest extends CompilationRuleTest {
{
compilationRule = new CompilationRule(new Supplier<JavaCompiler>() {
@Override
public JavaCompiler get() {
return new EclipseCompiler();
}
});
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@
import com.google.common.truth.FailureStrategy;
import com.google.common.truth.TestVerb;

import org.eclipse.jdt.internal.compiler.tool.EclipseCompiler;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.JUnit4;
Expand Down Expand Up @@ -107,6 +108,15 @@ public void compilesWithoutError() {
.compilesWithoutError();
}

@Test
public void compilesWithoutErrorWithEclipseCompiler() {
assertAbout(javaSource())
.that(JavaFileObjects.forResource(Resources.getResource("HelloWorld.java")))
.withCompiler(new EclipseCompiler())
.withCompilerOptions("-nowarn", "-1.6")
.compilesWithoutError();
}

@Test
public void compilesWithoutWarnings() {
assertAbout(javaSource()).that(HELLO_WORLD).compilesWithoutWarnings();
Expand Down