Skip to content

Commit

Permalink
kebs-scalacheck - Scala 3 (#302)
Browse files Browse the repository at this point in the history
* split implementations to scala 2 and 3

* Add Scala 3 version of kebs-scalacheck

* extend missing ScalacheckInstances enumeratum trait

* remove jdk8 build

---------

Co-authored-by: Paweł Kiersznowski <pkiersznowski@iteratorshq.com>
  • Loading branch information
pk044 and Paweł Kiersznowski committed Aug 9, 2023
1 parent edc1ecb commit bbc6f08
Show file tree
Hide file tree
Showing 14 changed files with 190 additions and 36 deletions.
9 changes: 1 addition & 8 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -15,21 +15,14 @@ jobs:
matrix:
os: [ubuntu-latest]
scala: [2.12.17, 2.13.10, 3.3.0]
java: [temurin@8, temurin@17]
java: [temurin@17]
runs-on: ${{ matrix.os }}
steps:
- name: Checkout current branch (full)
uses: actions/checkout@v2
with:
fetch-depth: 0

- name: Setup Java (temurin@8)
if: matrix.java == 'temurin@8'
uses: actions/setup-java@v2
with:
distribution: temurin
java-version: 8

- name: Setup Java (temurin@17)
if: matrix.java == 'temurin@17'
uses: actions/setup-java@v2
Expand Down
10 changes: 6 additions & 4 deletions build.sbt
Original file line number Diff line number Diff line change
Expand Up @@ -124,6 +124,7 @@ val jsonschema = "com.github.andyglow" %% "scala-jsonschema" % "0.7.11"

val scalacheck = "org.scalacheck" %% "scalacheck" % "1.17.0" % "test"
val scalacheckShapeless = "com.github.alexarchambault" %% "scalacheck-shapeless_1.15" % "1.3.0"
val scalacheckDerived = "io.github.martinhh" %% "scalacheck-derived" % "0.2.0"
val scalacheckEnumeratum = "com.beachape" %% "enumeratum-scalacheck" % "1.7.3"

val enumeratumVersion = "1.7.3"
Expand Down Expand Up @@ -223,8 +224,10 @@ lazy val jsonschemaSettings = commonSettings ++ Seq(
lazy val scalacheckSettings = commonSettings ++ Seq(
libraryDependencies += scalacheck.cross(CrossVersion.for3Use2_13),
libraryDependencies += scalacheckEnumeratum.cross(CrossVersion.for3Use2_13),
libraryDependencies += scalacheckShapeless.cross(CrossVersion.for3Use2_13)
)
libraryDependencies += scalacheckShapeless.cross(CrossVersion.for3Use2_13),
) ++ Seq(
libraryDependencies ++= (if (scalaVersion.value.startsWith("3")) Seq(scalacheckDerived)
else Nil))

lazy val taggedSettings = commonSettings ++ Seq(
libraryDependencies += optionalSlick.cross(CrossVersion.for3Use2_13),
Expand Down Expand Up @@ -400,10 +403,9 @@ lazy val jsonschemaSupport = project

lazy val scalacheckSupport = project
.in(file("scalacheck"))
.dependsOn(core.jvm)
.dependsOn(core.jvm, opaque.jvm % "test -> test")
.settings(scalacheckSettings: _*)
.settings(publishSettings: _*)
.settings(disableScala(List("3")))
.settings(
name := "scalacheck",
description := "Automatic generation of scalacheck generators for case classes",
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
package pl.iterators.kebs.scalacheck

import enumeratum.ScalacheckInstances
import org.scalacheck.{Arbitrary, Gen, ScalacheckShapeless}
import pl.iterators.kebs.macros.CaseClass1Rep

import java.net.{URI, URL}
import java.time.temporal.ChronoUnit
import java.time._
import java.util.concurrent.TimeUnit
import scala.reflect.ClassTag
import scala.util.Random

trait CommonArbitrarySupport extends ScalacheckShapeless with ScalacheckInstances {
implicit def caseClass1RepArbitraryPredef[T, A](
implicit rep: CaseClass1Rep[T, A],
arbitrary: Arbitrary[A]
): Arbitrary[T] =
Arbitrary(arbitrary.arbitrary.map(rep.apply(_)))
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
package pl.iterators.kebs.scalacheck

import org.scalacheck.Arbitrary
import pl.iterators.kebs.scalacheck.CommonArbitrarySupport

trait Generator[T] extends CommonArbitrarySupport {
def ArbT: Arbitrary[T]

def generate: T = ArbT.arbitrary.sample.get
}

trait AllGenerators[T] {

val normal: Generator[T]

val minimal: Generator[T]

val maximal: Generator[T]
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
package pl.iterators.kebs.scalacheck

import org.scalacheck.{Arbitrary, Gen}
import pl.iterators.kebs.macros.CaseClass1Rep

import java.net.{URI, URL}
import java.time.temporal.ChronoUnit
import java.time._
import java.util.concurrent.TimeUnit
import scala.reflect.ClassTag
import scala.util.Random
import io.github.martinhh.derived.scalacheck.given
import enumeratum.ScalacheckInstances
trait CommonArbitrarySupport extends ScalacheckInstances {
implicit def caseClass1RepArbitraryPredef[T, A](
implicit rep: CaseClass1Rep[T, A],
arbitrary: Arbitrary[A]
): Arbitrary[T] =
Arbitrary(arbitrary.arbitrary.map(rep.apply(_)))
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
package pl.iterators.kebs.scalacheck

import pl.iterators.kebs.scalacheck.macros.KebsScalacheckGeneratorsMacro
import scala.quoted.Quotes
import scala.deriving.Mirror
import pl.iterators.kebs.scalacheck.AllGenerators
trait KebsScalacheckGenerators {
inline implicit final def allGenerators[T](using inline m: Mirror.Of[T]): AllGenerators[T] = KebsScalacheckGeneratorsMacro.materializeGenerators[T]
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
package pl.iterators.kebs.scalacheck.macros

import pl.iterators.kebs.scalacheck._
import scala.quoted.*
import org.scalacheck.Arbitrary
import scala.deriving.Mirror
import io.github.martinhh.derived.scalacheck.deriveArbitrary
object KebsScalacheckGeneratorsMacro {

inline implicit def materializeGenerators[T](using inline m: Mirror.Of[T]): AllGenerators[T] = {

new AllGenerators[T] {

trait GeneratorCreator
extends CommonArbitrarySupport {

def create: Generator[T]
}

object MinimalGeneratorCreator
extends GeneratorCreator
with MinimalArbitrarySupport {

override def create = new Generator[T] {
def ArbT: Arbitrary[T] = deriveArbitrary[T]
}
}

object NormalGeneratorCreator
extends GeneratorCreator {

override def create = new Generator[T] {
def ArbT: Arbitrary[T] = deriveArbitrary[T]
}
}

object MaximalGeneratorCreator
extends GeneratorCreator
with MaximalArbitrarySupport {

override def create = new Generator[T] {
def ArbT: Arbitrary[T] = deriveArbitrary[T]
}
}

override val minimal: Generator[T] = MinimalGeneratorCreator.create
override val maximal: Generator[T] = MaximalGeneratorCreator.create
override val normal: Generator[T] = NormalGeneratorCreator.create
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -11,14 +11,6 @@ import java.util.concurrent.TimeUnit
import scala.reflect.ClassTag
import scala.util.Random

trait CommonArbitrarySupport extends ScalacheckShapeless with ScalacheckInstances {
implicit def caseClass1RepArbitraryPredef[T, A](
implicit rep: CaseClass1Rep[T, A],
arbitrary: Arbitrary[A]
): Arbitrary[T] =
Arbitrary(arbitrary.arbitrary.map(rep.apply(_)))
}

trait MinimalArbitrarySupport {
implicit def emptyOption[T: Arbitrary]: Arbitrary[Option[T]] =
Arbitrary(Gen.const(Option.empty[T]))
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@

import org.scalatest.funsuite.AnyFunSuite
import org.scalatest.matchers.should.Matchers
import pl.iterators.kebs.scalacheck._
import java.net.{URI, URL}
import java.time.{Duration, Instant, LocalDate, LocalDateTime, LocalTime, ZonedDateTime}

case class WrappedInt(int: Int)
case class WrappedIntAnyVal(int: Int) extends AnyVal
case class BasicSample(
someNumber: Int,
someText: String,
wrappedNumber: WrappedInt,
wrappedNumberAnyVal: WrappedIntAnyVal,
)

class AnyValGeneratorsTests extends AnyFunSuite with Matchers {

object KebsProtocol extends KebsScalacheckGenerators

object KebsProtocolWithFancyPredefs extends KebsScalacheckGenerators with KebsArbitraryPredefs

test("Basic sample test") {
import KebsProtocol._

noException should be thrownBy allGenerators[BasicSample].normal.generate
}
}
35 changes: 35 additions & 0 deletions scalacheck/src/test/scala-3/OpaqueGeneratorsTests.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
package pl.iterators.kebs.scalacheck

import org.scalatest.funsuite.AnyFunSuite
import org.scalatest.matchers.should.Matchers
import java.net.{URI, URL}
import java.time.{Duration, Instant, LocalDate, LocalDateTime, LocalTime, ZonedDateTime}
import pl.iterators.kebs.opaque.Opaque


case class WrappedInt(int: Int)

opaque type OpaqueInt = Int
object OpaqueInt extends Opaque[OpaqueInt, Int] {
override def apply(value: Int) = value
}

case class BasicSampleWithOpaque(
someNumber: Int,
someText: String,
wrappedNumber: WrappedInt,
opaqueInt: OpaqueInt
)

class OpaqueGeneratorsTests extends AnyFunSuite with Matchers {

object KebsProtocol extends KebsScalacheckGenerators

object KebsProtocolWithFancyPredefs extends KebsScalacheckGenerators with KebsArbitraryPredefs

test("Basic sample with opaque type test") {
import KebsProtocol._

noException should be thrownBy allGenerators[BasicSampleWithOpaque].normal.generate
}
}
Original file line number Diff line number Diff line change
@@ -1,19 +1,10 @@
package pl.iterators.kebs.scalacheck

import org.scalatest.funsuite.AnyFunSuite
import org.scalatest.matchers.should.Matchers

import java.net.{URI, URL}
import java.time.{Duration, Instant, LocalDate, LocalDateTime, LocalTime, ZonedDateTime}

case class WrappedInt(int: Int)
case class WrappedIntAnyVal(int: Int) extends AnyVal
case class BasicSample(
someNumber: Int,
someText: String,
wrappedNumber: WrappedInt,
wrappedNumberAnyVal: WrappedIntAnyVal,
)
import pl.iterators.kebs.scalacheck._

case class CollectionsSample(
listOfNumbers: List[Int],
Expand Down Expand Up @@ -41,12 +32,6 @@ class GeneratorsTests extends AnyFunSuite with Matchers {

object KebsProtocolWithFancyPredefs extends KebsScalacheckGenerators with KebsArbitraryPredefs

test("Basic sample test") {
import KebsProtocol._

noException should be thrownBy allGenerators[BasicSample].normal.generate
}

test("Collections sample test") {
import KebsProtocol._

Expand Down

0 comments on commit bbc6f08

Please sign in to comment.