Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

kebs-scalacheck - Scala 3 #302

Merged
merged 5 commits into from
Aug 9, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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
Loading