Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Migrate tests to MUnit + other improvements #210

Merged
merged 11 commits into from
Mar 31, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 4 additions & 12 deletions build.sbt
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,12 @@ import Dependencies._
import sbtcrossproject.CrossPlugin.autoImport.{crossProject, CrossType}
import org.scalajs.sbtplugin.ScalaJSCrossVersion

val scala212 = "2.12.8"
val scala213 = "2.13.0-RC2"
val scala212 = "2.12.11"
val scala213 = "2.13.1"

inThisBuild(
List(
scalaVersion := "2.12.8",
scalaVersion := scala212,
// crossScalaVersions := List(scala212, scala213),
licenses += ("MIT", url("http://opensource.org/licenses/MIT")),
homepage := Some(url("https://github.com/buildo/retro")),
Expand All @@ -19,6 +19,7 @@ inThisBuild(
url("https://github.com/gabro"),
),
),
testFrameworks += new TestFramework("munit.Framework"),
),
)

Expand Down Expand Up @@ -118,24 +119,15 @@ lazy val metarpheusCore = crossProject(JSPlatform, JVMPlatform)
.settings(
name := "metarpheus-core",
dynverTagPrefix := "metarpheus-",
)
.jvmSettings(
libraryDependencies ++= metarpheusCoreDependencies,
)
.jsSettings(
libraryDependencies ++= metarpheusCoreDependencies.map { dep =>
if (dep.configurations == Some(Test.name)) dep
else dep.cross(ScalaJSCrossVersion.binary)
},
)

lazy val metarpheusJsFacade = project
.in(file("metarpheus/jsFacade"))
.enablePlugins(ScalaJSPlugin, ScalaJSBundlerPlugin)
.settings(
name := "metarpheus-js-facade",
scalaJSLinkerConfig ~= { _.withModuleKind(ModuleKind.CommonJSModule) },
scalacOptions += "-P:scalajs:sjsDefinedByDefault",
libraryDependencies ++= metarpheusJsFacadeDependencies.map(_.cross(ScalaJSCrossVersion.binary)),
dynverTagPrefix := "metarpheus-",
)
Expand Down
2 changes: 1 addition & 1 deletion ci/pipeline.yml
Original file line number Diff line number Diff line change
Expand Up @@ -107,7 +107,7 @@ resources:
icon: docker
source:
repository: buildo/scala-sbt-alpine
tag: 8u201_2.12.8_1.2.8
tag: 8u201_2.12.11_1.3.8

jobs:

Expand Down
2 changes: 1 addition & 1 deletion ci/release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ image_resource:
type: docker-image
source:
repository: hseeberger/scala-sbt
tag: 8u181_2.12.8_1.2.8
tag: 8u242_1.3.8_2.12.10

inputs:
- name: retro
Expand Down
2 changes: 1 addition & 1 deletion enumero/ci/test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ image_resource:
type: docker-image
source:
repository: buildo/scala-sbt-alpine
tag: 8u201_2.12.8_1.2.8
tag: 8u201_2.12.11_1.3.8

inputs:
- name: retro
Expand Down
31 changes: 14 additions & 17 deletions enumero/circe/src/test/scala/CirceSupportSpec.scala
Original file line number Diff line number Diff line change
@@ -1,12 +1,10 @@
import io.buildo.enumero._
import io.buildo.enumero.circe._
import io.circe.{DecodingFailure, Json}
import io.circe.syntax._
import io.circe.parser._
import io.circe.parser.parse

import org.scalatest.{Matchers, WordSpec}
class CirceSupportSuite extends munit.FunSuite {

class CirceSupportSpec extends WordSpec with Matchers {
sealed trait Planet extends CaseEnum
object Planet {
case object Mercury extends Planet
Expand All @@ -17,36 +15,35 @@ class CirceSupportSpec extends WordSpec with Matchers {
val planetMap = Map[Planet, Int](
Planet.Mercury -> 12,
Planet.Venus -> 812763,
Planet.Earth -> 0
Planet.Earth -> 0,
)

val planetMapJson: Json = parse("""
val planetMapJson = parse("""
{
"Mercury": 12,
"Venus": 812763,
"Earth": 0
}
""").getOrElse(Json.Null)
""").right.get

"CirceSupport handles encoding of a map with CaseEnum keys" in {
test("CirceSupport handles encoding a map with CaseEnum keys") {
val encodedJson = planetMap.asJson

encodedJson shouldBe planetMapJson
assertEquals(encodedJson, planetMapJson)
}

"CirceSupport handles dencoding of a json with CaseEnum keys" in {
planetMapJson.as[Map[Planet, Int]].getOrElse(Json.Null) shouldBe planetMap
test("CirceSupport handles decoding a json with CaseEnum keys") {
assertEquals(planetMapJson.as[Map[Planet, Int]].right.get, planetMap)
}

"CirceSupport handles dencoding of a json with wrong CaseEnum keys" in {
parse("""
test("CirceSupport handles decoding a json with wrong CaseEnum keys") {
val decodeResult = parse("""
{
"Mercury": 12,
"Venus": 812763,
"wrongKey": 0
}
""")
.getOrElse(Json.Null)
.as[Map[Planet, Int]] shouldBe a[Left[_, DecodingFailure]]
""").right.get
.as[Map[Planet, Int]]
assert(decodeResult.isLeft)
}
}
75 changes: 35 additions & 40 deletions enumero/core/src/test/scala/CaseEnumIndex.scala
Original file line number Diff line number Diff line change
@@ -1,66 +1,61 @@
import io.buildo.enumero._
import scala.language.reflectiveCalls

import org.scalatest.{Matchers, WordSpec}

class CaseEnumIndexSpec extends WordSpec with Matchers {
class CaseEnumIndexSuite extends munit.FunSuite {
sealed trait Planet extends IndexedCaseEnum { type Index = Int }
object Planet {
case object Mercury extends Planet { val index = 1 }
case object Venus extends Planet { val index = 2 }
case object Earth extends Planet { val index = 3 }
}

"CaseEnumIndexMacro" should {
"construct a sensible CaseEnumIndex" in {
val converter = CaseEnumIndex.caseEnumIndex[Planet]
test("CaseEnumIndexMacro should construct a sensible CaseEnumIndex") {
val converter = CaseEnumIndex.caseEnumIndex[Planet]

val pairs = List(Planet.Mercury -> 1, Planet.Venus -> 2, Planet.Earth -> 3)
val pairs = List(Planet.Mercury -> 1, Planet.Venus -> 2, Planet.Earth -> 3)

for ((co, index) <- pairs) {
converter.caseToIndex(co).shouldBe(index)
converter.caseFromIndex(index).shouldBe(Some(co))
}
for ((co, index) <- pairs) {
assertEquals(converter.caseToIndex(co), index)
assertEquals(converter.caseFromIndex(index), Some(co))
}
}

"CaseEnumIndex" should {
"provide the typeclass instance" in {
trait FakeBinaryPickler[T] {
def pickle(c: T)(picklerState: { def writeInt(int: Int) }): Unit
def unpickle(unpicklerState: { def getInt(): Int }): Option[T]
}
test("CaseEnumIndex should provide the typeclass instance") {
trait FakeBinaryPickler[T] {
def pickle(c: T)(picklerState: { def writeInt(int: Int): Unit }): Unit
def unpickle(unpicklerState: { def getInt(): Int }): Option[T]
}

implicit def fakeBinaryPickler[T <: IndexedCaseEnum { type Index = Int }](
implicit instance: CaseEnumIndex[T]
) = new FakeBinaryPickler[T] {
implicit def fakeBinaryPickler[T <: IndexedCaseEnum { type Index = Int }](
implicit instance: CaseEnumIndex[T],
) = new FakeBinaryPickler[T] {

def pickle(c: T)(picklerState: { def writeInt(int: Int) }): Unit = {
picklerState.writeInt(instance.caseToIndex(c))
}
def unpickle(unpicklerState: { def getInt(): Int }): Option[T] = {
instance.caseFromIndex(unpicklerState.getInt())
}
def pickle(c: T)(picklerState: { def writeInt(int: Int): Unit }): Unit = {
picklerState.writeInt(instance.caseToIndex(c))
}

object picklerState {
var value: Int = 0
def writeInt(int: Int): Unit = {
value = int
}
def unpickle(unpicklerState: { def getInt(): Int }): Option[T] = {
instance.caseFromIndex(unpicklerState.getInt())
}
val binaryPickler = implicitly[FakeBinaryPickler[Planet]]
binaryPickler.pickle(Planet.Venus)(picklerState)
picklerState.value.shouldBe(2)
}

object unpicklerState {
def getInt(): Int = 3
object picklerState {
var value: Int = 0
def writeInt(int: Int): Unit = {
value = int
}
binaryPickler.unpickle(unpicklerState).shouldBe(Some(Planet.Earth))
}
val binaryPickler = implicitly[FakeBinaryPickler[Planet]]
binaryPickler.pickle(Planet.Venus)(picklerState)
assertEquals(picklerState.value, 2)

"retrieve a typeclass instance using apply" in {
CaseEnumIndex[Planet].caseFromIndex(1) shouldBe Some(Planet.Mercury)
object unpicklerState {
def getInt(): Int = 3
}
assertEquals(binaryPickler.unpickle(unpicklerState), Some(Planet.Earth))
}

test("CaseEnumIndex should retrieve a typeclass instance using apply") {
assertEquals(CaseEnumIndex[Planet].caseFromIndex(1), Some(Planet.Mercury))
}

}
94 changes: 43 additions & 51 deletions enumero/core/src/test/scala/CaseEnumMacroSpec.scala
Original file line number Diff line number Diff line change
@@ -1,8 +1,6 @@
import io.buildo.enumero.annotations.{enum, indexedEnum}

import org.scalatest.{Matchers, WordSpec}

class CaseEnumMacroSpec extends WordSpec with Matchers {
class CaseEnumMacroSuite extends munit.FunSuite {
@enum trait Planet {
Mercury
Venus
Expand All @@ -14,43 +12,39 @@ class CaseEnumMacroSpec extends WordSpec with Matchers {
object Ale
}

"@enum annotation" should {
"produce a valid CaseEnum-style ADT" in {
Planet.Earth shouldBe a[Product]
Planet.Earth shouldBe a[Serializable]
Planet.Earth shouldBe a[Planet]
Planet.Mercury should not be a[Planet.Earth.type]
Planet.Earth shouldBe Planet.Earth
}
test("@enum annotation should produce a valid CaseEnum-style ADT") {
assert(Planet.Earth.isInstanceOf[Product])
assert(Planet.Earth.isInstanceOf[Serializable])
assert(Planet.Earth.isInstanceOf[Planet])
assertEquals(Planet.Earth, Planet.Earth)
}

"produce a valid CaseEnum-style ADT (alternative syntax)" in {
Beer.Lager shouldBe a[Product]
Beer.Lager shouldBe a[Serializable]
Beer.Lager shouldBe a[Beer]
Beer.Ale should not be a[Beer.Lager.type]
Beer.Lager shouldBe Beer.Lager
}
test("@enum annotation should produce a valid CaseEnum-style ADT (alternative syntax)") {
assert(Beer.Lager.isInstanceOf[Product])
assert(Beer.Lager.isInstanceOf[Serializable])
assert(Beer.Lager.isInstanceOf[Beer])
assertEquals(Beer.Lager, Beer.Lager)
Copy link
Member

@veej veej Mar 27, 2020

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

we lost an assertion here (Beer.Ale)

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

it was intentional, when I tried to rewrite the assertion it wouldn't even compile ("fruitless type test") and it's such an obvious test that I preferred to drop it.

}

"allow accessing the values of the enumeration" in {
val typecheck: Set[Planet] = Planet.values
Planet.values shouldBe Set(Planet.Mercury, Planet.Venus, Planet.Earth)
}
test("@enum annotation should allow accessing the values of the enumeration") {
(Planet.values: Set[Planet]) // typecheck
assertEquals(Planet.values, Set(Planet.Mercury, Planet.Venus, Planet.Earth))
}

"allow printing / parsing the values of the enumeration" in {
Planet.caseFromString("Earth") shouldBe Some(Planet.Earth)
Planet.caseFromString("Nope") shouldBe None
Planet.caseToString(Planet.Earth) shouldBe "Earth"
"Planet.caseToString(Beer.Lager)" shouldNot typeCheck
}
test("@enum annotation should allow printing / parsing the values of the enumeration") {
assertEquals(Planet.caseFromString("Earth"), Some(Planet.Earth))
assertEquals(Planet.caseFromString("Nope"), None)
assertEquals(Planet.caseToString(Planet.Earth), "Earth")
compileErrors("Planet.caseToString(Beer.Lager)")
}

"allow accessing the enumeration name" in {
Planet.name shouldBe "Planet"
}
test("@enum annotation should allow accessing the enumeration name") {
assertEquals(Planet.name, "Planet")
}

}

class IndexedCaseEnumMacroSpec extends WordSpec with Matchers {
class IndexedCaseEnumMacroSpec extends munit.FunSuite {
@indexedEnum trait Planet {
type Index = Int
Mercury { 1 }
Expand All @@ -64,26 +58,24 @@ class IndexedCaseEnumMacroSpec extends WordSpec with Matchers {
Ale { 2 }
}

"@indexedEnum annotation" should {
"produce a valid IndexedCaseEnum-style ADT" in {
val typecheck: Int = 3: Planet#Index
Planet.Earth shouldBe a[Product]
Planet.Earth shouldBe a[Serializable]
Planet.Earth shouldBe a[Planet]
Planet.Mercury should not be a[Planet.Earth.type]
Planet.Earth shouldBe Planet.Earth
Planet.Earth.index shouldBe 3
}
test("@indexedEnum annotation should produce a valid IndexedCaseEnum-style ADT") {
val _: Int = 3: Planet#Index // typecheck
assert(Planet.Earth.isInstanceOf[Product])
assert(Planet.Earth.isInstanceOf[Serializable])
assert(Planet.Earth.isInstanceOf[Planet])
assertEquals(Planet.Earth, Planet.Earth)
assertEquals(Planet.Earth.index, 3)
}

"produce a valid IndexedCaseEnum-style ADT (alternative syntax)" in {
val typecheck: Int = 2: Planet#Index
Beer.Lager shouldBe a[Product]
Beer.Lager shouldBe a[Serializable]
Beer.Lager shouldBe a[Beer]
Beer.Ale should not be a[Beer.Lager.type]
Beer.Lager shouldBe Beer.Lager
Beer.Ale.index shouldBe 2
}
test(
"@indexedEnum annotation should produce a valid IndexedCaseEnum-style ADT (alternative syntax)",
) {
val _: Int = 2: Planet#Index // typecheck
assert(Beer.Lager.isInstanceOf[Product])
assert(Beer.Lager.isInstanceOf[Serializable])
assert(Beer.Lager.isInstanceOf[Beer])
assertEquals(Beer.Lager, Beer.Lager)
assertEquals(Beer.Ale.index, 2)
}

}
Loading