diff --git a/ce2/js/src/main/scala/munit/CatsEffectSuitePlatform.scala b/ce2/js/src/main/scala/munit/CatsEffectSuitePlatform.scala new file mode 100644 index 0000000..700f522 --- /dev/null +++ b/ce2/js/src/main/scala/munit/CatsEffectSuitePlatform.scala @@ -0,0 +1,25 @@ +/* + * Copyright 2021 Typelevel + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package munit + +import cats.effect.IO + +private[munit] trait CatsEffectSuitePlatform { self: CatsEffectSuite => + + private[munit] def unsafeRunSyncOrForget[A](ioa: IO[A]): Unit = ioa.unsafeRunAsyncAndForget() + +} diff --git a/ce2/jvm/src/main/scala/munit/CatsEffectSuitePlatform.scala b/ce2/jvm/src/main/scala/munit/CatsEffectSuitePlatform.scala new file mode 100644 index 0000000..f680555 --- /dev/null +++ b/ce2/jvm/src/main/scala/munit/CatsEffectSuitePlatform.scala @@ -0,0 +1,28 @@ +/* + * Copyright 2021 Typelevel + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package munit + +import cats.effect.IO + +private[munit] trait CatsEffectSuitePlatform { self: CatsEffectSuite => + + private[munit] def unsafeRunSyncOrForget[A](ioa: IO[A]): Unit = { + ioa.unsafeRunSync() + () + } + +} diff --git a/ce2/shared/src/main/scala/munit/CatsEffectSuite.scala b/ce2/shared/src/main/scala/munit/CatsEffectSuite.scala index 265f80c..cfe21c0 100644 --- a/ce2/shared/src/main/scala/munit/CatsEffectSuite.scala +++ b/ce2/shared/src/main/scala/munit/CatsEffectSuite.scala @@ -22,6 +22,7 @@ import scala.concurrent.{Future, ExecutionContext} abstract class CatsEffectSuite extends FunSuite + with CatsEffectSuitePlatform with CatsEffectAssertions with CatsEffectFixtures with CatsEffectFunFixtures { @@ -48,3 +49,8 @@ abstract class CatsEffectSuite ) } + +object CatsEffectSuite { + private[munit] type Deferred[F[_], A] = cats.effect.concurrent.Deferred[F, A] + private[munit] val Deferred = cats.effect.concurrent.Deferred +} diff --git a/ce3/js/src/main/scala/munit/CatsEffectSuitePlatform.scala b/ce3/js/src/main/scala/munit/CatsEffectSuitePlatform.scala new file mode 100644 index 0000000..06a7a60 --- /dev/null +++ b/ce3/js/src/main/scala/munit/CatsEffectSuitePlatform.scala @@ -0,0 +1,25 @@ +/* + * Copyright 2021 Typelevel + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package munit + +import cats.effect.IO + +private[munit] trait CatsEffectSuitePlatform { self: CatsEffectSuite => + + private[munit] def unsafeRunSyncOrForget[A](ioa: IO[A]): Unit = ioa.unsafeRunAndForget() + +} diff --git a/ce3/jvm/src/main/scala/munit/CatsEffectSuitePlatform.scala b/ce3/jvm/src/main/scala/munit/CatsEffectSuitePlatform.scala new file mode 100644 index 0000000..f680555 --- /dev/null +++ b/ce3/jvm/src/main/scala/munit/CatsEffectSuitePlatform.scala @@ -0,0 +1,28 @@ +/* + * Copyright 2021 Typelevel + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package munit + +import cats.effect.IO + +private[munit] trait CatsEffectSuitePlatform { self: CatsEffectSuite => + + private[munit] def unsafeRunSyncOrForget[A](ioa: IO[A]): Unit = { + ioa.unsafeRunSync() + () + } + +} diff --git a/ce3/shared/src/main/scala/munit/CatsEffectSuite.scala b/ce3/shared/src/main/scala/munit/CatsEffectSuite.scala index 46b0c4e..00be20b 100644 --- a/ce3/shared/src/main/scala/munit/CatsEffectSuite.scala +++ b/ce3/shared/src/main/scala/munit/CatsEffectSuite.scala @@ -23,6 +23,7 @@ import scala.concurrent.{ExecutionContext, Future} abstract class CatsEffectSuite extends FunSuite + with CatsEffectSuitePlatform with CatsEffectAssertions with CatsEffectFixtures with CatsEffectFunFixtures { @@ -47,3 +48,8 @@ abstract class CatsEffectSuite ) } + +object CatsEffectSuite { + private[munit] type Deferred[F[_], A] = cats.effect.kernel.Deferred[F, A] + private[munit] val Deferred = cats.effect.kernel.Deferred +} diff --git a/common/js/src/main/scala/munit/CatsEffectFixtures.scala b/common/js/src/main/scala/munit/CatsEffectFixturesPlatform.scala similarity index 90% rename from common/js/src/main/scala/munit/CatsEffectFixtures.scala rename to common/js/src/main/scala/munit/CatsEffectFixturesPlatform.scala index ba5f5ec..9a21cf3 100644 --- a/common/js/src/main/scala/munit/CatsEffectFixtures.scala +++ b/common/js/src/main/scala/munit/CatsEffectFixturesPlatform.scala @@ -16,4 +16,4 @@ package munit -trait CatsEffectFixtures { self: CatsEffectSuite => } +trait CatsEffectFixturesPlatform { self: CatsEffectSuite => } diff --git a/common/jvm/src/main/scala/munit/CatsEffectFixtures.scala b/common/jvm/src/main/scala/munit/CatsEffectFixturesPlatform.scala similarity index 96% rename from common/jvm/src/main/scala/munit/CatsEffectFixtures.scala rename to common/jvm/src/main/scala/munit/CatsEffectFixturesPlatform.scala index 056c776..f3f7330 100644 --- a/common/jvm/src/main/scala/munit/CatsEffectFixtures.scala +++ b/common/jvm/src/main/scala/munit/CatsEffectFixturesPlatform.scala @@ -18,7 +18,7 @@ package munit import cats.effect.{IO, Resource} -trait CatsEffectFixtures { self: CatsEffectSuite => +trait CatsEffectFixturesPlatform { self: CatsEffectSuite => object ResourceSuiteLocalFixture { diff --git a/common/jvm/src/test/scala/munit/CatsEffectFixturesSpec.scala b/common/jvm/src/test/scala/munit/CatsEffectFixturesPlatformSpec.scala similarity index 89% rename from common/jvm/src/test/scala/munit/CatsEffectFixturesSpec.scala rename to common/jvm/src/test/scala/munit/CatsEffectFixturesPlatformSpec.scala index 5afc1ed..c66188b 100644 --- a/common/jvm/src/test/scala/munit/CatsEffectFixturesSpec.scala +++ b/common/jvm/src/test/scala/munit/CatsEffectFixturesPlatformSpec.scala @@ -17,8 +17,9 @@ package munit import cats.effect.{IO, Resource} +import scala.concurrent.duration._ -class CatsEffectFixturesSpec extends CatsEffectSuite with CatsEffectAssertions { +class CatsEffectFixturesPlatformSpec extends CatsEffectSuite with CatsEffectAssertions { var acquired: Int = 0 var released: Int = 0 @@ -26,12 +27,12 @@ class CatsEffectFixturesSpec extends CatsEffectSuite with CatsEffectAssertions { val fixture = ResourceSuiteLocalFixture( "fixture", Resource.make( - IO { + IO.sleep(1.millis) *> IO { acquired += 1 () } )(_ => - IO { + IO.sleep(1.millis) *> IO { released += 1 () } diff --git a/common/shared/src/main/scala/munit/CatsEffectFixtures.scala b/common/shared/src/main/scala/munit/CatsEffectFixtures.scala new file mode 100644 index 0000000..e81a9e2 --- /dev/null +++ b/common/shared/src/main/scala/munit/CatsEffectFixtures.scala @@ -0,0 +1,52 @@ +/* + * Copyright 2021 Typelevel + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package munit + +import cats.effect.{IO, Resource} + +trait CatsEffectFixtures extends CatsEffectFixturesPlatform { self: CatsEffectSuite => + + import CatsEffectSuite.Deferred + + /** Similar to `ResourceSuiteLocalFixture`, but supported on both JVM and JS via several caveats. + * Instead of directly providing `T` provides a (memoized) `IO[T]` that is backed by a + * `Deferred[T]`. It is unsafe because on JS the resource is closed concurrently without + * backpressure, + * i.e. the suite will complete even while the resource has not closed yet. On JVM it is + * semantically equivalent to `ResourceSuiteLocalFixture`. Note also that constructing this + * fixture is impure because it unsafely allocates a `Deferred`. + */ + object UnsafeResourceSuiteLocalDeferredFixture { + + def apply[T](name: String, resource: Resource[IO, T]): Fixture[IO[T]] = + new Fixture[IO[T]](name) { + val value: Deferred[IO, (T, IO[Unit])] = Deferred.unsafe + + def apply(): IO[T] = value.get.map(_._1) + + override def beforeAll(): Unit = { + val resourceEffect = resource.allocated.flatMap(value.complete) + unsafeRunSyncOrForget(resourceEffect) + } + + override def afterAll(): Unit = { + unsafeRunSyncOrForget(value.get.flatMap(_._2)) + } + } + } + +} diff --git a/common/shared/src/test/scala/munit/CatsEffectFixturesSpec.scala b/common/shared/src/test/scala/munit/CatsEffectFixturesSpec.scala new file mode 100644 index 0000000..a07e9c1 --- /dev/null +++ b/common/shared/src/test/scala/munit/CatsEffectFixturesSpec.scala @@ -0,0 +1,62 @@ +/* + * Copyright 2021 Typelevel + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package munit + +import cats.effect.{IO, Resource} +import scala.concurrent.duration._ + +class CatsEffectFixturesSpec extends CatsEffectSuite with CatsEffectAssertions { + + @volatile var acquired: Int = 0 + @volatile var released: Int = 0 + + val fixture = UnsafeResourceSuiteLocalDeferredFixture( + "fixture", + Resource.make( + IO.sleep(1.millis) *> IO { + acquired += 1 + () + } + )(_ => + IO.sleep(1.millis) *> IO { + released += 1 + () + } + ) + ) + + override def munitFixtures = List(fixture) + + override def beforeAll(): Unit = { + assertEquals(acquired, 0) + assertEquals(released, 0) + } + + override def afterAll(): Unit = { + assertEquals(acquired, 1) + // assertEquals(released, 1) // Release is async, no way to check + } + + test("first test") { + fixture().assertEquals(()) + } + + test("second test") { + fixture().assertEquals(()) + } + +}