Issue #3105: fixed indentation test to verify more contents of input

This commit is contained in:
rnveach 2016-04-15 14:57:37 -04:00 committed by Roman Ivanov
parent fe17b53a8e
commit 62075f0a54
2 changed files with 159 additions and 76 deletions

View File

@ -91,6 +91,7 @@
<suppress checks="AvoidStaticImport" files=".*[\\/]src[\\/](test|it)[\\/]"/>
<suppress checks="MethodCount" files="[\\/]ImportOrderCheckTest.java$"/>
<suppress checks="MethodCount" files="[\\/]IndentationCheckTest.java$"/>
<suppress checks="ClassDataAbstractionCoupling" files="[\\/]IndentationCheckTest.java$"/>
<suppress checks="MethodCount" files="[\\/]JavadocMethodCheckTest.java$"/>
<suppress checks="MethodCount" files="[\\/]MainTest.java$"/>
<suppress checks="EqualsAvoidNull" files="[\\/]Int.*FilterTest.java$"/>

View File

@ -25,6 +25,7 @@ import static com.puppycrawl.tools.checkstyle.checks.indentation.IndentationChec
import static com.puppycrawl.tools.checkstyle.checks.indentation.IndentationCheck.MSG_ERROR_MULTI;
import static org.junit.Assert.assertArrayEquals;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;
import java.io.BufferedReader;
import java.io.File;
@ -42,7 +43,10 @@ import java.util.regex.Pattern;
import org.junit.Test;
import com.puppycrawl.tools.checkstyle.BaseCheckTestSupport;
import com.puppycrawl.tools.checkstyle.Checker;
import com.puppycrawl.tools.checkstyle.DefaultConfiguration;
import com.puppycrawl.tools.checkstyle.api.AuditEvent;
import com.puppycrawl.tools.checkstyle.api.AuditListener;
import com.puppycrawl.tools.checkstyle.api.Configuration;
import com.puppycrawl.tools.checkstyle.utils.CommonUtils;
@ -52,57 +56,42 @@ import com.puppycrawl.tools.checkstyle.utils.CommonUtils;
*/
public class IndentationCheckTest extends BaseCheckTestSupport {
private static final Pattern LINE_WITH_COMMENT_REGEX =
Pattern.compile(".*?(//indent:(\\d+)"
+ " exp:((>=\\d+)|(\\d+(,\\d+)*?))( warn)?)$");
Pattern.compile(".*?//indent:(\\d+)(?: ioffset:(\\d+))?"
+ " exp:(>=)?(\\d+(?:,\\d+)*?)( warn)?$");
private static final Pattern GET_INDENT_FROM_COMMENT_REGEX =
Pattern.compile("//indent:(\\d+).*?");
private static final Pattern MULTILEVEL_COMMENT_REGEX =
Pattern.compile("//indent:\\d+ exp:(\\d+(,\\d+)+?)( warn)?");
private static final Pattern SINGLE_LEVEL_COMMENT_REGEX =
Pattern.compile("//indent:\\d+ exp:(\\d+)( warn)?");
private static final Pattern NON_STRICT_LEVEL_COMMENT_REGEX =
Pattern.compile("//indent:\\d+ exp:>=(\\d+)( warn)?");
private static final String[] EMPTY_EXPECTED = {};
private static Integer[] getLinesWithWarnAndCheckComments(String aFileName,
private static IndentComment[] getLinesWithWarnAndCheckComments(String aFileName,
final int tabWidth)
throws IOException {
final List<Integer> result = new ArrayList<>();
final List<IndentComment> result = new ArrayList<>();
try (BufferedReader br = new BufferedReader(new InputStreamReader(
new FileInputStream(aFileName), StandardCharsets.UTF_8))) {
int lineNumber = 1;
for (String line = br.readLine(); line != null; line = br.readLine()) {
final Matcher match = LINE_WITH_COMMENT_REGEX.matcher(line);
if (match.matches()) {
final String comment = match.group(1);
final int indentInComment = getIndentFromComment(comment);
final IndentComment warn = new IndentComment(match, lineNumber);
final int actualIndent = getLineStart(line, tabWidth);
if (actualIndent != indentInComment) {
if (actualIndent != warn.getIndent()) {
throw new IllegalStateException(String.format(Locale.ROOT,
"File \"%1$s\" has incorrect indentation in comment."
"File \"%1$s\" has incorrect indentation in comment. "
+ "Line %2$d: comment:%3$d, actual:%4$d.",
aFileName,
lineNumber,
indentInComment,
warn.getIndent(),
actualIndent));
}
if (isWarnComment(comment)) {
result.add(lineNumber);
}
if (!isCommentConsistent(comment)) {
if (!isCommentConsistent(warn)) {
throw new IllegalStateException(String.format(Locale.ROOT,
"File \"%1$s\" has inconsistent comment on line %2$d",
aFileName,
lineNumber));
}
if (warn.isWarning()) {
result.add(warn);
}
}
else if (!line.isEmpty()) {
throw new IllegalStateException(String.format(Locale.ROOT,
@ -114,55 +103,34 @@ public class IndentationCheckTest extends BaseCheckTestSupport {
lineNumber++;
}
}
return result.toArray(new Integer[result.size()]);
return result.toArray(new IndentComment[result.size()]);
}
private static int getIndentFromComment(String comment) {
final Matcher match = GET_INDENT_FROM_COMMENT_REGEX.matcher(comment);
match.matches();
return Integer.parseInt(match.group(1));
}
private static boolean isCommentConsistent(IndentComment comment) {
final String[] levels = comment.getExpectedWarning().split(", ");
final int indent = comment.getIndent() + comment.getIndentOffset();
private static boolean isWarnComment(String comment) {
return comment.endsWith(" warn");
}
private static boolean isCommentConsistent(String comment) {
final int indentInComment = getIndentFromComment(comment);
final boolean isWarnComment = isWarnComment(comment);
final Matcher multilevelMatch = MULTILEVEL_COMMENT_REGEX.matcher(comment);
if (multilevelMatch.matches()) {
final String[] levels = multilevelMatch.group(1).split(",");
final String indentInCommentStr = String.valueOf(indentInComment);
if (levels.length > 1) {
// multi
final boolean containsActualLevel =
Arrays.asList(levels).contains(indentInCommentStr);
Arrays.asList(levels).contains(String.valueOf(indent));
return containsActualLevel && !isWarnComment
|| !containsActualLevel && isWarnComment;
return containsActualLevel != comment.isWarning();
}
else {
final int expectedWarning = Integer.parseInt(comment.getExpectedWarning());
final Matcher singleLevelMatch = SINGLE_LEVEL_COMMENT_REGEX.matcher(comment);
if (singleLevelMatch.matches()) {
final int expectedLevel = Integer.parseInt(singleLevelMatch.group(1));
return isSingleLevelCommentConsistent(indentInComment, isWarnComment, expectedLevel);
if (comment.isExpectedNonStrict()) {
// non-strict
final boolean test = indent >= expectedWarning;
return test != comment.isWarning();
}
else {
// single
final boolean test = expectedWarning == indent;
return test != comment.isWarning();
}
}
final Matcher nonStrictLevelMatch = NON_STRICT_LEVEL_COMMENT_REGEX.matcher(comment);
if (nonStrictLevelMatch.matches()) {
final int expectedMinimalIndent = Integer.parseInt(nonStrictLevelMatch.group(1));
return indentInComment >= expectedMinimalIndent && !isWarnComment
|| indentInComment < expectedMinimalIndent && isWarnComment;
}
throw new IllegalStateException("Comments are not consistent");
}
private static boolean isSingleLevelCommentConsistent(int indentInComment,
boolean isWarnComment, int expectedLevel) {
return expectedLevel == indentInComment && !isWarnComment
|| expectedLevel != indentInComment && isWarnComment;
}
private static int getLineStart(String line, final int tabWidth) {
@ -174,23 +142,30 @@ public class IndentationCheckTest extends BaseCheckTestSupport {
return 0;
}
private void verifyWarns(Configuration config, String filePath,
String... expected)
throws Exception {
verifyWarns(config, filePath, expected, 0);
}
private void verifyWarns(Configuration config, String filePath,
String[] expected, int warnCountCorrection)
throws Exception {
final int tabWidth = Integer.parseInt(config.getAttribute("tabWidth"));
final Integer[] linesWithWarn =
final IndentComment[] linesWithWarn =
getLinesWithWarnAndCheckComments(filePath, tabWidth);
assertEquals("Expected warning count in UT does not match warn"
+ " comment count in input file", linesWithWarn.length
+ warnCountCorrection,
expected.length);
verify(config, filePath, expected);
verify(config, filePath, expected, linesWithWarn);
}
private void verifyWarns(Configuration config, String filePath,
String... expected)
throws Exception {
verifyWarns(config, filePath, expected, 0);
private void verify(Configuration config, String filePath, String[] expected,
final IndentComment... linesWithWarn) throws Exception {
final Checker checker = createChecker(config);
checker.addListener(new IndentAudit(linesWithWarn));
verify(checker, new File[] {new File(filePath)}, filePath, expected);
}
@Override
@ -1587,7 +1562,7 @@ public class IndentationCheckTest extends BaseCheckTestSupport {
checkConfig.addAttribute("tabWidth", "4");
checkConfig.addAttribute("basicOffset", "4");
checkConfig.addAttribute("lineWrappingIndentation", "8");
final String[] expected = EMPTY_EXPECTED;
final String[] expected = CommonUtils.EMPTY_STRING_ARRAY;
verifyWarns(checkConfig, getNonCompilablePath("InputLambda2.java"), expected, 0);
}
@ -1608,4 +1583,111 @@ public class IndentationCheckTest extends BaseCheckTestSupport {
final String[] expected = CommonUtils.EMPTY_STRING_ARRAY;
verify(checkConfig, fileName, expected);
}
private static final class IndentAudit implements AuditListener {
private final IndentComment[] comments;
private int position;
private IndentAudit(IndentComment... comments) {
this.comments = comments;
}
@Override
public void auditStarted(AuditEvent event) {
// No code needed
}
@Override
public void auditFinished(AuditEvent event) {
// No code needed
}
@Override
public void fileStarted(AuditEvent event) {
// No code needed
}
@Override
public void fileFinished(AuditEvent event) {
// No code needed
}
@Override
public void addError(AuditEvent event) {
final int line = event.getLine();
final String message = event.getMessage();
final IndentComment comment = comments[position];
position++;
assertTrue(
"input expected warning #" + position + " at line " + comment.getLineNumber()
+ " to report '" + comment.getExpectedMessage() + "' but got instead: "
+ line + ": " + message,
message.endsWith(comment.getExpectedMessage()));
}
@Override
public void addException(AuditEvent event, Throwable throwable) {
// No code needed
}
}
private static final class IndentComment {
private final int lineNumber;
private final int indent;
/** Used for when violations report nodes not first on the line. */
private final int indentOffset;
private final boolean expectedNonStrict;
private final String expectedWarning;
private final boolean warning;
private IndentComment(Matcher match, int lineNumber) {
this.lineNumber = lineNumber;
indent = Integer.parseInt(match.group(1));
if (match.group(2) == null) {
indentOffset = 0;
}
else {
indentOffset = Integer.parseInt(match.group(2));
}
expectedNonStrict = match.group(3) != null;
expectedWarning = match.group(4).replace(",", ", ");
warning = match.group(5) != null;
}
public String getExpectedMessage() {
if (expectedWarning.contains(",")) {
return "incorrect indentation level " + (indent + indentOffset)
+ ", expected level should be one of the following: " + expectedWarning
+ ".";
}
return "incorrect indentation level " + (indent + indentOffset)
+ ", expected level should be " + expectedWarning + ".";
}
public int getLineNumber() {
return lineNumber;
}
public int getIndent() {
return indent;
}
public int getIndentOffset() {
return indentOffset;
}
public boolean isExpectedNonStrict() {
return expectedNonStrict;
}
public String getExpectedWarning() {
return expectedWarning;
}
public boolean isWarning() {
return warning;
}
}
}