Skip to content

Commit

Permalink
Support alternate JavaCompilers (such as ECJ) in JavaSourcesSubject
Browse files Browse the repository at this point in the history
  • Loading branch information
doanduyhai authored and tbroyer committed Mar 13, 2016
1 parent 88dfce7 commit 35ae925
Show file tree
Hide file tree
Showing 6 changed files with 82 additions and 58 deletions.
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 @@ -55,9 +55,8 @@ private Compilation() {}
*
* @throws RuntimeException if compilation fails.
*/
static Result compile(Iterable<? extends Processor> processors,
static Result compile(JavaCompiler compiler, Iterable<? extends Processor> processors,
Set<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 @@ -71,7 +70,7 @@ static Result compile(Iterable<? extends Processor> processors,
fileManager,
diagnosticCollector,
ImmutableSet.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 @@ -83,8 +82,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 @@ -94,7 +92,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
53 changes: 27 additions & 26 deletions src/main/java/com/google/testing/compile/CompilationRule.java
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
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 Down Expand Up @@ -89,36 +90,36 @@ public Statement apply(final Statement base, Description description) {
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 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);
}
}
return false;
@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;
}
}));
boolean successful = task.call();
checkState(successful);
Expand Down
32 changes: 20 additions & 12 deletions src/main/java/com/google/testing/compile/JavaSourcesSubject.java
Original file line number Diff line number Diff line change
Expand Up @@ -43,11 +43,8 @@
import java.util.Set;

import javax.annotation.processing.Processor;
import javax.tools.Diagnostic;
import javax.tools.*;
import javax.tools.Diagnostic.Kind;
import javax.tools.FileObject;
import javax.tools.JavaFileManager;
import javax.tools.JavaFileObject;

/**
* A <a href="https://github.com/truth0/truth">Truth</a> {@link Subject} that evaluates the result
Expand All @@ -58,13 +55,20 @@
@SuppressWarnings("restriction") // Sun APIs usage intended
public final class JavaSourcesSubject
extends Subject<JavaSourcesSubject, Iterable<? extends JavaFileObject>>
implements CompileTester, ProcessedCompileTesterFactory {
implements ProcessedCompileTesterFactory {
private final Set<String> options = Sets.newHashSet();
private JavaCompiler compiler = ToolProvider.getSystemJavaCompiler();

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


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

@Override
public ProcessedCompileTesterFactory withCompilerOptions(Iterable<String> options) {
Iterables.addAll(this.options, options);
Expand Down Expand Up @@ -154,7 +158,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 @@ -165,7 +169,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 @@ -279,7 +283,7 @@ private void failWithCandidate(JavaFileObject expectedSource,
@Override
public SuccessfulCompilationClause compilesWithoutError() {
Compilation.Result result =
Compilation.compile(processors, ImmutableSet.copyOf(options), getSubject());
Compilation.compile(compiler, processors, ImmutableSet.copyOf(options), getSubject());
if (!result.successful()) {
ImmutableList<Diagnostic<? extends JavaFileObject>> errors =
result.diagnosticsByKind().get(Kind.ERROR);
Expand All @@ -297,7 +301,7 @@ public SuccessfulCompilationClause compilesWithoutError() {

@Override
public UnsuccessfulCompilationClause failsToCompile() {
Result result = Compilation.compile(processors, ImmutableSet.copyOf(options), getSubject());
Result result = Compilation.compile(compiler, processors, ImmutableSet.copyOf(options), getSubject());
if (result.successful()) {
String message = Joiner.on('\n').join(
"Compilation was expected to fail, but contained no errors.",
Expand Down Expand Up @@ -553,15 +557,19 @@ public SuccessfulFileClause withContents(ByteSource expectedByteSource) {

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 ProcessedCompileTesterFactory withCompiler(JavaCompiler javaCompiler) {
return this.delegate.withCompiler(javaCompiler);
}

@Override
public ProcessedCompileTesterFactory withCompilerOptions(Iterable<String> options) {
return delegate.withCompilerOptions(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. */
@CheckReturnValue ProcessedCompileTesterFactory withCompilerOptions(Iterable<String> options);
Expand Down
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 @@ -81,6 +82,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 compilesWithoutError_failureReportsFiles() {
try {
Expand Down Expand Up @@ -116,16 +126,16 @@ public void compilesWithoutError_exceptionCreatedOrPassedThrough() {
VERIFY.about(javaSource())
.that(JavaFileObjects.forResource("HelloWorld.java"))
.processedWith(new AbstractProcessor() {
@Override
public Set<String> getSupportedAnnotationTypes() {
return ImmutableSet.of("*");
}

@Override
public boolean process(Set<? extends TypeElement> annotations,
RoundEnvironment roundEnv) {
throw e;
}
@Override
public Set<String> getSupportedAnnotationTypes() {
return ImmutableSet.of("*");
}

@Override
public boolean process(Set<? extends TypeElement> annotations,
RoundEnvironment roundEnv) {
throw e;
}
})
.compilesWithoutError();
fail();
Expand Down

0 comments on commit 35ae925

Please sign in to comment.