/*
* Copyright 2015 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.JDK;
import static com.google.errorprone.BugPattern.SeverityLevel.SUGGESTION;
import static org.junit.Assert.fail;
import com.google.errorprone.BugCheckerRefactoringTestHelper.TestMode;
import com.google.errorprone.bugpatterns.BugChecker;
import com.google.errorprone.bugpatterns.BugChecker.AnnotationTreeMatcher;
import com.google.errorprone.bugpatterns.BugChecker.CompilationUnitTreeMatcher;
import com.google.errorprone.bugpatterns.BugChecker.ReturnTreeMatcher;
import com.google.errorprone.fixes.SuggestedFix;
import com.google.errorprone.matchers.Description;
import com.google.errorprone.util.ASTHelpers;
import com.sun.source.tree.AnnotationTree;
import com.sun.source.tree.CompilationUnitTree;
import com.sun.source.tree.ReturnTree;
import java.io.IOException;
import java.nio.file.FileAlreadyExistsException;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.JUnit4;
/** Tests for {@link BugCheckerRefactoringTestHelper}. */
@RunWith(JUnit4.class)
public class BugCheckerRefactoringTestHelperTest {
private BugCheckerRefactoringTestHelper helper;
@Before
public void setUp() {
helper = BugCheckerRefactoringTestHelper.newInstance(new ReturnNullRefactoring(), getClass());
}
@Test
public void testNoMatch() throws IOException {
helper
.addInputLines("in/Test.java", "public class Test {}")
.addOutputLines("out/Test.java", "public class Test {}")
.doTest();
}
@Test
public void testReplace() throws IOException {
helper
.addInputLines(
"in/Test.java",
"public class Test {",
" public Object foo() {",
" Integer i = 1 + 2;",
" return i;",
" }",
"}")
.addOutputLines(
"out/Test.java",
"public class Test {",
" public Object foo() {",
" Integer i = 1 + 2;",
" return null;",
" }",
"}")
.doTest();
}
@Test(expected = AssertionError.class)
public void testReplaceFail() throws IOException {
helper
.addInputLines(
"in/Test.java",
"public class Test {",
" public Object foo() {",
" Integer i = 1 + 2;",
" return i;",
" }",
"}")
.addOutputLines(
"out/Test.java",
"public class Test {",
" public Object foo() {",
" Integer i = 1 + 2;",
" return i;",
" }",
"}")
.doTest();
}
@Test
public void testReplaceTextMatch() throws IOException {
helper
.addInputLines(
"in/Test.java",
"public class Test {",
" public Object foo() {",
" Integer i = 1 + 2;",
" return i;",
" }",
"}")
.addOutputLines(
"out/Test.java",
"public class Test {",
" public Object foo() {",
" Integer i = 1 + 2;",
" return null;",
" }",
"}")
.doTest(TestMode.TEXT_MATCH);
}
@Test(expected = AssertionError.class)
public void testReplaceTextMatchFail() throws IOException {
helper
.addInputLines(
"in/Test.java",
"public class Test {",
" public Object foo() {",
" Integer i = 1 + 2;",
" return i;",
" }",
"}")
.addOutputLines(
"out/Test.java",
"public class Test {",
" public Object foo() {",
" Integer i = 1 + 2;",
" return null;",
" }",
"}")
.doTest(TestMode.TEXT_MATCH);
}
@Test
public void compilationErrorFail() throws IOException {
try {
helper
.addInputLines("syntax_error.java", "public clazz Bar { ! this should fail }")
.expectUnchanged()
.doTest();
} catch (AssertionError e) {
assertThat(e.getMessage()).contains("compilation failed unexpectedly");
return;
}
fail("compilation succeeded unexpectedly");
}
@Test
public void testAnnotationFullName() throws IOException {
BugCheckerRefactoringTestHelper.newInstance(new RemoveAnnotationRefactoring(), getClass())
.addInputLines("bar/Foo.java", "package bar;", "public @interface Foo {", "};")
.expectUnchanged()
.addInputLines("foo/Bar.java", "import bar.Foo;", "public @Foo class Bar {", "}")
.addOutputLines("out/foo/Bar.java", "import bar.Foo;", "public class Bar {", "}")
.doTest(TestMode.TEXT_MATCH);
}
/** Mock {@link BugChecker} for testing only. */
@BugPattern(
name = "ReturnNullRefactoring",
summary = "Mock refactoring that replaces all returns with 'return null;' statement.",
explanation = "For test purposes only.",
category = JDK,
severity = SUGGESTION
)
public static class ReturnNullRefactoring extends BugChecker implements ReturnTreeMatcher {
@Override
public Description matchReturn(ReturnTree tree, VisitorState state) {
return describeMatch(tree, SuggestedFix.replace(tree, "return null;"));
}
}
/** Mock {@link BugChecker} for testing only. */
@BugPattern(
name = "RemoveAnnotationRefactoring",
summary = "Mock refactoring that removes all annotations declared in package bar ",
explanation = "For test purposes only.",
category = JDK,
severity = SUGGESTION
)
public static class RemoveAnnotationRefactoring extends BugChecker
implements AnnotationTreeMatcher {
@Override
public Description matchAnnotation(AnnotationTree tree, VisitorState state) {
if (ASTHelpers.getType(tree).asElement().toString().startsWith("bar.")) {
return describeMatch(tree, SuggestedFix.replace(tree, ""));
}
return Description.NO_MATCH;
}
}
@Test
public void testFileAlreadyExists() throws IOException {
try {
helper
.addInputLines("Test.java", "public class Test {}")
.addOutputLines("Test.java", "public class Test {}")
.doTest();
fail();
} catch (FileAlreadyExistsException e) {
assertThat(e).hasMessage("Test.java");
}
}
@Test
public void compilationError() throws Exception {
try {
helper
.addInputLines("Test.java", "public class Test extends NoSuch {}")
.expectUnchanged()
.doTest();
} catch (AssertionError e) {
assertThat(e.getMessage()).contains("error: cannot find symbol");
return;
}
fail("compilation succeeded unexpectedly");
}
@Test
public void staticLastImportOrder() throws Exception {
BugCheckerRefactoringTestHelper.newInstance(new ImportArrayList(), getClass())
.setImportOrder("static-last")
.addInputLines("pkg/A.java", "import static java.lang.Math.min;", "class A {", "}")
.addOutputLines(
"out/pkg/A.java",
"import java.util.ArrayList;",
"",
"import static java.lang.Math.min;",
"class A {",
"}")
.doTest(TestMode.TEXT_MATCH);
}
/** Mock {@link BugChecker} for testing only. */
@BugPattern(
name = "ImportArrayList",
summary = "Mock refactoring that imports an ArrayList",
explanation = "For test purposes only.",
category = JDK,
severity = SUGGESTION
)
public static class ImportArrayList extends BugChecker implements CompilationUnitTreeMatcher {
@Override
public Description matchCompilationUnit(CompilationUnitTree tree, VisitorState state) {
SuggestedFix fix = SuggestedFix.builder().addImport("java.util.ArrayList").build();
return buildDescription(tree).addFix(fix).build();
}
}
}