Skip to content

Commit

Permalink
Resolve typelevel#1549. Enable all cross modules for Scala Native. De…
Browse files Browse the repository at this point in the history
  • Loading branch information
arashi01 committed Jan 29, 2021
1 parent aa91908 commit 0c332b9
Show file tree
Hide file tree
Showing 8 changed files with 185 additions and 22 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
package alleycats.tests

import org.scalacheck.Test.Parameters

trait TestSettings {

lazy val checkConfiguration: Parameters =
Parameters.default
.withMinSuccessfulTests(50)
.withMaxDiscardRatio(5.0f)
.withMaxSize(10)
.withMinSize(0)
.withWorkers(1)
}
107 changes: 88 additions & 19 deletions build.sbt
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ val scalaCheckVersion = "1.15.2"
val disciplineVersion = "1.1.3"

val disciplineScalatestVersion = "2.0.1"
val disciplineMunitVersion = "1.0.4"
val disciplineMunitVersion = "1.0.5"

val kindProjectorVersion = "0.11.3"

Expand All @@ -41,7 +41,7 @@ val GraalVM8 = "[email protected]"

ThisBuild / githubWorkflowJavaVersions := Seq(PrimaryJava, LTSJava, LatestJava, GraalVM8)

val Scala212 = "2.12.12"
val Scala212 = "2.12.13"
val Scala213 = "2.13.4"
val DottyOld = "3.0.0-M2"
val DottyNew = "3.0.0-M3"
Expand All @@ -52,15 +52,15 @@ ThisBuild / scalaVersion := Scala213
ThisBuild / githubWorkflowPublishTargetBranches := Seq() // disable publication for now

ThisBuild / githubWorkflowBuildMatrixAdditions +=
"platform" -> List("jvm", "js")
"platform" -> List("jvm", "js", "native")

ThisBuild / githubWorkflowBuildMatrixExclusions ++=
githubWorkflowJavaVersions.value.filterNot(Set(PrimaryJava)).map { java =>
MatrixExclude(Map("platform" -> "js", "java" -> java))
githubWorkflowJavaVersions.value.filterNot(Set(PrimaryJava)).flatMap { java =>
Seq(MatrixExclude(Map("platform" -> "js", "java" -> java)), MatrixExclude(Map("platform" -> "native", "java" -> java)))
}

ThisBuild / githubWorkflowBuildMatrixExclusions ++=
Seq("jvm", "js").map { platform =>
Seq("jvm", "js", "native").map { platform =>
MatrixExclude(
Map("platform" -> platform, "java" -> LatestJava, "scala" -> DottyOld)
) // 3.0.0-M1 doesn't work on JDK 14+
Expand All @@ -71,12 +71,14 @@ ThisBuild / githubWorkflowArtifactUpload := false

val JvmCond = s"matrix.platform == 'jvm'"
val JsCond = s"matrix.platform == 'js'"
val NativeCond = s"matrix.platform == 'native'"

val Scala2Cond = s"(matrix.scala != '$DottyOld' && matrix.scala != '$DottyNew')"
val Scala3Cond = s"(matrix.scala == '$DottyOld' || matrix.scala == '$DottyNew')"

ThisBuild / githubWorkflowBuild := Seq(
WorkflowStep.Sbt(List("validateAllJS"), name = Some("Validate JavaScript"), cond = Some(JsCond)),
WorkflowStep.Sbt(List("validateAllNative"), name = Some("Validate Scala Native"), cond = Some(NativeCond)),
WorkflowStep.Use(UseRef.Public("actions", "setup-python", "v2"),
name = Some("Setup Python"),
params = Map("python-version" -> "3.x"),
Expand Down Expand Up @@ -160,6 +162,7 @@ lazy val commonSettings = Seq(
resolvers ++= Seq(Resolver.sonatypeRepo("releases"), Resolver.sonatypeRepo("snapshots")),
parallelExecution in Test := false,
testFrameworks += new TestFramework("munit.Framework"),
doctestTestFramework := DoctestTestFramework.Munit,
scalacOptions in (Compile, doc) := (scalacOptions in (Compile, doc)).value.filter(_ != "-Xfatal-warnings"),
Compile / doc / sources := {
val old = (Compile / doc / sources).value
Expand Down Expand Up @@ -223,6 +226,15 @@ lazy val commonJsSettings = Seq(
coverageEnabled := false
)

lazy val commonNativeSettings = Seq(
// currently sbt-doctest doesn't work in Native/JS builds
// https://github.com/tkawachi/sbt-doctest/issues/52
doctestGenTests := Seq.empty,
coverageEnabled := false,
// Currently scala-native does not support Dotty
crossScalaVersions := { crossScalaVersions.value filterNot Seq(DottyOld, DottyNew).contains }
)

lazy val commonJvmSettings = Seq(
testOptions in Test += {
val flag = if (githubIsWorkflowBuild.value) "-oCI" else "-oDF"
Expand Down Expand Up @@ -521,8 +533,8 @@ lazy val cats = project
.settings(moduleName := "root")
.settings(publishSettings) // these settings are needed to release all aggregated modules under this root module
.settings(noPublishSettings) // this is to exclude the root module itself from being published.
.aggregate(catsJVM, catsJS)
.dependsOn(catsJVM, catsJS, tests.jvm % "test-internal -> test")
.aggregate(catsJVM, catsJS, catsNative)
.dependsOn(catsJVM, catsJS, catsNative, tests.jvm % "test-internal -> test")

lazy val catsJVM = project
.in(file(".catsJVM"))
Expand Down Expand Up @@ -589,7 +601,40 @@ lazy val catsJS = project
)
.enablePlugins(ScalaJSPlugin)

lazy val kernel = crossProject(JSPlatform, JVMPlatform)
lazy val catsNative = project
.in(file(".catsNative"))
.settings(moduleName := "cats")
.settings(noPublishSettings)
.settings(catsSettings)
.settings(commonNativeSettings)
.aggregate(kernel.native,
kernelLaws.native,
core.native,
laws.native,
free.native,
testkit.native,
tests.native,
alleycatsCore.native,
alleycatsLaws.native,
alleycatsTests.native,
native
)
.dependsOn(
kernel.native,
kernelLaws.native,
core.native,
laws.native,
free.native,
testkit.native,
tests.native % "test-internal -> test",
alleycatsCore.native,
alleycatsLaws.native,
alleycatsTests.native % "test-internal -> test",
native
)
.enablePlugins(ScalaNativePlugin)

lazy val kernel = crossProject(JSPlatform, JVMPlatform, NativePlatform)
.crossType(CrossType.Pure)
.in(file("kernel"))
.settings(moduleName := "cats-kernel", name := "Cats kernel")
Expand All @@ -600,11 +645,12 @@ lazy val kernel = crossProject(JSPlatform, JVMPlatform)
.settings(includeGeneratedSrc)
.jsSettings(commonJsSettings)
.jvmSettings(commonJvmSettings ++ mimaSettings("cats-kernel"))
.nativeSettings(commonNativeSettings)
.settings(
libraryDependencies += "org.scalacheck" %%% "scalacheck" % scalaCheckVersion % Test
)

lazy val kernelLaws = crossProject(JSPlatform, JVMPlatform)
lazy val kernelLaws = crossProject(JSPlatform, JVMPlatform, NativePlatform)
.in(file("kernel-laws"))
.settings(moduleName := "cats-kernel-laws", name := "Cats kernel laws")
.settings(commonSettings)
Expand All @@ -617,8 +663,9 @@ lazy val kernelLaws = crossProject(JSPlatform, JVMPlatform)
.jvmSettings(commonJvmSettings ++ mimaSettings("cats-kernel-laws", includeCats1 = false))
.jsSettings(coverageEnabled := false)
.dependsOn(kernel)
.nativeSettings(commonNativeSettings)

lazy val core = crossProject(JSPlatform, JVMPlatform)
lazy val core = crossProject(JSPlatform, JVMPlatform, NativePlatform)
.crossType(CrossType.Pure)
.dependsOn(kernel)
.settings(moduleName := "cats-core", name := "Cats core")
Expand All @@ -638,8 +685,10 @@ lazy val core = crossProject(JSPlatform, JVMPlatform)
)
.jsSettings(commonJsSettings)
.jvmSettings(commonJvmSettings ++ mimaSettings("cats-core"))
.settings(testingDependencies)
.nativeSettings(commonNativeSettings)

lazy val laws = crossProject(JSPlatform, JVMPlatform)
lazy val laws = crossProject(JSPlatform, JVMPlatform, NativePlatform)
.crossType(CrossType.Pure)
.dependsOn(kernel, core, kernelLaws)
.settings(moduleName := "cats-laws", name := "Cats laws")
Expand All @@ -649,16 +698,18 @@ lazy val laws = crossProject(JSPlatform, JVMPlatform)
.jsSettings(commonJsSettings)
.jvmSettings(commonJvmSettings ++ mimaSettings("cats-laws", includeCats1 = false))
.jsSettings(coverageEnabled := false)
.nativeSettings(commonNativeSettings)

lazy val free = crossProject(JSPlatform, JVMPlatform)
lazy val free = crossProject(JSPlatform, JVMPlatform, NativePlatform)
.crossType(CrossType.Pure)
.dependsOn(core, tests % "test-internal -> test")
.settings(moduleName := "cats-free", name := "Cats Free")
.settings(catsSettings)
.jsSettings(commonJsSettings)
.jvmSettings(commonJvmSettings ++ mimaSettings("cats-free"))
.nativeSettings(commonNativeSettings)

lazy val tests = crossProject(JSPlatform, JVMPlatform)
lazy val tests = crossProject(JSPlatform, JVMPlatform, NativePlatform)
.crossType(CrossType.Pure)
.dependsOn(testkit % Test)
.settings(moduleName := "cats-tests")
Expand All @@ -668,8 +719,9 @@ lazy val tests = crossProject(JSPlatform, JVMPlatform)
.jsSettings(commonJsSettings)
.jvmSettings(commonJvmSettings)
.settings(scalacOptions in Test := (scalacOptions in Test).value.filter(_ != "-Xfatal-warnings"))
.nativeSettings(commonNativeSettings)

lazy val testkit = crossProject(JSPlatform, JVMPlatform)
lazy val testkit = crossProject(JSPlatform, JVMPlatform, NativePlatform)
.crossType(CrossType.Pure)
.dependsOn(core, laws)
.enablePlugins(BuildInfoPlugin)
Expand All @@ -680,8 +732,9 @@ lazy val testkit = crossProject(JSPlatform, JVMPlatform)
.jsSettings(commonJsSettings)
.jvmSettings(commonJvmSettings ++ mimaSettings("cats-testkit", includeCats1 = false))
.settings(scalacOptions := scalacOptions.value.filter(_ != "-Xfatal-warnings"))
.nativeSettings(commonNativeSettings)

lazy val alleycatsCore = crossProject(JSPlatform, JVMPlatform)
lazy val alleycatsCore = crossProject(JSPlatform, JVMPlatform, NativePlatform)
.crossType(CrossType.Pure)
.in(file("alleycats-core"))
.dependsOn(core)
Expand All @@ -692,8 +745,9 @@ lazy val alleycatsCore = crossProject(JSPlatform, JVMPlatform)
.settings(includeGeneratedSrc)
.jsSettings(commonJsSettings)
.jvmSettings(commonJvmSettings ++ mimaSettings("alleycats-core", includeCats1 = false))
.nativeSettings(commonNativeSettings)

lazy val alleycatsLaws = crossProject(JSPlatform, JVMPlatform)
lazy val alleycatsLaws = crossProject(JSPlatform, JVMPlatform, NativePlatform)
.crossType(CrossType.Pure)
.in(file("alleycats-laws"))
.dependsOn(alleycatsCore, laws)
Expand All @@ -706,8 +760,9 @@ lazy val alleycatsLaws = crossProject(JSPlatform, JVMPlatform)
.jsSettings(commonJsSettings)
.jvmSettings(commonJvmSettings ++ mimaSettings("alleycats-laws", includeCats1 = false))
.jsSettings(coverageEnabled := false)
.nativeSettings(commonNativeSettings)

lazy val alleycatsTests = crossProject(JSPlatform, JVMPlatform)
lazy val alleycatsTests = crossProject(JSPlatform, JVMPlatform, NativePlatform)
.in(file("alleycats-tests"))
.dependsOn(alleycatsLaws, tests % "test-internal -> test")
.settings(moduleName := "alleycats-tests")
Expand All @@ -716,6 +771,7 @@ lazy val alleycatsTests = crossProject(JSPlatform, JVMPlatform)
.jsSettings(commonJsSettings)
.jvmSettings(commonJvmSettings)
.settings(scalacOptions in Test := (scalacOptions in Test).value.filter(_ != "-Xfatal-warnings"))
.nativeSettings(commonNativeSettings)

// bench is currently JVM-only

Expand Down Expand Up @@ -761,6 +817,14 @@ lazy val js = project
.settings(commonJsSettings)
.enablePlugins(ScalaJSPlugin)

// cats-native is Native-only
lazy val native = project
.dependsOn(core.native, tests.native % "test-internal -> test")
.settings(moduleName := "cats-native")
.settings(catsSettings)
.settings(commonNativeSettings)
.enablePlugins(ScalaNativePlugin)

// cats-jvm is JVM-only
lazy val jvm = project
.dependsOn(core.jvm, tests.jvm % "test-internal -> test")
Expand Down Expand Up @@ -872,7 +936,12 @@ addCommandAlias("validateKernelJS", "kernelLawsJS/test")
addCommandAlias("validateFreeJS", "freeJS/test")
addCommandAlias("validateAlleycatsJS", "alleycatsTestsJS/test")
addCommandAlias("validateAllJS", "all testsJS/test js/test kernelLawsJS/test freeJS/test alleycatsTestsJS/test")
addCommandAlias("validate", ";clean;validateJS;validateKernelJS;validateFreeJS;validateJVM")
addCommandAlias("validateNative", ";testsNative/test;native/test")
addCommandAlias("validateKernelNative", "kernelLawsNative/test")
addCommandAlias("validateFreeNative", "freeNative/test")
addCommandAlias("validateAlleycatsNative", "alleycatsTestsNative/test")
addCommandAlias("validateAllNative", "all testsNative/test native/test kernelLawsNative/test freeNative/test alleycatsTestsNative/test")
addCommandAlias("validate", ";clean;validateJS;validateKernelJS;validateFreeJS;validateNative;validateKernelNative;validateFreeNative;validateJVM")

addCommandAlias("prePR", "fmt")

Expand Down
1 change: 1 addition & 0 deletions kernel-laws/js/src/main/scala/cats/platform/Platform.scala
Original file line number Diff line number Diff line change
Expand Up @@ -5,5 +5,6 @@ private[cats] object Platform {
// $COVERAGE-OFF$
final val isJvm = false
final val isJs = true
final val isNative = false
// $COVERAGE-ON$
}
Original file line number Diff line number Diff line change
Expand Up @@ -5,5 +5,6 @@ private[cats] object Platform {
// $COVERAGE-OFF$
final val isJvm = true
final val isJs = false
final val isNative = false
// $COVERAGE-ON$
}
10 changes: 10 additions & 0 deletions kernel-laws/native/src/main/scala/cats/platform/Platform.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
package cats.platform

private[cats] object Platform {
// using `final val` makes compiler constant-fold any use of these values, dropping dead code automatically
// $COVERAGE-OFF$
final val isJvm = false
final val isJs = false
final val isNative = true
// $COVERAGE-ON$
}
Original file line number Diff line number Diff line change
Expand Up @@ -18,14 +18,13 @@ object SerializableLaws {
// This part is a bit tricky. Basically, we only want to test
// serializability on the JVM.
//
// `Platform.isJs` is a constant expression, so we can rely on
// `Platform.isJvm` is a constant expression, so we can rely on
// scalac to prune away the "other" branch. Thus, when Scala.js
// looks at this method it won't "see" the branch which was removed,
// and will avoid an error trying to support java.io.*.

def serializable[A](a: A): Prop =
if (Platform.isJs) Prop(_ => Result(status = Proof))
else
if (Platform.isJvm) {
Prop { _ =>
import java.io.{ByteArrayInputStream, ByteArrayOutputStream, ObjectInputStream, ObjectOutputStream}

Expand All @@ -48,4 +47,6 @@ object SerializableLaws {
if (ois != null) ois.close() // scalastyle:ignore null
}
}
}
else Prop(_ => Result(status = Proof))
}
65 changes: 65 additions & 0 deletions native/src/test/scala/cats/native/tests/FutureSuite.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
package cats.native.tests

import cats.kernel.laws.discipline.{MonoidTests => MonoidLawTests, SemigroupTests => SemigroupLawTests}
import cats.kernel.{Eq, Semigroup}
import cats.laws.discipline._
import cats.laws.discipline.arbitrary._
import cats.syntax.either._
import cats.tests.{CatsSuite, ListWrapper}
import org.scalacheck.Arbitrary.arbitrary
import org.scalacheck.rng.Seed
import org.scalacheck.{Arbitrary, Cogen}

import scala.concurrent.{Await, ExecutionContextExecutor, Future}
import scala.concurrent.duration._

class FutureSuite extends CatsSuite {
val timeout = 3.seconds

// TODO: We shouldn't do this! See: https://github.com/scala-js/scala-js/issues/2102
implicit private object SynchronousExecutor extends ExecutionContextExecutor {
def execute(runnable: Runnable): Unit =
try {
runnable.run()
} catch {
case t: Throwable => reportFailure(t)
}

def reportFailure(t: Throwable): Unit =
t.printStackTrace()
}

def futureEither[A](f: Future[A]): Future[Either[Throwable, A]] =
f.map(Either.right[Throwable, A]).recover { case t => Either.left(t) }

implicit def eqfa[A: Eq]: Eq[Future[A]] =
new Eq[Future[A]] {
def eqv(fx: Future[A], fy: Future[A]): Boolean = {
val fz = futureEither(fx).zip(futureEither(fy))
Await.result(fz.map { case (tx, ty) => tx === ty }, timeout)
}
}

implicit def cogen[A: Cogen]: Cogen[Future[A]] =
Cogen[Future[A]] { (seed: Seed, t: Future[A]) =>
Cogen[A].perturb(seed, Await.result(t, timeout))
}

implicit val throwableEq: Eq[Throwable] =
Eq.by[Throwable, String](_.toString)

// Need non-fatal Throwables for Future recoverWith/handleError
implicit val nonFatalArbitrary: Arbitrary[Throwable] =
Arbitrary(arbitrary[Exception].map(identity))

checkAll("Future with Throwable", MonadErrorTests[Future, Throwable].monadError[Int, Int, Int])
checkAll("Future", MonadTests[Future].monad[Int, Int, Int])
checkAll("Future", CoflatMapTests[Future].coflatMap[Int, Int, Int])

{
implicit val F: Semigroup[ListWrapper[Int]] = ListWrapper.semigroup[Int]
checkAll("Future[ListWrapper[Int]]", SemigroupLawTests[Future[ListWrapper[Int]]].semigroup)
}

checkAll("Future[Int]", MonoidLawTests[Future[Int]].monoid)
}
Loading

0 comments on commit 0c332b9

Please sign in to comment.