Skip to content
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

PrivateMethodTester fails for AnyVal types #2224

Open
cptwunderlich opened this issue Jan 27, 2023 · 1 comment
Open

PrivateMethodTester fails for AnyVal types #2224

cptwunderlich opened this issue Jan 27, 2023 · 1 comment

Comments

@cptwunderlich
Copy link

Using Scala 2, I tried testing a private method using PrivateMethodTester, which takes an AnyVal wrapper type.
Invocation fails with IllegalArgumentException("Can't find a private method named: "....

While debugging the issue, I found that Java reflection is used to get the argument types and then compared to the nominal argument types.

However, AnyVal types get erased.
Adding the following test case to PrivateMethodTesterSpec.scala should fail:

it("should work if the private method takes an AnyVal") {

    final case class Wrapper(value: Int) extends AnyVal

    class Modest {
      private def secret(w: Wrapper) = w.value + 42
    }
    val secret = PrivateMethod[Int](Symbol("secret"))
    assert(((new Modest) invokePrivate secret(Wrapper(1))) === 43)
}

Passing a value of the underlying type directly to the invocation, in this case secret(1), works.

IMHO, this is unexpected. I have no experience with Scala reflection and couldn't get something to work. Also, it seems like this has changed a lot from version 2 to 3.


scalatest version: 3.2.15
scala version: 2.13.10
java version: openjdk 11.0.17

@cheeseng
Copy link
Contributor

cheeseng commented Jul 5, 2023

@cptwunderlich Sorry for the really late response, somehow I missed this.

The PrivateMethodTester is implemented with java reflection, and at runtime there's no way we can determine that Wrapper is AnyVal, at JVM level the def secret takes an int as its argument but an instance Wrapper is being passed in. There is no precise way at runtime we can determine that Wrapper is an AnyVal and handle it accordingly.

One possible approach is we have do the check at compile time, there's a way to determine the whether a type being passed in is AnyVal like described here:

https://stackoverflow.com/questions/19656353/scala-recognising-objects-of-value-classes

To use that I imagine we'll need overload functions of apply with type parameters here that takes different number of arguments here:

https://github.com/scalatest/scalatest/blob/main/jvm/core/src/main/scala/org/scalatest/PrivateMethodTester.scala#L108

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

No branches or pull requests

2 participants