Skip to content

Improve TooManyInvocationsError reporting#2315

Merged
leonard84 merged 9 commits intospockframework:masterfrom
leonard84:report-unmatched-on-too-many-invocations
Mar 9, 2026
Merged

Improve TooManyInvocationsError reporting#2315
leonard84 merged 9 commits intospockframework:masterfrom
leonard84:report-unmatched-on-too-many-invocations

Conversation

@leonard84
Copy link
Member

@leonard84 leonard84 commented Mar 7, 2026

it now reports unsatisfied interactions with argument mismatch details.

Varargs methods now correctly expand args in mismatch descriptions instead of reporting <too few arguments>.

Summary by CodeRabbit

  • Enhancements
    • Verification errors now include richer diagnostics listing relevant unsatisfied interactions and per-invocation mismatch details.
    • Varargs argument mismatches are reported by expanding varargs for clearer, per-argument messages.
  • Tests
    • Expanded test suite with numerous cases validating improved error messages, scope/context handling, and varargs mismatch reporting.

it now reports unsatisfied interactions with argument mismatch details.

Varargs methods now correctly expand args in mismatch descriptions
instead of reporting `<too few arguments>`.
@leonard84 leonard84 self-assigned this Mar 7, 2026
@coderabbitai
Copy link

coderabbitai bot commented Mar 7, 2026

📝 Walkthrough

Walkthrough

Adds diagnostic context for TooManyInvocationsError: new interface methods to expose non-exhausted interactions and target/method matching, a diagnostic utility for scoring/rendering invocations, runtime changes to collect scope context and enrich errors, varargs mismatch handling improvements, and expanded tests and release notes.

Changes

Cohort / File(s) Summary
Interface Extensions
spock-core/src/main/java/org/spockframework/mock/IInteractionScope.java, spock-core/src/main/java/org/spockframework/mock/IMockInteraction.java
Added getNonExhaustedInteractions() default on IInteractionScope and matchesTargetAndMethod(IMockInvocation) default on IMockInteraction to expose scope state and provide target/method-only matching.
Diagnostic Utility & Error Enrichment
spock-core/src/main/java/org/spockframework/mock/InteractionDiagnostics.java, spock-core/src/main/java/org/spockframework/mock/TooManyInvocationsError.java
New package-private InteractionDiagnostics class centralizes scoring and mismatch rendering. TooManyInvocationsError can be enriched with scope context (enrichWithScopeContext) to append ordered unmatched/unsatisfied interaction diagnostics.
Runtime: scope & controller
spock-core/src/main/java/org/spockframework/mock/runtime/InteractionScope.java, spock-core/src/main/java/org/spockframework/mock/runtime/MockController.java
InteractionScope exposes non-exhausted interactions and extracts unsatisfied interactions; MockController collects active scopes during invocation handling and enriches TooManyInvocationsError with aggregated scope context.
Mock interaction implementations
spock-core/src/main/java/org/spockframework/mock/runtime/MockInteraction.java, spock-core/src/main/java/org/spockframework/mock/runtime/MockInteractionDecorator.java
Added matchesTargetAndMethod(IMockInvocation) implementation in MockInteraction and delegating override in MockInteractionDecorator to support target/method filtering for diagnostics.
Argument constraint logic
spock-core/src/main/java/org/spockframework/mock/constraint/PositionalArgumentListConstraint.java
When argument counts differ and varargs are expandable, varargs are expanded before mismatch analysis to produce accurate per-argument mismatch descriptions.
Refactor: TooFewInvocations
spock-core/src/main/java/org/spockframework/mock/TooFewInvocationsError.java
Removed local scoring/rendering code and delegated to InteractionDiagnostics for scoring and formatted output.
Tests
spock-specs/src/test/groovy/org/spockframework/smoke/mock/TooManyInvocations.groovy, spock-specs/src/test/groovy/org/spockframework/smoke/mock/TooFewInvocations.groovy
Large additions/updates: many new/updated tests normalizing error message assertions, new helper normalize, extensive coverage for unmatched/unsatisfied interactions, varargs and wildcard scenarios; updated expected outputs to match refactored diagnostics.
Docs
docs/release_notes.adoc
Release notes for 2.5 documenting TooManyInvocationsError enhancements and varargs mismatch correction.

Sequence Diagram(s)

sequenceDiagram
    actor Caller
    participant MockController
    participant InteractionScope
    participant IMockInteraction
    participant TooManyInvocationsError
    participant InteractionDiagnostics

    Caller->>MockController: invoke mocked method
    MockController->>InteractionScope: handle invocation
    InteractionScope->>IMockInteraction: match constraints
    InteractionScope-->>MockController: raises InteractionNotSatisfiedError/TooManyInvocationsError

    alt Error is TooManyInvocationsError
        MockController->>InteractionScope: getNonExhaustedInteractions()
        InteractionScope-->>MockController: List<IMockInteraction>
        MockController->>TooManyInvocationsError: enrichWithScopeContext(interactions)
        TooManyInvocationsError->>IMockInteraction: matchesTargetAndMethod(invocation)
        IMockInteraction-->>TooManyInvocationsError: boolean
        TooManyInvocationsError->>InteractionDiagnostics: scoreMatchingInvocations(...) / appendMismatchDescriptions(...)
        InteractionDiagnostics-->>TooManyInvocationsError: scored list / formatted text
        TooManyInvocationsError-->>MockController: enriched message
    end

    MockController-->>Caller: throw enriched error
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~60 minutes

Poem

🐰 A hop, a sniff, the mocks align—

Unsatisfied calls now show their sign.
Varargs stretched and mismatches told,
Diagnostics scored and neatly rolled.
I nibble bugs and cheer: "Good fold!" 🥕

🚥 Pre-merge checks | ✅ 2 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 15.79% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (2 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title directly describes the primary change: improving error reporting for TooManyInvocationsError with unsatisfied interactions and argument mismatch details.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@greptile-apps
Copy link

greptile-apps bot commented Mar 7, 2026

Greptile Summary

This PR significantly improves TooManyInvocationsError diagnostics by appending an "Unmatched invocations (ordered by similarity)" section that shows unsatisfied interactions alongside per-argument mismatch details, and fixes a pre-existing bug where varargs methods incorrectly reported <too few arguments> in mismatch descriptions.

Key changes:

  • TooManyInvocationsError gains enrichWithScopeContext + appendUnmatchedInvocations to render unsatisfied interactions with argument diffs against the accepted invocations pool
  • MockController.handle intercepts TooManyInvocationsError and calls the new enrichError hook on the active scope
  • IMockInteraction.matchesTargetAndMethod is added to separate target+method matching from argument matching, enabling the "relevant unsatisfied" pre-filter
  • PositionalArgumentListConstraint.describeMismatch is fixed to expand varargs before comparing argument counts
  • ScoredInvocation.count is set in the constructor but never read — not in compareTo, not in display — making it dead code; if it was intended for secondary tie-breaking it is missing from the comparison logic
  • Both IInteractionScope.enrichError and IMockInteraction.matchesTargetAndMethod are added to public interfaces without default implementations, which is a source-incompatible change for any third-party code implementing these interfaces directly

Confidence Score: 4/5

  • Safe to merge; issues are style/API-compatibility concerns that do not affect runtime correctness.
  • The feature logic is sound and is backed by a comprehensive test suite. The two deductions are: (1) an unused count field in ScoredInvocation that is dead code (minor), and (2) two new methods added to public interfaces without default implementations, which is a source-incompatible change for third-party implementors of IMockInteraction or IInteractionScope. Neither issue causes incorrect behavior within the framework itself, but the API compatibility concern is worth addressing before the release.
  • IMockInteraction.java and IInteractionScope.java — missing default implementations on newly added interface methods. TooManyInvocationsError.java — unused count field in ScoredInvocation.

Important Files Changed

Filename Overview
spock-core/src/main/java/org/spockframework/mock/TooManyInvocationsError.java Core change: adds enrichWithScopeContext and appendUnmatchedInvocations to enrich the error message with unsatisfied interactions and argument-mismatch details. Contains an unused count field in ScoredInvocation and the associated dead-code argument in scoreInvocations.
spock-core/src/main/java/org/spockframework/mock/IMockInteraction.java Adds matchesTargetAndMethod to the public interface without a default implementation, which is a binary and source-incompatible change for external implementors.
spock-core/src/main/java/org/spockframework/mock/IInteractionScope.java Adds enrichError to the public interface without a default implementation, a source-incompatible change for third-party implementations.
spock-core/src/main/java/org/spockframework/mock/runtime/MockController.java Intercepts TooManyInvocationsError in handle() and enriches it with the current scope's unsatisfied interactions. The synchronized block is correctly placed and uses scopes.getFirst(), which is the active then-block scope.
spock-core/src/main/java/org/spockframework/mock/runtime/MockInteraction.java Implements matchesTargetAndMethod by skipping PositionalArgumentListConstraint and NamedArgumentListConstraint — correctly isolating target+method matching from argument matching.
spock-core/src/main/java/org/spockframework/mock/constraint/PositionalArgumentListConstraint.java Fixes varargs expansion in describeMismatch so that vararg methods no longer report <too few arguments>. The guard condition correctly mirrors the one already present in isSatisfiedBy.
spock-core/src/main/java/org/spockframework/mock/runtime/InteractionScope.java Refactors verifyInteractions to reuse getUnsatisfiedInteractions() and adds enrichError which forwards to TooManyInvocationsError.enrichWithScopeContext.
spock-specs/src/test/groovy/org/spockframework/smoke/mock/TooManyInvocations.groovy Comprehensive new tests covering wildcard interactions, multiple unsatisfied interactions, varargs, multi-argument mismatch, cross-mock/cross-method filtering, and satisfied/exhausted interactions. Well-structured and provides good regression coverage.

Sequence Diagram

sequenceDiagram
    participant SUT as SUT (when block)
    participant MC as MockController
    participant IS as InteractionScope
    participant MI as MockInteraction
    participant TMIE as TooManyInvocationsError

    SUT->>MC: handle(invocation)
    MC->>IS: match(invocation)
    IS-->>MC: exhausted interaction
    MC->>MI: accept(invocation)
    MI-->>MC: Supplier that throws TooManyInvocationsError
    MC->>MC: resultSupplier.get()
    MC->>IS: enrichError(error) [synchronized]
    IS->>IS: getUnsatisfiedInteractions()
    IS->>TMIE: enrichWithScopeContext(unsatisfiedList)
    MC->>MC: errors.add(e) then rethrow

    Note over TMIE: getMessage() called later
    TMIE->>TMIE: build header and accepted invocations
    loop for each relevant unsatisfied interaction
        TMIE->>MI: matchesTargetAndMethod(acceptedInvocation)
        MI-->>TMIE: true or false
        TMIE->>MI: computeSimilarityScore(invocation)
        MI-->>TMIE: score
        TMIE->>MI: describeMismatch(invocation)
        MI-->>TMIE: mismatch text
    end
    TMIE-->>SUT: formatted error with mismatch details
Loading

Last reviewed commit: faba9f0

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 5

🧹 Nitpick comments (1)
spock-specs/src/test/groovy/org/spockframework/smoke/mock/TooManyInvocations.groovy (1)

44-56: Consider a small normalized-message assertion helper.

The new tests repeat the same normalize(e.message) / expected = normalize(...) scaffold many times. A tiny helper would leave each test focused on the message body and make future formatter edits cheaper.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In
`@spock-specs/src/test/groovy/org/spockframework/smoke/mock/TooManyInvocations.groovy`
around lines 44 - 56, Introduce a small helper to centralize the repeated
normalize-and-compare logic: add a method (e.g.
assertNormalizedMessage(actualMessage, expectedBody) or
assertNormalizedException(e, expectedBody)) that calls normalize on the actual
and on the trimmed expected body and performs the equality assertion; replace
the repeated patterns in TooManyInvocations.groovy (where code uses
normalize(e.message), builds expected = normalize("""...""".trim()), and then
compares) with calls to this new helper so each test only contains the expected
message body.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@docs/release_notes.adoc`:
- Line 15: Rewrite the release note bullet to a full, scannable sentence:
replace the fragment "* Fix argument mismatch description for varargs methods
now correctly expanding varargs instead of reporting `<too few arguments>`" with
a clearer line like "Fix argument mismatch descriptions for varargs methods by
expanding varargs instead of reporting `<too few arguments>`", ensuring the
phrasing mentions "argument mismatch descriptions", "varargs methods", and the
behavior change (expanding varargs vs reporting `<too few arguments>`).

In
`@spock-core/src/main/java/org/spockframework/mock/constraint/PositionalArgumentListConstraint.java`:
- Around line 53-55: The current logic in PositionalArgumentListConstraint only
calls expandVarArgs(args) when argConstraints.size() != args.size(), which fails
for single-vararg calls where the raw invocation.getArguments() is an array
wrapper; change the condition to call expandVarArgs whenever
hasExpandableVarArgs(invocation.getMethod(), args) is true (regardless of
argConstraints.size() equality) so args is expanded before comparison; update
the block that references argConstraints, args,
hasExpandableVarArgs(invocation.getMethod(), args), and expandVarArgs(args) to
always expand when hasExpandableVarArgs returns true.

In `@spock-core/src/main/java/org/spockframework/mock/IInteractionScope.java`:
- Around line 35-36: Change the abstract method declaration "void
enrichError(TooManyInvocationsError error);" in the public interface
IInteractionScope into a default method: declare "default void
enrichError(TooManyInvocationsError error) { ... }" so external custom
implementations keep working; implement the default body with the common
behavior used by Spock's internal implementations (or a safe no-op if the common
logic cannot be moved here) and, if needed, extract shared logic into a
private/static helper used by the default method and existing implementations so
callers of IInteractionScope.enrichError get the same behavior without breaking
binary compatibility.

In `@spock-core/src/main/java/org/spockframework/mock/IMockInteraction.java`:
- Around line 51-52: Change the new abstract method signature boolean
matchesTargetAndMethod(IMockInvocation invocation) in the IMockInteraction
interface to a default method that delegates to the existing
matches(IMockInvocation invocation) to preserve binary compatibility; implement
default boolean matchesTargetAndMethod(IMockInvocation invocation) { return
matches(invocation); } so third‑party implementations need not be recompiled and
can still override if desired (mirroring the delegation used in
DefaultInteraction).

In
`@spock-core/src/main/java/org/spockframework/mock/runtime/MockController.java`:
- Around line 65-68: The catch block uses scopes.getFirst() which can change
before the catch runs; instead capture the specific scope that matched the
invocation while still inside the original synchronized section and use that
captured scope to call enrichError; modify MockController so the code path that
performs the matching (inside the synchronized block where scopes and invocation
checks occur) assigns the matching scope to a local variable (e.g.
matchingScope) and then in the TooManyInvocationsError catch call
matchingScope.enrichError((TooManyInvocationsError)e) rather than
scopes.getFirst(), ensuring the enrichError call uses the exact scope that
produced the error.

---

Nitpick comments:
In
`@spock-specs/src/test/groovy/org/spockframework/smoke/mock/TooManyInvocations.groovy`:
- Around line 44-56: Introduce a small helper to centralize the repeated
normalize-and-compare logic: add a method (e.g.
assertNormalizedMessage(actualMessage, expectedBody) or
assertNormalizedException(e, expectedBody)) that calls normalize on the actual
and on the trimmed expected body and performs the equality assertion; replace
the repeated patterns in TooManyInvocations.groovy (where code uses
normalize(e.message), builds expected = normalize("""...""".trim()), and then
compares) with calls to this new helper so each test only contains the expected
message body.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 2226f5d9-204b-4b43-8ffe-bbfe2e7e073b

📥 Commits

Reviewing files that changed from the base of the PR and between 383b3ea and faba9f0.

📒 Files selected for processing (12)
  • docs/release_notes.adoc
  • spock-core/src/main/java/org/spockframework/mock/DefaultInteraction.java
  • spock-core/src/main/java/org/spockframework/mock/DefaultJavaLangObjectInteractions.java
  • spock-core/src/main/java/org/spockframework/mock/IInteractionScope.java
  • spock-core/src/main/java/org/spockframework/mock/IMockInteraction.java
  • spock-core/src/main/java/org/spockframework/mock/TooManyInvocationsError.java
  • spock-core/src/main/java/org/spockframework/mock/constraint/PositionalArgumentListConstraint.java
  • spock-core/src/main/java/org/spockframework/mock/runtime/InteractionScope.java
  • spock-core/src/main/java/org/spockframework/mock/runtime/MockController.java
  • spock-core/src/main/java/org/spockframework/mock/runtime/MockInteraction.java
  • spock-core/src/main/java/org/spockframework/mock/runtime/MockInteractionDecorator.java
  • spock-specs/src/test/groovy/org/spockframework/smoke/mock/TooManyInvocations.groovy

@codecov
Copy link

codecov bot commented Mar 7, 2026

Codecov Report

❌ Patch coverage is 88.28829% with 13 lines in your changes missing coverage. Please review.
✅ Project coverage is 82.23%. Comparing base (c9b09cb) to head (e73fc94).
⚠️ Report is 1 commits behind head on master.

Files with missing lines Patch % Lines
...rg/spockframework/mock/InteractionDiagnostics.java 82.97% 4 Missing and 4 partials ⚠️
...g/spockframework/mock/runtime/MockInteraction.java 66.66% 1 Missing and 1 partial ⚠️
...ava/org/spockframework/mock/IInteractionScope.java 0.00% 1 Missing ⚠️
...java/org/spockframework/mock/IMockInteraction.java 0.00% 1 Missing ⚠️
...g/spockframework/mock/TooManyInvocationsError.java 96.15% 0 Missing and 1 partial ⚠️
Additional details and impacted files

Impacted file tree graph

@@             Coverage Diff              @@
##             master    #2315      +/-   ##
============================================
+ Coverage     82.13%   82.23%   +0.09%     
- Complexity     4797     4827      +30     
============================================
  Files           469      472       +3     
  Lines         14954    15036      +82     
  Branches       1888     1905      +17     
============================================
+ Hits          12283    12365      +82     
+ Misses         1984     1983       -1     
- Partials        687      688       +1     
Files with missing lines Coverage Δ
...rg/spockframework/mock/TooFewInvocationsError.java 96.00% <100.00%> (+4.16%) ⬆️
...k/constraint/PositionalArgumentListConstraint.java 97.67% <100.00%> (+0.11%) ⬆️
.../spockframework/mock/runtime/InteractionScope.java 100.00% <100.00%> (ø)
...rg/spockframework/mock/runtime/MockController.java 97.46% <100.00%> (+0.45%) ⬆️
...amework/mock/runtime/MockInteractionDecorator.java 62.50% <100.00%> (+2.50%) ⬆️
...ava/org/spockframework/mock/IInteractionScope.java 0.00% <0.00%> (ø)
...java/org/spockframework/mock/IMockInteraction.java 0.00% <0.00%> (ø)
...g/spockframework/mock/TooManyInvocationsError.java 94.73% <96.15%> (+1.18%) ⬆️
...g/spockframework/mock/runtime/MockInteraction.java 81.96% <66.66%> (-1.67%) ⬇️
...rg/spockframework/mock/InteractionDiagnostics.java 82.97% <82.97%> (ø)

... and 2 files with indirect coverage changes

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

@AndreasTu AndreasTu added this to the 2.5 milestone Mar 8, 2026
Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

🧹 Nitpick comments (2)
spock-core/src/main/java/org/spockframework/mock/InteractionDiagnostics.java (2)

65-76: Off-by-one in mismatch description limit.

The loop appends the invocation header (count * invocation) for all entries, but only appends mismatch descriptions for the first 5 (idx++ < MAX_MISMATCH_DESCRIPTIONS). However, the increment happens after comparison, so when idx=4, the check passes, then idx becomes 5. On the next iteration with idx=5, the check fails. This means exactly 5 descriptions are rendered, which is correct.

One minor nit: The header is always rendered but the description may be omitted after 5 entries. Consider adding a note like "(mismatch details omitted)" for entries beyond the limit to clarify why some invocations lack descriptions.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@spock-core/src/main/java/org/spockframework/mock/InteractionDiagnostics.java`
around lines 65 - 76, In appendScoredInvocations, after rendering the invocation
header for entries beyond the MAX_MISMATCH_DESCRIPTIONS limit (using idx and the
existing idx++ check that controls appendMismatchDescription), append a short
note such as " (mismatch details omitted)" to the builder so callers can see why
there is no subsequent mismatch description; keep the current logic that calls
appendMismatchDescription(interaction, si.invocation) for the first
MAX_MISMATCH_DESCRIPTIONS entries and only add the omission note for subsequent
entries.

111-116: Consider using Integer.compare to avoid potential overflow.

While similarity scores are likely bounded in practice, score - other.score can overflow for extreme integer values. Using Integer.compare() is a safer idiom.

♻️ Safer comparison
     `@Override`
     public int compareTo(ScoredInvocation other) {
-      int result = score - other.score;
+      int result = Integer.compare(score, other.score);
       if (result != 0) return result;
       return invocation.toString().compareTo(other.invocation.toString());
     }
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@spock-core/src/main/java/org/spockframework/mock/InteractionDiagnostics.java`
around lines 111 - 116, The compareTo implementation in ScoredInvocation inside
InteractionDiagnostics uses subtraction (score - other.score) which can
overflow; replace that subtraction with Integer.compare(score, other.score) to
compute the primary ordering, and keep the existing tie-breaker using
invocation.toString().compareTo(other.invocation.toString()); update the
compareTo(ScoredInvocation other) method accordingly so it returns
Integer.compare(score, other.score) if non-zero, otherwise the invocation string
comparison.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Nitpick comments:
In
`@spock-core/src/main/java/org/spockframework/mock/InteractionDiagnostics.java`:
- Around line 65-76: In appendScoredInvocations, after rendering the invocation
header for entries beyond the MAX_MISMATCH_DESCRIPTIONS limit (using idx and the
existing idx++ check that controls appendMismatchDescription), append a short
note such as " (mismatch details omitted)" to the builder so callers can see why
there is no subsequent mismatch description; keep the current logic that calls
appendMismatchDescription(interaction, si.invocation) for the first
MAX_MISMATCH_DESCRIPTIONS entries and only add the omission note for subsequent
entries.
- Around line 111-116: The compareTo implementation in ScoredInvocation inside
InteractionDiagnostics uses subtraction (score - other.score) which can
overflow; replace that subtraction with Integer.compare(score, other.score) to
compute the primary ordering, and keep the existing tie-breaker using
invocation.toString().compareTo(other.invocation.toString()); update the
compareTo(ScoredInvocation other) method accordingly so it returns
Integer.compare(score, other.score) if non-zero, otherwise the invocation string
comparison.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 833d2e05-8d26-4eed-a3bc-ca529f9a063c

📥 Commits

Reviewing files that changed from the base of the PR and between faba9f0 and 65aae0d.

📒 Files selected for processing (7)
  • docs/release_notes.adoc
  • spock-core/src/main/java/org/spockframework/mock/InteractionDiagnostics.java
  • spock-core/src/main/java/org/spockframework/mock/TooFewInvocationsError.java
  • spock-core/src/main/java/org/spockframework/mock/TooManyInvocationsError.java
  • spock-core/src/main/java/org/spockframework/mock/runtime/MockController.java
  • spock-specs/src/test/groovy/org/spockframework/smoke/mock/TooFewInvocations.groovy
  • spock-specs/src/test/groovy/org/spockframework/smoke/mock/TooManyInvocations.groovy
🚧 Files skipped from review as they are similar to previous changes (1)
  • docs/release_notes.adoc

and check all active scopes
@leonard84 leonard84 requested a review from AndreasTu March 8, 2026 19:07
Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In
`@spock-core/src/main/java/org/spockframework/mock/InteractionDiagnostics.java`:
- Around line 113-118: The compareTo implementation in InteractionDiagnostics'
ScoredInvocation currently compares only count then invocation.toString(),
ignoring the computed similarity score; update
ScoredInvocation.compareTo(ScoredInvocation other) to order by score first
(higher score => comes first), then by count (higher count => comes first), and
finally by invocation.toString() as a stable tie-breaker — use a numeric
comparison for the score (e.g., Double.compare with appropriate sign for
descending order) followed by Integer.compare for count and string comparison
for invocation.toString().

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: a9ad7b05-f38c-4edb-975d-1f0c35bd8dc8

📥 Commits

Reviewing files that changed from the base of the PR and between 65aae0d and 13e615a.

📒 Files selected for processing (6)
  • spock-core/src/main/java/org/spockframework/mock/IInteractionScope.java
  • spock-core/src/main/java/org/spockframework/mock/IMockInteraction.java
  • spock-core/src/main/java/org/spockframework/mock/InteractionDiagnostics.java
  • spock-core/src/main/java/org/spockframework/mock/runtime/InteractionScope.java
  • spock-core/src/main/java/org/spockframework/mock/runtime/MockController.java
  • spock-specs/src/test/groovy/org/spockframework/smoke/mock/TooManyInvocations.groovy
🚧 Files skipped from review as they are similar to previous changes (1)
  • spock-core/src/main/java/org/spockframework/mock/runtime/MockController.java

AndreasTu
AndreasTu previously approved these changes Mar 8, 2026
Copy link
Member

@AndreasTu AndreasTu left a comment

Choose a reason for hiding this comment

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

Thanks for the change and the fixes.

Some test assertions are failing, but the other stuff looks good to me.

@leonard84 leonard84 force-pushed the report-unmatched-on-too-many-invocations branch from 13e615a to 0c764ab Compare March 8, 2026 22:01
@leonard84 leonard84 enabled auto-merge (squash) March 8, 2026 22:04
@leonard84 leonard84 requested a review from AndreasTu March 8, 2026 22:04
Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

♻️ Duplicate comments (1)
spock-core/src/main/java/org/spockframework/mock/InteractionDiagnostics.java (1)

113-118: ⚠️ Potential issue | 🟠 Major

Sort the most relevant invocations to the front.

Line 115 still orders by increasing score, and count is no longer used at all. Since Lines 72-74 and 84-87 only render mismatch details for the first five entries, this can put the least useful diagnostics at the top and hide the better matches behind the cap.

Suggested fix
     `@Override`
     public int compareTo(ScoredInvocation other) {
-      int result = Integer.compare(score, other.score);
+      int result = Integer.compare(other.score, score);
       if (result != 0) return result;
+      result = Integer.compare(other.count, count);
+      if (result != 0) return result;
       return invocation.toString().compareTo(other.invocation.toString());
     }
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@spock-core/src/main/java/org/spockframework/mock/InteractionDiagnostics.java`
around lines 113 - 118, The compareTo implementation in ScoredInvocation orders
by increasing score and ignores count, causing low-relevance entries to appear
first; update ScoredInvocation.compareTo to sort by descending score (compare
other.score to score), then by descending count (compare other.count to count)
as a tie-breaker, and finally by invocation.toString() for deterministic
ordering so the most relevant invocations appear at the front.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In
`@spock-core/src/main/java/org/spockframework/mock/InteractionDiagnostics.java`:
- Around line 95-96: The catch in InteractionDiagnostics currently appends a
hardcoded "<Renderer threw Exception>" even when an AssertionError is caught;
update the catch block in InteractionDiagnostics so the message reflects the
actual throwable (e.g. use a neutral phrase or include
e.getClass().getSimpleName()) instead of always saying "Exception". Locate the
catch (AssertionError | Exception e) and change the builder.append call to
include the runtime type or a neutral label (for example "<Renderer threw: " +
e.getClass().getSimpleName() + ">: " + e.getMessage() or "<Renderer threw an
error>: " + e.getMessage()) so diagnostics are accurate.

---

Duplicate comments:
In
`@spock-core/src/main/java/org/spockframework/mock/InteractionDiagnostics.java`:
- Around line 113-118: The compareTo implementation in ScoredInvocation orders
by increasing score and ignores count, causing low-relevance entries to appear
first; update ScoredInvocation.compareTo to sort by descending score (compare
other.score to score), then by descending count (compare other.count to count)
as a tie-breaker, and finally by invocation.toString() for deterministic
ordering so the most relevant invocations appear at the front.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 17b3c0b7-ed41-4cbb-b00d-330f9ac9d3c2

📥 Commits

Reviewing files that changed from the base of the PR and between 13e615a and 0c764ab.

📒 Files selected for processing (2)
  • spock-core/src/main/java/org/spockframework/mock/IMockInteraction.java
  • spock-core/src/main/java/org/spockframework/mock/InteractionDiagnostics.java
🚧 Files skipped from review as they are similar to previous changes (1)
  • spock-core/src/main/java/org/spockframework/mock/IMockInteraction.java

@leonard84 leonard84 merged commit 9c6342c into spockframework:master Mar 9, 2026
38 of 39 checks passed
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