All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.mockito.VerifyMacro.scala Maven / Gradle / Ivy

The newest version!
package org.mockito

import org.mockito.Utils._
import org.mockito.internal.MacroDebug.debugResult
import org.mockito.internal.verification.VerificationModeFactory
import org.mockito.verification.VerificationMode

import scala.reflect.macros.blackbox

object Called {
  def by[T](stubbing: T): T = macro DoSomethingMacro.calledBy[T]
}

object VerifyMacro extends VerificationMacroTransformer {
  def wasMacro[T: c.WeakTypeTag, R](c: blackbox.Context)(called: c.Tree)(order: c.Expr[VerifyOrder]): c.Expr[R] = {
    val r = c.Expr[R](transformVerification(c)(c.macroApplication))
    debugResult(c)("mockito-print-verify")(r.tree)
    r
  }

  def wasNeverCalledAgainMacro[T: c.WeakTypeTag, R](c: blackbox.Context)(called: c.Tree)($ev: c.Tree): c.Expr[R] = {
    val r = c.Expr[R](transformVerification(c)(c.macroApplication))
    debugResult(c)("mockito-print-verify")(r.tree)
    r
  }

  object Never extends ScalaVerificationMode {
    override def verificationMode: VerificationMode = Mockito.never
  }

  object NeverAgain extends ScalaVerificationMode {
    override def verificationMode: VerificationMode = VerificationModeFactory.noMoreInteractions()
  }

  object Once extends ScalaVerificationMode {
    override def verificationMode: VerificationMode = Mockito.times(1)
  }

}

private[mockito] trait VerificationMacroTransformer {
  protected def transformInvocation(c: blackbox.Context)(invocation: c.Tree, order: c.Tree, times: c.Tree): c.Tree = {
    import c.universe._

    try doTransformInvocation(c)(invocation, order, times)
    catch {
      case e: Exception => throw new Exception(s"Error when transforming invocation ${show(invocation)}", e)
    }
  }

  protected def doTransformInvocation(c: blackbox.Context)(invocation: c.Tree, order: c.Tree, times: c.Tree): c.Tree = {
    import c.universe._

    val pf: PartialFunction[c.Tree, c.Tree] = {
      case q"$obj.$method[..$targs](...$args)" =>
        val newArgs = args.map(a => transformArgs(c)(a))
        q"verification($order.verifyWithMode($obj, $times).$method[..$targs](...$newArgs))"
      case q"$obj.$method[..$targs]" =>
        q"verification($order.verifyWithMode($obj, $times).$method[..$targs])"
    }

    if (pf.isDefinedAt(invocation))
      pf(invocation)
    else if (invocation.children.nonEmpty && pf.isDefinedAt(invocation.children.last)) {
      val vals = invocation.children.dropRight(1)
      val valsByName = vals.collect { case line @ q"$_ val $name:$_ = $value" =>
        name.toString -> (value.asInstanceOf[c.Tree], line)
      }.toMap

      val inlinedArgsCall = invocation.children.last match {
        case q"$obj.$method[..$targs](...$args)" =>
          val newArgs = args.map { a =>
            transformArgs(c)(a).map {
              case p if show(p).startsWith("x$") => transformArg(c)(valsByName(p.toString)._1)
              case other                         => other
            }
          }
          q"verification($order.verifyWithMode($obj, $times).$method[..$targs](...$newArgs))"
      }

      val call = show(inlinedArgsCall)
      val usedVals = valsByName.collect {
        case (name, (_, line)) if call.contains(name) => line
      }

      q"..$usedVals; $inlinedArgsCall"
    } else throw new Exception(s"Couldn't recognize invocation ${show(invocation)}")
  }

  protected def transformVerification[T: c.WeakTypeTag, R](c: blackbox.Context)(called: c.Tree): c.Tree = {
    import c.universe._

    def transformMockWasNeverCalled(obj: c.Tree, called: c.Tree): c.Tree =
      called match {
        case q"$_.called"      => q"verification(_root_.org.mockito.MockitoSugar.verifyZeroInteractions($obj))"
        case q"$_.calledAgain" => q"verification(_root_.org.mockito.MockitoSugar.verifyNoMoreInteractions($obj))"
        case q"$_.calledAgain.apply($_.ignoringStubs)" =>
          q"verification(_root_.org.mockito.MockitoSugar.verifyNoMoreInteractions(_root_.org.mockito.MockitoSugar.ignoreStubs($obj): _*))"
      }

    called match {
      case q"$_.VerifyingOps[$_]($invocation).was($_.called)($order)" =>
        transformInvocation(c)(invocation, order, q"_root_.org.mockito.VerifyMacro.Once")

      case q"$_.VerifyingOps[$_]($a.$b).wasNever($called)($order)" =>
        q"""
           if (_root_.org.mockito.MockitoSugar.mockingDetails($a).isMock) {
            ${called match {
            case q"$_.calledAgain" =>
              val calledPattern = show(q"$a.$b")
              q"""throw new _root_.org.mockito.exceptions.misusing.NotAMockException(Seq(
                "[" + $calledPattern + "] is not a mock!",
                "Example of correct verification:",
                "    myMock wasNever called",
                ""
              ).mkString("\n"))
             """
            case _ => transformInvocation(c)(q"$a.$b", order, q"_root_.org.mockito.VerifyMacro.Never")
          }}
          } else { 
            ${transformMockWasNeverCalled(q"$a.$b", called)}
          }
         """

      case q"$_.VerifyingOps[$_]($obj.$method[..$targs](...$args)).wasNever($_.called)($order)" =>
        transformInvocation(c)(q"$obj.$method[..$targs](...$args)", order, q"_root_.org.mockito.VerifyMacro.Never")

      case q"$_.VerifyingOps[$_]($obj).wasNever($called)($_)" =>
        transformMockWasNeverCalled(obj, called)

      case q"$_.VerifyingOps[$_]($invocation).wasCalled($times)($order)" =>
        transformInvocation(c)(invocation, order, times)

      case o => throw new Exception(s"VerifyMacro: Couldn't recognize ${show(o)}")
    }
  }
}

trait ScalaVerificationMode {
  def verificationMode: VerificationMode
}

sealed trait VerifyOrder {
  def verify[T](mock: T): T
  def verifyWithMode[T](mock: T, mode: ScalaVerificationMode): T
}

object VerifyUnOrdered extends VerifyOrder {
  override def verify[T](mock: T): T                                      = Mockito.verify(mock)
  override def verifyWithMode[T](mock: T, mode: ScalaVerificationMode): T = Mockito.verify(mock, mode.verificationMode)
}

case class VerifyInOrder(mocks: Seq[AnyRef]) extends VerifyOrder {
  private val _inOrder = Mockito.inOrder(mocks: _*)

  override def verify[T](mock: T): T                                      = _inOrder.verify(mock)
  override def verifyWithMode[T](mock: T, mode: ScalaVerificationMode): T = _inOrder.verify(mock, mode.verificationMode)
  def verifyNoMoreInteractions(): Unit                                    = _inOrder.verifyNoMoreInteractions()
}

object VerifyOrder {
  implicit val unOrdered: VerifyOrder = VerifyUnOrdered
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy