Skip to content

Commit 0c332b9

Browse files
committed
Resolve typelevel#1549. Enable all cross modules for Scala Native. Depends on typelevel/discipline-munit#73.
1 parent aa91908 commit 0c332b9

File tree

8 files changed

+185
-22
lines changed

8 files changed

+185
-22
lines changed
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
package alleycats.tests
2+
3+
import org.scalacheck.Test.Parameters
4+
5+
trait TestSettings {
6+
7+
lazy val checkConfiguration: Parameters =
8+
Parameters.default
9+
.withMinSuccessfulTests(50)
10+
.withMaxDiscardRatio(5.0f)
11+
.withMaxSize(10)
12+
.withMinSize(0)
13+
.withWorkers(1)
14+
}

build.sbt

Lines changed: 88 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@ val scalaCheckVersion = "1.15.2"
2727
val disciplineVersion = "1.1.3"
2828

2929
val disciplineScalatestVersion = "2.0.1"
30-
val disciplineMunitVersion = "1.0.4"
30+
val disciplineMunitVersion = "1.0.5"
3131

3232
val kindProjectorVersion = "0.11.3"
3333

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

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

44-
val Scala212 = "2.12.12"
44+
val Scala212 = "2.12.13"
4545
val Scala213 = "2.13.4"
4646
val DottyOld = "3.0.0-M2"
4747
val DottyNew = "3.0.0-M3"
@@ -52,15 +52,15 @@ ThisBuild / scalaVersion := Scala213
5252
ThisBuild / githubWorkflowPublishTargetBranches := Seq() // disable publication for now
5353

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

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

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

7272
val JvmCond = s"matrix.platform == 'jvm'"
7373
val JsCond = s"matrix.platform == 'js'"
74+
val NativeCond = s"matrix.platform == 'native'"
7475

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

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

229+
lazy val commonNativeSettings = Seq(
230+
// currently sbt-doctest doesn't work in Native/JS builds
231+
// https://github.com/tkawachi/sbt-doctest/issues/52
232+
doctestGenTests := Seq.empty,
233+
coverageEnabled := false,
234+
// Currently scala-native does not support Dotty
235+
crossScalaVersions := { crossScalaVersions.value filterNot Seq(DottyOld, DottyNew).contains }
236+
)
237+
226238
lazy val commonJvmSettings = Seq(
227239
testOptions in Test += {
228240
val flag = if (githubIsWorkflowBuild.value) "-oCI" else "-oDF"
@@ -521,8 +533,8 @@ lazy val cats = project
521533
.settings(moduleName := "root")
522534
.settings(publishSettings) // these settings are needed to release all aggregated modules under this root module
523535
.settings(noPublishSettings) // this is to exclude the root module itself from being published.
524-
.aggregate(catsJVM, catsJS)
525-
.dependsOn(catsJVM, catsJS, tests.jvm % "test-internal -> test")
536+
.aggregate(catsJVM, catsJS, catsNative)
537+
.dependsOn(catsJVM, catsJS, catsNative, tests.jvm % "test-internal -> test")
526538

527539
lazy val catsJVM = project
528540
.in(file(".catsJVM"))
@@ -589,7 +601,40 @@ lazy val catsJS = project
589601
)
590602
.enablePlugins(ScalaJSPlugin)
591603

592-
lazy val kernel = crossProject(JSPlatform, JVMPlatform)
604+
lazy val catsNative = project
605+
.in(file(".catsNative"))
606+
.settings(moduleName := "cats")
607+
.settings(noPublishSettings)
608+
.settings(catsSettings)
609+
.settings(commonNativeSettings)
610+
.aggregate(kernel.native,
611+
kernelLaws.native,
612+
core.native,
613+
laws.native,
614+
free.native,
615+
testkit.native,
616+
tests.native,
617+
alleycatsCore.native,
618+
alleycatsLaws.native,
619+
alleycatsTests.native,
620+
native
621+
)
622+
.dependsOn(
623+
kernel.native,
624+
kernelLaws.native,
625+
core.native,
626+
laws.native,
627+
free.native,
628+
testkit.native,
629+
tests.native % "test-internal -> test",
630+
alleycatsCore.native,
631+
alleycatsLaws.native,
632+
alleycatsTests.native % "test-internal -> test",
633+
native
634+
)
635+
.enablePlugins(ScalaNativePlugin)
636+
637+
lazy val kernel = crossProject(JSPlatform, JVMPlatform, NativePlatform)
593638
.crossType(CrossType.Pure)
594639
.in(file("kernel"))
595640
.settings(moduleName := "cats-kernel", name := "Cats kernel")
@@ -600,11 +645,12 @@ lazy val kernel = crossProject(JSPlatform, JVMPlatform)
600645
.settings(includeGeneratedSrc)
601646
.jsSettings(commonJsSettings)
602647
.jvmSettings(commonJvmSettings ++ mimaSettings("cats-kernel"))
648+
.nativeSettings(commonNativeSettings)
603649
.settings(
604650
libraryDependencies += "org.scalacheck" %%% "scalacheck" % scalaCheckVersion % Test
605651
)
606652

607-
lazy val kernelLaws = crossProject(JSPlatform, JVMPlatform)
653+
lazy val kernelLaws = crossProject(JSPlatform, JVMPlatform, NativePlatform)
608654
.in(file("kernel-laws"))
609655
.settings(moduleName := "cats-kernel-laws", name := "Cats kernel laws")
610656
.settings(commonSettings)
@@ -617,8 +663,9 @@ lazy val kernelLaws = crossProject(JSPlatform, JVMPlatform)
617663
.jvmSettings(commonJvmSettings ++ mimaSettings("cats-kernel-laws", includeCats1 = false))
618664
.jsSettings(coverageEnabled := false)
619665
.dependsOn(kernel)
666+
.nativeSettings(commonNativeSettings)
620667

621-
lazy val core = crossProject(JSPlatform, JVMPlatform)
668+
lazy val core = crossProject(JSPlatform, JVMPlatform, NativePlatform)
622669
.crossType(CrossType.Pure)
623670
.dependsOn(kernel)
624671
.settings(moduleName := "cats-core", name := "Cats core")
@@ -638,8 +685,10 @@ lazy val core = crossProject(JSPlatform, JVMPlatform)
638685
)
639686
.jsSettings(commonJsSettings)
640687
.jvmSettings(commonJvmSettings ++ mimaSettings("cats-core"))
688+
.settings(testingDependencies)
689+
.nativeSettings(commonNativeSettings)
641690

642-
lazy val laws = crossProject(JSPlatform, JVMPlatform)
691+
lazy val laws = crossProject(JSPlatform, JVMPlatform, NativePlatform)
643692
.crossType(CrossType.Pure)
644693
.dependsOn(kernel, core, kernelLaws)
645694
.settings(moduleName := "cats-laws", name := "Cats laws")
@@ -649,16 +698,18 @@ lazy val laws = crossProject(JSPlatform, JVMPlatform)
649698
.jsSettings(commonJsSettings)
650699
.jvmSettings(commonJvmSettings ++ mimaSettings("cats-laws", includeCats1 = false))
651700
.jsSettings(coverageEnabled := false)
701+
.nativeSettings(commonNativeSettings)
652702

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

661-
lazy val tests = crossProject(JSPlatform, JVMPlatform)
712+
lazy val tests = crossProject(JSPlatform, JVMPlatform, NativePlatform)
662713
.crossType(CrossType.Pure)
663714
.dependsOn(testkit % Test)
664715
.settings(moduleName := "cats-tests")
@@ -668,8 +719,9 @@ lazy val tests = crossProject(JSPlatform, JVMPlatform)
668719
.jsSettings(commonJsSettings)
669720
.jvmSettings(commonJvmSettings)
670721
.settings(scalacOptions in Test := (scalacOptions in Test).value.filter(_ != "-Xfatal-warnings"))
722+
.nativeSettings(commonNativeSettings)
671723

672-
lazy val testkit = crossProject(JSPlatform, JVMPlatform)
724+
lazy val testkit = crossProject(JSPlatform, JVMPlatform, NativePlatform)
673725
.crossType(CrossType.Pure)
674726
.dependsOn(core, laws)
675727
.enablePlugins(BuildInfoPlugin)
@@ -680,8 +732,9 @@ lazy val testkit = crossProject(JSPlatform, JVMPlatform)
680732
.jsSettings(commonJsSettings)
681733
.jvmSettings(commonJvmSettings ++ mimaSettings("cats-testkit", includeCats1 = false))
682734
.settings(scalacOptions := scalacOptions.value.filter(_ != "-Xfatal-warnings"))
735+
.nativeSettings(commonNativeSettings)
683736

684-
lazy val alleycatsCore = crossProject(JSPlatform, JVMPlatform)
737+
lazy val alleycatsCore = crossProject(JSPlatform, JVMPlatform, NativePlatform)
685738
.crossType(CrossType.Pure)
686739
.in(file("alleycats-core"))
687740
.dependsOn(core)
@@ -692,8 +745,9 @@ lazy val alleycatsCore = crossProject(JSPlatform, JVMPlatform)
692745
.settings(includeGeneratedSrc)
693746
.jsSettings(commonJsSettings)
694747
.jvmSettings(commonJvmSettings ++ mimaSettings("alleycats-core", includeCats1 = false))
748+
.nativeSettings(commonNativeSettings)
695749

696-
lazy val alleycatsLaws = crossProject(JSPlatform, JVMPlatform)
750+
lazy val alleycatsLaws = crossProject(JSPlatform, JVMPlatform, NativePlatform)
697751
.crossType(CrossType.Pure)
698752
.in(file("alleycats-laws"))
699753
.dependsOn(alleycatsCore, laws)
@@ -706,8 +760,9 @@ lazy val alleycatsLaws = crossProject(JSPlatform, JVMPlatform)
706760
.jsSettings(commonJsSettings)
707761
.jvmSettings(commonJvmSettings ++ mimaSettings("alleycats-laws", includeCats1 = false))
708762
.jsSettings(coverageEnabled := false)
763+
.nativeSettings(commonNativeSettings)
709764

710-
lazy val alleycatsTests = crossProject(JSPlatform, JVMPlatform)
765+
lazy val alleycatsTests = crossProject(JSPlatform, JVMPlatform, NativePlatform)
711766
.in(file("alleycats-tests"))
712767
.dependsOn(alleycatsLaws, tests % "test-internal -> test")
713768
.settings(moduleName := "alleycats-tests")
@@ -716,6 +771,7 @@ lazy val alleycatsTests = crossProject(JSPlatform, JVMPlatform)
716771
.jsSettings(commonJsSettings)
717772
.jvmSettings(commonJvmSettings)
718773
.settings(scalacOptions in Test := (scalacOptions in Test).value.filter(_ != "-Xfatal-warnings"))
774+
.nativeSettings(commonNativeSettings)
719775

720776
// bench is currently JVM-only
721777

@@ -761,6 +817,14 @@ lazy val js = project
761817
.settings(commonJsSettings)
762818
.enablePlugins(ScalaJSPlugin)
763819

820+
// cats-native is Native-only
821+
lazy val native = project
822+
.dependsOn(core.native, tests.native % "test-internal -> test")
823+
.settings(moduleName := "cats-native")
824+
.settings(catsSettings)
825+
.settings(commonNativeSettings)
826+
.enablePlugins(ScalaNativePlugin)
827+
764828
// cats-jvm is JVM-only
765829
lazy val jvm = project
766830
.dependsOn(core.jvm, tests.jvm % "test-internal -> test")
@@ -872,7 +936,12 @@ addCommandAlias("validateKernelJS", "kernelLawsJS/test")
872936
addCommandAlias("validateFreeJS", "freeJS/test")
873937
addCommandAlias("validateAlleycatsJS", "alleycatsTestsJS/test")
874938
addCommandAlias("validateAllJS", "all testsJS/test js/test kernelLawsJS/test freeJS/test alleycatsTestsJS/test")
875-
addCommandAlias("validate", ";clean;validateJS;validateKernelJS;validateFreeJS;validateJVM")
939+
addCommandAlias("validateNative", ";testsNative/test;native/test")
940+
addCommandAlias("validateKernelNative", "kernelLawsNative/test")
941+
addCommandAlias("validateFreeNative", "freeNative/test")
942+
addCommandAlias("validateAlleycatsNative", "alleycatsTestsNative/test")
943+
addCommandAlias("validateAllNative", "all testsNative/test native/test kernelLawsNative/test freeNative/test alleycatsTestsNative/test")
944+
addCommandAlias("validate", ";clean;validateJS;validateKernelJS;validateFreeJS;validateNative;validateKernelNative;validateFreeNative;validateJVM")
876945

877946
addCommandAlias("prePR", "fmt")
878947

kernel-laws/js/src/main/scala/cats/platform/Platform.scala

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,5 +5,6 @@ private[cats] object Platform {
55
// $COVERAGE-OFF$
66
final val isJvm = false
77
final val isJs = true
8+
final val isNative = false
89
// $COVERAGE-ON$
910
}

kernel-laws/jvm/src/main/scala/cats/platform/Platform.scala

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,5 +5,6 @@ private[cats] object Platform {
55
// $COVERAGE-OFF$
66
final val isJvm = true
77
final val isJs = false
8+
final val isNative = false
89
// $COVERAGE-ON$
910
}
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
package cats.platform
2+
3+
private[cats] object Platform {
4+
// using `final val` makes compiler constant-fold any use of these values, dropping dead code automatically
5+
// $COVERAGE-OFF$
6+
final val isJvm = false
7+
final val isJs = false
8+
final val isNative = true
9+
// $COVERAGE-ON$
10+
}

kernel-laws/shared/src/main/scala/cats/kernel/laws/SerializableLaws.scala

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -18,14 +18,13 @@ object SerializableLaws {
1818
// This part is a bit tricky. Basically, we only want to test
1919
// serializability on the JVM.
2020
//
21-
// `Platform.isJs` is a constant expression, so we can rely on
21+
// `Platform.isJvm` is a constant expression, so we can rely on
2222
// scalac to prune away the "other" branch. Thus, when Scala.js
2323
// looks at this method it won't "see" the branch which was removed,
2424
// and will avoid an error trying to support java.io.*.
2525

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

@@ -48,4 +47,6 @@ object SerializableLaws {
4847
if (ois != null) ois.close() // scalastyle:ignore null
4948
}
5049
}
50+
}
51+
else Prop(_ => Result(status = Proof))
5152
}
Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
1+
package cats.native.tests
2+
3+
import cats.kernel.laws.discipline.{MonoidTests => MonoidLawTests, SemigroupTests => SemigroupLawTests}
4+
import cats.kernel.{Eq, Semigroup}
5+
import cats.laws.discipline._
6+
import cats.laws.discipline.arbitrary._
7+
import cats.syntax.either._
8+
import cats.tests.{CatsSuite, ListWrapper}
9+
import org.scalacheck.Arbitrary.arbitrary
10+
import org.scalacheck.rng.Seed
11+
import org.scalacheck.{Arbitrary, Cogen}
12+
13+
import scala.concurrent.{Await, ExecutionContextExecutor, Future}
14+
import scala.concurrent.duration._
15+
16+
class FutureSuite extends CatsSuite {
17+
val timeout = 3.seconds
18+
19+
// TODO: We shouldn't do this! See: https://github.com/scala-js/scala-js/issues/2102
20+
implicit private object SynchronousExecutor extends ExecutionContextExecutor {
21+
def execute(runnable: Runnable): Unit =
22+
try {
23+
runnable.run()
24+
} catch {
25+
case t: Throwable => reportFailure(t)
26+
}
27+
28+
def reportFailure(t: Throwable): Unit =
29+
t.printStackTrace()
30+
}
31+
32+
def futureEither[A](f: Future[A]): Future[Either[Throwable, A]] =
33+
f.map(Either.right[Throwable, A]).recover { case t => Either.left(t) }
34+
35+
implicit def eqfa[A: Eq]: Eq[Future[A]] =
36+
new Eq[Future[A]] {
37+
def eqv(fx: Future[A], fy: Future[A]): Boolean = {
38+
val fz = futureEither(fx).zip(futureEither(fy))
39+
Await.result(fz.map { case (tx, ty) => tx === ty }, timeout)
40+
}
41+
}
42+
43+
implicit def cogen[A: Cogen]: Cogen[Future[A]] =
44+
Cogen[Future[A]] { (seed: Seed, t: Future[A]) =>
45+
Cogen[A].perturb(seed, Await.result(t, timeout))
46+
}
47+
48+
implicit val throwableEq: Eq[Throwable] =
49+
Eq.by[Throwable, String](_.toString)
50+
51+
// Need non-fatal Throwables for Future recoverWith/handleError
52+
implicit val nonFatalArbitrary: Arbitrary[Throwable] =
53+
Arbitrary(arbitrary[Exception].map(identity))
54+
55+
checkAll("Future with Throwable", MonadErrorTests[Future, Throwable].monadError[Int, Int, Int])
56+
checkAll("Future", MonadTests[Future].monad[Int, Int, Int])
57+
checkAll("Future", CoflatMapTests[Future].coflatMap[Int, Int, Int])
58+
59+
{
60+
implicit val F: Semigroup[ListWrapper[Int]] = ListWrapper.semigroup[Int]
61+
checkAll("Future[ListWrapper[Int]]", SemigroupLawTests[Future[ListWrapper[Int]]].semigroup)
62+
}
63+
64+
checkAll("Future[Int]", MonoidLawTests[Future[Int]].monoid)
65+
}

0 commit comments

Comments
 (0)