Created
January 4, 2019 05:10
-
-
Save yasuabe/eefb873b02fe1e69588ac1dd47c9e59b to your computer and use it in GitHub Desktop.
refined and scalacheck
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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