Skip to content

Instantly share code, notes, and snippets.

@yasuabe
Created January 4, 2019 05:10
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save yasuabe/eefb873b02fe1e69588ac1dd47c9e59b to your computer and use it in GitHub Desktop.
Save yasuabe/eefb873b02fe1e69588ac1dd47c9e59b to your computer and use it in GitHub Desktop.
refined and scalacheck
package scala_check
import scala.util.Try
import cats.syntax.either._
import cats.Apply
import cats.syntax.apply._
import shapeless.nat._
import eu.timepit.refined.api.Refined
import eu.timepit.refined.W
import eu.timepit.refined.numeric.Interval.Closed
import eu.timepit.refined.string.MatchesRegex
import eu.timepit.refined.refineV
import org.scalacheck.Prop.forAll
import org.scalacheck.{Arbitrary, Gen, Properties}
import Arbitrary.arbitrary
import eu.timepit.refined.scalacheck.numeric._
import IceCream._
case class IceCream(name: Name, numCherries: Num, inCone: Boolean) {
def show: String = s"$name,$numCherries,$inCone"
}
object IceCream {
type NameP = MatchesRegex[W.`"[a-zA-Z0-9 ]{2,10}"`.T]
type Name = String Refined NameP
type NumP = Closed[_1, _10]
type Num = Int Refined NumP
private def refine[A, B](f: => A)(g: A => Either[String, B]) =
Try(f).fold(_.getMessage.asLeft, g)
def read(s: String): Either[String, IceCream] = {
val params = raw"([a-zA-Z0-9 ]+),([0-9]+),(true|false)".r
s match {
case params(s1, s2, s3) => for {
name <- refineV[NameP](s1)
num <- refine(s2.toInt)(refineV[NumP](_))
cone <- refine(s3.toBoolean)(_.asRight)
} yield IceCream(name, num, cone)
case _ => s"ERROR: $s".asLeft
}
}
}
object IceCreamSpec extends Properties("IceCream") {
import Gen._
implicit val genApply: Apply[Gen] = new Apply[Gen] {
def ap[A, B](gf: Gen[A => B])(ga: Gen[A]): Gen[B] = gf flatMap ga.map
def map[A, B](ga: Gen[A])(f: A => B): Gen[B] = ga map f
}
val genName = (for {
len <- chooseNum(2, 10)
chars <- listOfN(len, oneOf(alphaChar, numChar, const(' ')))
} yield refineV[NameP](chars.mkString)).map(_.right.get)
val genIceCream = (genName, arbitrary[Num], arbitrary[Boolean]) mapN IceCream.apply
val genString = oneOf(
(genName, arbitrary[Num], arbitrary[Boolean]) mapN ((s, n, b) => s"$s,$n,$b"),
asciiStr
)
property("∀ ic: IceCream, read(show(ic))==ic") = forAll(genIceCream) { ic =>
// println(ic)
read(ic.show).right.get == ic
}
property("∀ s: String s.t. read(s)=Right(ic), show(ic)==s") = forAll(genString) { s =>
// println(s)
read(s).map(_.show).forall(_ == s)
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment