Skip to content

Add unit tests for ProblemTextFilter - #126

Open
leoweigl wants to merge 2 commits into
0verEngineer:mainfrom
leoweigl:test/problem-text-filter
Open

leoweigl wants to merge 2 commits into
0verEngineer:mainfrom
leoweigl:test/problem-text-filter

Conversation

@leoweigl

Copy link
Copy Markdown
Contributor

Follow-up to #125: this adds tests for the problem filter list.

Why the small change in src/main

ProblemTextFilter.isFiltered(String) reads the filter list via SettingsState.getInstance(), which needs a running IntelliJ application. That makes the filter logic impossible to reach from a plain unit test.

So I split it up:

  • The public isFiltered(String) still reads the setting, and then passes it to
  • a new package-private overload isFiltered(String problemText, String rawFilterList), marked @VisibleForTesting, which contains the existing logic.
  • getFilters() now takes the raw filter list as a parameter instead of reading the setting itself.

The behavior of the public method is unchanged, and the static cache is still keyed by the raw filter string, so a changed setting is still re-parsed as before.

What is covered

ProblemTextFilterTest covers the cases described in the Javadoc (15 test cases in total):

  • plain entries match the text beginning, ignoring case
  • leading spaces and blank entries (e.g. ;;) are ignored, so they don't filter everything
  • glob entries match the whole text, and regex symbols inside a glob are treated literally
  • re: entries match anywhere in the text, and the re: prefix is case-insensitive
  • invalid regex entries are ignored instead of breaking the filter
  • null problem text is filtered, null or empty filter lists filter nothing
  • a changed filter list is applied (cache invalidation)

Testing

./gradlew test passes locally: ListenerTest 6/6, ProblemTextFilterTest 15/15.

The CHANGELOG has an entry under [Unreleased] → Added.

@0verEngineer 0verEngineer left a comment

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

A few remarks on the tests. The cache race in ProblemTextFilter is tracked separately in #127.

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"));

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is the same assertion as the line above, so the sequence checks less than it looks like. Was this meant to use a different list or text? With only two lists that alternate, the test would also pass with a cache that is rebuilt on every call, so a third distinct list (e.g. field → *fiel → re:never → field) would make it actually exercise the invalidation.


import static org.junit.jupiter.api.Assertions.*;

class ProblemTextFilterTest {

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

All tests share the static cache in ProblemTextFilter (cachedRawFilterList / cachedFilters) and never reset it, so what a test actually exercises depends on what the previous test left behind. For example, if nullFilterListIsIgnored runs first, Objects.equals(null, null) is true on the initial state and parse(null) is never called. A small package-private resetCache() (@VisibleForTesting) called from a @BeforeEach would make the tests independent of the method order.


@Test
void regexMatchesTextPattern() {
assertTrue(ProblemTextFilter.isFiltered("'ThreadXsleep()' called in loop", "re:ad.sleep"));

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There is no test for an entry that both starts with re: and contains */?, so the regex-before-glob precedence in toFilter() is not covered. If the two checks were swapped, re:foo.*bar would become a glob with a literal re: prefix and no test would fail. Something like assertTrue(ProblemTextFilter.isFiltered("foo x bar", "re:foo.*bar")) would pin it down.


@ParameterizedTest
@CsvSource({
"Field 'x' is never used,todo;fIELD",

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nit: ' is JUnit's default quote character in @CsvSource. It works here because the quotes are in the middle of the field, but a row whose text starts with an apostrophe (like 'Thread.sleep()' called in loop used further down) would be parsed as a quoted field. Setting quoteCharacter = '"' avoids that trap for future rows.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants