Skip to content

Make vararg checks Scala friendly (for mockito-scala) #3651

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 4 commits into from
May 19, 2025

Conversation

jozic
Copy link
Contributor

@jozic jozic commented May 17, 2025

Motivation

changes in #2807 and other work on varargs made mockito-scala not being able to upgrade mockito-core to 4.10+ as Scala varargs are represented a bit differently.
This PR adds support for default Scala varargs encoding. This and several other minor changes will allow us to upgrade mockito-core in mockito-scala project. Which will fix/close or make it possible to proceed with fixes for

Checklist

  • Read the contributing guide
  • PR should be motivated, i.e. what does it fix, why, and if relevant how
  • If possible / relevant include an example in the description, that could help all readers
    including project members to get a better picture of the change
  • Avoid other runtime dependencies
  • Meaningful commit history ; intention is important please rebase your commit history so that each
    commit is meaningful and help the people that will explore a change in 2 years
  • The pull request follows coding style (run ./gradlew spotlessApply for auto-formatting)
  • Mention Fixes #<issue number> in the description if relevant
  • At least one commit should end with Fixes #<issue number> if relevant

@codecov-commenter
Copy link

codecov-commenter commented May 17, 2025

Codecov Report

All modified and coverable lines are covered by tests ✅

Project coverage is 86.47%. Comparing base (3a631cb) to head (087acb0).
Report is 10 commits behind head on main.

Additional details and impacted files
@@             Coverage Diff              @@
##               main    #3651      +/-   ##
============================================
+ Coverage     86.44%   86.47%   +0.03%     
- Complexity     2956     2964       +8     
============================================
  Files           341      341              
  Lines          8985     9000      +15     
  Branches       1103     1105       +2     
============================================
+ Hits           7767     7783      +16     
+ Misses          936      935       -1     
  Partials        282      282              

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

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

@jozic
Copy link
Contributor Author

jozic commented May 17, 2025

it's not trivial to test scala vararg path, but by making optionalClass method protected i can run a test that covers that branch as well

    // Helper interface to mock Scala Seq
    private interface MockScalaSeq {
    }

    @Test
    public void shouldDetectScalaVarargsProperly() throws Exception {
        // Create a mock Invocation that simulates Scala varargs behavior
        Invocation mockInvocation = mock(Invocation.class);

        // Create a mock method with our fake Scala Seq parameter
        Method mockMethod = mock(Method.class);
        when(mockMethod.getParameterTypes()).thenReturn(new Class<?>[]{ MockScalaSeq.class });
        when(mockMethod.isVarArgs()).thenReturn(false); // Scala varargs are not Java varargs

        // Set up the invocation to return different lengths for raw vs processed arguments
        when(mockInvocation.getMethod()).thenReturn(mockMethod);
        when(mockInvocation.getRawArguments()).thenReturn(new Object[]{new Object[]{"1", "2"}});
        when(mockInvocation.getArguments()).thenReturn(new Object[]{"1", "2"}); // Different length

        // Set up matchers
        List<ArgumentMatcher<?>> matchers = asList(new Equals("1"), new Equals("2"));

        // Create a strategy with spied optionalClass method to force Scala detection
        MatcherApplicationStrategy spyStrategy = spy(getMatcherApplicationStrategyFor(mockInvocation, matchers));

        // Mock the optionalClass method behavior to simulate Scala presence
        doReturn(Optional.of(MockScalaSeq.class)).when(spyStrategy).optionalClass(eq("scala.collection.Seq"));

        // When: Test the strategy
        boolean match = spyStrategy.forEachMatcherAndArgument(recordAction);

        // Then: Assert the match was successful
        assertTrue("Failed to match Scala varargs pattern", match);
        recordAction.assertContainsExactly(new Equals("1"), new Equals("2"));
    }

@jozic jozic marked this pull request as ready for review May 17, 2025 23:11
@TimvdLippe
Copy link
Contributor

Can you add that testcase to our testsuite and make the method package-protected? That way we don't leak it to our users.

Thanks for the fix!

@jozic
Copy link
Contributor Author

jozic commented May 18, 2025

@TimvdLippe added this and several other tests, everything should be covered by the tests now

@jozic
Copy link
Contributor Author

jozic commented May 18, 2025

interesting, CI complains

 org.mockito.internal.invocation.MatcherApplicationStrategyTest ✘ shouldDetectScalaVarargsProperly (1.2s)

    org.mockito.exceptions.base.MockitoException: 
    Cannot mock/spy class java.lang.reflect.Method
    Mockito cannot mock/spy because :
     - final class
        at app//org.mockito.internal.invocation.MatcherApplicationStrategyTest.shouldDetectScalaVarargsProperly(MatcherApplicationStrategyTest.java:275)

but i can't reproduce this neither with jdk 17 or jdk 21

➜  mockito git:(fix-mockito-scala-varargs) ./gradlew :mockito-core:test --tests "org.mockito.internal.invocation.MatcherApplicationStrategyTest"

> Configure project :
Building version '5.17.1-SNAPSHOT'
  - reason: shipkit-auto-version deduced snapshot based on tag: 'v5.17.0'
OpenJDK 64-Bit Server VM warning: Sharing is only supported for boot loader classes because bootstrap classpath has been appended

> Task :mockito-core:test



  17 passing (2.4s)


BUILD SUCCESSFUL in 3s
19 actionable tasks: 5 executed, 14 up-to-date

Publishing build scan...
https://gradle.com/s/jgxrfueeqcawg
                                                                                                                                                                                         /4.2s
➜  mockito git:(fix-mockito-scala-varargs) java --version
openjdk 21.0.7 2025-04-15 LTS
OpenJDK Runtime Environment Temurin-21.0.7+6 (build 21.0.7+6-LTS)
OpenJDK 64-Bit Server VM Temurin-21.0.7+6 (build 21.0.7+6-LTS, mixed mode, sharing)                                                                                                      /0.1s
➜  mockito git:(fix-mockito-scala-varargs) sdk use java 17.0.15-tem

Using java version 17.0.15-tem in this shell.                                                                                                                                            /0.3s
➜  mockito git:(fix-mockito-scala-varargs) ./gradlew :mockito-core:test --tests "org.mockito.internal.invocation.MatcherApplicationStrategyTest"

> Configure project :
Building version '5.17.1-SNAPSHOT'
  - reason: shipkit-auto-version deduced snapshot based on tag: 'v5.17.0'
OpenJDK 64-Bit Server VM warning: Sharing is only supported for boot loader classes because bootstrap classpath has been appended

> Task :mockito-core:test



  17 passing (3.4s)


BUILD SUCCESSFUL in 5s
19 actionable tasks: 8 executed, 6 from cache, 5 up-to-date

Publishing build scan...
https://gradle.com/s/z23sogms32exm
                                                                                                                                                                                         /5.7s
➜  mockito git:(fix-mockito-scala-varargs) 

@jozic
Copy link
Contributor Author

jozic commented May 18, 2025

one more attempt :) removed mocking of final Method class

Copy link
Contributor

@TimvdLippe TimvdLippe left a comment

Choose a reason for hiding this comment

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

Thanks a lot for fixing and great tests!

@TimvdLippe TimvdLippe merged commit 8f15169 into mockito:main May 19, 2025
18 checks passed
@jozic jozic deleted the fix-mockito-scala-varargs branch May 19, 2025 10:20
@jozic
Copy link
Contributor Author

jozic commented May 19, 2025

Thanks for reviewing and merging @TimvdLippe !

Do you have an idea when this can be released? I plan to send some PRs to mockito-scala to upgrade to the latest mockito-core.

Also, do you mind also merging existing green PRs in mockito-scala? Those with dependency updates.
Or you can give me permission to merge in that repo. I promise not to abuse it :)
Thanks again!

@TimvdLippe
Copy link
Contributor

Hey, yes I want to fix the Bytebuddy version bump as well and then plan to release that. Will also look at mockito-scala. If I can't get to that in reasonable time, then I will reach out to you to ask for assistance. Thanks for offering!

@TimvdLippe
Copy link
Contributor

5.18.0 has been released: https://repo1.maven.org/maven2/org/mockito/mockito-core/5.18.0/

svc-squareup-copybara pushed a commit to cashapp/misk that referenced this pull request May 21, 2025
| Package | Type | Package file | Manager | Update | Change |
|---|---|---|---|---|---|
| [org.mockito:mockito-core](https://github.com/mockito/mockito) |
dependencies | misk/gradle/libs.versions.toml | gradle | minor |
`5.17.0` -> `5.18.0` |
|
[com.google.api-client:google-api-client](https://github.com/googleapis/google-api-java-client)
| dependencies | misk/gradle/libs.versions.toml | gradle | minor |
`2.7.2` -> `2.8.0` |
|
[com.google.cloud:google-cloud-logging](https://github.com/googleapis/java-logging)
| dependencies | misk/gradle/libs.versions.toml | gradle | patch |
`3.22.3` -> `3.22.4` |
| [software.amazon.awssdk:sdk-core](https://aws.amazon.com/sdkforjava) |
dependencies | misk/gradle/libs.versions.toml | gradle | patch |
`2.31.46` -> `2.31.47` |
| [software.amazon.awssdk:sqs](https://aws.amazon.com/sdkforjava) |
dependencies | misk/gradle/libs.versions.toml | gradle | patch |
`2.31.46` -> `2.31.47` |
|
[software.amazon.awssdk:dynamodb-enhanced](https://aws.amazon.com/sdkforjava)
| dependencies | misk/gradle/libs.versions.toml | gradle | patch |
`2.31.46` -> `2.31.47` |
| [software.amazon.awssdk:dynamodb](https://aws.amazon.com/sdkforjava) |
dependencies | misk/gradle/libs.versions.toml | gradle | patch |
`2.31.46` -> `2.31.47` |
| [software.amazon.awssdk:aws-core](https://aws.amazon.com/sdkforjava) |
dependencies | misk/gradle/libs.versions.toml | gradle | patch |
`2.31.46` -> `2.31.47` |
| [software.amazon.awssdk:bom](https://aws.amazon.com/sdkforjava) |
dependencies | misk/gradle/libs.versions.toml | gradle | patch |
`2.31.46` -> `2.31.47` |
| [software.amazon.awssdk:auth](https://aws.amazon.com/sdkforjava) |
dependencies | misk/gradle/libs.versions.toml | gradle | patch |
`2.31.46` -> `2.31.47` |

---

### Release Notes

<details>
<summary>mockito/mockito (org.mockito:mockito-core)</summary>

### [`v5.18.0`](https://github.com/mockito/mockito/releases/tag/v5.18.0)

<sup><sup>*Changelog generated by [Shipkit Changelog Gradle
Plugin](https://github.com/shipkit/shipkit-changelog)*</sup></sup>

##### 5.18.0

- 2025-05-20 - [5
commit(s)](mockito/mockito@v5.17.0...v5.18.0)
by Eugene Platonov, Patrick Doyle, Tim van der Lippe, dependabot\[bot]
- Make vararg checks Scala friendly (for mockito-scala)
[(#&#8203;3651)](mockito/mockito#3651)
- For UnfinishedStubbingException, suggest the possibility of another
thread [(#&#8203;3636)](mockito/mockito#3636)
- UnfinishedStubbingException ought to suggest the possibility of
another thread
[(#&#8203;3635)](mockito/mockito#3635)

</details>

<details>
<summary>googleapis/google-api-java-client
(com.google.api-client:google-api-client)</summary>

###
[`v2.8.0`](https://github.com/googleapis/google-api-java-client/blob/HEAD/CHANGELOG.md#280-2025-05-20)

##### Features

- Next release from main branch is 2.8.0
([#&#8203;2563](googleapis/google-api-java-client#2563))
([57882ad](googleapis/google-api-java-client@57882ad))

##### Bug Fixes

- **deps:** Update project.http.version to v1.47.0
([#&#8203;2543](googleapis/google-api-java-client#2543))
([922c382](googleapis/google-api-java-client@922c382))

</details>

<details>
<summary>googleapis/java-logging
(com.google.cloud:google-cloud-logging)</summary>

###
[`v3.22.4`](https://github.com/googleapis/java-logging/blob/HEAD/CHANGELOG.md#3224-2025-05-20)

##### Bug Fixes

- **deps:** Update the Java code generator (gapic-generator-java) to
2.58.0
([45b4878](googleapis/java-logging@45b4878))

##### Dependencies

- Update dependency com.google.cloud:sdk-platform-java-config to v3.48.0
([#&#8203;1808](googleapis/java-logging#1808))
([6327c51](googleapis/java-logging@6327c51))
- Update googleapis/sdk-platform-java action to v2.58.0
([#&#8203;1806](googleapis/java-logging#1806))
([b94da77](googleapis/java-logging@b94da77))

</details>

---

### Configuration

📅 **Schedule**: Branch creation - "after 6pm every weekday,before 2am
every weekday" in timezone Australia/Melbourne, Automerge - At any time
(no schedule defined).

🚦 **Automerge**: Enabled.

♻ **Rebasing**: Never, or you tick the rebase/retry checkbox.

👻 **Immortal**: This PR will be recreated if closed unmerged. Get
[config help](https://github.com/renovatebot/renovate/discussions) if
that's undesired.

---

- [ ] <!-- rebase-check -->If you want to rebase/retry this PR, check
this box

---

This PR has been generated by [Renovate
Bot](https://github.com/renovatebot/renovate).

GitOrigin-RevId: 9d8d16785ba298d4d94b37ef9064309b97747442
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.

3 participants