Skip to content

Commit

Permalink
Merge pull request #306 from alejandrohdezma/munit1.0
Browse files Browse the repository at this point in the history
BREAKING | Update to MUnit 1.0
  • Loading branch information
alejandrohdezma authored Apr 23, 2024
2 parents 3e53928 + d299202 commit 2f0f464
Show file tree
Hide file tree
Showing 22 changed files with 877 additions and 483 deletions.
4 changes: 0 additions & 4 deletions .github/auto_assign.yml

This file was deleted.

187 changes: 128 additions & 59 deletions .github/docs/README.md

Large diffs are not rendered by default.

11 changes: 5 additions & 6 deletions build.sbt
Original file line number Diff line number Diff line change
@@ -1,11 +1,10 @@
val Scala3 = "3.3.0" // scala-steward:off
ThisBuild / scalaVersion := "2.13.13"
ThisBuild / crossScalaVersions := Seq("2.12.19", "2.13.13", Scala3)
ThisBuild / versionPolicyIntention := Compatibility.BinaryAndSourceCompatible
ThisBuild / crossScalaVersions := Seq("2.12.19", "2.13.13", "3.3.3")
ThisBuild / versionPolicyIntention := Compatibility.None

ThisBuild / organization := "com.alejandrohdezma"

addCommandAlias("ci-test", "scalafmtCheckAll; versionPolicyCheck; mdoc; +test")
addCommandAlias("ci-test", "fix --check; versionPolicyCheck; mdoc; +test")
addCommandAlias("ci-docs", "github; headerCreateAll; mdoc")
addCommandAlias("ci-publish", "versionCheck; github; ci-release")

Expand All @@ -16,11 +15,11 @@ lazy val documentation = project

lazy val `http4s-munit` = module
.settings(Test / fork := true)
.settings(libraryDependencies += "org.scalameta" %% "munit" % "0.7.29")
.settings(libraryDependencies += "org.scalameta" %% "munit" % "1.0.0-M12")
.settings(libraryDependencies += "org.http4s" %% "http4s-client" % "0.23.26")
.settings(libraryDependencies += "org.http4s" %% "http4s-dsl" % "0.23.26")
.settings(libraryDependencies += "org.http4s" %% "http4s-ember-client" % "0.23.26" % Optional)
.settings(libraryDependencies += "org.typelevel" %% "munit-cats-effect-3" % "1.0.7")
.settings(libraryDependencies += "org.typelevel" %% "munit-cats-effect" % "2.0.0-M5")
.settings(libraryDependencies += "io.circe" %% "circe-parser" % "0.14.6")
.settings(libraryDependencies += "ch.qos.logback" % "logback-classic" % "1.5.5" % Test)
.settings(libraryDependencies += "org.http4s" %% "http4s-circe" % "0.23.26" % Test)
Expand Down
3 changes: 2 additions & 1 deletion modules/http4s-munit/src/main/scala/munit/ClientSuite.scala
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,7 @@ import org.http4s.dsl.Http4sDslBinCompat
* @author
* Alejandro Hernández
*/
@deprecated("Extend Http4sMUnitSyntax instead", since = "0.16.0")
trait ClientSuite extends CatsEffectSuite with Http4sDslBinCompat[IO] {

implicit class ClientTypeOps(t: Client.type) {
Expand Down Expand Up @@ -94,7 +95,7 @@ trait ClientSuite extends CatsEffectSuite with Http4sDslBinCompat[IO] {
def fixture[A](
f: Client[IO] => Resource[IO, A]
): PartialFunction[Request[IO], IO[Response[IO]]] => SyncIO[FunFixture[A]] =
pf => ResourceFixture(f(from(pf)))
pf => ResourceFunFixture(f(from(pf)))

}

Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright 2020-2023 Alejandro Hernández <https://github.com/alejandrohdezma>
* Copyright 2020-2022 Alejandro Hernández <https://github.com/alejandrohdezma>
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
Expand All @@ -16,16 +16,14 @@

package munit

import cats.Show
import cats.effect.IO
import cats.effect.Resource
import cats.effect.SyncIO

import org.http4s.AuthedRequest
import org.http4s.AuthedRoutes
import org.http4s.ContextRequest
import org.http4s.Request
import org.http4s.Response
import org.http4s.client.Client
import org.typelevel.vault.Key

/** Base class for suites testing `AuthedRoutes`.
*
Expand Down Expand Up @@ -53,42 +51,20 @@ import org.http4s.Response
* }
* }}}
*/
abstract class Http4sAuthedRoutesSuite[A: Show] extends Http4sSuite[AuthedRequest[IO, A]] {
@deprecated("Use `Http4sSuite` overriding `http4sMUnitClientFixture` instead", since = "0.16.0")
abstract class Http4sAuthedRoutesSuite[A] extends Http4sSuite {

@SuppressWarnings(Array("scalafix:DisableSyntax.valInAbstract"))
implicit val key: Key[A] = Key.newKey[IO, A].unsafeRunSync()

/** The HTTP routes being tested */
val routes: AuthedRoutes[A, IO]

/** @inheritdoc */
override def http4sMUnitNameCreator(
request: AuthedRequest[IO, A],
followingRequests: List[String],
testOptions: TestOptions,
config: Http4sMUnitConfig
): String = Http4sMUnitDefaults.http4sMUnitNameCreator(
request,
followingRequests,
testOptions,
config,
http4sMUnitNameCreatorReplacements()
)

implicit class Request2AuthedRequest(request: Request[IO]) {

/** Converts an `IO[Request[IO]]` into an `IO[AuthedRequest[IO, A]]` by providing the `A` context. */
def context(context: A): AuthedRequest[IO, A] = AuthedRequest(context, request)

/** Converts an `IO[Request[IO]]` into an `IO[AuthedRequest[IO, A]]` by providing the `A` context. */
def ->(a: A): AuthedRequest[IO, A] = context(a)

}

implicit class Http4sMUnitTestCreatorOps(creator: Http4sMUnitTestCreator) {

/** Allows overriding the routes used when running this test. */
def withRoutes(newRoutes: AuthedRoutes[A, IO]): Http4sMUnitTestCreator = creator.copy(
http4sMUnitFunFixture =
SyncIO.pure(FunFixture(_ => req => newRoutes.orNotFound.run(req).to[Resource[IO, *]], _ => ()))
)
/** Alias for adding a request's context. */
@deprecated("Use `.context` instead", since = "0.16.0")
def ->(a: A): Request[IO] = request.context(a)

}

Expand All @@ -100,8 +76,9 @@ abstract class Http4sAuthedRoutesSuite[A: Show] extends Http4sSuite[AuthedReques

}

def http4sMUnitFunFixture: SyncIO[FunFixture[ContextRequest[IO, A] => Resource[IO, Response[IO]]]] =
SyncIO.pure(FunFixture(_ => routes.orNotFound.run(_).to[Resource[IO, *]], _ => ()))
/** @inheritdoc */
override def http4sMUnitClientFixture: SyncIO[FunFixture[Client[IO]]] =
AuthedRequest.fromContext[A].andThen(routes).orFail.asFixture

/** Declares a test for the provided request. That request will be executed using the routes provided in `routes`.
*
Expand All @@ -126,7 +103,11 @@ abstract class Http4sAuthedRoutesSuite[A: Show] extends Http4sSuite[AuthedReques
* }
* }}}
*/
def test(request: AuthedRequest[IO, A]): Http4sMUnitTestCreator =
Http4sMUnitTestCreator(request, http4sMUnitFunFixture)
override def test(request: Request[IO]): Http4sMUnitTestCreator = {
if (!request.attributes.contains(key))
fail("Auth context not found on request, remember to add one with `.context`", clues(request))

super.test(request)
}

}
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright 2020-2023 Alejandro Hernández <https://github.com/alejandrohdezma>
* Copyright 2020-2022 Alejandro Hernández <https://github.com/alejandrohdezma>
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
Expand All @@ -17,13 +17,10 @@
package munit

import cats.effect.IO
import cats.effect.Resource
import cats.effect.SyncIO

import org.http4s.ContextRequest
import org.http4s.HttpRoutes
import org.http4s.Request
import org.http4s.Response
import org.http4s.client.Client

/** Base class for suites testing `HttpRoutes`.
*
Expand Down Expand Up @@ -53,7 +50,8 @@ import org.http4s.Response
* @author
* José Gutiérrez
*/
trait Http4sHttpRoutesSuite extends Http4sSuite[Request[IO]] {
@deprecated("Use `Http4sSuite` overriding `http4sMUnitClientFixture` instead", since = "0.16.0")
trait Http4sHttpRoutesSuite extends Http4sSuite {

/** The HTTP routes being tested.
*
Expand All @@ -65,64 +63,14 @@ trait Http4sHttpRoutesSuite extends Http4sSuite[Request[IO]] {
*/
val routes: HttpRoutes[IO]

/** @inheritdoc */
override def http4sMUnitNameCreator(
request: Request[IO],
followingRequests: List[String],
testOptions: TestOptions,
config: Http4sMUnitConfig
): String =
Http4sMUnitDefaults.http4sMUnitNameCreator(
ContextRequest((), request),
followingRequests,
testOptions,
config,
http4sMUnitNameCreatorReplacements()
)

implicit class Http4sMUnitTestCreatorOps(creator: Http4sMUnitTestCreator) {

/** Allows overriding the routes used when running this test. */
def withRoutes(newRoutes: HttpRoutes[IO]): Http4sMUnitTestCreator = creator.copy(
http4sMUnitFunFixture =
SyncIO.pure(FunFixture(_ => req => newRoutes.orNotFound.run(req).to[Resource[IO, *]], _ => ()))
)

}

implicit class HttpRoutesCompanionOps(companion: HttpRoutes.type) {

/** An HttpRoutes instance that always fails */
val fail: HttpRoutes[IO] = HttpRoutes(request => Assertions.fail("This should not be called", clues(request)))

}

def http4sMUnitFunFixture: SyncIO[FunFixture[Request[IO] => Resource[IO, Response[IO]]]] =
SyncIO.pure(FunFixture(_ => req => routes.orNotFound.run(req).to[Resource[IO, *]], _ => ()))

/** Declares a test for the provided request. That request will be executed using the routes provided in `routes`.
*
* @example
* {{{
* test(GET(uri"users" / 42)) { response =>
* // test body
* }
* }}}
*
* @example
* {{{
* test(POST(json, uri"users")).alias("Create a new user") { response =>
* // test body
* }
* }}}
*
* @example
* {{{
* test(GET(uri"users" / 42)).flaky { response =>
* // test body
* }
* }}}
*/
def test(request: Request[IO]): Http4sMUnitTestCreator = Http4sMUnitTestCreator(request, http4sMUnitFunFixture)
/** @inheritdoc */
override def http4sMUnitClientFixture: SyncIO[FunFixture[Client[IO]]] = routes.orFail.asFixture

}
Original file line number Diff line number Diff line change
Expand Up @@ -16,46 +16,21 @@

package munit

import cats.Show
import cats.effect.IO
import cats.syntax.all._

import org.http4s.ContextRequest
import org.http4s.Uri
import org.http4s.Request

object Http4sMUnitDefaults {

def http4sMUnitNameCreator[A: Show](
request: ContextRequest[IO, A],
@deprecated("Use Http4sMUnitTestNameCreator.default instead", since = "0.16.0")
def http4sMUnitNameCreator(
request: Request[IO],
followingRequests: List[String],
testOptions: TestOptions,
config: Http4sMUnitConfig,
replacements: Seq[(String, String)] = Nil // scalafix:ok
): String = {
val clue = followingRequests.+:(testOptions.name).filter(_.nonEmpty) match {
case Nil => ""
case List(head) => s" ($head)"
case List(first, second) => s" ($first and then $second)"
case list => s"${list.init.mkString(" (", ", ", ", and then")} ${list.last})"
}

val context = request.context match {
case _: Unit => None
case context => context.show.some.filterNot(_.isEmpty())
}

val reps = config.repetitions match {
case Some(rep) if rep > 1 =>
s" - executed $rep times" + config.maxParallel.fold("")(paral => s" with $paral in parallel")
case _ => ""
}

val nameWithoutReplacements = s"${request.req.method.name} -> ${Uri.decode(request.req.uri.renderString)}" +
s"$clue${context.fold("")(" as " + _)}$reps"

replacements.foldLeft(nameWithoutReplacements) { case (name, (value, replacement)) =>
name.replaceAll(value, replacement)
}
}
replacements: Seq[(String, String)] = Nil
): String = Http4sMUnitTestNameCreator.default
.replacing(replacements: _*)
.nameFor(request, followingRequests, testOptions, config)

}
Loading

0 comments on commit 2f0f464

Please sign in to comment.