From e8df41a04dfa403f7d96b55d66b547723031e288 Mon Sep 17 00:00:00 2001 From: Georgi Krastev Date: Fri, 27 Aug 2021 13:19:36 +0300 Subject: [PATCH 1/2] Port FoldableSuite to Scala 3 - Update scalafmt to 3.0 and use `scala3` dialect - Refactor `FunctorSuite` to make use of Scala 3 features --- .scalafmt.conf | 3 +- .../test/scala-3/cats/derived/foldable.scala | 88 +++++++++++++++++++ .../test/scala-3/cats/derived/functor.scala | 72 +++++++-------- 3 files changed, 123 insertions(+), 40 deletions(-) create mode 100644 core/src/test/scala-3/cats/derived/foldable.scala diff --git a/.scalafmt.conf b/.scalafmt.conf index d45701aa..b4486c93 100644 --- a/.scalafmt.conf +++ b/.scalafmt.conf @@ -1,4 +1,5 @@ -version = "2.7.5" +version = "3.0.0" +runner.dialect = "scala3" align.preset = none maxColumn = 120 includeNoParensInSelectChains = false diff --git a/core/src/test/scala-3/cats/derived/foldable.scala b/core/src/test/scala-3/cats/derived/foldable.scala new file mode 100644 index 00000000..cc1704dd --- /dev/null +++ b/core/src/test/scala-3/cats/derived/foldable.scala @@ -0,0 +1,88 @@ +/* + * Copyright (c) 2015 Miles Sabin + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package cats +package derived + +import cats.laws.discipline.{FoldableTests, SerializableTests} +import cats.syntax.all.* +import org.scalacheck.Arbitrary +import scala.compiletime.* + +class FoldableSuite extends KittensSuite: + import FoldableSuite.* + import TestDefns.* + + inline def foldableTests[F[_]]: FoldableTests[F] = + FoldableTests[F](summonInline) + + inline def testFoldable(inline context: String): Unit = + checkAll(s"$context.Foldable[IList]", foldableTests[IList].foldable[Int, Long]) + checkAll(s"$context.Foldable[Tree]", foldableTests[Tree].foldable[Int, Long]) + checkAll(s"$context.Foldable[GenericAdt]", foldableTests[GenericAdt].foldable[Int, Long]) + checkAll(s"$context.Foldable[OptList]", foldableTests[OptList].foldable[Int, Long]) + checkAll(s"$context.Foldable[ListSnoc]", foldableTests[ListSnoc].foldable[Int, Long]) + checkAll(s"$context.Foldable[AndChar]", foldableTests[AndChar].foldable[Int, Long]) + checkAll(s"$context.Foldable[Interleaved]", foldableTests[Interleaved].foldable[Int, Long]) + checkAll(s"$context.Foldable[BoxNel]", foldableTests[BoxNel].foldable[Int, Long]) + checkAll(s"$context.Foldable is Serializable", SerializableTests.serializable(summonInline[Foldable[Tree]])) + + locally { + import auto.foldable.given + testFoldable("auto") + } + + locally { + import semiInstances.given + testFoldable("semiauto") + } + +end FoldableSuite + +object FoldableSuite: + import TestDefns.* + + type OptList[A] = Option[List[A]] + type ListSnoc[A] = List[Snoc[A]] + type AndChar[A] = (A, Char) + type BoxNel[A] = Box[Nel[A]] + + object semiInstances: + given Foldable[IList] = semiauto.foldable + given Foldable[Tree] = semiauto.foldable + given Foldable[GenericAdt] = semiauto.foldable + given Foldable[OptList] = semiauto.foldable + given Foldable[ListSnoc] = semiauto.foldable + given Foldable[AndChar] = semiauto.foldable + given Foldable[Interleaved] = semiauto.foldable + given Foldable[BoxNel] = semiauto.foldable + + final case class Nel[+A](head: A, tail: List[A]) + object Nel: + given [A: Eq]: Eq[Nel[A]] = + (x, y) => x.head === y.head && x.tail === y.tail + + given [A: Arbitrary]: Arbitrary[Nel[A]] = + Arbitrary(for + head <- Arbitrary.arbitrary[A] + tail <- Arbitrary.arbitrary[List[A]] + yield Nel(head, tail)) + + given Foldable[Nel] with + def foldLeft[A, B](fa: Nel[A], b: B)(f: (B, A) => B) = fa.tail.foldl(b)(f) + def foldRight[A, B](fa: Nel[A], lb: Eval[B])(f: (A, Eval[B]) => Eval[B]) = fa.tail.foldr(lb)(f) + +end FoldableSuite diff --git a/core/src/test/scala-3/cats/derived/functor.scala b/core/src/test/scala-3/cats/derived/functor.scala index 96ca253b..104e33a0 100644 --- a/core/src/test/scala-3/cats/derived/functor.scala +++ b/core/src/test/scala-3/cats/derived/functor.scala @@ -17,44 +17,38 @@ package cats package derived -import cats.laws.discipline._ -import cats.laws.discipline.eq._ +import cats.laws.discipline.* +import cats.laws.discipline.eq.* +import scala.compiletime.* -class FunctorSuite extends KittensSuite { +class FunctorSuite extends KittensSuite: import TestDefns.* - implicit val exhaustivePred: ExhaustiveCheck[Predicate[Boolean]] = + given ExhaustiveCheck[Predicate[Boolean]] = ExhaustiveCheck.instance(List(_ => true, _ => false, identity, !_)) - def testFunctor(context: String)(implicit - iList: Functor[IList], - tree: Functor[Tree], - genericAdt: Functor[GenericAdt], - optList: Functor[OptList], - listSnoc: Functor[ListSnoc], - andChar: Functor[AndChar], - interleaved: Functor[Interleaved], - nestedPred: Functor[NestedPred] - ): Unit = { - checkAll(s"$context.Functor[IList]", FunctorTests[IList].functor[Int, String, Long]) - checkAll(s"$context.Functor[Tree]", FunctorTests[Tree].functor[Int, String, Long]) - checkAll(s"$context.Functor[GenericAdt]", FunctorTests[GenericAdt].functor[Int, String, Long]) - checkAll(s"$context.Functor[OptList]", FunctorTests[OptList].functor[Int, String, Long]) - checkAll(s"$context.Functor[ListSnoc]", FunctorTests[ListSnoc].functor[Int, String, Long]) - // FIXME: Testing `FunctorTests[AndChar].functor[Int, String, Int]` causes a ClassCastException - checkAll(s"$context.Functor[AndChar]", FunctorTests[AndChar].functor[Int, String, Int]) - checkAll(s"$context.Functor[Interleaved]", FunctorTests[Interleaved].functor[Int, String, Long]) - checkAll(s"$context.Functor[NestedPred]", FunctorTests[NestedPred].functor[Boolean, Int, Boolean]) - checkAll(s"$context.Functor is Serializable", SerializableTests.serializable(Functor[Tree])) - } + inline def functorTests[F[_]]: FunctorTests[F] = + FunctorTests[F](summonInline) + + inline def testFunctor(inline context: String): Unit = + checkAll(s"$context.Functor[IList]", functorTests[IList].functor[Int, String, Long]) + checkAll(s"$context.Functor[Tree]", functorTests[Tree].functor[Int, String, Long]) + checkAll(s"$context.Functor[GenericAdt]", functorTests[GenericAdt].functor[Int, String, Long]) + checkAll(s"$context.Functor[OptList]", functorTests[OptList].functor[Int, String, Long]) + checkAll(s"$context.Functor[ListSnoc]", functorTests[ListSnoc].functor[Int, String, Long]) + // FIXME: Testing `functorTests[AndChar].functor[Int, String, Long]` causes a ClassCastException + checkAll(s"$context.Functor[AndChar]", functorTests[AndChar].functor[Int, String, Int]) + checkAll(s"$context.Functor[Interleaved]", functorTests[Interleaved].functor[Int, String, Long]) + checkAll(s"$context.Functor[NestedPred]", functorTests[NestedPred].functor[Boolean, Int, Boolean]) + checkAll(s"$context.Functor is Serializable", SerializableTests.serializable(summonInline[Functor[Tree]])) - { + locally { import auto.functor.given testFunctor("auto") } - { - import semiInstances._ + locally { + import semiInstances.given testFunctor("semiauto") } @@ -64,14 +58,14 @@ class FunctorSuite extends KittensSuite { type Predicate[A] = A => Boolean type NestedPred[A] = Predicate[Predicate[A]] - object semiInstances { - implicit val iList: Functor[IList] = semiauto.functor - implicit val tree: Functor[Tree] = semiauto.functor - implicit val genericAdt: Functor[GenericAdt] = semiauto.functor - implicit val optList: Functor[OptList] = semiauto.functor - implicit val listSnoc: Functor[ListSnoc] = semiauto.functor - implicit val andChar: Functor[AndChar] = semiauto.functor - implicit val interleaved: Functor[Interleaved] = semiauto.functor - implicit val nestedPred: Functor[NestedPred] = semiauto.functor - } -} + object semiInstances: + given Functor[IList] = semiauto.functor + given Functor[Tree] = semiauto.functor + given Functor[GenericAdt] = semiauto.functor + given Functor[OptList] = semiauto.functor + given Functor[ListSnoc] = semiauto.functor + given Functor[AndChar] = semiauto.functor + given Functor[Interleaved] = semiauto.functor + given Functor[NestedPred] = semiauto.functor + +end FunctorSuite From 909edefe5eb993a75d61b106aa3db76dcf404e02 Mon Sep 17 00:00:00 2001 From: Georgi Krastev Date: Fri, 27 Aug 2021 15:40:14 +0300 Subject: [PATCH 2/2] Move derives tests to suite companion objects --- .../{foldable.scala => FoldableSuite.scala} | 14 +++++++++++++ .../scala-3/cats/derived/FoldableTests.scala | 17 ---------------- .../{functor.scala => FunctorSuite.scala} | 20 +++++++++++++++++++ .../scala-3/cats/derived/FunctorTests.scala | 18 ----------------- 4 files changed, 34 insertions(+), 35 deletions(-) rename core/src/test/scala-3/cats/derived/{foldable.scala => FoldableSuite.scala} (90%) delete mode 100644 core/src/test/scala-3/cats/derived/FoldableTests.scala rename core/src/test/scala-3/cats/derived/{functor.scala => FunctorSuite.scala} (86%) delete mode 100644 core/src/test/scala-3/cats/derived/FunctorTests.scala diff --git a/core/src/test/scala-3/cats/derived/foldable.scala b/core/src/test/scala-3/cats/derived/FoldableSuite.scala similarity index 90% rename from core/src/test/scala-3/cats/derived/foldable.scala rename to core/src/test/scala-3/cats/derived/FoldableSuite.scala index cc1704dd..ff03f9af 100644 --- a/core/src/test/scala-3/cats/derived/foldable.scala +++ b/core/src/test/scala-3/cats/derived/FoldableSuite.scala @@ -85,4 +85,18 @@ object FoldableSuite: def foldLeft[A, B](fa: Nel[A], b: B)(f: (B, A) => B) = fa.tail.foldl(b)(f) def foldRight[A, B](fa: Nel[A], lb: Eval[B])(f: (A, Eval[B]) => Eval[B]) = fa.tail.foldr(lb)(f) + case class Single[A](value: A) derives Foldable + + enum Many[+A] derives Foldable: + case Naught + case More(value: A, rest: Many[A]) + + enum AtMostOne[+A] derives Foldable: + case Naught + case Single(value: A) + + enum AtLeastOne[+A] derives Foldable: + case Single(value: A) + case More(value: A, rest: Option[AtLeastOne[A]]) + end FoldableSuite diff --git a/core/src/test/scala-3/cats/derived/FoldableTests.scala b/core/src/test/scala-3/cats/derived/FoldableTests.scala deleted file mode 100644 index 4bb39f00..00000000 --- a/core/src/test/scala-3/cats/derived/FoldableTests.scala +++ /dev/null @@ -1,17 +0,0 @@ -package cats.derived - -import cats.Foldable -import cats.derived.* - -class FoldableTests { - - case class Box[A](value: A) derives Foldable - - sealed trait Maybe[+A] derives Foldable - case object Nufin extends Maybe[Nothing] - case class Just[A](value: A) extends Maybe[A] - - sealed trait CList[A] derives Foldable - case object CNil extends CList[Nothing] - case class CCons[A](head: A, tail: CList[A]) extends CList[A] -} diff --git a/core/src/test/scala-3/cats/derived/functor.scala b/core/src/test/scala-3/cats/derived/FunctorSuite.scala similarity index 86% rename from core/src/test/scala-3/cats/derived/functor.scala rename to core/src/test/scala-3/cats/derived/FunctorSuite.scala index 104e33a0..80d9445e 100644 --- a/core/src/test/scala-3/cats/derived/functor.scala +++ b/core/src/test/scala-3/cats/derived/FunctorSuite.scala @@ -22,6 +22,7 @@ import cats.laws.discipline.eq.* import scala.compiletime.* class FunctorSuite extends KittensSuite: + import FunctorSuite.* import TestDefns.* given ExhaustiveCheck[Predicate[Boolean]] = @@ -52,6 +53,11 @@ class FunctorSuite extends KittensSuite: testFunctor("semiauto") } +end FunctorSuite + +object FunctorSuite: + import TestDefns.* + type OptList[A] = Option[List[A]] type ListSnoc[A] = List[Snoc[A]] type AndChar[A] = (A, Char) @@ -68,4 +74,18 @@ class FunctorSuite extends KittensSuite: given Functor[Interleaved] = semiauto.functor given Functor[NestedPred] = semiauto.functor + case class Single[A](value: A) derives Functor + + enum Many[+A] derives Functor: + case Naught + case More(value: A, rest: Many[A]) + + enum AtMostOne[+A] derives Functor: + case Naught + case Single(value: A) + + enum AtLeastOne[+A] derives Functor: + case Single(value: A) + case More(value: A, rest: Option[AtLeastOne[A]]) + end FunctorSuite diff --git a/core/src/test/scala-3/cats/derived/FunctorTests.scala b/core/src/test/scala-3/cats/derived/FunctorTests.scala deleted file mode 100644 index d97ff399..00000000 --- a/core/src/test/scala-3/cats/derived/FunctorTests.scala +++ /dev/null @@ -1,18 +0,0 @@ -package cats.derived - -import cats.Functor -import cats.derived.* - -class FunctorTests { - - case class Box[A](value: A) derives Functor - - sealed trait Maybe[+A] derives Functor - case object Nufin extends Maybe[Nothing] - case class Just[A](value: A) extends Maybe[A] - - sealed trait CList[A] derives Functor - case object CNil extends CList[Nothing] - case class CCons[A](head: A, tail: CList[A]) extends CList[A] - -}