Documentation

Plausible.Testable

Testable Class #

Testable propositions have a procedure that can generate counter-examples together with a proof that they invalidate the proposition.

This is a port of the Haskell QuickCheck library.

Creating Customized Instances #

The type classes Testable, SampleableExt and Shrinkable are the means by which Plausible creates samples and tests them. For instance, the proposition ∀ i j : Nat, i ≤ j has a Testable instance because Nat is sampleable and i ≤ j is decidable. Once Plausible finds the Testable instance, it can start using the instance to repeatedly creating samples and checking whether they satisfy the property. Once it has found a counter-example it will then use a Shrinkable instance to reduce the example. This allows the user to create new instances and apply Plausible to new situations.

What do I do if I'm testing a property about my newly defined type? #

Let us consider a type made for a new formalization:

structure MyType where
  x : Nat
  y : Nat
  h : x ≤ y
  deriving Repr

How do we test a property about MyType? For instance, let us consider Testable.check <| ∀ a b : MyType, a.y ≤ b.x → a.x ≤ b.y. Writing this property as is will give us an error because we do not have an instance of Shrinkable MyType and SampleableExt MyType. We can define one as follows:

instance : Shrinkable MyType where
  shrink := fun ⟨x, y, _⟩ =>
    let proxy := Shrinkable.shrink (x, y - x)
    proxy.map (fun (fst, snd) => ⟨fst, fst + snd, by omega⟩)

instance : SampleableExt MyType :=
  SampleableExt.mkSelfContained do
    let x ← SampleableExt.interpSample Nat
    let xyDiff ← SampleableExt.interpSample Nat
    return ⟨x, x + xyDiff, by omega⟩

Again, we take advantage of the fact that other types have useful Shrinkable implementations, in this case Prod.

Main definitions #

References #

inductive Plausible.TestResult (p : Prop) :

Result of trying to disprove p

  • success {p : Prop} : Unit ⊕' pTestResult p

    Succeed when we find another example satisfying p. In success h, h is an optional proof of the proposition. Without the proof, all we know is that we found one example where p holds. With a proof, the one test was sufficient to prove that p holds and we do not need to keep finding examples.

  • gaveUp {p : Prop} : NatTestResult p

    Give up when a well-formed example cannot be generated. gaveUp n tells us that n invalid examples were tried.

  • failure {p : Prop} : ¬pList StringNatTestResult p

    A counter-example to p; the strings specify values for the relevant variables. failure h vs n also carries a proof that p does not hold. This way, we can guarantee that there will be no false positive. The last component, n, is the number of times that the counter-example was shrunk.

Instances For

    Configuration for testing a property.

    • numInst : Nat

      How many test instances to generate.

    • maxSize : Nat

      The maximum size of the values to generate.

    • numRetries : Nat
    • traceDiscarded : Bool

      Enable tracing of values that didn't fulfill preconditions and were thus discarded.

    • traceSuccesses : Bool

      Enable tracing of values that fulfilled the property and were thus discarded.

    • traceShrink : Bool

      Enable basic tracing of shrinking.

    • traceShrinkCandidates : Bool

      Enable tracing of all attempted values during shrinking.

    • randomSeed : Option Nat

      Hard code the seed to use for the RNG

    • quiet : Bool

      Disable output.

    Instances For
      Equations
      • One or more equations did not get rendered due to their size.
      Instances For
        @[implicit_reducible]
        Equations
        • One or more equations did not get rendered due to their size.
        def Plausible.elabConfig :
        Lean.SyntaxLean.Elab.Tactic.TacticM Configuration

        Allow elaboration of Configuration arguments to tactics.

        Equations
        • One or more equations did not get rendered due to their size.
        Instances For

          PrintableProp p allows one to print a proposition so that Plausible can indicate how values relate to each other. It's basically a poor man's delaborator.

          • printProp : String
          Instances
            @[implicit_reducible, instance 100]
            Equations

            Testable p uses random examples to try to disprove p.

            Instances
              def Plausible.NamedBinder (_n : String) (p : Prop) :
              Equations
              Instances For
                Equations
                Instances For
                  def Plausible.TestResult.combine {p q : Prop} :
                  Unit ⊕' (pq)Unit ⊕' pUnit ⊕' q

                  Applicative combinator proof carrying test results.

                  Equations
                  Instances For
                    def Plausible.TestResult.imp {p q : Prop} (h : qp) (r : TestResult p) :
                    optParam (Unit ⊕' (pq)) (PSum.inl ())TestResult q

                    If q → p, then ¬ p → ¬ q which means that testing p can allow us to find counter-examples to q.

                    Equations
                    Instances For
                      def Plausible.TestResult.iff {p q : Prop} (h : q p) (r : TestResult p) :

                      Test q by testing p and proving the equivalence between the two.

                      Equations
                      Instances For
                        def Plausible.TestResult.addInfo {p q : Prop} (x : String) (h : qp) (r : TestResult p) :
                        optParam (Unit ⊕' (pq)) (PSum.inl ())TestResult q

                        When we assign a value to a universally quantified variable, we record that value using this function so that our counter-examples can be informative.

                        Equations
                        Instances For
                          def Plausible.TestResult.addVarInfo {p q : Prop} {γ : Type u_1} [Repr γ] (var : String) (x : γ) (h : qp) (r : TestResult p) :
                          optParam (Unit ⊕' (pq)) (PSum.inl ())TestResult q

                          Add some formatting to the information recorded by addInfo.

                          Equations
                          Instances For
                            Equations
                            Instances For

                              A configuration with all the trace options enabled, useful for debugging.

                              Equations
                              Instances For
                                def Plausible.Testable.runPropE (p : Prop) [Testable p] (cfg : Configuration) (min : Bool) :
                                Equations
                                • One or more equations did not get rendered due to their size.
                                Instances For
                                  def Plausible.Testable.slimTrace {m : TypeType u_1} [Pure m] (s : String) :
                                  m PUnit

                                  A dbgTrace with special formatting

                                  Equations
                                  Instances For
                                    @[implicit_reducible]
                                    instance Plausible.Testable.andTestable {p q : Prop} [Testable p] [Testable q] :
                                    Testable (p q)
                                    Equations
                                    • One or more equations did not get rendered due to their size.
                                    @[implicit_reducible]
                                    instance Plausible.Testable.orTestable {p q : Prop} [Testable p] [Testable q] :
                                    Testable (p q)
                                    Equations
                                    • One or more equations did not get rendered due to their size.
                                    @[implicit_reducible]
                                    instance Plausible.Testable.iffTestable {p q : Prop} [Testable (p q ¬p ¬q)] :
                                    Testable (p q)
                                    Equations
                                    • One or more equations did not get rendered due to their size.
                                    @[implicit_reducible]
                                    instance Plausible.Testable.decGuardTestable {p : Prop} {var : String} [PrintableProp p] [Decidable p] {β : pProp} [(h : p) → Testable (β h)] :
                                    Testable (NamedBinder var (∀ (h : p), β h))
                                    Equations
                                    • One or more equations did not get rendered due to their size.
                                    @[implicit_reducible]
                                    instance Plausible.Testable.forallTypesTestable {var : String} {f : TypeProp} [Testable (f Int)] :
                                    Testable (NamedBinder var (∀ (x : Type), f x))
                                    Equations
                                    • One or more equations did not get rendered due to their size.
                                    @[implicit_reducible, instance 100]
                                    instance Plausible.Testable.forallTypesULiftTestable {var : String} {f : Type u → Prop} [Testable (f (ULift Int))] :
                                    Testable (NamedBinder var (∀ (x : Type u), f x))
                                    Equations
                                    • One or more equations did not get rendered due to their size.
                                    def Plausible.Testable.formatFailure (s : String) (xs : List String) (n : Nat) :
                                    String

                                    Format the counter-examples found in a test failure.

                                    Equations
                                    • Plausible.Testable.formatFailure s xs n = "\n".intercalate ["\n===================", s, "\n".intercalate xs, toString "(" ++ toString n ++ toString " shrinks)", "-------------------"]
                                    Instances For

                                      Increase the number of shrinking steps in a test result.

                                      Equations
                                      Instances For
                                        @[implicit_reducible]
                                        instance Plausible.Testable.instInhabitedOptionTOfPure {α : Type u} {m : Type u → Type u_1} [Pure m] :
                                        Inhabited (OptionT m α)
                                        Equations
                                        partial def Plausible.Testable.minimizeAux {α : Sort u_1} [SampleableExt α] {β : αProp} [(x : α) → Testable (β x)] (cfg : Configuration) (var : String) (x : SampleableExt.proxy α) (n : Nat) :

                                        Shrink a counter-example x by using Shrinkable.shrink x, picking the first candidate that falsifies a property and recursively shrinking that one. The process is guaranteed to terminate because shrink x produces a proof that all the values it produces are smaller (according to SizeOf) than x.

                                        def Plausible.Testable.minimize {α : Sort u_1} [SampleableExt α] {β : αProp} [(x : α) → Testable (β x)] (cfg : Configuration) (var : String) (x : SampleableExt.proxy α) (r : TestResult (β (SampleableExt.interp x))) :

                                        Once a property fails to hold on an example, look for smaller counter-examples to show the user.

                                        Equations
                                        • One or more equations did not get rendered due to their size.
                                        Instances For
                                          @[implicit_reducible]
                                          instance Plausible.Testable.varTestable {var : String} {α : Type u_1} [SampleableExt α] {β : αProp} [(x : α) → Testable (β x)] :
                                          Testable (NamedBinder var (∀ (x : α), β x))

                                          Test a universal property by creating a sample of the right type and instantiating the bound variable with it.

                                          Equations
                                          • One or more equations did not get rendered due to their size.
                                          @[implicit_reducible]
                                          instance Plausible.Testable.propVarTestable {var : String} {β : PropProp} [(b : Bool) → Testable (β (b = true))] :
                                          Testable (NamedBinder var (∀ (p : Prop), β p))

                                          Test a universal property about propositions

                                          Equations
                                          • One or more equations did not get rendered due to their size.
                                          @[implicit_reducible, instance 10000]
                                          instance Plausible.Testable.unusedVarTestable {var : String} {α : Sort u_1} {β : Prop} [Nonempty α] [Testable β] :
                                          Testable (NamedBinder var (∀ (a : α), β))
                                          Equations
                                          • One or more equations did not get rendered due to their size.
                                          @[implicit_reducible, instance 2000]
                                          instance Plausible.Testable.subtypeVarTestable {var : String} {α : Type u} {p β : αProp} [(x : α) → PrintableProp (p x)] [(x : α) → Testable (β x)] [SampleableExt (Subtype p)] {var' : String} :
                                          Testable (NamedBinder var (∀ (x : α), NamedBinder var' (p xβ x)))
                                          Equations
                                          • One or more equations did not get rendered due to their size.
                                          @[implicit_reducible, instance 100]
                                          Equations
                                          • One or more equations did not get rendered due to their size.
                                          @[implicit_reducible]
                                          instance Plausible.Eq.printableProp {α : Type u_1} [Repr α] {x y : α} :
                                          Equations
                                          @[implicit_reducible]
                                          instance Plausible.Ne.printableProp {α : Type u_1} [Repr α] {x y : α} :
                                          PrintableProp (x y)
                                          Equations
                                          @[implicit_reducible]
                                          instance Plausible.LE.printableProp {α : Type u_1} [Repr α] [LE α] {x y : α} :
                                          PrintableProp (x y)
                                          Equations
                                          @[implicit_reducible]
                                          instance Plausible.LT.printableProp {α : Type u_1} [Repr α] [LT α] {x y : α} :
                                          Equations
                                          @[implicit_reducible]
                                          Equations
                                          @[implicit_reducible]
                                          Equations
                                          @[implicit_reducible]
                                          Equations
                                          @[implicit_reducible]
                                          Equations
                                          @[implicit_reducible]
                                          Equations
                                          @[implicit_reducible]
                                          Equations
                                          @[implicit_reducible]
                                          Equations
                                          @[implicit_reducible]
                                          instance Plausible.Bool.printableProp {b : Bool} :
                                          PrintableProp (b = true)
                                          Equations
                                          def Plausible.retry {p : Prop} (cmd : Gen (TestResult p)) :
                                          NatGen (TestResult p)

                                          Execute cmd and repeat every time the result is gaveUp (at most n times).

                                          Equations
                                          Instances For
                                            def Plausible.giveUp {p : Prop} (x : Nat) :

                                            Count the number of times the test procedure gave up.

                                            Equations
                                            Instances For

                                              Try n times to find a counter-example for p.

                                              Equations
                                              Instances For

                                                Try to find a counter-example of p.

                                                Equations
                                                Instances For

                                                  Run a test suite for p in IO using the global RNG in stdGenRef.

                                                  Equations
                                                  • One or more equations did not get rendered due to their size.
                                                  Instances For
                                                    partial def Plausible.Decorations.addDecorations (e : Lean.Expr) :
                                                    Lean.MetaM Lean.Expr

                                                    Traverse the syntax of a proposition to find universal quantifiers quantifiers and add NamedBinder annotations next to them.

                                                    @[reducible, inline]

                                                    DecorationsOf p is used as a hint to mk_decorations to specify that the goal should be satisfied with a proposition equivalent to p with added annotations.

                                                    Equations
                                                    Instances For

                                                      In a goal of the shape DecorationsOf p, mk_decoration examines the syntax of p and adds NamedBinder around universal quantifications to improve error messages. This tool can be used in the declaration of a function as follows:

                                                      def foo (p : Prop) (p' : Decorations.DecorationsOf p := by mk_decorations) [Testable p'] : ...
                                                      

                                                      p is the parameter given by the user, p' is a definitionally equivalent proposition where the quantifiers are annotated with NamedBinder.

                                                      Equations
                                                      Instances For
                                                        def Plausible.Testable.check (p : Prop) (cfg : Configuration := { }) (p' : Decorations.DecorationsOf p := by mk_decorations) [Testable p'] :
                                                        Lean.CoreM PUnit

                                                        Run a test suite for p and throw an exception if p does not hold.

                                                        Equations
                                                        • One or more equations did not get rendered due to their size.
                                                        Instances For
                                                          def Plausible.«command#test_» :
                                                          Lean.ParserDescr
                                                          Equations
                                                          • Plausible.«command#test_» = Lean.ParserDescr.node `Plausible.«command#test_» 1022 (Lean.ParserDescr.binary `andthen (Lean.ParserDescr.symbol "#test ") (Lean.ParserDescr.cat `term 0))
                                                          Instances For