Created
October 1, 2025 14:05
-
-
Save zainab-ali/ceaf90cb04773262468f3d369e1fc0ec to your computer and use it in GitHub Desktop.
Demonstrates usage of `Provider` vs `SharedResourceSuite`
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
//> using scala "3.7.0" | |
//> using test.dep org.typelevel::weaver-cats::0.11-5acfd6a-SNAPSHOT | |
//> using repository "https://central.sonatype.com/repository/maven-snapshots" | |
import cats.effect.* | |
import cats.* | |
import cats.data.OptionT | |
import weaver.* | |
import fs2.* | |
type MyEffect[A] = OptionT[IO, A] | |
val asyncInstance = implicitly[Async[MyEffect]] | |
val parallelInstance = implicitly[Parallel[MyEffect]] | |
// This demonstrates how `getSuite` might be used to construct tests with different effect types. | |
abstract class MyOldSuite extends MutableFSuite[MyEffect] with BaseCatsSuite { | |
outer => | |
// The Async instance for OptionT causes a deadlock in the stream on parEvalMap. | |
// Set the concurrency to 1 so evalMap is used instead. | |
override def maxParallelism: Int = 1 | |
type Res = Unit | |
def sharedResource: Resource[MyEffect, Unit] = Resource.pure(()) | |
// The user has to declare an UnsafeRun instance for their effect type | |
implicit protected def effectCompat: UnsafeRun[MyEffect] = | |
new UnsafeRun[MyEffect] { | |
implicit def effect: cats.effect.kernel.Async[MyEffect] = asyncInstance | |
implicit def parallel: cats.Parallel[MyEffect] = parallelInstance | |
type CancelToken = CatsUnsafeRun.CancelToken | |
def background(task: MyEffect[Unit]): CancelToken = | |
CatsUnsafeRun.background(task.value.as(())) | |
def cancel(token: CancelToken): Unit = CatsUnsafeRun.cancel(token) | |
def unsafeRunAndForget(task: MyEffect[Unit]): Unit = | |
CatsUnsafeRun.unsafeRunAndForget(task.value.as(())) | |
def unsafeRunSync(task: MyEffect[Unit]): Unit = | |
CatsUnsafeRun.unsafeRunSync(task.value.as(())) | |
def unsafeRunToFuture( | |
task: MyEffect[Unit]): scala.concurrent.Future[Unit] = | |
CatsUnsafeRun.unsafeRunToFuture(task.value.as(())) | |
} | |
// If any tests return None, discard all test outcomes. | |
// This is unlikely to be what users will implement, but I'm not | |
// sure what the real use cases of OptionT are. | |
def getSuite: weaver.EffectSuite[IO] = new EffectSuite[IO] { | |
implicit protected def effectCompat: UnsafeRun[IO] = CatsUnsafeRun | |
def spec(args: List[String]): Stream[IO, TestOutcome] = { | |
val maybeOutcomes = outer.spec(args).compile.toList.value | |
Stream.evals(maybeOutcomes.map(_.getOrElse(Nil))) | |
} | |
} | |
} | |
// A usage example. None of the tests are reported due to the OptionT.none instance. | |
object MyOldTest extends MyOldSuite with Expectations.Helpers { | |
test("Should not be reported")(OptionT.none[IO, Expectations]) | |
test("Should also not be reported")(OptionT(IO(Some(success)))) | |
test("Should also also not be reported")(OptionT(IO(Some(failure("fail!"))))) | |
} | |
// This demonstrates how `SharedResourceSuite` can be used instead. | |
abstract class MyNewSuite extends SharedResourceSuite[IO] with BaseIOSuite { | |
type Res = Unit | |
def sharedResource: Resource[IO, Unit] = Resource.pure(()) | |
// The user would define how to transform their effect into IO | |
private def transformMyEffectToIO: MyEffect[Expectations] => IO[Expectations] = | |
_.value.flatMap { | |
case None => Expectations.Helpers.ignore("Ignoring") | |
case Some(exp) => IO(exp) | |
} | |
// Define a DSL for registering tests using a different effect type | |
def test(name: TestName)(run: MyEffect[Expectations]): Unit = | |
registerTest(name)(_ => Test(name.name, transformMyEffectToIO(run))) | |
} | |
// A usage example. Tests returning an OptionT.none instance are reported as ignored. | |
object MyNewTest extends MyNewSuite with Expectations.Helpers { | |
test("Should be ignored")(OptionT.none) | |
test("Should succeed")(OptionT(IO(Some(success)))) | |
test("Should fail")(OptionT(IO(Some(failure("fail!"))))) | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment