Skip to content

Instantly share code, notes, and snippets.

@yasuabe
Last active December 26, 2017 06:04
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/a5cfff487d65a5ed0cc27418eb7d8e3b to your computer and use it in GitHub Desktop.
Save yasuabe/a5cfff487d65a5ed0cc27418eb7d8e3b to your computer and use it in GitHub Desktop.
property(redefine+cats+scalacheck)
package ratio1
import cats.Apply
import cats.instances.int._
import cats.syntax.all._
import eu.timepit.refined.cats._
import eu.timepit.refined.refineMV
import eu.timepit.refined.scalacheck.numeric.chooseRefinedNum
import org.scalacheck.Gen._
import org.scalacheck.Prop.forAll
import org.scalacheck.{Arbitrary, Gen, Prop, Properties}
import ratio1.Rational._
trait Helper {
implicit val genApply: Apply[Gen] = new Apply[Gen] {
override def ap[A, B] (gf: Gen[A => B])(ga: Gen[A]): Gen[B] = gf flatMap ga.map
override def map[A, B](ga: Gen[A]) (f: A => B): Gen[B] = ga map f
}
def double[A](ga: Gen[A]): Gen[(A, A)] = (ga, ga).mapN((_, _))
def triple[A](ga: Gen[A]): Gen[(A, A, A)] = (ga, ga, ga).mapN((_, _, _))
val lower: NonZeroInt = refineMV[NonZero](-10)
val upper: NonZeroInt = refineMV[NonZero](10)
val genNZInt: Gen[NonZeroInt] = chooseRefinedNum(lower, upper)
implicit val arbNonZeroInt: Arbitrary[NonZeroInt] = Arbitrary(genNZInt)
val intGen: Gen[Int] = chooseNum(-100, 100)
val nzIntGen: Gen[NonZeroInt] =
chooseRefinedNum(refineMV[NonZero](-100), refineMV[NonZero](100))
}
object NonZeroIntSpec extends Properties("NonZeroInt") with Helper {
import NonZeroInt.one
property("Group: communitativity") = forAll(double(genNZInt)) { case (n1, n2) =>
n1 * n2 === n2 * n1
}
property("Group: associativity") = forAll(triple(genNZInt)) { case (n1, n2, n3) =>
(n1 * n2) * n3 === n1 * (n2 * n3)
}
property("Group: identity element") = forAll(genNZInt) { n1 =>
one * n1 === one * n1 && one * n1 === n1
}
}
object RationalSpec extends Properties("Rational") with Helper {
val gen: Gen[Rational] = (intGen, nzIntGen).mapN(Rational(_, _))
property("Rational: equality") = forAll(nzIntGen, intGen, nzIntGen) { (m, n, d) =>
Rational(n, d) === Rational(n * m.value, d * m)
}
property("Group: communitativity") = forAll(double(gen)) { case (r1, r2) =>
r1 + r2 == r2 + r1
}
property("Group: associativity") = forAll(triple(gen)) { case (r1, r2, r3) =>
(r1 + r2) + r3 == r1 + (r2 + r3)
}
property("Group: identity element") = forAll(gen) { r1 =>
zero + r1 == zero + r1 && zero + r1 === r1
}
property("Group: inverse element") = forAll(gen) { r1 =>
val inv = r1.negate
r1 + inv === inv + r1 && inv + r1 === zero
}
property("Ring: communitativity") = forAll(double(gen)) { case (r1, r2) =>
r1 * r2 == r2 * r1
}
property("Ring: associativity") = forAll(triple(gen)) { case (r1, r2, r3) =>
(r1 * r2) * r3 == r1 * (r2 * r3)
}
property("Ring: unity") = forAll(gen) { r1 =>
one * r1 === one * r1 && one * r1 === r1
}
property("Ring: distributivity(1)") = forAll(triple(gen)) { case (r1, r2, r3) =>
r1 * (r2 + r3) == r1 * r2 + r1 * r3
}
property("Ring: distributivity(2)") = forAll(triple(gen)) { case (r1, r2, r3) =>
(r1 + r2) * r3 == r1 * r3 + r2 * r3
}
property("Field: inverse element") = forAll(gen.suchThat(_ =!= zero)) { r =>
val inv = r.invert.toOption.get
r * inv === inv * r && inv * r === one
}
property("Field: inverse zero has no value") = Prop {
zero.invert.isLeft
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment