diff --git a/build.sbt b/build.sbt index c7186a5b6d..a887eeb188 100644 --- a/build.sbt +++ b/build.sbt @@ -126,7 +126,9 @@ lazy val cats: Project = (project in file("integrations/cats")) libraryDependencies ++= Seq( "org.typelevel" %% "cats-core" % "2.1.1", scalaTest % Test, - scalaCheck % Test + scalaCheck % Test, + "org.typelevel" %% "discipline-scalatest" % "1.0.1" % Test, + "org.typelevel" %% "cats-laws" % "2.1.1" % Test ) ) .dependsOn(core) diff --git a/core/src/main/scala/sttp/tapir/EndpointIO.scala b/core/src/main/scala/sttp/tapir/EndpointIO.scala index 24c9b31d6a..9062e66c54 100644 --- a/core/src/main/scala/sttp/tapir/EndpointIO.scala +++ b/core/src/main/scala/sttp/tapir/EndpointIO.scala @@ -421,7 +421,9 @@ object EndpointIO { // - case class Example[+T](value: T, name: Option[String], summary: Option[String]) + case class Example[+T](value: T, name: Option[String], summary: Option[String]) { + def map[B](f: T => B): Example[B] = copy(value = f(value)) + } object Example { def of[T](t: T, name: Option[String] = None, summary: Option[String] = None): Example[T] = Example(t, name, summary) diff --git a/integrations/cats/src/main/scala/sttp/tapir/integ/cats/ExampleInstances.scala b/integrations/cats/src/main/scala/sttp/tapir/integ/cats/ExampleInstances.scala new file mode 100644 index 0000000000..cb529dd35f --- /dev/null +++ b/integrations/cats/src/main/scala/sttp/tapir/integ/cats/ExampleInstances.scala @@ -0,0 +1,10 @@ +package sttp.tapir.integ.cats + +import cats.Functor +import sttp.tapir.EndpointIO.Example + +trait ExampleInstances { + implicit val exampleFunctor: Functor[Example] = new Functor[Example] { + override def map[A, B](example: Example[A])(f: A => B): Example[B] = example.map(f) + } +} diff --git a/integrations/cats/src/main/scala/sttp/tapir/integ/cats/instances.scala b/integrations/cats/src/main/scala/sttp/tapir/integ/cats/instances.scala new file mode 100644 index 0000000000..5f3d91d41c --- /dev/null +++ b/integrations/cats/src/main/scala/sttp/tapir/integ/cats/instances.scala @@ -0,0 +1,3 @@ +package sttp.tapir.integ.cats + +object instances extends ExampleInstances diff --git a/integrations/cats/src/test/scala/sttp/tapir/integ/cats/ExampleFunctorLawSpec.scala b/integrations/cats/src/test/scala/sttp/tapir/integ/cats/ExampleFunctorLawSpec.scala new file mode 100644 index 0000000000..8f24dd3d7d --- /dev/null +++ b/integrations/cats/src/test/scala/sttp/tapir/integ/cats/ExampleFunctorLawSpec.scala @@ -0,0 +1,25 @@ +package sttp.tapir.integ.cats + +import cats.Eq +import cats.laws.discipline.FunctorTests +import org.scalacheck.Arbitrary +import org.scalatest.funsuite.AnyFunSuite +import org.scalatestplus.scalacheck.Checkers +import org.typelevel.discipline.scalatest.FunSuiteDiscipline +import sttp.tapir.EndpointIO.Example +import sttp.tapir.integ.cats.instances._ + +class ExampleFunctorLawSpec extends AnyFunSuite with FunSuiteDiscipline with Checkers { + implicit def exampleEq[A]: Eq[Example[A]] = Eq.fromUniversalEquals + + implicit def exampleArbitrary[T: Arbitrary]: Arbitrary[Example[T]] = Arbitrary { + for { + t <- Arbitrary.arbitrary[T] + name <- Arbitrary.arbitrary[Option[String]] + summary <- Arbitrary.arbitrary[Option[String]] + } yield Example(t, name, summary) + } + + checkAll("Example.FunctorLaws", FunctorTests[Example].functor[Int, Int, String]) +} + diff --git a/integrations/cats/src/test/scala/sttp/tapir/integ/cats/TapirCodecCatsTest.scala b/integrations/cats/src/test/scala/sttp/tapir/integ/cats/TapirCodecCatsTest.scala index a7e47299b5..d951c7dcaa 100644 --- a/integrations/cats/src/test/scala/sttp/tapir/integ/cats/TapirCodecCatsTest.scala +++ b/integrations/cats/src/test/scala/sttp/tapir/integ/cats/TapirCodecCatsTest.scala @@ -2,7 +2,8 @@ package sttp.tapir.integ.cats import cats.data.{NonEmptyChain, NonEmptyList, NonEmptySet} import org.scalacheck.{Arbitrary, Gen} -import org.scalatest.{FlatSpec, Matchers} +import org.scalatest.flatspec.AnyFlatSpec +import org.scalatest.matchers.should.Matchers import org.scalatestplus.scalacheck.Checkers import org.scalacheck.Arbitrary.arbString import sttp.tapir.SchemaType.{SArray, SString} @@ -12,7 +13,7 @@ import codec._ import scala.collection.immutable.SortedSet -class TapirCodecCatsTest extends FlatSpec with Matchers with Checkers { +class TapirCodecCatsTest extends AnyFlatSpec with Matchers with Checkers { case class Test(value: String) it should "find schema for cats collections" in {