typelevel / algebra
1
package algebra.laws
2

3
import cats.kernel._
4
import org.scalacheck.Prop
5
import org.scalacheck.Prop._
6
import org.scalacheck.{Arbitrary, Prop}
7
import cats.kernel.instances.boolean._
8

9
object Rules {
10

11
  // Comparison operators for testing are supplied by CheckEqOps and
12
  // CheckOrderOps in package.scala. They are:
13
  //
14
  //    ?==  Ensure that x equals y
15
  //    ?!=  Ensure that x does not equal y
16
  //    ?<   Ensure that x < y
17
  //    ?<=  Ensure that x <= y
18
  //    ?>   Ensure that x > y
19
  //    ?>=  Ensure that x >= y
20
  //
21
  // The reason to prefer these operators is that when tests fail, we
22
  // will get more detaild output about what the failing values were
23
  // (in addition to the input values generated by ScalaCheck).
24

25
  def associativity[A: Arbitrary: Eq](f: (A, A) => A): (String, Prop) =
26 3
    "associativity" -> forAll { (x: A, y: A, z: A) =>
27 3
      f(f(x, y), z) ?== f(x, f(y, z))
28
    }
29

30
  def leftIdentity[A: Arbitrary: Eq](id: A)(f: (A, A) => A): (String, Prop) =
31 3
    "leftIdentity" -> forAll { (x: A) =>
32 3
      f(id, x) ?== x
33
    }
34

35
  def rightIdentity[A: Arbitrary: Eq](id: A)(f: (A, A) => A): (String, Prop) =
36 3
    "rightIdentity" -> forAll { (x: A) =>
37 3
      f(x, id) ?== x
38
    }
39

40
  def leftInverse[A: Arbitrary: Eq](id: A)(f: (A, A) => A)(inv: A => A): (String, Prop) =
41 3
    "left inverse" -> forAll { (x: A) =>
42 3
      id ?== f(inv(x), x)
43
    }
44

45
  def rightInverse[A: Arbitrary: Eq](id: A)(f: (A, A) => A)(inv: A => A): (String, Prop) =
46 3
    "right inverse" -> forAll { (x: A) =>
47 3
      id ?== f(x, inv(x))
48
    }
49

50
  def commutative[A: Arbitrary: Eq](f: (A, A) => A): (String, Prop) =
51 3
    "commutative" -> forAll { (x: A, y: A) =>
52 3
      f(x, y) ?== f(y, x)
53
    }
54

55
  def idempotence[A: Arbitrary: Eq](f: (A, A) => A): (String, Prop) =
56 3
    "idempotence" -> forAll { (x: A) =>
57 3
      f(x, x) ?== x
58
    }
59

60
  def consistentInverse[A: Arbitrary: Eq](name: String)(m: (A, A) => A)(f: (A, A) => A)(inv: A => A): (String, Prop) =
61 3
    s"consistent $name" -> forAll { (x: A, y: A) =>
62 3
      m(x, y) ?== f(x, inv(y))
63
    }
64

65
  def repeat0[A: Arbitrary: Eq](name: String, sym: String, id: A)(r: (A, Int) => A): (String, Prop) =
66 3
    s"$name(a, 0) == $sym" -> forAll { (a: A) =>
67 3
      r(a, 0) ?== id
68
    }
69

70
  def repeat1[A: Arbitrary: Eq](name: String)(r: (A, Int) => A): (String, Prop) =
71 3
    s"$name(a, 1) == a" -> forAll { (a: A) =>
72 3
      r(a, 1) ?== a
73
    }
74

75
  def repeat2[A: Arbitrary: Eq](name: String, sym: String)(r: (A, Int) => A)(f: (A, A) => A): (String, Prop) =
76 3
    s"$name(a, 2) == a $sym a" -> forAll { (a: A) =>
77 3
      r(a, 2) ?== f(a, a)
78
    }
79

80
  def collect0[A: Arbitrary: Eq](name: String, sym: String, id: A)(c: Seq[A] => A): (String, Prop) =
81 3
    s"$name(Nil) == $sym" -> forAll { (a: A) =>
82 3
      c(Nil) ?== id
83
    }
84

85
  def isId[A: Arbitrary: Eq](name: String, id: A)(p: A => Boolean): (String, Prop) =
86 3
    name -> forAll { (x: A) =>
87 3
      Eq.eqv(x, id) ?== p(x)
88
    }
89

90
  def distributive[A: Arbitrary: Eq](a: (A, A) => A)(m: (A, A) => A): (String, Prop) =
91 3
    "distributive" -> forAll { (x: A, y: A, z: A) =>
92 3
      (m(x, a(y, z)) ?== a(m(x, y), m(x, z))) &&
93 3
      (m(a(x, y), z) ?== a(m(x, z), m(y, z)))
94
    }
95

96
  // ugly platform-specific code follows
97

98
  def serializable[M](m: M): (String, Prop) =
99 3
    "serializable" -> (if (IsSerializable()) {
100 3
      Prop(_ => Result(status = Proof))
101
    } else {
102 0
      Prop(_ => IsSerializable.testSerialization(m))
103
    })
104
}

Read our documentation on viewing source code .

Loading