From a6d47a46f959a9332d858fd31a19d895ec7452dd Mon Sep 17 00:00:00 2001 From: Bruno Bonanno Date: Sat, 16 Mar 2019 20:17:00 +0000 Subject: [PATCH 1/3] Use scalactic Prettifier for EqTo Use EqTo to wrap arguments of a ScalaInvocation --- .../mockito/internal/handler/package.scala | 4 +- .../mockito/internal/handler/package.scala | 4 +- .../mockito/internal/handler/package.scala | 4 +- .../main/scala/org/mockito/MockitoAPI.scala | 34 +++++++++-------- .../scala/org/mockito/ReflectionUtils.scala | 8 ---- .../internal/handler/ScalaMockHandler.scala | 38 ++++++++----------- .../ScalaInvocation.scala | 22 +++++++---- .../mockito/internal/invocation/package.scala | 14 +++++++ .../scala/org/mockito/matchers/EqTo.scala | 9 ++--- .../matchers/EqMatchers_VersionSpecific.scala | 4 +- .../matchers/EqMatchers_VersionSpecific.scala | 9 ++--- .../matchers/EqMatchers_VersionSpecific.scala | 9 ++--- .../scala/org/mockito/IdiomaticMockito.scala | 13 ++++--- .../org/mockito/MockitoScalaSession.scala | 8 ++-- .../scalatest/ResetMocksAfterEachTest.scala | 11 +++--- .../org/mockito/IdiomaticMockitoTest.scala | 23 +++++++++++ .../user/org/mockito/MockitoSugarTest.scala | 27 ++++++++++++- .../scala/user/org/mockito/TestModel.scala | 2 + .../MacroMatchers_211.scala | 10 ++--- 19 files changed, 148 insertions(+), 105 deletions(-) rename common/src/main/scala/org/mockito/internal/{handler => invocation}/ScalaInvocation.scala (76%) create mode 100644 common/src/main/scala/org/mockito/internal/invocation/package.scala diff --git a/common/src/main/scala-2.11/org/mockito/internal/handler/package.scala b/common/src/main/scala-2.11/org/mockito/internal/handler/package.scala index c175abe8..425e3686 100644 --- a/common/src/main/scala-2.11/org/mockito/internal/handler/package.scala +++ b/common/src/main/scala-2.11/org/mockito/internal/handler/package.scala @@ -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) diff --git a/common/src/main/scala-2.12/org/mockito/internal/handler/package.scala b/common/src/main/scala-2.12/org/mockito/internal/handler/package.scala index c175abe8..425e3686 100644 --- a/common/src/main/scala-2.12/org/mockito/internal/handler/package.scala +++ b/common/src/main/scala-2.12/org/mockito/internal/handler/package.scala @@ -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) diff --git a/common/src/main/scala-2.13.0-M5/org/mockito/internal/handler/package.scala b/common/src/main/scala-2.13.0-M5/org/mockito/internal/handler/package.scala index a78f4c10..2a380d70 100644 --- a/common/src/main/scala-2.13.0-M5/org/mockito/internal/handler/package.scala +++ b/common/src/main/scala-2.13.0-M5/org/mockito/internal/handler/package.scala @@ -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) diff --git a/common/src/main/scala/org/mockito/MockitoAPI.scala b/common/src/main/scala/org/mockito/MockitoAPI.scala index ea912e76..6f0387a2 100644 --- a/common/src/main/scala/org/mockito/MockitoAPI.scala +++ b/common/src/main/scala/org/mockito/MockitoAPI.scala @@ -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 /** @@ -139,7 +141,7 @@ private[mockito] trait MockitoEnhancer extends MockCreator { * verify(aMock).iHaveSomeDefaultArguments("I'm not gonna pass the second argument", "default value") * 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 Mockito.mock(type: Class[T], defaultAnswer: Answer[_]) @@ -155,7 +157,7 @@ private[mockito] trait MockitoEnhancer extends MockCreator { * verify(aMock).iHaveSomeDefaultArguments("I'm not gonna pass the second argument", "default value") * 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)) /** @@ -172,7 +174,7 @@ private[mockito] trait MockitoEnhancer extends MockCreator { * verify(aMock).iHaveSomeDefaultArguments("I'm not gonna pass the second argument", "default value") * 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 { @@ -221,12 +223,12 @@ private[mockito] trait MockitoEnhancer extends MockCreator { * verify(aMock).iHaveSomeDefaultArguments("I'm not gonna pass the second argument", "default value") * 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) } @@ -234,7 +236,7 @@ private[mockito] trait MockitoEnhancer extends MockCreator { * Delegates to Mockito.reset(T... mocks), 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() diff --git a/common/src/main/scala/org/mockito/ReflectionUtils.scala b/common/src/main/scala/org/mockito/ReflectionUtils.scala index 4d5e6853..7ef9979e 100644 --- a/common/src/main/scala/org/mockito/ReflectionUtils.scala +++ b/common/src/main/scala/org/mockito/ReflectionUtils.scala @@ -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 - } diff --git a/common/src/main/scala/org/mockito/internal/handler/ScalaMockHandler.scala b/common/src/main/scala/org/mockito/internal/handler/ScalaMockHandler.scala index 4a5c0a9b..640c264f 100644 --- a/common/src/main/scala/org/mockito/internal/handler/ScalaMockHandler.scala +++ b/common/src/main/scala/org/mockito/internal/handler/ScalaMockHandler.scala @@ -5,15 +5,14 @@ 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)) @@ -21,17 +20,16 @@ class ScalaMockHandler[T](mockSettings: MockCreationSettings[T]) extends MockHan 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) @@ -39,19 +37,13 @@ class ScalaMockHandler[T](mockSettings: MockCreationSettings[T]) extends MockHan } 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] diff --git a/common/src/main/scala/org/mockito/internal/handler/ScalaInvocation.scala b/common/src/main/scala/org/mockito/internal/invocation/ScalaInvocation.scala similarity index 76% rename from common/src/main/scala/org/mockito/internal/handler/ScalaInvocation.scala rename to common/src/main/scala/org/mockito/internal/invocation/ScalaInvocation.scala index a91813af..10ad2084 100644 --- a/common/src/main/scala/org/mockito/internal/handler/ScalaInvocation.scala +++ b/common/src/main/scala/org/mockito/internal/invocation/ScalaInvocation.scala @@ -1,11 +1,15 @@ -package org.mockito.internal.handler +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.{MockitoMethod, RealMethod} import org.mockito.internal.invocation.mockref.MockReference -import org.mockito.invocation.{Invocation, Location, StubInfo} +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, @@ -13,8 +17,8 @@ class ScalaInvocation(val mockRef: MockReference[AnyRef], rawArguments: Array[AnyRef], realMethod: RealMethod, location: Location, - sequenceNumber: Int) - extends Invocation + sequenceNumber: Int)(implicit $pt: Prettifier) + extends Invocation with VerificationAwareInvocation { private var verified: Boolean = false @@ -42,13 +46,15 @@ class ScalaInvocation(val mockRef: MockReference[AnyRef], override def equals(other: Any): Boolean = other match { case that: ScalaInvocation => super.equals(that) && - getMock == that.getMock && - mockitoMethod == that.mockitoMethod && - (arguments sameElements that.arguments) + 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) } diff --git a/common/src/main/scala/org/mockito/internal/invocation/package.scala b/common/src/main/scala/org/mockito/internal/invocation/package.scala new file mode 100644 index 00000000..e97edb35 --- /dev/null +++ b/common/src/main/scala/org/mockito/internal/invocation/package.scala @@ -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 + +} diff --git a/common/src/main/scala/org/mockito/matchers/EqTo.scala b/common/src/main/scala/org/mockito/matchers/EqTo.scala index 1d03d3ab..12dc7690 100644 --- a/common/src/main/scala/org/mockito/matchers/EqTo.scala +++ b/common/src/main/scala/org/mockito/matchers/EqTo.scala @@ -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) } diff --git a/core/src/main/scala-2.11/org/mockito/matchers/EqMatchers_VersionSpecific.scala b/core/src/main/scala-2.11/org/mockito/matchers/EqMatchers_VersionSpecific.scala index 3ec70fc6..c2a683d6 100644 --- a/core/src/main/scala-2.11/org/mockito/matchers/EqMatchers_VersionSpecific.scala +++ b/core/src/main/scala-2.11/org/mockito/matchers/EqMatchers_VersionSpecific.scala @@ -1,7 +1,5 @@ package org.mockito.matchers -import org.scalactic.Equality - import scala.language.experimental.macros trait EqMatchers_VersionSpecific { @@ -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, diff --git a/core/src/main/scala-2.12/org/mockito/matchers/EqMatchers_VersionSpecific.scala b/core/src/main/scala-2.12/org/mockito/matchers/EqMatchers_VersionSpecific.scala index 09db237f..7d384515 100644 --- a/core/src/main/scala-2.12/org/mockito/matchers/EqMatchers_VersionSpecific.scala +++ b/core/src/main/scala-2.12/org/mockito/matchers/EqMatchers_VersionSpecific.scala @@ -1,11 +1,8 @@ package org.mockito.matchers import org.mockito.internal.ValueClassExtractor -import org.mockito.{ArgumentMatcher, ArgumentMatchers => JavaMatchers} -import org.scalactic.Equality -import org.scalactic.TripleEquals._ - -import scala.collection.mutable +import org.mockito.{ArgumentMatchers => JavaMatchers} +import org.scalactic.{Equality, Prettifier} trait EqMatchers_VersionSpecific { @@ -13,7 +10,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], $vce: ValueClassExtractor[T]): T = { + def eqTo[T](value: T)(implicit $eq: Equality[T], $vce: ValueClassExtractor[T], $pt: Prettifier): T = { JavaMatchers.argThat(new EqTo[T](value)) value } diff --git a/core/src/main/scala-2.13.0-M5/org/mockito/matchers/EqMatchers_VersionSpecific.scala b/core/src/main/scala-2.13.0-M5/org/mockito/matchers/EqMatchers_VersionSpecific.scala index 4c2d844b..0888a5b0 100644 --- a/core/src/main/scala-2.13.0-M5/org/mockito/matchers/EqMatchers_VersionSpecific.scala +++ b/core/src/main/scala-2.13.0-M5/org/mockito/matchers/EqMatchers_VersionSpecific.scala @@ -1,11 +1,8 @@ package org.mockito.matchers import org.mockito.internal.ValueClassExtractor -import org.mockito.{ArgumentMatcher, ArgumentMatchers => JavaMatchers} -import org.scalactic.Equality -import org.scalactic.TripleEquals._ - -import scala.collection.immutable.ArraySeq +import org.mockito.{ArgumentMatchers => JavaMatchers} +import org.scalactic.{Equality, Prettifier} trait EqMatchers_VersionSpecific { @@ -13,7 +10,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], $vce: ValueClassExtractor[T]): T = { + def eqTo[T](value: T)(implicit $eq: Equality[T], $vce: ValueClassExtractor[T], $pt: Prettifier): T = { JavaMatchers.argThat(new EqTo[T](value)) value } diff --git a/core/src/main/scala/org/mockito/IdiomaticMockito.scala b/core/src/main/scala/org/mockito/IdiomaticMockito.scala index 249f7075..f8dafa10 100644 --- a/core/src/main/scala/org/mockito/IdiomaticMockito.scala +++ b/core/src/main/scala/org/mockito/IdiomaticMockito.scala @@ -4,6 +4,7 @@ import org.mockito.MockitoSugar._ import org.mockito.VerifyMacro._ import org.mockito.WhenMacro._ import org.mockito.stubbing.{ DefaultAnswer, ScalaOngoingStubbing } +import org.scalactic.Prettifier import scala.language.experimental.macros import scala.reflect.ClassTag @@ -11,18 +12,20 @@ import scala.reflect.runtime.universe.WeakTypeTag trait IdiomaticMockito extends MockCreator { - 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 = MockitoSugar.mock[T](name) - override def mock[T <: AnyRef: ClassTag: WeakTypeTag](mockSettings: MockSettings): T = MockitoSugar.mock[T](mockSettings) + override def mock[T <: AnyRef: ClassTag: WeakTypeTag](mockSettings: MockSettings)(implicit $pt: Prettifier): T = + MockitoSugar.mock[T](mockSettings) - override def mock[T <: AnyRef: ClassTag: WeakTypeTag](defaultAnswer: DefaultAnswer): T = + override def mock[T <: AnyRef: ClassTag: WeakTypeTag](defaultAnswer: DefaultAnswer)(implicit $pt: Prettifier): T = MockitoSugar.mock[T](defaultAnswer) - override def mock[T <: AnyRef: ClassTag: WeakTypeTag](implicit defaultAnswer: DefaultAnswer): T = + override def mock[T <: AnyRef: ClassTag: WeakTypeTag](implicit defaultAnswer: DefaultAnswer, $pt: Prettifier): T = MockitoSugar.mock[T] - override def spy[T <: AnyRef: ClassTag: WeakTypeTag](realObj: T, lenient: Boolean = false): T = MockitoSugar.spy(realObj, lenient) + override def spy[T <: AnyRef: ClassTag: WeakTypeTag](realObj: T, lenient: Boolean = false)(implicit $pt: Prettifier): T = + MockitoSugar.spy(realObj, lenient) override def spyLambda[T <: AnyRef: ClassTag](realObj: T): T = MockitoSugar.spyLambda(realObj) diff --git a/core/src/main/scala/org/mockito/MockitoScalaSession.scala b/core/src/main/scala/org/mockito/MockitoScalaSession.scala index 6d662e3d..ec6d236b 100644 --- a/core/src/main/scala/org/mockito/MockitoScalaSession.scala +++ b/core/src/main/scala/org/mockito/MockitoScalaSession.scala @@ -1,13 +1,13 @@ package org.mockito -import org.mockito.MockitoScalaSession.{ MockitoScalaSessionListener, UnexpectedInvocations } -import org.mockito.exceptions.misusing.{ UnexpectedInvocationException, UnnecessaryStubbingException } +import org.mockito.MockitoScalaSession.{MockitoScalaSessionListener, UnexpectedInvocations} +import org.mockito.exceptions.misusing.{UnexpectedInvocationException, UnnecessaryStubbingException} import org.mockito.internal.stubbing.StubbedInvocationMatcher -import org.mockito.invocation.{ DescribedInvocation, Invocation, Location } +import org.mockito.invocation.{DescribedInvocation, Invocation, Location} import org.mockito.listeners.MockCreationListener import org.mockito.mock.MockCreationSettings import org.mockito.quality.Strictness -import org.mockito.quality.Strictness.{ LENIENT, STRICT_STUBS } +import org.mockito.quality.Strictness.{LENIENT, STRICT_STUBS} import org.mockito.session.MockitoSessionLogger import org.scalactic.TripleEquals._ diff --git a/core/src/main/scala/org/mockito/integrations/scalatest/ResetMocksAfterEachTest.scala b/core/src/main/scala/org/mockito/integrations/scalatest/ResetMocksAfterEachTest.scala index 37daa53c..dabbabca 100644 --- a/core/src/main/scala/org/mockito/integrations/scalatest/ResetMocksAfterEachTest.scala +++ b/core/src/main/scala/org/mockito/integrations/scalatest/ResetMocksAfterEachTest.scala @@ -2,8 +2,9 @@ package org.mockito.integrations.scalatest import java.util.concurrent.ConcurrentHashMap -import org.mockito.{MockCreator, MockitoSugar, MockSettings} +import org.mockito.{MockCreator, MockSettings, MockitoSugar} import org.mockito.stubbing.DefaultAnswer +import org.scalactic.Prettifier import org.scalatest.{Outcome, TestSuite} import scala.collection.JavaConverters._ @@ -34,15 +35,15 @@ trait ResetMocksAfterEachTest extends TestSuite with MockCreator { self: MockCre mock } - abstract override def mock[T <: AnyRef: ClassTag: WeakTypeTag](implicit defaultAnswer: DefaultAnswer): T = + abstract override def mock[T <: AnyRef: ClassTag: WeakTypeTag](implicit defaultAnswer: DefaultAnswer, $pt: Prettifier): T = addMock(super.mock[T]) - abstract override def mock[T <: AnyRef: ClassTag: WeakTypeTag](defaultAnswer: DefaultAnswer): T = + abstract override def mock[T <: AnyRef: ClassTag: WeakTypeTag](defaultAnswer: DefaultAnswer)(implicit $pt: Prettifier): T = addMock(super.mock[T](defaultAnswer)) - abstract override def mock[T <: AnyRef: ClassTag: WeakTypeTag](mockSettings: MockSettings): T = + abstract override def mock[T <: AnyRef: ClassTag: WeakTypeTag](mockSettings: MockSettings)(implicit $pt: Prettifier): T = addMock(super.mock[T](mockSettings)) - abstract override def mock[T <: AnyRef: ClassTag: WeakTypeTag](name: String)(implicit defaultAnswer: DefaultAnswer): T = + abstract override def mock[T <: AnyRef: ClassTag: WeakTypeTag](name: String)(implicit defaultAnswer: DefaultAnswer, $pt: Prettifier): T = addMock(super.mock[T](name)) } diff --git a/core/src/test/scala/user/org/mockito/IdiomaticMockitoTest.scala b/core/src/test/scala/user/org/mockito/IdiomaticMockitoTest.scala index 5608e57e..62dfa72b 100644 --- a/core/src/test/scala/user/org/mockito/IdiomaticMockitoTest.scala +++ b/core/src/test/scala/user/org/mockito/IdiomaticMockitoTest.scala @@ -4,6 +4,7 @@ import org.mockito.captor.ArgCaptor import org.mockito.exceptions.verification._ import org.mockito.invocation.InvocationOnMock import org.mockito.{ArgumentMatchersSugar, IdiomaticMockito, MockitoSugar} +import org.scalactic.Prettifier import org.scalatest.prop.TableDrivenPropertyChecks import org.scalatest.{Matchers, WordSpec} import user.org.mockito.matchers.{ValueCaseClass, ValueClass} @@ -12,6 +13,13 @@ case class Bread(name: String) extends AnyVal case class Cheese(name: String) class IdiomaticMockitoTest extends WordSpec with Matchers with IdiomaticMockito with ArgumentMatchersSugar with TableDrivenPropertyChecks { + implicit val prettifier: Prettifier = new Prettifier { + override def apply(o: Any): String = o match { + case Baz2(_, s) => s"PrettifiedBaz($s)" + case other => Prettifier.default(other) + } + } + val scenarios = Table( ("testDouble", "orgDouble", "foo"), ("mock", () => mock[Org], () => mock[Foo]), @@ -580,6 +588,21 @@ class IdiomaticMockitoTest extends WordSpec with Matchers with IdiomaticMockito } + "use Prettifier for the arguments" in { + val aMock = orgDouble() + + aMock.baz(42, Baz2(69, "hola")) + + val e = the[ArgumentsAreDifferent] thrownBy { + aMock.baz(42, Baz2(69, "chau")) was called + } + + e.getMessage should include("Argument(s) are different! Wanted:") + e.getMessage should include("org.baz(42, PrettifiedBaz(hola));") + e.getMessage should include("Actual invocation has different arguments:") + e.getMessage should include("org.baz(42, PrettifiedBaz(chau));") + } + "default answer should deal with default arguments" in { val aMock = foo() diff --git a/core/src/test/scala/user/org/mockito/MockitoSugarTest.scala b/core/src/test/scala/user/org/mockito/MockitoSugarTest.scala index 0936bdc8..bbd9e4e1 100644 --- a/core/src/test/scala/user/org/mockito/MockitoSugarTest.scala +++ b/core/src/test/scala/user/org/mockito/MockitoSugarTest.scala @@ -1,10 +1,11 @@ package user.org.mockito import org.mockito.captor.ArgCaptor -import org.mockito.exceptions.verification.WantedButNotInvoked +import org.mockito.exceptions.verification.{ArgumentsAreDifferent, WantedButNotInvoked} import org.mockito.invocation.InvocationOnMock import org.mockito.stubbing.{CallsRealMethods, DefaultAnswer, ScalaFirstStubbing} import org.mockito.{ArgumentMatchersSugar, MockitoSugar} +import org.scalactic.Prettifier import org.scalatest.prop.TableDrivenPropertyChecks import org.scalatest.{EitherValues, Matchers, OptionValues, WordSpec} import user.org.mockito.matchers.ValueCaseClass @@ -20,6 +21,13 @@ class MockitoSugarTest with OptionValues with TableDrivenPropertyChecks { + implicit val prettifier: Prettifier = new Prettifier { + override def apply(o: Any): String = o match { + case Baz2(_, s) => s"PrettifiedBaz($s)" + case other => Prettifier.default(other) + } + } + val scenarios = Table( ("testDouble", "foo", "higherKinded", "concreteHigherKinded", "fooWithBaz", "baz", "parametrisedTraitInt"), ("mock", @@ -241,6 +249,21 @@ class MockitoSugarTest aMock.traitMethod(4) shouldBe ValueCaseClass(42) aMock.traitMethod(4) shouldBe ValueCaseClass(43) } + + "use Prettifier for the arguments" in { + val aMock = foo() + + aMock.baz(42, Baz2(69, "hola")) + + val e = the[ArgumentsAreDifferent] thrownBy { + verify(aMock).baz(42, Baz2(69, "chau")) + } + + e.getMessage should include("Argument(s) are different! Wanted:") + e.getMessage should include("foo.baz(42, PrettifiedBaz(hola));") + e.getMessage should include("Actual invocation has different arguments:") + e.getMessage should include("foo.baz(42, PrettifiedBaz(chau));") + } } } @@ -310,7 +333,7 @@ class MockitoSugarTest a[WantedButNotInvoked] should be thrownBy verify(aMock).varargMethod(1, 2) } - "should stop the user passing traits in the settings" in { + "stop the user passing traits in the settings" in { a[IllegalArgumentException] should be thrownBy { mock[Foo](withSettings.extraInterfaces(classOf[Baz])) } diff --git a/core/src/test/scala/user/org/mockito/TestModel.scala b/core/src/test/scala/user/org/mockito/TestModel.scala index 08752e3a..5c4ae0d0 100644 --- a/core/src/test/scala/user/org/mockito/TestModel.scala +++ b/core/src/test/scala/user/org/mockito/TestModel.scala @@ -25,6 +25,8 @@ class Foo { def returnsValueCaseClass: ValueCaseClass = ValueCaseClass(-1) def returnsValueCaseClass(i: Int): ValueCaseClass = ValueCaseClass(i) + + def baz(i: Int, b: Baz2): String = "not mocked" } class Bar { diff --git a/macro/src/main/scala-2.11/org.mockito.matchers/MacroMatchers_211.scala b/macro/src/main/scala-2.11/org.mockito.matchers/MacroMatchers_211.scala index 4539b846..1c2b55a9 100644 --- a/macro/src/main/scala-2.11/org.mockito.matchers/MacroMatchers_211.scala +++ b/macro/src/main/scala-2.11/org.mockito.matchers/MacroMatchers_211.scala @@ -2,29 +2,29 @@ package org.mockito.matchers import org.mockito.internal.ValueClassExtractor import org.mockito.{ArgumentMatchers => JavaMatchers} -import org.scalactic.Equality +import org.scalactic.{Equality, Prettifier} import scala.language.experimental.macros import scala.reflect.macros.blackbox object MacroMatchers_211 { - def eqTo[T](value: T)(implicit $eq: Equality[T], $vce: ValueClassExtractor[T]): T = { + def eqTo[T](value: T)(implicit $eq: Equality[T], $vce: ValueClassExtractor[T], $pt: Prettifier): T = { JavaMatchers.argThat(new EqTo[T](value)) value } - def eqToMatcher[T: c.WeakTypeTag](c: blackbox.Context)(value: c.Expr[T])(eq: c.Tree): c.Expr[T] = { + def eqToMatcher[T: c.WeakTypeTag](c: blackbox.Context)(value: c.Expr[T]): c.Expr[T] = { import c.universe._ def isValueClass(tpe: Tree) = tpe.symbol.isClass && tpe.symbol.asClass.isDerivedValueClass val r = c.Expr[T] { c.macroApplication match { - case q"$_.eqTo[$tpe](new $clazz($arg))($_)" if isValueClass(tpe) => + case q"$_.eqTo[$tpe](new $clazz($arg))" if isValueClass(tpe) => q"new $clazz(_root_.org.mockito.matchers.MacroMatchers_211.eqTo($arg))" - case q"$_.eqTo[$tpe](..$arg)($_)" => + case q"$_.eqTo[$tpe](..$arg)" => q"_root_.org.mockito.matchers.MacroMatchers_211.eqTo[$tpe](..$arg)" case o => throw new Exception(s"Couldn't recognize ${show(o)}") From 137f01ffa9a1e78380e1cfbd2e996e6614e10064 Mon Sep 17 00:00:00 2001 From: Bruno Bonanno <241804+bbonanno@users.noreply.github.com> Date: Thu, 4 Apr 2019 18:03:22 +0100 Subject: [PATCH 2/3] Update to mockito 2.26.0 --- build.sbt | 2 +- .../internal/invocation/ScalaInvocation.scala | 29 ++++++++++--------- 2 files changed, 16 insertions(+), 15 deletions(-) diff --git a/build.sbt b/build.sbt index 1a6d8594..a04484ac 100644 --- a/build.sbt +++ b/build.sbt @@ -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", diff --git a/common/src/main/scala/org/mockito/internal/invocation/ScalaInvocation.scala b/common/src/main/scala/org/mockito/internal/invocation/ScalaInvocation.scala index 10ad2084..3cb298b8 100644 --- a/common/src/main/scala/org/mockito/internal/invocation/ScalaInvocation.scala +++ b/common/src/main/scala/org/mockito/internal/invocation/ScalaInvocation.scala @@ -25,20 +25,21 @@ class ScalaInvocation(val mockRef: MockReference[AnyRef], 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 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 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 From 6622328dba30801854b876d262b1d515a96b4744 Mon Sep 17 00:00:00 2001 From: Bruno Bonanno <241804+bbonanno@users.noreply.github.com> Date: Thu, 4 Apr 2019 18:05:04 +0100 Subject: [PATCH 3/3] Bump version to 1.3.0 --- version.properties | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/version.properties b/version.properties index 82b0f48b..220f0538 100644 --- a/version.properties +++ b/version.properties @@ -1,4 +1,4 @@ #Version of the produced binaries. This file is intended to be checked-in. #It will be automatically bumped by release automation. -version=1.2.6 +version=1.3.0 previousVersion=1.2.5