Skip to content

Commit

Permalink
Implementation & test
Browse files Browse the repository at this point in the history
Also follow the same ScalaMocks pattern as the core library
  • Loading branch information
fmonniot committed Dec 9, 2023
1 parent 96cbce5 commit 89a66a8
Show file tree
Hide file tree
Showing 3 changed files with 63 additions and 16 deletions.
9 changes: 7 additions & 2 deletions build.sbt
Expand Up @@ -47,8 +47,13 @@ lazy val cats = project
.in(file("./cats"))
.dependsOn(core)
.settings(
name := "scala3mock-scalatest",
libraryDependencies += "org.typelevel" %% "cats-core" % "2.9.0"
name := "scala3mock-cats",
libraryDependencies += "org.typelevel" %% "cats-core" % "2.9.0",

libraryDependencies ++= Seq(
"org.scalameta" %% "munit" % "1.0.0-M10" % Test,
"org.typelevel" %% "cats-effect" % "3.5.2" % Test
)
)

lazy val scalatest = project
Expand Down
Expand Up @@ -4,26 +4,45 @@ import cats.MonadError
import eu.monniot.scala3mock.context.{Call, MockContext}
import eu.monniot.scala3mock.functions.MockFunction1
import eu.monniot.scala3mock.handlers.{CallHandler, Handler, UnorderedHandlers}
import eu.monniot.scala3mock.main.TestExpectationEx
import eu.monniot.scala3mock.MockExpectationFailed

import scala.annotation.unused
import scala.collection.mutable.ListBuffer
import scala.util.control.NonFatal



object ScalaMocks extends ScalaMocks

/** Helper trait that provide access to all components (mandatory or optional)
* used by the library to build mocks.
*/
trait ScalaMocks
extends eu.monniot.scala3mock.functions.MockFunctions
with eu.monniot.scala3mock.macros.Mocks
with eu.monniot.scala3mock.matchers.Matchers:

// apparently using export in 3.2.2 lose the default value of the
// parameter. That might have been fixed in 3.3+, but we can't use
// that version so for now we will duplicate the definition.
def withExpectations[F[_], A](verifyAfterRun: Boolean = true)(
f: MockContext ?=> F[A]
)(using MonadError[F, Throwable]): F[A] = eu.monniot.scala3mock.cats.withExpectations(verifyAfterRun)(f)


// A standalone function to run a test with a mock context, asserting all expectations at the end.
def withExpectations[F[_], A](verifyAfterRun: Boolean = true)(
f: MockContext ?=> F[A]
)(using MonadError[F, Throwable]): F[A] =

val ctx = new MockContext:
override type ExpectationException = TestExpectationEx
override type ExpectationException = MockExpectationFailed

override def newExpectationException(
message: String,
methodName: Option[String]
): ExpectationException =
new TestExpectationEx(message, methodName)
new MockExpectationFailed(message, methodName)

override def toString() = s"MockContext(callLog = $callLog)"

Expand All @@ -42,14 +61,16 @@ def withExpectations[F[_], A](verifyAfterRun: Boolean = true)(
if !oldExpectationContext.isSatisfied then
ctx.reportUnsatisfiedExpectation(oldCallLog, oldExpectationContext)

try
initializeExpectations()
MonadError[F, Throwable] // TODO Wire the result and verification correctly
val result = f(using ctx)
if verifyAfterRun then verifyExpectations()
result
catch
case NonFatal(ex) =>
// do not verify expectations - just clear them. Throw original exception
// see issue #72
throw ex
initializeExpectations()
val me = MonadError[F, Throwable]

me.flatMap(f(using ctx)) { a =>
if verifyAfterRun then
try
verifyExpectations()
me.pure(a)
catch
case t => me.raiseError(t)
else
me.pure(a)
}
21 changes: 21 additions & 0 deletions cats/src/test/scala/eu/monniot/scala3mock/cats/CatsSuite.scala
@@ -0,0 +1,21 @@
package eu.monniot.scala3mock.cats

import cats.effect.SyncIO

class CatsSuite extends munit.FunSuite with ScalaMocks {

test("it should validate expectations after a lazy data type evaluated") {
// An implicit assumption of this code block is that the expectations
// are not validated on exit of the `withExpectations` function but when
// the returned Monad is being evaluated.
val fa = withExpectations() {
val intToStringMock = mockFunction[Int, String]
intToStringMock.expects(*)

SyncIO(intToStringMock(2))
}

assertEquals(fa.unsafeRunSync(), null)
}

}

0 comments on commit 89a66a8

Please sign in to comment.