Skip to content

Use Scalactic Prettifier for EqTo #93

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 3 commits into from
Apr 4, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion build.sbt
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ lazy val commonSettings =
)

lazy val commonLibraries = Seq(
"org.mockito" % "mockito-core" % "2.24.0",
"org.mockito" % "mockito-core" % "2.26.0",
"org.scalactic" %% "scalactic" % "3.0.6-SNAP6",
"ru.vyarus" % "generics-resolver" % "3.0.0",
"org.scalatest" %% "scalatest" % "3.0.6-SNAP6" % "provided",
Expand Down
Original file line number Diff line number Diff line change
@@ -1,11 +1,9 @@
package org.mockito.internal

import org.mockito.internal.invocation.MockitoMethod

import scala.collection.mutable

package object handler {
def unwrapVarargs(method: MockitoMethod, args: Array[Any]): Array[Any] =
def unwrapVarargs(args: Array[Any]): Array[Any] =
args.flatMap[Any, Array[Any]] {
case a: mutable.WrappedArray[_] => a.array
case other => Array[Any](other)
Expand Down
Original file line number Diff line number Diff line change
@@ -1,11 +1,9 @@
package org.mockito.internal

import org.mockito.internal.invocation.MockitoMethod

import scala.collection.mutable

package object handler {
def unwrapVarargs(method: MockitoMethod, args: Array[Any]): Array[Any] =
def unwrapVarargs(args: Array[Any]): Array[Any] =
args.flatMap[Any, Array[Any]] {
case a: mutable.WrappedArray[_] => a.array
case other => Array[Any](other)
Expand Down
Original file line number Diff line number Diff line change
@@ -1,11 +1,9 @@
package org.mockito.internal

import org.mockito.internal.invocation.MockitoMethod

import scala.collection.immutable.ArraySeq

package object handler {
def unwrapVarargs(method: MockitoMethod, args: Array[Any]): Array[Any] =
def unwrapVarargs(args: Array[Any]): Array[Any] =
args.toIterable.flatMap {
case a: ArraySeq[_] => a.unsafeArray
case other => Array[Any](other)
Expand Down
34 changes: 18 additions & 16 deletions common/src/main/scala/org/mockito/MockitoAPI.scala
Original file line number Diff line number Diff line change
Expand Up @@ -20,21 +20,23 @@ import org.mockito.internal.progress.ThreadSafeMockingProgress.mockingProgress
import org.mockito.internal.util.reflection.LenientCopyTool
import org.mockito.invocation.InvocationOnMock
import org.mockito.mock.MockCreationSettings
import org.mockito.stubbing.{Answer, DefaultAnswer, ScalaFirstStubbing, Stubber}
import org.mockito.verification.{VerificationMode, VerificationWithTimeout}
import org.mockito.stubbing.{ Answer, DefaultAnswer, ScalaFirstStubbing, Stubber }
import org.mockito.verification.{ VerificationMode, VerificationWithTimeout }
import org.scalactic.Prettifier

import scala.collection.JavaConverters._
import scala.reflect.ClassTag
import scala.reflect.runtime.universe.WeakTypeTag

private[mockito] trait MockCreator {
def mock[T <: AnyRef: ClassTag: WeakTypeTag](implicit defaultAnswer: DefaultAnswer): T
def mock[T <: AnyRef: ClassTag: WeakTypeTag](defaultAnswer: Answer[_]): T = mock[T](DefaultAnswer(defaultAnswer))
def mock[T <: AnyRef: ClassTag: WeakTypeTag](defaultAnswer: DefaultAnswer): T
def mock[T <: AnyRef: ClassTag: WeakTypeTag](mockSettings: MockSettings): T
def mock[T <: AnyRef: ClassTag: WeakTypeTag](name: String)(implicit defaultAnswer: DefaultAnswer): T

def spy[T <: AnyRef: ClassTag: WeakTypeTag](realObj: T, lenient: Boolean): T
def mock[T <: AnyRef: ClassTag: WeakTypeTag](implicit defaultAnswer: DefaultAnswer, $pt: Prettifier): T
def mock[T <: AnyRef: ClassTag: WeakTypeTag](defaultAnswer: Answer[_])(implicit $pt: Prettifier): T =
mock[T](DefaultAnswer(defaultAnswer))
def mock[T <: AnyRef: ClassTag: WeakTypeTag](defaultAnswer: DefaultAnswer)(implicit $pt: Prettifier): T
def mock[T <: AnyRef: ClassTag: WeakTypeTag](mockSettings: MockSettings)(implicit $pt: Prettifier): T
def mock[T <: AnyRef: ClassTag: WeakTypeTag](name: String)(implicit defaultAnswer: DefaultAnswer, $pt: Prettifier): T

def spy[T <: AnyRef: ClassTag: WeakTypeTag](realObj: T, lenient: Boolean)(implicit $pt: Prettifier): T
def spyLambda[T <: AnyRef: ClassTag](realObj: T): T

/**
Expand Down Expand Up @@ -139,7 +141,7 @@ private[mockito] trait MockitoEnhancer extends MockCreator {
* <code>verify(aMock).iHaveSomeDefaultArguments("I'm not gonna pass the second argument", "default value")</code>
* as the value for the second parameter would have been null...
*/
override def mock[T <: AnyRef: ClassTag: WeakTypeTag](implicit defaultAnswer: DefaultAnswer): T = mock(withSettings)
override def mock[T <: AnyRef: ClassTag: WeakTypeTag](implicit defaultAnswer: DefaultAnswer, $pt: Prettifier): T = mock(withSettings)

/**
* Delegates to <code>Mockito.mock(type: Class[T], defaultAnswer: Answer[_])</code>
Expand All @@ -155,7 +157,7 @@ private[mockito] trait MockitoEnhancer extends MockCreator {
* <code>verify(aMock).iHaveSomeDefaultArguments("I'm not gonna pass the second argument", "default value")</code>
* as the value for the second parameter would have been null...
*/
override def mock[T <: AnyRef: ClassTag: WeakTypeTag](defaultAnswer: DefaultAnswer): T =
override def mock[T <: AnyRef: ClassTag: WeakTypeTag](defaultAnswer: DefaultAnswer)(implicit $pt: Prettifier): T =
mock(withSettings(defaultAnswer))

/**
Expand All @@ -172,7 +174,7 @@ private[mockito] trait MockitoEnhancer extends MockCreator {
* <code>verify(aMock).iHaveSomeDefaultArguments("I'm not gonna pass the second argument", "default value")</code>
* as the value for the second parameter would have been null...
*/
override def mock[T <: AnyRef: ClassTag: WeakTypeTag](mockSettings: MockSettings): T = {
override def mock[T <: AnyRef: ClassTag: WeakTypeTag](mockSettings: MockSettings)(implicit $pt: Prettifier): T = {
val interfaces = ReflectionUtils.interfaces

val realClass: Class[T] = mockSettings match {
Expand Down Expand Up @@ -221,20 +223,20 @@ private[mockito] trait MockitoEnhancer extends MockCreator {
* <code>verify(aMock).iHaveSomeDefaultArguments("I'm not gonna pass the second argument", "default value")</code>
* as the value for the second parameter would have been null...
*/
override def mock[T <: AnyRef: ClassTag: WeakTypeTag](name: String)(implicit defaultAnswer: DefaultAnswer): T =
override def mock[T <: AnyRef: ClassTag: WeakTypeTag](name: String)(implicit defaultAnswer: DefaultAnswer, $pt: Prettifier): T =
mock(withSettings.name(name))

def spy[T <: AnyRef: ClassTag: WeakTypeTag](realObj: T, lenient: Boolean = false): T = {
def spy[T <: AnyRef: ClassTag: WeakTypeTag](realObj: T, lenient: Boolean = false)(implicit $pt: Prettifier): T = {
def mockSettings: MockSettings = Mockito.withSettings().defaultAnswer(CALLS_REAL_METHODS).spiedInstance(realObj)
val settings = if(lenient) mockSettings.lenient() else mockSettings
val settings = if (lenient) mockSettings.lenient() else mockSettings
mock[T](settings)
}

/**
* Delegates to <code>Mockito.reset(T... mocks)</code>, but restores the default stubs that
* deal with default argument values
*/
def reset(mocks: AnyRef*): Unit = {
def reset(mocks: AnyRef*)(implicit $pt: Prettifier): Unit = {
val mp = mockingProgress()
mp.validateState()
mp.reset()
Expand Down
8 changes: 0 additions & 8 deletions common/src/main/scala/org/mockito/ReflectionUtils.scala
Original file line number Diff line number Diff line change
Expand Up @@ -99,12 +99,4 @@ private[mockito] object ReflectionUtils {
.getOrElse(ArgumentExtractor.Empty)
}
)

def readDeclaredField[T](o: AnyRef, field: String): Option[T] =
scala.util.Try {
val f = o.getClass.getDeclaredField(field)
f.setAccessible(true)
f.get(o).asInstanceOf[T]
}.toOption

}

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -5,53 +5,45 @@ import java.lang.reflect.Method
import java.lang.reflect.Modifier.isAbstract
import java.util.concurrent.ConcurrentHashMap

import org.mockito.ReflectionUtils.readDeclaredField
import org.mockito.internal.handler.ScalaMockHandler._
import org.mockito.internal.invocation.mockref.MockReference
import org.mockito.internal.invocation.{ InterceptedInvocation, MockitoMethod, RealMethod }
import org.mockito.internal.invocation._
import org.mockito.invocation.{ Invocation, MockHandler }
import org.mockito.mock.MockCreationSettings
import org.scalactic.Prettifier
import org.scalactic.TripleEquals._

class ScalaMockHandler[T](mockSettings: MockCreationSettings[T]) extends MockHandlerImpl[T](mockSettings) {
class ScalaMockHandler[T](mockSettings: MockCreationSettings[T])(implicit $pt: Prettifier) extends MockHandlerImpl[T](mockSettings) {

override def handle(invocation: Invocation): AnyRef =
if (invocation.getMethod.getName.contains("$default$") && !isAbstract(invocation.getMethod.getModifiers))
invocation.callRealMethod()
else {
val scalaInvocation = invocation match {
case i: InterceptedInvocation =>
val scalaInvocation = for {
mockitoMethod <- i.mockitoMethod
mockRef <- i.mockRef
realMethod <- i.realMethod
rawArguments = i.getRawArguments
arguments = if (rawArguments != null && rawArguments.nonEmpty)
unwrapVarargs(mockitoMethod, unwrapByNameArgs(mockitoMethod, rawArguments.asInstanceOf[Array[Any]]))
val mockitoMethod = i.getMockitoMethod
val rawArguments = i.getRawArguments
val arguments =
if (rawArguments != null && rawArguments.nonEmpty)
unwrapVarargs(unwrapByNameArgs(mockitoMethod.getJavaMethod, rawArguments))
.asInstanceOf[Array[AnyRef]]
else rawArguments
} yield new ScalaInvocation(mockRef, mockitoMethod, arguments, rawArguments, realMethod, i.getLocation, i.getSequenceNumber)
scalaInvocation.getOrElse(invocation)

new ScalaInvocation(i.getMockRef, mockitoMethod, arguments, rawArguments, i.getRealMethod, i.getLocation, i.getSequenceNumber)

case other => other
}
super.handle(scalaInvocation)
}
}

object ScalaMockHandler {
def apply[T](mockSettings: MockCreationSettings[T]): MockHandler[T] =
def apply[T](mockSettings: MockCreationSettings[T])(implicit $pt: Prettifier): MockHandler[T] =
new InvocationNotifierHandler[T](new ScalaNullResultGuardian[T](new ScalaMockHandler(mockSettings)), mockSettings)

implicit class InterceptedInvocationOps(i: InterceptedInvocation) {
def mockitoMethod: Option[MockitoMethod] = readDeclaredField(i, "mockitoMethod")
def mockRef: Option[MockReference[Object]] = readDeclaredField(i, "mockRef")
def realMethod: Option[RealMethod] = readDeclaredField(i, "realMethod")
}

private def unwrapByNameArgs(method: MockitoMethod, args: Array[Any]): Array[Any] =
private def unwrapByNameArgs(method: Method, args: Array[AnyRef]): Array[Any] =
Extractors
.getOrDefault(method.getJavaMethod.getDeclaringClass, ArgumentExtractor.Empty)
.transformArgs(method.getJavaMethod, args.asInstanceOf[Array[Any]])
.getOrDefault(method.getDeclaringClass, ArgumentExtractor.Empty)
.transformArgs(method, args.asInstanceOf[Array[Any]])

val Extractors = new ConcurrentHashMap[Class[_], ArgumentExtractor]

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
package org.mockito.internal.invocation

import java.lang.reflect.Method
import java.util

import org.mockito.ArgumentMatcher
import org.mockito.internal.exceptions.Reporter.cannotCallAbstractRealMethod
import org.mockito.internal.exceptions.VerificationAwareInvocation
import org.mockito.internal.invocation.mockref.MockReference
import org.mockito.internal.reporting.PrintSettings
import org.mockito.invocation.{ Invocation, Location, StubInfo }
import org.scalactic.Prettifier

class ScalaInvocation(val mockRef: MockReference[AnyRef],
val mockitoMethod: MockitoMethod,
val arguments: Array[AnyRef],
rawArguments: Array[AnyRef],
realMethod: RealMethod,
location: Location,
sequenceNumber: Int)(implicit $pt: Prettifier)
extends Invocation
with VerificationAwareInvocation {

private var verified: Boolean = false
private var _isIgnoredForVerification: Boolean = false
private var _stubInfo: StubInfo = _

override def getArguments: Array[AnyRef] = arguments
override def getArgument[T](index: Int): T = arguments(index).asInstanceOf[T]
override def getArgument[T](index: Int, clazz: Class[T]): T = clazz.cast(arguments(index))
override def getSequenceNumber: Int = sequenceNumber
override def getLocation: Location = location
override def getRawArguments: Array[AnyRef] = rawArguments
override def getRawReturnType: Class[_] = mockitoMethod.getReturnType
override def markVerified(): Unit = verified = true
override def stubInfo(): StubInfo = _stubInfo
override def markStubbed(stubInfo: StubInfo): Unit = _stubInfo = stubInfo
override def isIgnoredForVerification: Boolean = _isIgnoredForVerification
override def ignoreForVerification(): Unit = _isIgnoredForVerification = true
override def isVerified: Boolean = verified || isIgnoredForVerification
override def getMock: AnyRef = mockRef.get
override def getMethod: Method = mockitoMethod.getJavaMethod
override def callRealMethod(): AnyRef =
if (realMethod.isInvokable) realMethod.invoke
else throw cannotCallAbstractRealMethod

override def equals(other: Any): Boolean = other match {
case that: ScalaInvocation =>
super.equals(that) &&
getMock == that.getMock &&
mockitoMethod == that.mockitoMethod &&
(arguments sameElements that.arguments)
case _ => false
}
override def hashCode(): Int = {
val state = Seq(super.hashCode(), mockRef.get, mockitoMethod, arguments)
state.map(_.hashCode()).foldLeft(0)((a, b) => 31 * a + b)
}
override def toString: String = new PrintSettings().print(getArgumentsAsMatchers, this)
override def getArgumentsAsMatchers: util.List[ArgumentMatcher[_]] = argumentsToMatchers(arguments)
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
package org.mockito.internal

import org.mockito.ArgumentMatcher
import org.mockito.matchers.EqTo
import org.scalactic.Prettifier

import scala.collection.JavaConverters._

package object invocation {

def argumentsToMatchers(arguments: Iterable[Any])(implicit $pt: Prettifier): java.util.List[ArgumentMatcher[_]] =
arguments.map(EqTo(_).asInstanceOf[ArgumentMatcher[_]]).toList.asJava

}
9 changes: 4 additions & 5 deletions common/src/main/scala/org/mockito/matchers/EqTo.scala
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,10 @@ package org.mockito.matchers

import org.mockito.ArgumentMatcher
import org.mockito.internal.ValueClassExtractor
import org.scalactic.Equality
import org.scalactic.{ Equality, Prettifier }
import org.scalactic.TripleEquals._

case class EqTo[T](value: T)(implicit $eq: Equality[T], $vce: ValueClassExtractor[T]) extends ArgumentMatcher[T] {
override def matches(argument: T): Boolean =
value === argument || $vce.extractAs[T](value) === argument
override def toString: String = value.toString
case class EqTo[T](value: T)(implicit $eq: Equality[T], $vce: ValueClassExtractor[T], $pt: Prettifier) extends ArgumentMatcher[T] {
override def matches(argument: T): Boolean = value === argument || $vce.extractAs[T](value) === argument
override def toString: String = $pt(value)
}
Original file line number Diff line number Diff line change
@@ -1,7 +1,5 @@
package org.mockito.matchers

import org.scalactic.Equality

import scala.language.experimental.macros

trait EqMatchers_VersionSpecific {
Expand All @@ -10,7 +8,7 @@ trait EqMatchers_VersionSpecific {
* Creates a matcher that delegates on {{org.scalactic.Equality}} so you can always customise how the values are compared
* Also works with value classes
*/
def eqTo[T](value: T)(implicit eq: Equality[T]): T = macro MacroMatchers_211.eqToMatcher[T]
def eqTo[T](value: T): T = macro MacroMatchers_211.eqToMatcher[T]

/**
* It was intended to be used instead of eqTo when the argument is a value class,
Expand Down
Loading