diff --git a/build.sbt b/build.sbt index 8180144..08b3c06 100644 --- a/build.sbt +++ b/build.sbt @@ -112,6 +112,7 @@ lazy val testing = defineModule("testing", false)(project) ironScalacheck, scalacheck, scalatest % Test, + scalatestScalacheck % Test, )) lazy val zarr = defineModule("zarr")(project) diff --git a/modules/testing/src/main/scala/syntax/SyntaxForScalacheck.scala b/modules/testing/src/main/scala/syntax/SyntaxForScalacheck.scala index d2854d9..ae7c0d4 100644 --- a/modules/testing/src/main/scala/syntax/SyntaxForScalacheck.scala +++ b/modules/testing/src/main/scala/syntax/SyntaxForScalacheck.scala @@ -2,14 +2,21 @@ package at.ac.oeaw.imba.gerlich.gerlib.testing package syntax import org.scalacheck.{Arbitrary, Gen} +import org.scalacheck.Arbitrary.arbitrary /** Syntax enrichment on ScalaCheck data types */ trait SyntaxForScalacheck: - /** Add nicer syntax to arbitrary instances. */ + + /** Add nicer syntax to [[org.scalacheck.Arbitrary]] instances. */ extension [A](arb: Arbitrary[A]) infix def suchThat(p: A => Boolean): Arbitrary[A] = (arb.arbitrary `suchThat` p).toArbitrary + /** Add nicer syntax to the [[org.scalacheck.Arbitrary]] companion object. */ + extension (Arb: Arbitrary.type) + def oneOf[A: Arbitrary, B: Arbitrary]: Arbitrary[A | B] = + Arbitrary { Gen.oneOf(arbitrary[A], arbitrary[B]) } + /** Add nicer syntax to generators. */ extension [A](g: Gen[A]) def toArbitrary: Arbitrary[A] = Arbitrary(g) diff --git a/modules/testing/src/test/scala/TestSyntaxExtensions.scala b/modules/testing/src/test/scala/TestSyntaxExtensions.scala new file mode 100644 index 0000000..ad60f40 --- /dev/null +++ b/modules/testing/src/test/scala/TestSyntaxExtensions.scala @@ -0,0 +1,48 @@ +package at.ac.oeaw.imba.gerlich.gerlib +package testing + +import cats.Alternative +import cats.syntax.all.* + +import org.scalacheck.{Arbitrary, Gen} +import org.scalacheck.Arbitrary.arbitrary +import org.scalatest.funsuite.AnyFunSuite +import org.scalatest.matchers.should +import org.scalatestplus.scalacheck.ScalaCheckPropertyChecks +import at.ac.oeaw.imba.gerlich.gerlib.testing.syntax.SyntaxForScalacheck + +/** Tests for for the syntax extensions we provide to Scalacheck instances and + * companion objects + */ +class TestSyntaxExtensions + extends AnyFunSuite, + ScalaCheckPropertyChecks, + should.Matchers, + SyntaxForScalacheck // the trait under test + : + test( + "Arbitrary.oneOf produces values of each type, in plausible relative proportions." + ) { + given Arbitrary[Boolean | Int] = Arbitrary.oneOf[Boolean, Int] + val n = 10000 + val (lowerBound, upperBound) = + val zStar = 3.719016 + val p = 0.5 + val sd = scala.math.sqrt(n * p * p) + val exp = n * p + (-zStar * sd + exp, zStar * sd + exp) + forAll(Gen.listOfN(n, arbitrary[Boolean | Int])) { values => + val (bools, ints): (List[Boolean], List[Int]) = + Alternative[List].separate( + values map { + case p: Boolean => p.asLeft + case z: Int => z.asRight + } + ) + bools.length > lowerBound shouldBe true + bools.length < upperBound shouldBe true + ints.length > lowerBound shouldBe true + ints.length < upperBound shouldBe true + } + } +end TestSyntaxExtensions