diff --git a/CHANGELOG.md b/CHANGELOG.md index 0368959..59131d5 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,7 @@ ### Added - Unit tests for the different problem detection strategies, making sure there are no duplicate IDs and that every ID maps back to its listener +- Unit tests for the problem filter list, covering text beginning, glob and `re:` entries as well as blank and invalid entries ### Changed diff --git a/src/main/java/org/overengineer/inlineproblems/utils/ProblemTextFilter.java b/src/main/java/org/overengineer/inlineproblems/utils/ProblemTextFilter.java index 24040c5..a52c490 100644 --- a/src/main/java/org/overengineer/inlineproblems/utils/ProblemTextFilter.java +++ b/src/main/java/org/overengineer/inlineproblems/utils/ProblemTextFilter.java @@ -1,6 +1,7 @@ package org.overengineer.inlineproblems.utils; import com.intellij.openapi.diagnostic.Logger; +import org.jetbrains.annotations.VisibleForTesting; import org.overengineer.inlineproblems.settings.SettingsState; import java.util.ArrayList; @@ -44,11 +45,19 @@ private ProblemTextFilter() { * @return true if the problem should be ignored because it matches one of the filters */ public static boolean isFiltered(String problemText) { + String rawFilterList = SettingsState.getInstance().getProblemFilterList(); + + return isFiltered(problemText, rawFilterList); + } + + @VisibleForTesting + static boolean isFiltered(String problemText, String rawFilterList) { if (problemText == null) { return true; } - List> filters = getFilters(); + List> filters = getFilters(rawFilterList); + if (filters.isEmpty()) { return false; } @@ -64,9 +73,7 @@ public static boolean isFiltered(String problemText) { return false; } - private static List> getFilters() { - String rawFilterList = SettingsState.getInstance().getProblemFilterList(); - + private static List> getFilters(String rawFilterList) { if (!Objects.equals(rawFilterList, cachedRawFilterList)) { cachedFilters = parse(rawFilterList); cachedRawFilterList = rawFilterList; diff --git a/src/test/java/org/overengineer/inlineproblems/utils/ProblemTextFilterTest.java b/src/test/java/org/overengineer/inlineproblems/utils/ProblemTextFilterTest.java new file mode 100644 index 0000000..614b3e2 --- /dev/null +++ b/src/test/java/org/overengineer/inlineproblems/utils/ProblemTextFilterTest.java @@ -0,0 +1,95 @@ +package org.overengineer.inlineproblems.utils; + +import org.junit.jupiter.api.Test; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.CsvSource; + +import static org.junit.jupiter.api.Assertions.*; + +class ProblemTextFilterTest { + + @Test + void prefixMatchesTextBegin() { + assertTrue(ProblemTextFilter.isFiltered("Field 'x' is never used", "field")); + assertTrue(ProblemTextFilter.isFiltered("Unused import statement", "unu")); + assertFalse(ProblemTextFilter.isFiltered("Field 'x' is never used", "never")); + assertFalse(ProblemTextFilter.isFiltered("Unused import statement", "import")); + } + + @ParameterizedTest + @CsvSource({ + "Field 'x' is never used,todo;fIELD", + "Unused import statement,UNU", + "Field 'x' is never used,re:NEVER", + "Unused import statement,*sTaT*;todo" + }) + void caseIsIgnored(String problemText, String rawFilterList) { + assertTrue(ProblemTextFilter.isFiltered(problemText, rawFilterList)); + } + + @Test + void blankFilterTextIsIgnored() { + assertFalse(ProblemTextFilter.isFiltered("Unused import statement", "")); + assertFalse(ProblemTextFilter.isFiltered("Unused import statement", ";;")); + assertFalse(ProblemTextFilter.isFiltered("Unused import statement", "; ;")); + assertFalse(ProblemTextFilter.isFiltered("Cannot resolve method 'foo(int)'", "re:")); + } + + @Test + void leadingSpacesAreIgnored() { + assertTrue(ProblemTextFilter.isFiltered("Field 'x' is never used", " field")); + assertTrue(ProblemTextFilter.isFiltered("Unused import statement", " *use*")); + assertTrue(ProblemTextFilter.isFiltered(" Unused import statement", "Unu")); + } + + @Test + void globMatchesTextPattern() { + assertTrue(ProblemTextFilter.isFiltered("Field 'x' is never used", "fie*")); + assertTrue(ProblemTextFilter.isFiltered("Unused import statement", "*t st*")); + assertFalse(ProblemTextFilter.isFiltered("Field 'x' is never used", "field?")); + assertTrue(ProblemTextFilter.isFiltered("Unused import statement", "*statement")); + } + + @Test + void globIgnoresRegexSymbols() { + assertTrue(ProblemTextFilter.isFiltered("Cannot resolve method 'foo(int)'", "*foo(int)?")); + assertTrue(ProblemTextFilter.isFiltered("Cannot resolve method 'foo(int)'", "*foo(*")); + assertTrue(ProblemTextFilter.isFiltered("'Thread.sleep()' called in loop", "*ad.sleep*")); + assertFalse(ProblemTextFilter.isFiltered("'Thread.sleep' called in loop", "*sleep()*")); + assertFalse(ProblemTextFilter.isFiltered("'ThreadXsleep()' called in loop", "*ad.sleep*")); + } + + @Test + void regexMatchesTextPattern() { + assertTrue(ProblemTextFilter.isFiltered("'ThreadXsleep()' called in loop", "re:ad.sleep")); + } + + @Test + void regexIdentifierCaseIsIgnored() { + assertTrue(ProblemTextFilter.isFiltered("'ThreadXsleep()' called in loop", "RE:ad.sleep")); + } + + @Test + void invalidRegexIsIgnored() { + assertDoesNotThrow(() -> ProblemTextFilter.isFiltered("Cannot resolve method 'foo(int)'", "re:foo(")); + assertTrue(ProblemTextFilter.isFiltered("Unused import statement", "re:imp(;unused")); + } + + @Test + void nullTextIsIgnored() { + assertTrue(ProblemTextFilter.isFiltered(null, ";;")); + } + + @Test + void nullFilterListIsIgnored() { + assertFalse(ProblemTextFilter.isFiltered("Unused import statement", null)); + } + + @Test + void changedFilterListIsApplied() { + assertTrue(ProblemTextFilter.isFiltered("Field 'x' is never used", "field")); + assertFalse(ProblemTextFilter.isFiltered("Field 'x' is never used", "*fiel")); + assertFalse(ProblemTextFilter.isFiltered("Field 'x' is never used", "*fiel")); + assertTrue(ProblemTextFilter.isFiltered("Field 'x' is never used", "field")); + } +}