/*
* Copyright 2011 Google Inc. All Rights Reserved.
*
* 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.errorprone;
import static com.google.common.truth.Truth.assertThat;
import static com.google.errorprone.BugPattern.Category.ONE_OFF;
import static com.google.errorprone.BugPattern.SeverityLevel.ERROR;
import static com.google.errorprone.DiagnosticTestHelper.diagnosticMessage;
import static java.nio.charset.StandardCharsets.UTF_8;
import static org.hamcrest.CoreMatchers.is;
import static org.hamcrest.Matchers.containsString;
import static org.hamcrest.Matchers.hasItem;
import static org.hamcrest.Matchers.not;
import static org.junit.Assert.assertThat;
import static org.junit.Assert.assertTrue;
import com.google.common.base.Joiner;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.Iterables;
import com.google.common.io.ByteStreams;
import com.google.errorprone.bugpatterns.BadShiftAmount;
import com.google.errorprone.bugpatterns.BugChecker;
import com.google.errorprone.bugpatterns.BugChecker.ExpressionStatementTreeMatcher;
import com.google.errorprone.bugpatterns.BugChecker.MethodInvocationTreeMatcher;
import com.google.errorprone.bugpatterns.BugChecker.MethodTreeMatcher;
import com.google.errorprone.bugpatterns.BugChecker.ReturnTreeMatcher;
import com.google.errorprone.bugpatterns.NonAtomicVolatileUpdate;
import com.google.errorprone.matchers.Description;
import com.google.errorprone.scanner.BuiltInCheckerSuppliers;
import com.google.errorprone.scanner.ScannerSupplier;
import com.sun.source.tree.ExpressionStatementTree;
import com.sun.source.tree.IdentifierTree;
import com.sun.source.tree.MemberSelectTree;
import com.sun.source.tree.MethodInvocationTree;
import com.sun.source.tree.MethodTree;
import com.sun.source.tree.ReturnTree;
import com.sun.source.tree.Tree;
import com.sun.tools.javac.main.Main.Result;
import java.io.File;
import java.io.IOException;
import java.io.PrintWriter;
import java.io.StringWriter;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import java.util.Locale;
import java.util.jar.JarEntry;
import java.util.jar.JarOutputStream;
import javax.lang.model.element.Name;
import javax.tools.Diagnostic;
import javax.tools.JavaFileObject;
import org.hamcrest.CoreMatchers;
import org.hamcrest.Matcher;
import org.junit.Before;
import org.junit.Ignore;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.TemporaryFolder;
import org.junit.runner.RunWith;
import org.junit.runners.JUnit4;
/**
* Integration tests for {@link ErrorProneCompiler}.
*
* @author alexeagle@google.com (Alex Eagle)
*/
@RunWith(JUnit4.class)
public class ErrorProneCompilerIntegrationTest {
private DiagnosticTestHelper diagnosticHelper;
private StringWriter outputStream;
private ErrorProneTestCompiler.Builder compilerBuilder;
ErrorProneTestCompiler compiler;
@Rule public final TemporaryFolder tmpFolder = new TemporaryFolder();
@Before
public void setUp() {
diagnosticHelper = new DiagnosticTestHelper();
outputStream = new StringWriter();
compilerBuilder =
new ErrorProneTestCompiler.Builder()
.report(BuiltInCheckerSuppliers.defaultChecks())
.redirectOutputTo(new PrintWriter(outputStream, true))
.listenToDiagnostics(diagnosticHelper.collector);
compiler = compilerBuilder.build();
}
@Test
public void fileWithError() throws Exception {
Result exitCode =
compiler.compile(
compiler
.fileManager()
.forResources(BadShiftAmount.class, "testdata/BadShiftAmountPositiveCases.java"));
assertThat(outputStream.toString(), exitCode, is(Result.ERROR));
Matcher<? super Iterable<Diagnostic<? extends JavaFileObject>>> matcher = hasItem(
diagnosticMessage(containsString("[BadShiftAmount]")));
assertTrue("Error should be found. " + diagnosticHelper.describe(),
matcher.matches(diagnosticHelper.getDiagnostics()));
}
@Test
public void fileWithWarning() throws Exception {
compilerBuilder.report(ScannerSupplier.fromBugCheckerClasses(NonAtomicVolatileUpdate.class));
compiler = compilerBuilder.build();
Result exitCode =
compiler.compile(
compiler
.fileManager()
.forResources(
NonAtomicVolatileUpdate.class,
"testdata/NonAtomicVolatileUpdatePositiveCases.java"));
assertThat(outputStream.toString(), exitCode, is(Result.OK));
Matcher<? super Iterable<Diagnostic<? extends JavaFileObject>>> matcher = hasItem(
diagnosticMessage(containsString("[NonAtomicVolatileUpdate]")));
assertTrue("Warning should be found. " + diagnosticHelper.describe(),
matcher.matches(diagnosticHelper.getDiagnostics()));
}
@Test
public void fileWithMultipleTopLevelClasses() throws Exception {
Result exitCode =
compiler.compile(
compiler
.fileManager()
.forResources(getClass(), "testdata/MultipleTopLevelClassesWithNoErrors.java"));
assertThat(outputStream.toString(), exitCode, is(Result.OK));
}
@Test
public void fileWithMultipleTopLevelClassesExtends() throws Exception {
Result exitCode =
compiler.compile(
compiler
.fileManager()
.forResources(
getClass(),
"testdata/MultipleTopLevelClassesWithNoErrors.java",
"testdata/ExtendedMultipleTopLevelClassesWithNoErrors.java"));
assertThat(outputStream.toString(), exitCode, is(Result.OK));
}
/**
* Regression test for a bug in which multiple top-level classes may cause
* NullPointerExceptions in the matchers.
*/
@Test
public void fileWithMultipleTopLevelClassesExtendsWithError() throws Exception {
Result exitCode =
compiler.compile(
compiler
.fileManager()
.forResources(
getClass(),
"testdata/MultipleTopLevelClassesWithErrors.java",
"testdata/ExtendedMultipleTopLevelClassesWithErrors.java"));
assertThat(outputStream.toString(), exitCode, is(Result.ERROR));
Matcher<? super Iterable<Diagnostic<? extends JavaFileObject>>> matcher = hasItem(
diagnosticMessage(containsString("[SelfAssignment]")));
assertTrue("Warning should be found. " + diagnosticHelper.describe(),
matcher.matches(diagnosticHelper.getDiagnostics()));
assertThat(diagnosticHelper.getDiagnostics()).hasSize(4);
}
@BugPattern(name = "", explanation = "", summary = "", severity = ERROR, category = ONE_OFF)
public static class Throwing extends BugChecker implements ExpressionStatementTreeMatcher {
@Override
public Description matchExpressionStatement(ExpressionStatementTree tree, VisitorState state) {
throw new IllegalStateException("test123");
}
}
@Test
public void unhandledExceptionsAreReportedWithoutBugParadeLink() throws Exception {
compilerBuilder.report(ScannerSupplier.fromBugCheckerClasses(Throwing.class));
compiler = compilerBuilder.build();
Result exitCode =
compiler.compile(
compiler
.fileManager()
.forResources(
getClass(),
"testdata/MultipleTopLevelClassesWithErrors.java",
"testdata/ExtendedMultipleTopLevelClassesWithErrors.java"));
assertThat(outputStream.toString(), exitCode, is(Result.ERROR));
Matcher<? super Iterable<Diagnostic<? extends JavaFileObject>>> matcher = hasItem(
diagnosticMessage(CoreMatchers.<String>allOf(
containsString("IllegalStateException: test123"),
containsString("unhandled exception was thrown by the Error Prone"))));
assertTrue("Error should be reported. " + diagnosticHelper.describe(),
matcher.matches(diagnosticHelper.getDiagnostics()));
}
/**
* Regression test for Issue 188, error-prone doesn't work with annotation processors.
*/
@Test
public void annotationProcessingWorks() throws Exception {
Result exitCode =
compiler.compile(
compiler
.fileManager()
.forResources(getClass(), "testdata/UsesAnnotationProcessor.java"),
Arrays.asList(new NullAnnotationProcessor()));
assertThat(outputStream.toString(), exitCode, is(Result.OK));
}
/**
* Test that if javac does dataflow on a class twice error-prone only analyses it once.
*/
@Test
public void reportReadyForAnalysisOnce() throws Exception {
Result exitCode =
compiler.compile(
compiler
.fileManager()
.forResources(
getClass(),
"testdata/FlowConstants.java",
"testdata/FlowSub.java",
// This order is important: the superclass needs to occur after the subclass in
// the sources so it goes through flow twice (once so it can be used when the
// subclass is desugared, once normally).
"testdata/FlowSuper.java"));
assertThat(outputStream.toString(), exitCode, is(Result.OK));
}
@BugPattern(
name = "ConstructorMatcher",
explanation = "",
category = ONE_OFF,
severity = ERROR,
summary = ""
)
public static class ConstructorMatcher extends BugChecker implements MethodTreeMatcher {
@Override
public Description matchMethod(MethodTree tree, VisitorState state) {
return describeMatch(tree);
}
}
@Test
public void ignoreGeneratedConstructors() throws Exception {
compilerBuilder.report(ScannerSupplier.fromBugCheckerClasses(ConstructorMatcher.class));
compiler = compilerBuilder.build();
Result exitCode = compiler.compile(
Arrays.asList(compiler.fileManager().forSourceLines("Test.java", "public class Test {}")));
Matcher<? super Iterable<Diagnostic<? extends JavaFileObject>>> matcher = not(hasItem(
diagnosticMessage(containsString("[ConstructorMatcher]"))));
assertTrue(
"Warning should be found. " + diagnosticHelper.describe(),
matcher.matches(diagnosticHelper.getDiagnostics()));
assertThat(outputStream.toString(), exitCode, is(Result.OK));
}
@BugPattern(
name = "SuperCallMatcher",
explanation = "",
category = ONE_OFF,
severity = ERROR,
summary = ""
)
static class SuperCallMatcher extends BugChecker implements MethodInvocationTreeMatcher {
@Override
public Description matchMethodInvocation(MethodInvocationTree tree, VisitorState state) {
Tree select = tree.getMethodSelect();
Name name;
if (select instanceof MemberSelectTree) {
name = ((MemberSelectTree) select).getIdentifier();
} else if (select instanceof IdentifierTree) {
name = ((IdentifierTree) select).getName();
} else {
return Description.NO_MATCH;
}
return name.contentEquals("super")
? describeMatch(tree)
: Description.NO_MATCH;
}
}
// TODO(cushon) - how can we distinguish between synthetic super() calls and real ones?
@Ignore
@Test
public void ignoreGeneratedSuperInvocations() throws Exception {
compilerBuilder.report(ScannerSupplier.fromBugCheckerClasses(SuperCallMatcher.class));
compiler = compilerBuilder.build();
Result exitCode = compiler.compile(Arrays.asList(
compiler.fileManager().forSourceLines("Test.java",
"public class Test {",
" public Test() {}",
"}")));
Matcher<? super Iterable<Diagnostic<? extends JavaFileObject>>> matcher = not(hasItem(
diagnosticMessage(containsString("[SuperCallMatcher]"))));
assertTrue(
"Warning should be found. " + diagnosticHelper.describe(),
matcher.matches(diagnosticHelper.getDiagnostics()));
assertThat(outputStream.toString(), exitCode, is(Result.OK));
}
@Test
public void invalidFlagCausesCmdErrResult() throws Exception {
String[] args = {"-Xep:"};
Result exitCode = compiler.compile(args,
Arrays.asList(compiler.fileManager().forSourceLines("Test.java",
"public class Test {",
" public Test() {}",
"}")));
outputStream.flush();
assertThat(outputStream.toString(), exitCode, is(Result.CMDERR));
}
@Test
public void flagEnablesCheck() throws Exception {
String[] testFile = {"public class Test {",
" public Test() {",
" if (true);",
" }",
"}"};
Result exitCode = compiler.compile(Arrays.asList(
compiler.fileManager().forSourceLines("Test.java", testFile)));
outputStream.flush();
assertThat(diagnosticHelper.getDiagnostics()).isEmpty();
assertThat(outputStream.toString(), exitCode, is(Result.OK));
String[] args = {"-Xep:EmptyIf"};
exitCode = compiler.compile(args,
Arrays.asList(compiler.fileManager().forSourceLines("Test.java", testFile)));
outputStream.flush();
Matcher<? super Iterable<Diagnostic<? extends JavaFileObject>>> matcher = hasItem(
diagnosticMessage(containsString("[EmptyIf]")));
assertTrue(
"Error should be found. " + diagnosticHelper.describe(),
matcher.matches(diagnosticHelper.getDiagnostics()));
assertThat(outputStream.toString(), exitCode, is(Result.ERROR));
}
@Test
public void severityIsResetOnNextCompilation() throws Exception {
String[] testFile = {
"public class Test {",
" void doIt (int i) {",
" i = i;",
" }",
"}"};
String[] args = {"-Xep:SelfAssignment:WARN"};
Result exitCode = compiler.compile(args,
Arrays.asList(compiler.fileManager().forSourceLines("Test.java", testFile)));
outputStream.flush();
Matcher<? super Iterable<Diagnostic<? extends JavaFileObject>>> matcher =
hasItem(diagnosticMessage(containsString("[SelfAssignment]")));
assertThat(outputStream.toString(), exitCode, is(Result.OK));
assertTrue(
"Warning should be found. " + diagnosticHelper.describe(),
matcher.matches(diagnosticHelper.getDiagnostics()));
// Should reset to default severity (ERROR)
exitCode = compiler.compile(
Arrays.asList(compiler.fileManager().forSourceLines("Test.java", testFile)));
outputStream.flush();
assertThat(outputStream.toString(), exitCode, is(Result.ERROR));
}
@Test
public void maturityIsResetOnNextCompilation() throws Exception {
String[] testFile = {"public class Test {",
" public Test() {",
" if (true);",
" }",
"}"};
String[] args = {"-Xep:EmptyIf"};
Result exitCode = compiler.compile(args,
Arrays.asList(compiler.fileManager().forSourceLines("Test.java", testFile)));
outputStream.flush();
Matcher<? super Iterable<Diagnostic<? extends JavaFileObject>>> matcher = hasItem(
diagnosticMessage(containsString("[EmptyIf]")));
assertThat(outputStream.toString(), exitCode, is(Result.ERROR));
assertTrue(
"Error should be found. " + diagnosticHelper.describe(),
matcher.matches(diagnosticHelper.getDiagnostics()));
diagnosticHelper.clearDiagnostics();
exitCode = compiler.compile(
Arrays.asList(compiler.fileManager().forSourceLines("Test.java", testFile)));
outputStream.flush();
assertThat(outputStream.toString(), exitCode, is(Result.OK));
assertThat(diagnosticHelper.getDiagnostics()).isEmpty();
}
@Test
public void suppressGeneratedWarning() throws Exception {
String[] generatedFile = {
"@javax.annotation.Generated(\"Foo\")",
"class Generated {",
" public Generated() {",
" if (true);",
" }",
"}"
};
{
String[] args = {"-Xep:EmptyIf:WARN"};
Result exitCode =
compiler.compile(
args,
Arrays.asList(
compiler.fileManager().forSourceLines("Generated.java", generatedFile)));
outputStream.flush();
assertThat(diagnosticHelper.getDiagnostics()).hasSize(1);
assertThat(diagnosticHelper.getDiagnostics().get(0).getMessage(Locale.ENGLISH))
.contains("[EmptyIf]");
assertThat(outputStream.toString(), exitCode, is(Result.OK));
}
diagnosticHelper.clearDiagnostics();
{
String[] args = {"-Xep:EmptyIf:WARN", "-XepDisableWarningsInGeneratedCode"};
Result exitCode =
compiler.compile(
args,
Arrays.asList(
compiler.fileManager().forSourceLines("Generated.java", generatedFile)));
outputStream.flush();
assertThat(diagnosticHelper.getDiagnostics()).hasSize(0);
assertThat(outputStream.toString(), exitCode, is(Result.OK));
}
}
@Test
public void cannotSuppressGeneratedError() throws Exception {
String[] generatedFile = {
"@javax.annotation.Generated(\"Foo\")",
"class Generated {",
" public Generated() {",
" if (true);",
" }",
"}"
};
String[] args = {"-Xep:EmptyIf:ERROR", "-XepDisableWarningsInGeneratedCode"};
Result exitCode =
compiler.compile(
args,
Arrays.asList(compiler.fileManager().forSourceLines("Generated.java", generatedFile)));
outputStream.flush();
assertThat(diagnosticHelper.getDiagnostics()).hasSize(1);
assertThat(diagnosticHelper.getDiagnostics().get(0).getMessage(Locale.ENGLISH))
.contains("[EmptyIf]");
assertThat(outputStream.toString(), exitCode, is(Result.ERROR));
}
@BugPattern(
name = "CrashOnReturn",
explanation = "",
summary = "",
severity = ERROR,
category = ONE_OFF
)
public static class CrashOnReturn extends BugChecker implements ReturnTreeMatcher {
@Override
public Description matchReturn(ReturnTree tree, VisitorState state) {
throw new NullPointerException();
}
}
@Test
public void crashSourcePosition() throws Exception {
compiler =
compilerBuilder.report(ScannerSupplier.fromBugCheckerClasses(CrashOnReturn.class)).build();
Result exitCode =
compiler.compile(
Arrays.asList(
compiler
.fileManager()
.forSourceLines(
"test/Test.java",
"package Test;",
"class Test {",
" void f() {",
" return;",
" }",
"}")));
assertThat(exitCode).named(outputStream.toString()).isEqualTo(Result.ERROR);
assertThat(diagnosticHelper.getDiagnostics()).hasSize(1);
Diagnostic<? extends JavaFileObject> diag =
Iterables.getOnlyElement(diagnosticHelper.getDiagnostics());
assertThat(diag.getLineNumber()).isEqualTo(4);
assertThat(diag.getColumnNumber()).isEqualTo(5);
assertThat(diag.getSource().toUri().toString()).endsWith("test/Test.java");
assertThat(diag.getMessage(Locale.ENGLISH))
.contains("An unhandled exception was thrown by the Error Prone static analysis plugin");
}
@Test
public void compilePolicy_bytodo() throws Exception {
Result exitCode =
compiler.compile(
new String[] {"-XDcompilePolicy=bytodo"}, Collections.<JavaFileObject>emptyList());
outputStream.flush();
assertThat(exitCode).named(outputStream.toString()).isEqualTo(Result.CMDERR);
assertThat(outputStream.toString()).contains("-XDcompilePolicy=bytodo is not supported");
}
@Test
public void compilePolicy_byfile() throws Exception {
Result exitCode =
compiler.compile(
new String[] {"-XDcompilePolicy=byfile"},
Arrays.asList(compiler.fileManager().forSourceLines("Test.java", "class Test {}")));
outputStream.flush();
assertThat(exitCode).named(outputStream.toString()).isEqualTo(Result.OK);
}
@Test
public void compilePolicy_simple() throws Exception {
Result exitCode =
compiler.compile(
new String[] {"-XDcompilePolicy=simple"},
Arrays.asList(compiler.fileManager().forSourceLines("Test.java", "class Test {}")));
outputStream.flush();
assertThat(exitCode).named(outputStream.toString()).isEqualTo(Result.OK);
}
@BugPattern(
name = "CPSChecker",
summary = "Using 'return' is considered harmful",
explanation = "Please refactor your code into continuation passing style.",
category = ONE_OFF,
severity = ERROR
)
public static class CPSChecker extends BugChecker implements ReturnTreeMatcher {
@Override
public Description matchReturn(ReturnTree tree, VisitorState state) {
return describeMatch(tree);
}
}
@Test
public void compilationWithError() throws Exception {
compilerBuilder.report(ScannerSupplier.fromBugCheckerClasses(CPSChecker.class));
compiler = compilerBuilder.build();
compiler.compile(
new String[] {
"-XDshouldStopPolicyIfError=LOWER",
},
Arrays.asList(
compiler
.fileManager()
.forSourceLines(
"Test.java",
"package test;",
"public class Test {",
" Object f() { return new NoSuch(); }",
"}")));
outputStream.flush();
String output = diagnosticHelper.getDiagnostics().toString();
assertThat(output).contains("error: cannot find symbol");
assertThat(output).doesNotContain("Using 'return' is considered harmful");
}
@Test
public void plugin() throws Exception {
Path base = tmpFolder.newFolder().toPath();
Path source = base.resolve("test/Test.java");
Files.createDirectories(source.getParent());
Files.write(
source,
Arrays.asList(
"package test;", //
"public class Test {",
" int f() { return 42; }",
"}"),
UTF_8);
Path jar = base.resolve("libproc.jar");
try (JarOutputStream jos = new JarOutputStream(Files.newOutputStream(jar))) {
jos.putNextEntry(new JarEntry("META-INF/services/" + BugChecker.class.getName()));
jos.write((CPSChecker.class.getName() + "\n").getBytes(UTF_8));
String classFile = CPSChecker.class.getName().replace('.', '/') + ".class";
jos.putNextEntry(new JarEntry(classFile));
ByteStreams.copy(getClass().getClassLoader().getResourceAsStream(classFile), jos);
}
// no plugins
{
List<String> args =
ImmutableList.of(
source.toAbsolutePath().toString(), "-processorpath", File.pathSeparator);
StringWriter out = new StringWriter();
Result result =
ErrorProneCompiler.compile(args.toArray(new String[0]), new PrintWriter(out, true));
assertThat(result).isEqualTo(Result.OK);
}
// with plugins
{
List<String> args =
ImmutableList.of(
source.toAbsolutePath().toString(),
"-processorpath",
jar.toAbsolutePath().toString());
StringWriter out = new StringWriter();
Result result =
ErrorProneCompiler.compile(args.toArray(new String[0]), new PrintWriter(out, true));
assertThat(out.toString()).contains("Using 'return' is considered harmful");
assertThat(result).isEqualTo(Result.ERROR);
}
}
@Test
public void pluginWithFlag() throws Exception {
Path base = tmpFolder.newFolder().toPath();
Path source = base.resolve("test/Test.java");
Files.createDirectories(source.getParent());
Files.write(
source,
Arrays.asList(
"package test;", //
"public class Test {",
" int f() { return 42; }",
"}"),
UTF_8);
Path jar = base.resolve("libproc.jar");
try (JarOutputStream jos = new JarOutputStream(Files.newOutputStream(jar))) {
jos.putNextEntry(new JarEntry("META-INF/services/" + BugChecker.class.getName()));
jos.write((CPSChecker.class.getName() + "\n").getBytes(UTF_8));
String classFile = CPSChecker.class.getName().replace('.', '/') + ".class";
jos.putNextEntry(new JarEntry(classFile));
ByteStreams.copy(getClass().getClassLoader().getResourceAsStream(classFile), jos);
}
// Plugin jar is on classpath, disabled.
{
List<String> args =
ImmutableList.of(
source.toAbsolutePath().toString(),
"-processorpath",
jar.toAbsolutePath().toString(),
"-XepDisableAllChecks");
StringWriter out = new StringWriter();
Result result =
ErrorProneCompiler.compile(args.toArray(new String[0]), new PrintWriter(out, true));
assertThat(result).isEqualTo(Result.OK);
}
// Plugin is disabled by -XepDisableAllChecks and re-enabled with -Xep:CPSChecker:ERROR
{
List<String> args =
ImmutableList.of(
source.toAbsolutePath().toString(),
"-processorpath",
jar.toAbsolutePath().toString(),
"-XepDisableAllChecks",
"-Xep:CPSChecker:ERROR");
StringWriter out = new StringWriter();
Result result =
ErrorProneCompiler.compile(args.toArray(new String[0]), new PrintWriter(out, true));
assertThat(out.toString()).contains("Using 'return' is considered harmful");
assertThat(result).isEqualTo(Result.ERROR);
}
}
@Test
public void paramsFiles() throws IOException {
Path dir = tmpFolder.newFolder("tmp").toPath();
Path source = dir.resolve("Test.java");
Files.write(
source,
Joiner.on('\n')
.join(
ImmutableList.of(
"class Test {", //
" boolean f(Integer i, String s) {",
" return i.equals(s);",
" }",
"}"))
.getBytes(UTF_8));
Path params = dir.resolve("params.txt");
Files.write(
params,
Joiner.on(' ')
.join(
ImmutableList.of(
"-Xep:EqualsIncompatibleType:ERROR",
source.toAbsolutePath().toAbsolutePath().toString()))
.getBytes(UTF_8));
StringWriter output = new StringWriter();
Result result =
ErrorProneCompiler.builder()
.redirectOutputTo(new PrintWriter(output, true))
.build()
.run(new String[] {"@" + params.toAbsolutePath().toString()});
assertThat(result).isEqualTo(Result.ERROR);
assertThat(output.toString()).contains("[EqualsIncompatibleType]");
}
}