Skip to content

Commit

Permalink
Port ReducibleSuite to Scala 3 (#379)
Browse files Browse the repository at this point in the history
  • Loading branch information
joroKr21 authored Aug 31, 2021
1 parent b4200bf commit c68362d
Show file tree
Hide file tree
Showing 3 changed files with 113 additions and 6 deletions.
4 changes: 2 additions & 2 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ jobs:
strategy:
matrix:
os: [ubuntu-latest]
scala: [2.12.13, 2.13.6, 3.0.0]
scala: [2.12.13, 2.13.6, 3.0.1]
java: [adopt@1.8]
ci: [test]
runs-on: ${{ matrix.os }}
Expand Down Expand Up @@ -63,7 +63,7 @@ jobs:
strategy:
matrix:
os: [ubuntu-latest]
scala: [3.0.0]
scala: [3.0.1]
java: [adopt@1.8]
runs-on: ${{ matrix.os }}
steps:
Expand Down
9 changes: 5 additions & 4 deletions build.sbt
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import sbt._

val scala212 = "2.12.13"
val scala213 = "2.13.6"
val scala3 = "3.0.0"
val scala3 = "3.0.1"

ThisBuild / crossScalaVersions := Seq(scala212, scala213, scala3)
ThisBuild / scalaVersion := scala3
Expand All @@ -26,9 +26,10 @@ lazy val commonSettings = Seq(
"-deprecation",
"-Xfatal-warnings"
),
scalacOptions ++= CrossVersion.partialVersion(scalaVersion.value).flatMap {
case (2, 12) => Some("-Ypartial-unification")
case _ => None
scalacOptions ++= CrossVersion.partialVersion(scalaVersion.value).toList.flatMap {
case (3, _) => List("-Xmax-inlines", "64")
case (2, 12) => List("-Ypartial-unification")
case _ => Nil
},
resolvers ++= Seq(
Resolver.sonatypeRepo("releases"),
Expand Down
106 changes: 106 additions & 0 deletions core/src/test/scala-3/cats/derived/ReducibleSuite.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,106 @@
/*
* 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.data.{NonEmptyList, OneAnd}
import cats.laws.discipline.arbitrary.*
import cats.laws.discipline.{ReducibleTests, SerializableTests}
import cats.syntax.all.*
import org.scalacheck.Arbitrary
import scala.compiletime.*

class ReducibleSuite extends KittensSuite:
import ReducibleSuite.*
import TestDefns.*

inline def reducibleTests[F[_]]: ReducibleTests[F] =
ReducibleTests[F](summonInline)

inline def testReducible(context: String): Unit =
checkAll(s"$context.Reducible[ICons]", reducibleTests[ICons].reducible[Option, Int, Long])
checkAll(s"$context.Reducible[Tree]", reducibleTests[Tree].reducible[Option, Int, Long])
checkAll(s"$context.Reducible[NelSCons]", reducibleTests[NelSCons].reducible[Option, Int, Long])
checkAll(s"$context.Reducible[NelAndOne]", reducibleTests[NelAndOne].reducible[Option, Int, Long])
checkAll(s"$context.Reducible[ListAndNel]", reducibleTests[ListAndNel].reducible[Option, Int, Long])
checkAll(s"$context.Reducible[Interleaved]", reducibleTests[Interleaved].reducible[Option, Int, Long])
checkAll(s"$context.Reducible[BoxZipper]", reducibleTests[BoxZipper].reducible[Option, Int, Long])
checkAll(s"$context.Reducible is Serializable", SerializableTests.serializable(summonInline[Reducible[Tree]]))

locally {
import auto.reducible.given
testReducible("auto")
}

locally {
import semiInstances.given
testReducible("semiauto")
}

end ReducibleSuite

object ReducibleSuite:
import TestDefns.*

type NelSCons[A] = NonEmptyList[SCons[A]]
type NelAndOne[A] = NonEmptyList[OneAnd[List, A]]
type BoxZipper[A] = Box[Zipper[A]]

object semiInstances:
given Reducible[ICons] = semiauto.reducible
given Reducible[Tree] = semiauto.reducible
given Reducible[NelSCons] = semiauto.reducible
given Reducible[NelAndOne] = semiauto.reducible
given Reducible[ListAndNel] = semiauto.reducible
given Reducible[Interleaved] = semiauto.reducible
given Reducible[BoxZipper] = semiauto.reducible

// FIXME: Doesn't work if we define `ListAndNel` as a type alias
final case class ListAndNel[A](list: List[A], nel: NonEmptyList[A])
object ListAndNel:
given [A: Eq]: Eq[ListAndNel[A]] =
(x, y) => x.list === y.list && x.nel === y.nel

given [A: Arbitrary]: Arbitrary[ListAndNel[A]] =
Arbitrary(for
list <- Arbitrary.arbitrary[List[A]]
nel <- Arbitrary.arbitrary[NonEmptyList[A]]
yield ListAndNel(list, nel))

final case class Zipper[+A](left: List[A], focus: A, right: List[A])
object Zipper:
given [A: Eq]: Eq[Zipper[A]] =
(x, y) => x.focus === y.focus && x.left === y.left && x.right === y.right

given [A: Arbitrary]: Arbitrary[Zipper[A]] =
Arbitrary(for
left <- Arbitrary.arbitrary[List[A]]
focus <- Arbitrary.arbitrary[A]
right <- Arbitrary.arbitrary[List[A]]
yield Zipper(left, focus, right))

given Reducible[Zipper] with
def reduceLeftTo[A, B](fa: Zipper[A])(f: A => B)(g: (B, A) => B) =
NonEmptyList(fa.focus, fa.right).reduceLeftTo(f)(g)
def reduceRightTo[A, B](fa: Zipper[A])(f: A => B)(g: (A, Eval[B]) => Eval[B]) =
NonEmptyList(fa.focus, fa.right).reduceRightTo(f)(g)
def foldLeft[A, B](fa: Zipper[A], b: B)(f: (B, A) => B) =
(fa.focus :: fa.right).foldl(b)(f)
def foldRight[A, B](fa: Zipper[A], lb: Eval[B])(f: (A, Eval[B]) => Eval[B]) =
(fa.focus :: fa.right).foldr(lb)(f)

end ReducibleSuite

0 comments on commit c68362d

Please sign in to comment.