Skip to content

Commit

Permalink
Merge pull request #277 from Kazark/munit
Browse files Browse the repository at this point in the history
Convert all specs from Specs2 to MUnit
  • Loading branch information
ChristopherDavenport authored Aug 2, 2021
2 parents c568174 + 4ec655a commit 9b9adfa
Show file tree
Hide file tree
Showing 7 changed files with 437 additions and 465 deletions.
7 changes: 6 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -9,4 +9,9 @@ tags
.bloop
.metals
project/metals.sbt
.bsp/
.bsp/

# gtags
GPATH
GRTAGS
GTAGS
13 changes: 7 additions & 6 deletions build.sbt
Original file line number Diff line number Diff line change
Expand Up @@ -81,8 +81,8 @@ val catsV = "2.6.1"
val catsEffectV = "2.5.1"
val catsCollectionV = "0.9.2"

val specs2V = "4.11.0"
val disciplineSpecs2V = "1.1.6"
val munitV = "0.7.25"
val munitCEV = "1.0.2"

lazy val commonSettings = Seq(
scalaVersion := "2.13.5",
Expand All @@ -91,16 +91,17 @@ lazy val commonSettings = Seq(
addCompilerPlugin("org.typelevel" %% "kind-projector" % "0.13.0" cross CrossVersion.full),
addCompilerPlugin("com.olegpy" %% "better-monadic-for" % "0.3.1"),

testFrameworks += new TestFramework("munit.Framework"),

libraryDependencies ++= Seq(
"org.typelevel" %% "cats-core" % catsV,
"org.typelevel" %% "cats-effect" % catsEffectV,
"io.chrisdavenport" %% "mapref" % "0.1.1",

"org.typelevel" %% "cats-effect-laws" % catsEffectV % Test,
"com.codecommit" %% "cats-effect-testing-specs2" % "0.5.3" % Test,
"org.specs2" %% "specs2-core" % specs2V % Test,
"org.specs2" %% "specs2-scalacheck" % specs2V % Test,
"org.typelevel" %% "discipline-specs2" % disciplineSpecs2V % Test,
"org.scalameta" %% "munit" % munitV % Test,
"org.scalameta" %% "munit-scalacheck" % munitV % Test,
"org.typelevel" %% "munit-cats-effect-2" % munitCEV % Test,
)
)

Expand Down
Original file line number Diff line number Diff line change
@@ -1,47 +1,43 @@
package io.chrisdavenport.mules.caffeine

import org.specs2.mutable.Specification
import scala.concurrent.duration._
import cats.effect._
// import cats.effect.implicits._
import cats.effect.IO
import cats.effect.testing.specs2.CatsIO
import munit._
import io.chrisdavenport.mules.TimeSpec

class CaffeineCacheSpec extends Specification with CatsIO {
"CaffeineCache" should {
"get a value in a quicker period than the timeout" in {
val setup = for {
cache <- CaffeineCache.build[IO, String, Int](Some(TimeSpec.unsafeFromDuration(1.second)), None, None)
_ <- cache.insert("Foo", 1)
_ <- Timer[IO].sleep(1.milli)
value <- cache.lookup("Foo")
} yield value
setup.map(_ must_=== Some(1))
class CaffeineCacheSpec extends CatsEffectSuite {
test("CaffeineCache should get a value in a quicker period than the timeout") {
for {
cache <- CaffeineCache.build[IO, String, Int](Some(TimeSpec.unsafeFromDuration(1.second)), None, None)
_ <- cache.insert("Foo", 1)
_ <- Timer[IO].sleep(1.milli)
value <- cache.lookup("Foo")
} yield {
assertEquals(value, Some(1))
}
}


"remove a value after delete" in {
val setup = for {
cache <- CaffeineCache.build[IO, String, Int](None, None, None)
_ <- cache.insert("Foo", 1)
_ <- cache.delete("Foo")
value <- cache.lookup("Foo")
} yield value
setup.map(_ must_=== None)
test("CaffeineCache should remove a value after delete") {
for {
cache <- CaffeineCache.build[IO, String, Int](None, None, None)
_ <- cache.insert("Foo", 1)
_ <- cache.delete("Foo")
value <- cache.lookup("Foo")
} yield {
assertEquals(value, None)
}
}


"Lookup after interval fails to get a value" in {
val setup = for {
cache <- CaffeineCache.build[IO, String, Int](Some(TimeSpec.unsafeFromDuration(1.second)), None, None)
_ <- cache.insert("Foo", 1)
_ <- Timer[IO].sleep(2.second)
value <- cache.lookup("Foo")
} yield value
setup.map(_ must_=== None)
test("CaffeineCache should Lookup after interval fails to get a value") {
for {
cache <- CaffeineCache.build[IO, String, Int](Some(TimeSpec.unsafeFromDuration(1.second)), None, None)
_ <- cache.insert("Foo", 1)
_ <- Timer[IO].sleep(2.second)
value <- cache.lookup("Foo")
} yield {
assertEquals(value, None)
}


}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,127 +2,104 @@ package io.chrisdavenport.mules

import cats.effect.laws.util.TestContext
import cats.effect._
import cats.implicits._
import org.specs2.mutable.Specification
import cats.syntax.all._
import munit._

import scala.concurrent.duration._

class AutoMemoryCacheSpec extends Specification {

class AutoMemoryCacheSpec extends CatsEffectSuite {
val cacheKeyExpiration = TimeSpec.unsafeFromDuration(12.hours)
val checkExpirationsEvery = TimeSpec.unsafeFromDuration(10.millis)

"Auto MemoryCache.ofSingleImmutableMap" should {
private val ctx = TestContext()

"expire keys" in WithTestContext { ctx => implicit cs => implicit timer =>
val spec = Resource.eval(MemoryCache.ofSingleImmutableMap[IO, Int, String](cacheKeyExpiration.some))
.flatMap(cache => MemoryCache.liftToAuto(cache, checkExpirationsEvery).as(cache))
.use(cache =>
for {
_ <- cache.insert(1, "foo")
_ <- IO(ctx.tick(5.hours))
_ <- cache.insert(2, "bar")
a1 <- cache.lookupNoUpdate(1)
b1 <- cache.lookupNoUpdate(2)
_ <- IO {
assert(a1.contains("foo"))
assert(b1.contains("bar"))
}
_ <- IO(ctx.tick(7.hours + 1.second)) // expiration time reached
a2 <- cache.lookupNoUpdate(1)
b2 <- cache.lookupNoUpdate(2)
_ <- IO {
assert(a2.isEmpty) // not here
assert(b2.contains("bar"))
}
} yield ()
)
spec.as(1).unsafeRunSync() must_== 1
}
implicit override def munitContextShift: ContextShift[IO] =
IO.contextShift(ctx)
implicit override def munitTimer: Timer[IO] =
ctx.timer

"resets expiration" in WithTestContext { ctx => implicit cs => implicit timer =>
val spec = Resource.eval(MemoryCache.ofSingleImmutableMap[IO, Int, String](cacheKeyExpiration.some))
.flatMap(cache => MemoryCache.liftToAuto(cache, checkExpirationsEvery).as(cache))
.use(cache =>
test("Auto MemoryCache.ofSingleImmutableMap should expire keys") {
Resource.eval(MemoryCache.ofSingleImmutableMap[IO, Int, String](cacheKeyExpiration.some))
.flatMap(cache => MemoryCache.liftToAuto(cache, checkExpirationsEvery).as(cache))
.use(cache =>
for {
_ <- cache.insert(1, "foo")
_ <- IO(ctx.tick(5.hours))
_ <- cache.insert(2, "bar")
a1 <- cache.lookupNoUpdate(1)
_ <- IO { assert(a1.contains("foo")) }
_ <- cache.insert(1, "bar")
_ <- IO(ctx.tick(7.hours + 1.second)) // expiration time reached for first timestamp
b1 <- cache.lookupNoUpdate(2)
_ <- IO(ctx.tick(7.hours + 1.second)) // expiration time reached
a2 <- cache.lookupNoUpdate(1)
_ <- IO { assert(a2.contains("bar")) }
_ <- IO(ctx.tick(5.hours)) // expiration time reached for last timestamp
a3 <- cache.lookupNoUpdate(1)
_ <- IO { assert(a3.isEmpty) }
} yield ()
b2 <- cache.lookupNoUpdate(2)
} yield {
assert(a1.contains("foo"))
assert(b1.contains("bar"))
assertEquals(a2, None) // not here
assert(b2.contains("bar"))
}
)
spec.as(1).unsafeRunSync() must_== 1
}

}

"Auto MemoryCache.ofConcurrentHashMap" should {

"expire keys" in WithTestContext { ctx => implicit cs => implicit timer =>
val spec = Resource.eval(MemoryCache.ofConcurrentHashMap[IO, Int, String](cacheKeyExpiration.some))
.flatMap(cache => MemoryCache.liftToAuto(cache, checkExpirationsEvery).as(cache))
.use(cache =>
for {
_ <- cache.insert(1, "foo")
_ <- IO(ctx.tick(5.hours))
_ <- cache.insert(2, "bar")
a1 <- cache.lookupNoUpdate(1)
b1 <- cache.lookupNoUpdate(2)
_ <- IO {
assert(a1.contains("foo"))
assert(b1.contains("bar"))
}
_ <- IO(ctx.tick(7.hours + 1.second)) // expiration time reached
a2 <- cache.lookupNoUpdate(1)
b2 <- cache.lookupNoUpdate(2)
_ <- IO {
assert(a2.isEmpty) // not here
assert(b2.contains("bar"))
}
} yield ()
)
spec.as(1).unsafeRunSync() must_== 1
}
test("Auto MemoryCache.ofSingleImmutableMap should resets expiration") {
Resource.eval(MemoryCache.ofSingleImmutableMap[IO, Int, String](cacheKeyExpiration.some))
.flatMap(cache => MemoryCache.liftToAuto(cache, checkExpirationsEvery).as(cache))
.use(cache =>
for {
_ <- cache.insert(1, "foo")
_ <- IO(ctx.tick(5.hours))
a1 <- cache.lookupNoUpdate(1)
_ <- cache.insert(1, "bar")
_ <- IO(ctx.tick(7.hours + 1.second)) // expiration time reached for first timestamp
a2 <- cache.lookupNoUpdate(1)
_ <- IO(ctx.tick(5.hours)) // expiration time reached for last timestamp
a3 <- cache.lookupNoUpdate(1)
} yield {
assert(a1.contains("foo"))
assert(a2.contains("bar"))
assert(a3.isEmpty)
})
}

"resets expiration" in WithTestContext { ctx => implicit cs => implicit timer =>
val spec = Resource.eval(MemoryCache.ofConcurrentHashMap[IO, Int, String](cacheKeyExpiration.some))
.flatMap(cache => MemoryCache.liftToAuto(cache, checkExpirationsEvery).as(cache))
.use(cache =>
test("Auto MemoryCache.ofConcurrentHashMap should expire keys") {
Resource.eval(MemoryCache.ofConcurrentHashMap[IO, Int, String](cacheKeyExpiration.some))
.flatMap(cache => MemoryCache.liftToAuto(cache, checkExpirationsEvery).as(cache))
.use(cache =>
for {
_ <- cache.insert(1, "foo")
_ <- IO(ctx.tick(5.hours))
_ <- cache.insert(2, "bar")
a1 <- cache.lookupNoUpdate(1)
_ <- IO { assert(a1.contains("foo")) }
_ <- cache.insert(1, "bar")
_ <- IO(ctx.tick(7.hours + 1.second)) // expiration time reached for first timestamp
b1 <- cache.lookupNoUpdate(2)
_ <- IO(ctx.tick(7.hours + 1.second)) // expiration time reached
a2 <- cache.lookupNoUpdate(1)
_ <- IO { assert(a2.contains("bar")) }
_ <- IO(ctx.tick(5.hours)) // expiration time reached for last timestamp
a3 <- cache.lookupNoUpdate(1)
_ <- IO { assert(a3.isEmpty) }
} yield ()
b2 <- cache.lookupNoUpdate(2)
} yield {
assert(a1.contains("foo"))
assert(b1.contains("bar"))
assertEquals(a2, None) // not here
assert(b2.contains("bar"))
}
)
spec.as(1).unsafeRunSync() must_== 1
}

}

}

object WithTestContext {

def apply[A](f: TestContext => ContextShift[IO] => Timer[IO] => A): A = {
val ctx = TestContext()
val cs: ContextShift[IO] = IO.contextShift(ctx)
val timer: Timer[IO] = ctx.timer[IO]
f(ctx)(cs)(timer)
test("Auto MemoryCache.ofConcurrentHashMap should resets expiration") {
Resource.eval(MemoryCache.ofConcurrentHashMap[IO, Int, String](cacheKeyExpiration.some))
.flatMap(cache => MemoryCache.liftToAuto(cache, checkExpirationsEvery).as(cache))
.use(cache =>
for {
_ <- cache.insert(1, "foo")
_ <- IO(ctx.tick(5.hours))
a1 <- cache.lookupNoUpdate(1)
_ <- cache.insert(1, "bar")
_ <- IO(ctx.tick(7.hours + 1.second)) // expiration time reached for first timestamp
a2 <- cache.lookupNoUpdate(1)
_ <- IO(ctx.tick(5.hours)) // expiration time reached for last timestamp
a3 <- cache.lookupNoUpdate(1)
} yield {
assert(a1.contains("foo"))
assert(a2.contains("bar"))
assertEquals(a3, None)
}
)
}

}
Loading

0 comments on commit 9b9adfa

Please sign in to comment.