SONARJAVA-6906 - Modify S8924 to raise only on inconsistent Mockito import usage - #6086
SONARJAVA-6906 - Modify S8924 to raise only on inconsistent Mockito import usage#6086NoemieBenard wants to merge 2 commits into
Conversation
This comment has been minimized.
This comment has been minimized.
| .map(clause -> ExpressionsHelper.concatenate((ExpressionTree) ((ImportTree) clause).qualifiedIdentifier())) | ||
| .toList(); | ||
|
|
||
| hasStaticMockitoImport = staticImportFqns.stream().anyMatch(fqn -> fqn.startsWith(MOCKITO_IMPORT_PREFIX)); |
There was a problem hiding this comment.
⚠️ Bug: S8924 rule description contradicts the new mixed-usage behavior
The check now only reports when the file also contains a static import of a Mockito member (hasStaticMockitoImport gate at MockitoStaticImportCheck.java:109), but S8924.html and S8924.json were not updated: the description still states "This rule raises an issue when Mockito core methods are called with the Mockito. prefix instead of being statically imported", and its Noncompliant example (import org.mockito.Mockito; with no static import, two // Noncompliant markers) is exactly the code the new MockitoStaticImportCheckNoStaticImportSample.java asserts is Compliant. Users reading the rule page will expect issues on fully-prefixed files and see none; the documented Noncompliant example no longer raises. Update the lead paragraph, the "How to fix it" text and the Noncompliant/Compliant examples to describe the mixed-import trigger, and adjust the title in S8924.json accordingly (the branch's two "Update rule metadata" commits only touched S9142).
Replace the first paragraph of S8924.html, and make the Noncompliant example contain at least one import static org.mockito.Mockito.… so it matches the implemented trigger; update the S8924.json title to something like "Mockito core methods should be imported consistently".:
<p>This rule raises an issue when a test file mixes both styles of accessing Mockito core methods: some calls use a static import while others keep
the <code>Mockito.</code> prefix. Files that consistently use the <code>Mockito.</code> prefix everywhere are not reported.</p>
- Apply fix
Check the box to apply the fix or reply for a change | Was this helpful? React with 👍 / 👎
| .map(clause -> ExpressionsHelper.concatenate((ExpressionTree) ((ImportTree) clause).qualifiedIdentifier())) | ||
| .toList(); | ||
|
|
||
| hasStaticMockitoImport = staticImportFqns.stream().anyMatch(fqn -> fqn.startsWith(MOCKITO_IMPORT_PREFIX)); |
There was a problem hiding this comment.
💡 Edge Case: S8924 gate triggers on static imports of Mockito fields, not methods
hasStaticMockitoImport is computed from any static import whose FQN starts with org.mockito.Mockito., so a static import of a Mockito constant such as import static org.mockito.Mockito.RETURNS_DEEP_STUBS; (or CALLS_REAL_METHODS, RETURNS_SELF, …) flips the gate on. A file that consistently uses the Mockito. prefix for every call but statically imports one such constant is then reported on every prefixed call — precisely the false positive this PR removes. Restrict the gate to static imports whose simple name is one of the method names the rule tracks.
Only consider a static import relevant when it imports one of the tracked Mockito methods (or a wildcard).:
private static final Set<String> MOCKITO_METHOD_NAMES =
Set.of("doReturn", "doThrow", "mock", "never", "spy", "times", "verify", "when");
// in collectConflictingImports:
hasStaticMockitoImport = staticImportFqns.stream()
.filter(fqn -> fqn.startsWith(MOCKITO_IMPORT_PREFIX))
.map(fqn -> fqn.substring(MOCKITO_IMPORT_PREFIX.length()))
.anyMatch(name -> "*".equals(name) || MOCKITO_METHOD_NAMES.contains(name));
- Apply fix
Check the box to apply the fix or reply for a change | Was this helpful? React with 👍 / 👎
|
❌ Ruling needs updating. A fix PR has been created: #6087 Please review and merge it into your branch. |
Ruling Diff SummaryDetected changes in 1 rule files: 2 issues removed, 0 issues added. S8924 (
|
3a79996 to
3e576a8
Compare
| package checks.tests; | ||
|
|
||
| import org.junit.jupiter.api.Test; | ||
| import org.mockito.Mockito; | ||
|
|
||
| class MockitoStaticImportCheckNoStaticImportSample { | ||
|
|
||
| interface MyService { | ||
| int getValue(); | ||
| } | ||
|
|
||
| @Test | ||
| void compliant_consistent_prefixed_usage() { | ||
| MyService service = Mockito.mock(MyService.class); // Compliant - no static import of Mockito methods in this file | ||
| MyService spied = Mockito.spy(service); |
There was a problem hiding this comment.
💡 Edge Case: New gate's "static imports present but none from Mockito" branch untested
The new file-level gate hasStaticMockitoImport has two ways to be false: no static imports at all, and static imports that exist but none resolving under org.mockito.Mockito.. MockitoStaticImportCheckNoStaticImportSample.java only has plain imports (org.junit.jupiter.api.Test, org.mockito.Mockito), so staticImportFqns is empty and the anyMatch predicate is never actually evaluated against a non-Mockito FQN; the other samples all contain import static org.mockito.Mockito.*-style imports, so the false branch with a non-empty static-import list is unexercised. Add a non-Mockito static import (e.g. import static org.junit.jupiter.api.Assertions.assertEquals; used in the test body) to the new sample so the predicate is really evaluated, and mirror the repo convention by also adding a test_no_static_import_without_semantic case using .withoutSemantic().
Add a non-Mockito static import to the sample so the gate's anyMatch predicate is exercised with a non-empty static import list (use assertEquals in the test body, e.g. assertEquals(42, service.getValue());).:
import org.junit.jupiter.api.Test;
import org.mockito.Mockito;
import static org.junit.jupiter.api.Assertions.assertEquals;
class MockitoStaticImportCheckNoStaticImportSample {
- Apply fix
Check the box to apply the fix or reply for a change | Was this helpful? React with 👍 / 👎
Code Review
|
| Auto-apply | Compact | Unblock |
|
|
|
Was this helpful? React with 👍 / 👎 | Gitar
|




Summary
Mockito.xxx()calls with at least one static import of a Mockito method, instead of flagging every prefixed call unconditionally.Mockito.prefix throughout, without any static import of a Mockito method, are no longer flagged.MockitoStaticImportCheckNoStaticImportSample.javaand a corresponding test case covering the fully-prefixed, no-static-import scenario.Summary by Gitar
CompilationOrPreparationInLoopChecktoPreparedStatementInsideLoopCheck(rule S9142) and removed regex checks.This will update automatically on new commits.