diff --git a/core/src/main/scala-3/cats/derived/derived.scala b/core/src/main/scala-3/cats/derived/Derived.scala similarity index 100% rename from core/src/main/scala-3/cats/derived/derived.scala rename to core/src/main/scala-3/cats/derived/Derived.scala diff --git a/core/src/main/scala-3/cats/derived/DerivedCommutativeMonoid.scala b/core/src/main/scala-3/cats/derived/DerivedCommutativeMonoid.scala new file mode 100644 index 00000000..7acc852b --- /dev/null +++ b/core/src/main/scala-3/cats/derived/DerivedCommutativeMonoid.scala @@ -0,0 +1,21 @@ +package cats.derived + +import cats.kernel.CommutativeMonoid +import shapeless3.deriving.K0 + +import scala.compiletime.* + +type DerivedCommutativeMonoid[A] = Derived[CommutativeMonoid[A]] +object DerivedCommutativeMonoid: + type Or[A] = Derived.Or[CommutativeMonoid[A]] + inline def apply[A]: CommutativeMonoid[A] = + import DerivedCommutativeMonoid.given + summonInline[DerivedCommutativeMonoid[A]].instance + + given [A](using inst: K0.ProductInstances[Or, A]): DerivedCommutativeMonoid[A] = + given K0.ProductInstances[CommutativeMonoid, A] = inst.unify + new Product[CommutativeMonoid, A] {} + + trait Product[F[x] <: CommutativeMonoid[x], A](using inst: K0.ProductInstances[F, A]) + extends DerivedMonoid.Product[F, A], + CommutativeMonoid[A] diff --git a/core/src/main/scala-3/cats/derived/DerivedCommutativeSemigroup.scala b/core/src/main/scala-3/cats/derived/DerivedCommutativeSemigroup.scala new file mode 100644 index 00000000..d4eabdd4 --- /dev/null +++ b/core/src/main/scala-3/cats/derived/DerivedCommutativeSemigroup.scala @@ -0,0 +1,21 @@ +package cats.derived + +import cats.kernel.CommutativeSemigroup +import shapeless3.deriving.K0 + +import scala.compiletime.* + +type DerivedCommutativeSemigroup[A] = Derived[CommutativeSemigroup[A]] +object DerivedCommutativeSemigroup: + type Or[A] = Derived.Or[CommutativeSemigroup[A]] + inline def apply[A]: CommutativeSemigroup[A] = + import DerivedCommutativeSemigroup.given + summonInline[DerivedCommutativeSemigroup[A]].instance + + given [A](using inst: K0.ProductInstances[Or, A]): DerivedCommutativeSemigroup[A] = + given K0.ProductInstances[CommutativeSemigroup, A] = inst.unify + new Product[CommutativeSemigroup, A] {} + + trait Product[F[x] <: CommutativeSemigroup[x], A](using inst: K0.ProductInstances[F, A]) + extends DerivedSemigroup.Product[F, A], + CommutativeSemigroup[A] diff --git a/core/src/main/scala-3/cats/derived/empty.scala b/core/src/main/scala-3/cats/derived/DerivedEmpty.scala similarity index 100% rename from core/src/main/scala-3/cats/derived/empty.scala rename to core/src/main/scala-3/cats/derived/DerivedEmpty.scala diff --git a/core/src/main/scala-3/cats/derived/foldable.scala b/core/src/main/scala-3/cats/derived/DerivedFoldable.scala similarity index 100% rename from core/src/main/scala-3/cats/derived/foldable.scala rename to core/src/main/scala-3/cats/derived/DerivedFoldable.scala diff --git a/core/src/main/scala-3/cats/derived/functor.scala b/core/src/main/scala-3/cats/derived/DerivedFunctor.scala similarity index 100% rename from core/src/main/scala-3/cats/derived/functor.scala rename to core/src/main/scala-3/cats/derived/DerivedFunctor.scala diff --git a/core/src/main/scala-3/cats/derived/DerivedMonoid.scala b/core/src/main/scala-3/cats/derived/DerivedMonoid.scala new file mode 100644 index 00000000..04d29d90 --- /dev/null +++ b/core/src/main/scala-3/cats/derived/DerivedMonoid.scala @@ -0,0 +1,22 @@ +package cats.derived + +import cats.Monoid +import shapeless3.deriving.K0 + +import scala.compiletime.* + +type DerivedMonoid[A] = Derived[Monoid[A]] +object DerivedMonoid: + type Or[A] = Derived.Or[Monoid[A]] + inline def apply[A]: Monoid[A] = + import DerivedMonoid.given + summonInline[DerivedMonoid[A]].instance + + given [A](using inst: K0.ProductInstances[Or, A]): DerivedMonoid[A] = + given K0.ProductInstances[Monoid, A] = inst.unify + new Product[Monoid, A] {} + + trait Product[F[x] <: Monoid[x], A](using inst: K0.ProductInstances[F, A]) + extends DerivedSemigroup.Product[F, A], + Monoid[A]: + val empty: A = inst.construct([A] => (F: F[A]) => F.empty) diff --git a/core/src/main/scala-3/cats/derived/reducible.scala b/core/src/main/scala-3/cats/derived/DerivedReducible.scala similarity index 100% rename from core/src/main/scala-3/cats/derived/reducible.scala rename to core/src/main/scala-3/cats/derived/DerivedReducible.scala diff --git a/core/src/main/scala-3/cats/derived/DerivedSemigroup.scala b/core/src/main/scala-3/cats/derived/DerivedSemigroup.scala new file mode 100644 index 00000000..8f0f8b29 --- /dev/null +++ b/core/src/main/scala-3/cats/derived/DerivedSemigroup.scala @@ -0,0 +1,20 @@ +package cats.derived + +import cats.Semigroup +import shapeless3.deriving.K0 + +import scala.compiletime.* + +type DerivedSemigroup[A] = Derived[Semigroup[A]] +object DerivedSemigroup: + type Or[A] = Derived.Or[Semigroup[A]] + inline def apply[A]: Semigroup[A] = + import DerivedSemigroup.given + summonInline[DerivedSemigroup[A]].instance + + given [A](using inst: K0.ProductInstances[Or, A]): DerivedSemigroup[A] = + given K0.ProductInstances[Semigroup, A] = inst.unify + new Product[Semigroup, A] {} + + trait Product[F[x] <: Semigroup[x], A](using inst: K0.ProductInstances[F, A]) extends Semigroup[A]: + def combine(x: A, y: A): A = inst.map2(x, y)([A] => (F: F[A], x: A, y: A) => F.combine(x, y)) diff --git a/core/src/main/scala-3/cats/derived/traverse.scala b/core/src/main/scala-3/cats/derived/DerivedTraverse.scala similarity index 100% rename from core/src/main/scala-3/cats/derived/traverse.scala rename to core/src/main/scala-3/cats/derived/DerivedTraverse.scala diff --git a/core/src/main/scala-3/cats/derived/commutativeMonoid.scala b/core/src/main/scala-3/cats/derived/commutativeMonoid.scala deleted file mode 100644 index 54d6ba3b..00000000 --- a/core/src/main/scala-3/cats/derived/commutativeMonoid.scala +++ /dev/null @@ -1,12 +0,0 @@ -package cats.derived - -import cats.kernel.CommutativeMonoid -import shapeless3.deriving.K0 - -trait ProductCommutativeMonoid[T[x] <: CommutativeMonoid[x], A](using inst: K0.ProductInstances[T, A]) - extends ProductCommutativeSemigroup[T, A], ProductMonoid[T, A], CommutativeMonoid[A] {} - -trait CommutativeMonoidDerivation: - extension (F: CommutativeMonoid.type) - inline def derived[A](using gen: K0.ProductGeneric[A]): CommutativeMonoid[A] = - new ProductCommutativeMonoid[CommutativeMonoid, A]{} diff --git a/core/src/main/scala-3/cats/derived/commutativeSemigroup.scala b/core/src/main/scala-3/cats/derived/commutativeSemigroup.scala deleted file mode 100644 index c2969d1d..00000000 --- a/core/src/main/scala-3/cats/derived/commutativeSemigroup.scala +++ /dev/null @@ -1,12 +0,0 @@ -package cats.derived - -import cats.kernel.CommutativeSemigroup -import shapeless3.deriving.{K0, Continue} - -trait ProductCommutativeSemigroup[T[x] <: CommutativeSemigroup[x], A](using inst: K0.ProductInstances[T, A]) - extends ProductSemigroup[T, A], CommutativeSemigroup[A] {} - -trait CommutativeSemigroupDerivation: - extension (F: CommutativeSemigroup.type) - inline def derived[A](using gen: K0.ProductGeneric[A]): CommutativeSemigroup[A] = - new ProductCommutativeSemigroup[CommutativeSemigroup, A]{} diff --git a/core/src/main/scala-3/cats/derived/monoid.scala b/core/src/main/scala-3/cats/derived/monoid.scala deleted file mode 100644 index 12e0d37e..00000000 --- a/core/src/main/scala-3/cats/derived/monoid.scala +++ /dev/null @@ -1,10 +0,0 @@ -package cats.derived - -import cats.Monoid -import shapeless3.deriving.K0 - -trait ProductMonoid[F[x] <: Monoid[x], A](using - inst: K0.ProductInstances[F, A] -) extends ProductSemigroup[F, A], - Monoid[A]: - val empty: A = inst.construct([A] => (F: F[A]) => F.empty) diff --git a/core/src/main/scala-3/cats/derived/package.scala b/core/src/main/scala-3/cats/derived/package.scala index 23a34452..ce4d8ca8 100644 --- a/core/src/main/scala-3/cats/derived/package.scala +++ b/core/src/main/scala-3/cats/derived/package.scala @@ -2,29 +2,22 @@ package cats.derived import alleycats.* import cats.* -import shapeless3.deriving.K0 +import cats.kernel.{CommutativeSemigroup, CommutativeMonoid} import scala.util.NotGiven extension (E: Empty.type) inline def derived[A]: Empty[A] = DerivedEmpty[A] - -extension (S: Semigroup.type) - inline def derived[A](using gen: K0.ProductGeneric[A]): Semigroup[A] = - new ProductSemigroup[Semigroup, A] {} - -extension (M: Monoid.type) - inline def derived[A](using gen: K0.ProductGeneric[A]): Monoid[A] = - new ProductMonoid[Monoid, A] {} - +extension (S: Semigroup.type) inline def derived[A]: Semigroup[A] = DerivedSemigroup[A] +extension (M: Monoid.type) inline def derived[A]: Monoid[A] = DerivedMonoid[A] +extension (S: CommutativeSemigroup.type) inline def derived[A]: CommutativeSemigroup[A] = DerivedCommutativeSemigroup[A] +extension (S: CommutativeMonoid.type) inline def derived[A]: CommutativeMonoid[A] = DerivedCommutativeMonoid[A] extension (F: Foldable.type) inline def derived[F[_]]: Foldable[F] = DerivedFoldable[F] extension (F: Functor.type) inline def derived[F[_]]: Functor[F] = DerivedFunctor[F] extension (F: Reducible.type) inline def derived[F[_]]: Reducible[F] = DerivedReducible[F] extension (F: Traverse.type) inline def derived[F[_]]: Traverse[F] = DerivedTraverse[F] object semiauto - extends CommutativeMonoidDerivation, - CommutativeSemigroupDerivation, - ContravariantDerivation, + extends ContravariantDerivation, EmptyKDerivation, EqDerivation, HashDerivation, @@ -37,6 +30,10 @@ object semiauto Instances: inline def empty[A]: Empty[A] = DerivedEmpty[A] + inline def semigroup[A]: Semigroup[A] = DerivedSemigroup[A] + inline def monoid[A]: Monoid[A] = DerivedMonoid[A] + inline def commutativeSemigroup[A]: CommutativeSemigroup[A] = DerivedCommutativeSemigroup[A] + inline def commutativeMonoid[A]: CommutativeMonoid[A] = DerivedCommutativeMonoid[A] inline def foldable[F[_]]: Foldable[F] = DerivedFoldable[F] inline def functor[F[_]]: Functor[F] = DerivedFunctor[F] inline def reducible[F[_]]: Reducible[F] = DerivedReducible[F] @@ -46,6 +43,18 @@ object auto: object empty: inline given [A](using NotGiven[Empty[A]]): Empty[A] = DerivedEmpty[A] + object semigroup: + inline given [A](using NotGiven[Semigroup[A]]): Semigroup[A] = DerivedSemigroup[A] + + object monoid: + inline given [A](using NotGiven[Monoid[A]]): Monoid[A] = DerivedMonoid[A] + + object commutativeSemigroup: + inline given [A](using NotGiven[CommutativeSemigroup[A]]): CommutativeSemigroup[A] = DerivedCommutativeSemigroup[A] + + object commutativeMonoid: + inline given [A](using NotGiven[CommutativeMonoid[A]]): CommutativeMonoid[A] = DerivedCommutativeMonoid[A] + object functor: inline given [F[_]](using NotGiven[Functor[F]]): Functor[F] = DerivedFunctor[F] diff --git a/core/src/main/scala-3/cats/derived/semigroup.scala b/core/src/main/scala-3/cats/derived/semigroup.scala deleted file mode 100644 index f9b005ee..00000000 --- a/core/src/main/scala-3/cats/derived/semigroup.scala +++ /dev/null @@ -1,10 +0,0 @@ -package cats.derived - -import cats.Semigroup -import shapeless3.deriving.K0 - -trait ProductSemigroup[F[x] <: Semigroup[x], A](using - inst: K0.ProductInstances[F, A] -) extends Semigroup[A]: - def combine(x: A, y: A): A = - inst.map2(x, y)([A] => (F: F[A], x: A, y: A) => F.combine(x, y)) diff --git a/core/src/test/scala-3/cats/derived/CommutativeMonoidSuite.scala b/core/src/test/scala-3/cats/derived/CommutativeMonoidSuite.scala new file mode 100644 index 00000000..2f6d8002 --- /dev/null +++ b/core/src/test/scala-3/cats/derived/CommutativeMonoidSuite.scala @@ -0,0 +1,76 @@ +/* + * Copyright (c) 2016 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.derived + +import cats.Eq +import cats.kernel.{CommutativeMonoid, CommutativeSemigroup} +import cats.kernel.laws.discipline.{CommutativeMonoidTests, SerializableTests} +import org.scalacheck.Arbitrary + +import scala.compiletime.* + +class CommutativeMonoidSuite extends KittensSuite: + import CommutativeMonoidSuite.* + import TestDefns.* + + inline def commutativeMonoidTests[A]: CommutativeMonoidTests[A] = + CommutativeMonoidTests[A](summonInline) + + inline def testCommutativeMonoid(inline context: String): Unit = + checkAll(s"$context.CommutativeMonoid[Foo]", commutativeMonoidTests[CommutativeFoo].commutativeMonoid) + // FIXME: Doesn't work + //checkAll(s"$context.CommutativeMonoid[Recursive]", commutativeMonoidTests[Recursive].commutativeMonoid) + checkAll(s"$context.CommutativeMonoid[Box[Mul]]", commutativeMonoidTests[Box[Mul]].commutativeMonoid) + checkAll( + s"$context.CommutativeMonoid is Serializable", + SerializableTests.serializable(summonInline[CommutativeMonoid[CommutativeFoo]]) + ) + test(s"$context.CommutativeMonoid respects existing instances") { + val box = summonInline[CommutativeMonoid[Box[Mul]]] + assert(box.empty == Box(Mul(1))) + assert(box.combine(Box(Mul(5)), Box(Mul(5))) == Box(Mul(25))) + } + + locally { + import auto.commutativeMonoid.given + testCommutativeMonoid("auto") + } + + locally { + import semiInstances.given + testCommutativeMonoid("semiauto") + } + +end CommutativeMonoidSuite + +object CommutativeMonoidSuite: + import TestDefns.* + + object semiInstances: + given CommutativeMonoid[CommutativeFoo] = semiauto.commutativeMonoid + given CommutativeMonoid[Recursive] = semiauto.commutativeMonoid + given CommutativeMonoid[Box[Mul]] = semiauto.commutativeMonoid + + final case class Mul(value: Int) + object Mul: + given Eq[Mul] = Eq.fromUniversalEquals + given Arbitrary[Mul] = Arbitrary(Arbitrary.arbitrary[Int].map(apply)) + given CommutativeMonoid[Mul] with + val empty = Mul(1) + def combine(x: Mul, y: Mul) = Mul(x.value * y.value) + +end CommutativeMonoidSuite diff --git a/core/src/test/scala-3/cats/derived/CommutativeMonoidTests.scala b/core/src/test/scala-3/cats/derived/CommutativeMonoidTests.scala index 7b5d5ded..96c2914f 100644 --- a/core/src/test/scala-3/cats/derived/CommutativeMonoidTests.scala +++ b/core/src/test/scala-3/cats/derived/CommutativeMonoidTests.scala @@ -1,9 +1,7 @@ package cats.derived -import alleycats.* -import cats.* import cats.kernel.CommutativeMonoid -import cats.derived.semiauto.* +import cats.derived.* class CommutativeMonoidTests { // case class Foo(i: Int, b: Option[Int]) derives CommutativeMonoid diff --git a/core/src/test/scala-3/cats/derived/CommutativeSemigroupSuite.scala b/core/src/test/scala-3/cats/derived/CommutativeSemigroupSuite.scala new file mode 100644 index 00000000..f261f29c --- /dev/null +++ b/core/src/test/scala-3/cats/derived/CommutativeSemigroupSuite.scala @@ -0,0 +1,76 @@ +/* + * 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.derived + +import cats.Eq +import cats.kernel.CommutativeSemigroup +import cats.kernel.laws.discipline.{CommutativeSemigroupTests, SerializableTests} +import org.scalacheck.Arbitrary + +import scala.compiletime.* + +class CommutativeSemigroupSuite extends KittensSuite: + import CommutativeSemigroupSuite.* + import TestDefns.* + + inline def commutativeSemigroupTests[A]: CommutativeSemigroupTests[A] = + CommutativeSemigroupTests[A](summonInline) + + inline def testCommutativeSemigroup(inline context: String): Unit = + checkAll( + s"$context.CommutativeSemigroup[CommutativeFoo]", + commutativeSemigroupTests[CommutativeFoo].commutativeSemigroup + ) + // FIXME: Doesn't work + //checkAll(s"$context.CommutativeSemigroup[Recursive]", commutativeSemigroupTests[Recursive].commutativeSemigroup) + checkAll(s"$context.CommutativeSemigroup[Box[Mul]]", commutativeSemigroupTests[Box[Mul]].commutativeSemigroup) + checkAll( + s"$context.CommutativeSemigroup is Serializable", + SerializableTests.serializable(summonInline[CommutativeSemigroup[CommutativeFoo]]) + ) + test(s"$context.CommutativeSemigroup respects existing instances") { + val box = summonInline[CommutativeSemigroup[Box[Mul]]] + assert(box.combine(Box(Mul(5)), Box(Mul(5))).content.value == 25) + } + + locally { + import auto.commutativeSemigroup.given + testCommutativeSemigroup("auto") + } + + locally { + import semiInstances.given + testCommutativeSemigroup("semiauto") + } + +end CommutativeSemigroupSuite + +object CommutativeSemigroupSuite: + import TestDefns.* + + object semiInstances: + given CommutativeSemigroup[CommutativeFoo] = semiauto.commutativeSemigroup + given CommutativeSemigroup[Recursive] = semiauto.commutativeSemigroup + given CommutativeSemigroup[Box[Mul]] = semiauto.commutativeSemigroup + + final case class Mul(value: Int) + object Mul: + given Eq[Mul] = Eq.fromUniversalEquals + given Arbitrary[Mul] = Arbitrary(Arbitrary.arbitrary[Int].map(apply)) + given CommutativeSemigroup[Mul] = (x, y) => Mul(x.value * y.value) + +end CommutativeSemigroupSuite diff --git a/core/src/test/scala-3/cats/derived/CommutativeSemigroupTests.scala b/core/src/test/scala-3/cats/derived/CommutativeSemigroupTests.scala index 46c46a3f..e790e0cf 100644 --- a/core/src/test/scala-3/cats/derived/CommutativeSemigroupTests.scala +++ b/core/src/test/scala-3/cats/derived/CommutativeSemigroupTests.scala @@ -1,9 +1,7 @@ package cats.derived -import alleycats.* -import cats.* import cats.kernel.CommutativeSemigroup -import cats.derived.semiauto.* +import cats.derived.* class CommutativeSemigroupTests { // case class Foo(i: Int, b: Option[Int]) derives CommutativeSemigroup diff --git a/core/src/test/scala-3/cats/derived/MonoidSuite.scala b/core/src/test/scala-3/cats/derived/MonoidSuite.scala new file mode 100644 index 00000000..bab92c9b --- /dev/null +++ b/core/src/test/scala-3/cats/derived/MonoidSuite.scala @@ -0,0 +1,74 @@ +/* + * Copyright (c) 2016 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.derived + +import cats.{Eq, Monoid} +import cats.kernel.laws.discipline.{MonoidTests, SerializableTests} +import org.scalacheck.Arbitrary + +import scala.compiletime.* + +class MonoidSuite extends KittensSuite: + import MonoidSuite.* + import TestDefns.* + + inline def monoidTests[A]: MonoidTests[A] = + MonoidTests[A](summonInline) + + inline def testMonoid(inline context: String): Unit = + checkAll(s"$context.Monoid[Foo]", monoidTests[Foo].monoid) + checkAll(s"$context.Monoid[Interleaved[Int]]", monoidTests[Interleaved[Int]].monoid) + checkAll(s"$context.Monoid[Box[Mul]]", monoidTests[Box[Mul]].monoid) + // FIXME: Doesn't work + //checkAll(s"$context.Monoid[Recursive]", monoidTests[Recursive].monoid) + checkAll(s"$context.Monoid is Serializable", SerializableTests.serializable(summonInline[Monoid[Foo]])) + test(s"$context.Monoid respects existing instances") { + val box = summonInline[Monoid[Box[Mul]]] + assert(box.empty == Box(Mul(1))) + assert(box.combine(Box(Mul(5)), Box(Mul(5))) == Box(Mul(25))) + } + + locally { + import auto.monoid.given + testMonoid("auto") + } + + locally { + import semiInstances.given + testMonoid("semiauto") + } + +end MonoidSuite + +object MonoidSuite: + import TestDefns.* + + object semiInstances: + given Monoid[Foo] = semiauto.monoid + given Monoid[Recursive] = semiauto.monoid + given Monoid[Interleaved[Int]] = semiauto.monoid + given Monoid[Box[Mul]] = semiauto.monoid + + final case class Mul(value: Int) + object Mul: + given Eq[Mul] = Eq.fromUniversalEquals + given Arbitrary[Mul] = Arbitrary(Arbitrary.arbitrary[Int].map(apply)) + given Monoid[Mul] with + val empty = Mul(1) + def combine(x: Mul, y: Mul) = Mul(x.value * y.value) + +end MonoidSuite diff --git a/core/src/test/scala-3/cats/derived/SemigroupSuite.scala b/core/src/test/scala-3/cats/derived/SemigroupSuite.scala new file mode 100644 index 00000000..0e2a764c --- /dev/null +++ b/core/src/test/scala-3/cats/derived/SemigroupSuite.scala @@ -0,0 +1,71 @@ +/* + * 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.derived + +import cats.{Eq, Semigroup} +import cats.kernel.laws.discipline.{SemigroupTests, SerializableTests} +import org.scalacheck.Arbitrary + +import scala.compiletime.* + +class SemigroupSuite extends KittensSuite: + import SemigroupSuite.* + import TestDefns.* + + inline def semigroupTests[A]: SemigroupTests[A] = + SemigroupTests[A](summonInline) + + inline def testSemigroup(inline context: String): Unit = + checkAll(s"$context.Semigroup[Foo]", semigroupTests[Foo].semigroup) + checkAll(s"$context.Semigroup[Interleaved[Int]]", semigroupTests[Interleaved[Int]].semigroup) + checkAll(s"$context.Semigroup[Box[Mul]]", semigroupTests[Box[Mul]].semigroup) + // FIXME: Doesn't work + //checkAll(s"$context.Semigroup[Recursive]", semigroupTests[Recursive].semigroup) + checkAll(s"$context.Semigroup is Serializable", SerializableTests.serializable(summonInline[Semigroup[Foo]])) + test(s"$context.Semigroup respects existing instances") { + val box = summonInline[Semigroup[Box[Mul]]] + assert(box.combine(Box(Mul(5)), Box(Mul(5))).content.value == 25) + } + + locally { + import auto.semigroup.given + testSemigroup("auto") + } + + locally { + import semiInstances.given + testSemigroup("semiauto") + } + +end SemigroupSuite + +object SemigroupSuite: + import TestDefns.* + + object semiInstances: + given Semigroup[Foo] = semiauto.semigroup + given Semigroup[Recursive] = semiauto.semigroup + given Semigroup[Interleaved[Int]] = semiauto.semigroup + given Semigroup[Box[Mul]] = semiauto.semigroup + + final case class Mul(value: Int) + object Mul: + given Eq[Mul] = Eq.fromUniversalEquals + given Arbitrary[Mul] = Arbitrary(Arbitrary.arbitrary[Int].map(apply)) + given Semigroup[Mul] = (x, y) => Mul(x.value * y.value) + +end SemigroupSuite