Skip to content

Commit

Permalink
Merge pull request #156 from escouvois/main
Browse files Browse the repository at this point in the history
Add ResourceFixture
  • Loading branch information
lhns authored Jun 23, 2024
2 parents df77817 + 4935c21 commit fcc6c7d
Show file tree
Hide file tree
Showing 5 changed files with 208 additions and 3 deletions.
4 changes: 2 additions & 2 deletions build.sbt
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,8 @@ ThisBuild / organization := "de.lhns"
name := (core.projectRefs.head / name).value

val V = new {
val catsEffect = "3.5.2"
val munit = "0.7.29"
val catsEffect = "3.5.4"
val munit = "1.0.0"
}

lazy val commonSettings: SettingsDefinition = Def.settings(
Expand Down
38 changes: 38 additions & 0 deletions core/src/main/scala/munit/TaglessFinalFixtures.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
/*
* Copyright 2021 Typelevel
* Modifications by Pierre Kisters
*
* 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.kernel.{Resource, _}

trait TaglessFinalFixtures[F[_]] {
object ResourceTestLocalFixture {
def apply[ A](name: String, resource: Resource[F, A])(implicit AsyncF: Async[F]): TaglessFixture[F, A] =
ResourceFixture.testLocal(name, resource)
}

object ResourceSuiteLocalFixture {
def apply[A](name: String, resource: Resource[F, A])(implicit AsyncF: Async[F]): TaglessFixture[F, A] =
ResourceFixture.suiteLocal(name, resource)
}

@deprecated("Use ResourceSuiteLocalFixture", "2.0.0")
object UnsafeResourceSuiteLocalDeferredFixture {
def apply[ A](name: String, resource: Resource[F, A])(implicit AsyncF: Async[F]): TaglessFixture[F, F[A]] =
ResourceSuiteLocalFixture(name, resource.map(AsyncF.pure(_)))
}
}
73 changes: 73 additions & 0 deletions core/src/main/scala/munit/TaglessFinalResourceFixture.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
/*
* 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.syntax.flatMap._
import cats.effect.kernel._

object ResourceFixture {

final class FixtureNotInstantiatedException(name: String)
extends Exception(
s"The fixture `$name` was not instantiated. Override `munitFixtures` and include a reference to this fixture."
)

def testLocal[F[_], A](name: String, resource: Resource[F, A])(implicit AsyncF: Async[F]): TaglessFixture[F, A] =
new TaglessFixture[F, A](name) {
@volatile var value: Option[(A, F[Unit])] = None

def apply(): A = value match {
case Some(v) => v._1
case None => throw new FixtureNotInstantiatedException(name)
}

override def beforeEach(context: BeforeEach): F[Unit] = resource.allocated.flatMap { value =>
AsyncF.delay(this.value = Some(value))
}

override def afterEach(context: AfterEach): F[Unit] = value.fold(AsyncF.unit)(_._2)
}

def suiteLocal[F[_], A](name: String, resource: Resource[F, A])(implicit AsyncF: Async[F]): TaglessFixture[F, A] =
new TaglessFixture[F, A](name) {
@volatile var value: Option[(A, F[Unit])] = None

def apply(): A = value match {
case Some(v) => v._1
case None => throw new FixtureNotInstantiatedException(name)
}

override def beforeAll(): F[Unit] = resource.allocated.flatMap { value =>
AsyncF.delay(this.value = Some(value))
}

override def afterAll(): F[Unit] = value.fold(AsyncF.unit)(_._2)
}

}

abstract class TaglessFixture[F[_], A](name: String)(implicit AsyncF: Async[F]) extends AnyFixture[A](name: String) {

override def beforeAll(): F[Unit] = AsyncF.unit

override def beforeEach(context: BeforeEach): F[Unit] = AsyncF.unit

override def afterEach(context: AfterEach): F[Unit] = AsyncF.unit

override def afterAll(): F[Unit] = AsyncF.unit

}
94 changes: 94 additions & 0 deletions core/src/test/scala/munit/TaglessFinalFixturesSpec.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,94 @@
/*
* 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 munit.ResourceFixture.FixtureNotInstantiatedException

import scala.concurrent.duration._

class TaglessFinalFixturesSpec extends CatsEffectSuite with TaglessFinalFixtures[IO] {

@volatile var acquired: Int = 0
@volatile var released: Int = 0

val fixture = ResourceSuiteLocalFixture(
"fixture",
Resource.make(
IO.sleep(1.millis) *> IO {
acquired += 1
()
}
)(_ =>
IO.sleep(1.millis) *> IO {
released += 1
()
}
)
)

val uninitializedFixture = ResourceSuiteLocalFixture(
"uninitialized-fixture",
Resource.make(IO.unit)(_ => IO.unit)
)

object AssertBeforeFixture extends Fixture[Unit]("assertBefore") {
def apply() = ()

override def beforeAll(): Unit = {
assertEquals(acquired, 0)
assertEquals(released, 0)
}

override def afterAll(): Unit = {
assertEquals(acquired, 1)
assertEquals(released, 0)
}
}

object AssertAfterFixture extends Fixture[Unit]("assertAfter") {
def apply() = ()

override def beforeAll(): Unit = {
assertEquals(acquired, 1)
assertEquals(released, 0)
}

override def afterAll(): Unit = {
assertEquals(acquired, 1)
assertEquals(released, 1)
}
}

override def munitFixtures = List[AnyFixture[_]](AssertBeforeFixture, fixture, AssertAfterFixture)

test("first test") {
IO(fixture()).assertEquals(())
}

test("second test") {
IO(fixture()).assertEquals(())
}

test("throws exception") {
IO(uninitializedFixture())
.interceptMessage[FixtureNotInstantiatedException](
"The fixture `uninitialized-fixture` was not instantiated. Override `munitFixtures` and include a reference to this fixture."
)
}

}
2 changes: 1 addition & 1 deletion project/plugins.sbt
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ addSbtPlugin("com.timushev.sbt" % "sbt-updates" % "0.6.4")

addSbtPlugin("com.eed3si9n" % "sbt-projectmatrix" % "0.9.1")

addSbtPlugin("org.scala-js" % "sbt-scalajs" % "1.14.0")
addSbtPlugin("org.scala-js" % "sbt-scalajs" % "1.16.0")

addSbtPlugin("org.xerial.sbt" % "sbt-sonatype" % "3.10.0")

Expand Down

0 comments on commit fcc6c7d

Please sign in to comment.