Repository: scala-steward-org/scala-steward
Pull request #2872 (2023-01-01 20:11:56)

Add pre-determined HTTP responses to `MockState`
This adds a `clientResponses: HttpApp[MockEff]` field to `MockState`. It is used by the http4s client in `MockContext` and allows to have different pre-determined responses in the different tests without constructing a new client in each test.

The changes in `VCSExtraAlgTest` demonstrate that this works.


Patch:
diff --git a/modules/core/src/main/scala/org/scalasteward/core/application/Context.scala b/modules/core/src/main/scala/org/scalasteward/core/application/Context.scala
index 8375f159..be764b2e 100644
--- a/modules/core/src/main/scala/org/scalasteward/core/application/Context.scala
+++ b/modules/core/src/main/scala/org/scalasteward/core/application/Context.scala
@@ -77,6 +77,8 @@ final class Context[F[_]](implicit
     val scalafmtAlg: ScalafmtAlg[F],
     val stewardAlg: StewardAlg[F],
     val updateAlg: UpdateAlg[F],
+    val urlChecker: UrlChecker[F],
+    val vcsExtraAlg: VCSExtraAlg[F],
     val vcsRepoAlg: VCSRepoAlg[F],
     val workspaceAlg: WorkspaceAlg[F]
 )
diff --git a/modules/core/src/main/scala/org/scalasteward/core/data/Version.scala b/modules/core/src/main/scala/org/scalasteward/core/data/Version.scala
index 77f6b72c..76ac0c6e 100644
--- a/modules/core/src/main/scala/org/scalasteward/core/data/Version.scala
+++ b/modules/core/src/main/scala/org/scalasteward/core/data/Version.scala
@@ -162,10 +162,11 @@ object Version {
     }
     final case class Alpha(value: String) extends Component {
       def isPreReleaseIdent: Boolean = order < 0
-      def isSnapshotIdent: Boolean = order <= -6
+      def isSnapshotIdent: Boolean = order <= -7
       def order: Int =
         value.toUpperCase match {
-          case "SNAP" | "SNAPSHOT" | "NIGHTLY" => -6
+          case "SNAP" | "SNAPSHOT" | "NIGHTLY" => -7
+          case "FEAT" | "FEATURE"              => -6
           case "ALPHA" | "PREVIEW"             => -5
           case "BETA" | "B"                    => -4
           case "EA" /* early access */         => -3


Test patch:
diff --git a/modules/core/src/test/scala/org/scalasteward/core/data/VersionTest.scala b/modules/core/src/test/scala/org/scalasteward/core/data/VersionTest.scala
index 12f31408..505bbdd3 100644
--- a/modules/core/src/test/scala/org/scalasteward/core/data/VersionTest.scala
+++ b/modules/core/src/test/scala/org/scalasteward/core/data/VersionTest.scala
@@ -225,7 +225,10 @@ class VersionTest extends DisciplineSuite {
       ("0.1.1", List("0.2.1-485fdf3b"), None),
       ("0.1.1-ALPHA", List("0.2.1-485fdf3b"), None),
       ("0.1.1-ALPHA", List("0.2.1-BETA"), None),
-      ("0.1.1", List("0.2.1-BETA"), None)
+      ("0.1.1", List("0.2.1-BETA"), None),
+      ("0.1.1", List("0.2.0-FEAT"), None),
+      ("0.1.1-FEAT", List("0.2.0"), Some("0.2.0")),
+      ("0.1.1-FEAT+3dfde9d7", List("0.2.0"), Some("0.2.0"))
     )
 
     val rnd = new Random()
@@ -277,7 +280,9 @@ class VersionTest extends DisciplineSuite {
       ("0.1.1-3dfde9d7", List("0.1.2"), Some("0.1.2")),
       ("0.1.1", List("0.1.2"), Some("0.1.2")),
       ("0.1.1-RC1", List("0.1.2"), Some("0.1.2")),
-      ("0.1.1-ALPHA", List("0.1.2"), Some("0.1.2"))
+      ("0.1.1-ALPHA", List("0.1.2"), Some("0.1.2")),
+      ("0.1.1", List("0.1.2-FEAT"), Some("0.1.2-FEAT")),
+      ("0.1.1", List("0.1.2-FEAT+3dfde9d7"), None)
     )
 
     val rnd = new Random()
diff --git a/modules/core/src/test/scala/org/scalasteward/core/mock/MockContext.scala b/modules/core/src/test/scala/org/scalasteward/core/mock/MockContext.scala
index 3fdf24dd..e5fe428d 100644
--- a/modules/core/src/test/scala/org/scalasteward/core/mock/MockContext.scala
+++ b/modules/core/src/test/scala/org/scalasteward/core/mock/MockContext.scala
@@ -1,8 +1,9 @@
 package org.scalasteward.core.mock
 
 import better.files.File
+import cats.data.Kleisli
+import cats.effect.kernel.Resource
 import cats.effect.unsafe.implicits.global
-import org.http4s.HttpApp
 import org.http4s.client.Client
 import org.scalasteward.core.application.Context
 import org.scalasteward.core.application.Context.StewardContext
@@ -16,7 +17,17 @@ import org.scalasteward.core.util.UrlCheckerClient
 import org.typelevel.log4cats.Logger
 
 object MockContext {
-  implicit private val client: Client[MockEff] = Client.fromHttpApp(HttpApp.notFound)
+  implicit private val client: Client[MockEff] =
+    Client[MockEff] { request =>
+      Resource.eval {
+        Kleisli { mockCtx =>
+          mockCtx.get.flatMap { mockState =>
+            mockState.clientResponses.run(request).run(mockCtx)
+          }
+        }
+      }
+    }
+
   implicit private val urlCheckerClient: UrlCheckerClient[MockEff] = UrlCheckerClient(client)
   implicit private val fileAlg: FileAlg[MockEff] = new MockFileAlg
   implicit private val logger: Logger[MockEff] = new MockLogger
diff --git a/modules/core/src/test/scala/org/scalasteward/core/mock/MockState.scala b/modules/core/src/test/scala/org/scalasteward/core/mock/MockState.scala
index 4d835ce8..d3bcf60f 100644
--- a/modules/core/src/test/scala/org/scalasteward/core/mock/MockState.scala
+++ b/modules/core/src/test/scala/org/scalasteward/core/mock/MockState.scala
@@ -3,7 +3,7 @@ package org.scalasteward.core.mock
 import better.files.File
 import cats.effect.{IO, Ref}
 import cats.syntax.all._
-import org.http4s.Uri
+import org.http4s.{HttpApp, Uri}
 import org.scalasteward.core.io.FileAlgTest.ioFileAlg
 import org.scalasteward.core.mock.MockState.TraceEntry
 import org.scalasteward.core.mock.MockState.TraceEntry.{Cmd, Log}
@@ -12,7 +12,8 @@ final case class MockState(
     trace: Vector[TraceEntry],
     commandOutputs: Map[List[String], List[String]],
     files: Map[File, String],
-    uris: Map[Uri, String]
+    uris: Map[Uri, String],
+    clientResponses: HttpApp[MockEff]
 ) {
   def addFiles(newFiles: (File, String)*): IO[MockState] =
     newFiles.toList
@@ -41,7 +42,8 @@ object MockState {
       trace = Vector.empty,
       commandOutputs = Map.empty,
       files = Map.empty,
-      uris = Map.empty
+      uris = Map.empty,
+      clientResponses = HttpApp.notFound
     )
 
   sealed trait TraceEntry extends Product with Serializable
diff --git a/modules/core/src/test/scala/org/scalasteward/core/mock/package.scala b/modules/core/src/test/scala/org/scalasteward/core/mock/package.scala
index 94e8acd3..82edd917 100644
--- a/modules/core/src/test/scala/org/scalasteward/core/mock/package.scala
+++ b/modules/core/src/test/scala/org/scalasteward/core/mock/package.scala
@@ -25,6 +25,6 @@ package object mock {
       state.toRef.flatMap(ref => fa.run(ref).flatMap(a => ref.get.map(s => (s, a))))
   }
 
-  def getFlatMapSet[F[_], A, B](f: A => F[A])(ref: Ref[F, A])(implicit F: FlatMap[F]): F[Unit] =
+  def getFlatMapSet[F[_], A](f: A => F[A])(ref: Ref[F, A])(implicit F: FlatMap[F]): F[Unit] =
     ref.get.flatMap(f).flatMap(ref.set)
 }
diff --git a/modules/core/src/test/scala/org/scalasteward/core/vcs/VCSExtraAlgTest.scala b/modules/core/src/test/scala/org/scalasteward/core/vcs/VCSExtraAlgTest.scala
index 92059aef..280bb560 100644
--- a/modules/core/src/test/scala/org/scalasteward/core/vcs/VCSExtraAlgTest.scala
+++ b/modules/core/src/test/scala/org/scalasteward/core/vcs/VCSExtraAlgTest.scala
@@ -1,120 +1,73 @@
 package org.scalasteward.core.vcs
 
-import cats.effect.IO
-import cats.effect.unsafe.implicits.global
-import munit.FunSuite
-import org.http4s.HttpRoutes
-import org.http4s.client.Client
-import org.http4s.dsl.io._
+import munit.CatsEffectSuite
+import org.http4s.HttpApp
+import org.http4s.dsl.Http4sDsl
 import org.http4s.implicits._
-import org.scalasteward.core.TestInstances.ioLogger
-import org.scalasteward.core.TestSyntax._
 import org.scalasteward.core.application.Config.VCSCfg
-import org.scalasteward.core.data.ReleaseRelatedUrl
-import org.scalasteward.core.mock.MockConfig
-import org.scalasteward.core.util._
+import org.scalasteward.core.data.ReleaseRelatedUrl._
+import org.scalasteward.core.data.Version
+import org.scalasteward.core.mock.MockContext.context._
+import org.scalasteward.core.mock.{MockEff, MockState}
 
-class VCSExtraAlgTest extends FunSuite {
-  val routes: HttpRoutes[IO] =
-    HttpRoutes.of[IO] {
-      case HEAD -> Root / "foo" / "bar" / "compare" / "v0.1.0...v0.2.0" => Ok("exist")
-      case HEAD -> Root / "foo" / "buz" / "compare" / "v0.1.0...v0.2.0" => PermanentRedirect()
-      case _                                                            => NotFound()
-    }
+class VCSExtraAlgTest extends CatsEffectSuite with Http4sDsl[MockEff] {
+  private val state = MockState.empty.copy(clientResponses = HttpApp {
+    case HEAD -> Root / "foo" / "bar" / "compare" / "v0.1.0...v0.2.0" => Ok("exist")
+    case HEAD -> Root / "foo" / "buz" / "compare" / "v0.1.0...v0.2.0" => PermanentRedirect()
+    case _                                                            => NotFound()
+  })
 
-  implicit val client: UrlCheckerClient[IO] =
-    UrlCheckerClient[IO](Client.fromHttpApp[IO](routes.orNotFound))
-  implicit val urlChecker: UrlChecker[IO] =
-    UrlChecker.create[IO](MockConfig.config).unsafeRunSync()
+  private val v1 = Version("0.1.0")
+  private val v2 = Version("0.2.0")
 
-  private val updateFoo = ("com.example".g % "foo".a % "0.1.0" %> "0.2.0").single
-  private val updateBar = ("com.example".g % "bar".a % "0.1.0" %> "0.2.0").single
-  private val updateBuz = ("com.example".g % "buz".a % "0.1.0" %> "0.2.0").single
-
-  test("getBranchCompareUrl: std vsc") {
-    val vcsExtraAlg = VCSExtraAlg.create[IO](MockConfig.config.vcsCfg)
-
-    assertEquals(
-      vcsExtraAlg
-        .getReleaseRelatedUrls(
-          repoUrl = uri"https://github.com/foo/foo",
-          currentVersion = updateFoo.currentVersion,
-          nextVersion = updateFoo.nextVersion
-        )
-        .unsafeRunSync(),
-      List.empty
-    )
+  test("getReleaseRelatedUrls: repoUrl not found") {
+    val obtained =
+      vcsExtraAlg.getReleaseRelatedUrls(uri"https://github.com/foo/foo", v1, v2).runA(state)
+    assertIO(obtained, List.empty)
+  }
 
-    assertEquals(
-      vcsExtraAlg
-        .getReleaseRelatedUrls(
-          repoUrl = uri"https://github.com/foo/bar",
-          currentVersion = updateBar.currentVersion,
-          nextVersion = updateBar.nextVersion
-        )
-        .unsafeRunSync(),
-      List(
-        ReleaseRelatedUrl.VersionDiff(uri"https://github.com/foo/bar/compare/v0.1.0...v0.2.0")
-      )
-    )
+  test("getReleaseRelatedUrls: repoUrl ok") {
+    val obtained =
+      vcsExtraAlg.getReleaseRelatedUrls(uri"https://github.com/foo/bar", v1, v2).runA(state)
+    val expected = List(VersionDiff(uri"https://github.com/foo/bar/compare/v0.1.0...v0.2.0"))
+    assertIO(obtained, expected)
+  }
 
-    assertEquals(
-      vcsExtraAlg
-        .getReleaseRelatedUrls(
-          repoUrl = uri"https://github.com/foo/buz",
-          currentVersion = updateBuz.currentVersion,
-          nextVersion = updateBuz.nextVersion
-        )
-        .unsafeRunSync(),
-      List.empty
-    )
+  test("getReleaseRelatedUrls: repoUrl permanent redirect") {
+    val obtained =
+      vcsExtraAlg.getReleaseRelatedUrls(uri"https://github.com/foo/buz", v1, v2).runA(state)
+    assertIO(obtained, List.empty)
   }
 
-  test("getBranchCompareUrl: github on prem") {
-    val config = VCSCfg(
-      VCSType.GitHub,
-      uri"https://github.on-prem.com/",
-      "",
-      doNotFork = false,
-      addLabels = false
-    )
-    val githubOnPremVcsExtraAlg = VCSExtraAlg.create[IO](config)
+  private val config = VCSCfg(
+    VCSType.GitHub,
+    uri"https://github.on-prem.com/",
+    "",
+    doNotFork = false,
+    addLabels = false
+  )
+  private val githubOnPremVcsExtraAlg = VCSExtraAlg.create[MockEff](config)
 
-    assertEquals(
-      githubOnPremVcsExtraAlg
-        .getReleaseRelatedUrls(
-          repoUrl = uri"https://github.on-prem.com/foo/foo",
-          currentVersion = updateFoo.currentVersion,
-          nextVersion = updateFoo.nextVersion
-        )
-        .unsafeRunSync(),
-      List.empty
-    )
+  test("getReleaseRelatedUrls: on-prem, repoUrl not found") {
+    val obtained = githubOnPremVcsExtraAlg
+      .getReleaseRelatedUrls(uri"https://github.on-prem.com/foo/foo", v1, v2)
+      .runA(state)
+    assertIO(obtained, List.empty)
+  }
 
-    assertEquals(
-      githubOnPremVcsExtraAlg
-        .getReleaseRelatedUrls(
-          repoUrl = uri"https://github.on-prem.com/foo/bar",
-          currentVersion = updateBar.currentVersion,
-          nextVersion = updateBar.nextVersion
-        )
-        .unsafeRunSync(),
-      List(
-        ReleaseRelatedUrl.VersionDiff(
-          uri"https://github.on-prem.com/foo/bar/compare/v0.1.0...v0.2.0"
-        )
-      )
-    )
+  test("getReleaseRelatedUrls: on-prem, repoUrl ok") {
+    val obtained = githubOnPremVcsExtraAlg
+      .getReleaseRelatedUrls(uri"https://github.on-prem.com/foo/bar", v1, v2)
+      .runA(state)
+    val expected =
+      List(VersionDiff(uri"https://github.on-prem.com/foo/bar/compare/v0.1.0...v0.2.0"))
+    assertIO(obtained, expected)
+  }
 
-    assertEquals(
-      githubOnPremVcsExtraAlg
-        .getReleaseRelatedUrls(
-          repoUrl = uri"https://github.on-prem.com/foo/buz",
-          currentVersion = updateFoo.currentVersion,
-          nextVersion = updateFoo.nextVersion
-        )
-        .unsafeRunSync(),
-      List.empty
-    )
+  test("getReleaseRelatedUrls: on-prem, repoUrl permanent redirect") {
+    val obtained = githubOnPremVcsExtraAlg
+      .getReleaseRelatedUrls(uri"https://github.on-prem.com/foo/buz", v1, v2)
+      .runA(state)
+    assertIO(obtained, List.empty)
   }
 }