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 #
TestableclassTestable.check: a way to test a proposition using random examples
References #
Result of trying to disprove p
- success
{p : Prop}
: Unit ⊕' p → TestResult p
Succeed when we find another example satisfying
p. Insuccess h,his an optional proof of the proposition. Without the proof, all we know is that we found one example wherepholds. With a proof, the one test was sufficient to prove thatpholds and we do not need to keep finding examples. - gaveUp
{p : Prop}
: Nat → TestResult p
Give up when a well-formed example cannot be generated.
gaveUp ntells us thatninvalid examples were tried. - failure
{p : Prop}
: ¬p → List String → Nat → TestResult p
A counter-example to
p; the strings specify values for the relevant variables.failure h vs nalso carries a proof thatpdoes 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
Equations
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.
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
Equations
- One or more equations did not get rendered due to their size.
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
Equations
- Plausible.instPrintableProp = { printProp := "⋯" }
Equations
- Plausible.NamedBinder _n p = p
Instances For
Equations
- (Plausible.TestResult.success (PSum.inl val)).toString = "success (no proof)"
- (Plausible.TestResult.success (PSum.inr val)).toString = "success (proof)"
- (Plausible.TestResult.gaveUp n).toString = toString "gave " ++ toString n ++ toString " times"
- (Plausible.TestResult.failure a counters a_1).toString = toString "failed " ++ toString counters
Instances For
Equations
Combine the test result for properties p and q to create a test for their conjunction.
Equations
- (Plausible.TestResult.failure h xs n).and x✝ = Plausible.TestResult.failure ⋯ xs n
- x✝.and (Plausible.TestResult.failure h xs n) = Plausible.TestResult.failure ⋯ xs n
- (Plausible.TestResult.success h1).and (Plausible.TestResult.success h2) = Plausible.TestResult.success (Plausible.TestResult.combine (Plausible.TestResult.combine (PSum.inr ⋯) h1) h2)
- (Plausible.TestResult.gaveUp n).and (Plausible.TestResult.gaveUp m) = Plausible.TestResult.gaveUp (n + m)
- (Plausible.TestResult.gaveUp n).and x✝ = Plausible.TestResult.gaveUp n
- x.and (Plausible.TestResult.gaveUp n) = Plausible.TestResult.gaveUp n
Instances For
Combine the test result for properties p and q to create a test for their disjunction.
Equations
- (Plausible.TestResult.failure h1 xs n).or (Plausible.TestResult.failure h2 ys m) = Plausible.TestResult.failure ⋯ (xs ++ ys) (n + m)
- (Plausible.TestResult.success h).or x✝ = Plausible.TestResult.success (Plausible.TestResult.combine (PSum.inr ⋯) h)
- x✝.or (Plausible.TestResult.success h) = Plausible.TestResult.success (Plausible.TestResult.combine (PSum.inr ⋯) h)
- (Plausible.TestResult.gaveUp n).or (Plausible.TestResult.gaveUp m) = Plausible.TestResult.gaveUp (n + m)
- (Plausible.TestResult.gaveUp n).or x✝ = Plausible.TestResult.gaveUp n
- x.or (Plausible.TestResult.gaveUp n) = Plausible.TestResult.gaveUp n
Instances For
If q → p, then ¬ p → ¬ q which means that testing p can allow us
to find counter-examples to q.
Equations
- Plausible.TestResult.imp h (Plausible.TestResult.failure h2 xs n) p = Plausible.TestResult.failure ⋯ xs n
- Plausible.TestResult.imp h (Plausible.TestResult.success h2) p = Plausible.TestResult.success (Plausible.TestResult.combine p h2)
- Plausible.TestResult.imp h (Plausible.TestResult.gaveUp n) p = Plausible.TestResult.gaveUp n
Instances For
Test q by testing p and proving the equivalence between the two.
Equations
- Plausible.TestResult.iff h r = Plausible.TestResult.imp ⋯ r (PSum.inr ⋯)
Instances For
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
- Plausible.TestResult.addInfo x h (Plausible.TestResult.failure h2 xs n) p = Plausible.TestResult.failure ⋯ (x :: xs) n
- Plausible.TestResult.addInfo x h r p = Plausible.TestResult.imp h r p
Instances For
Add some formatting to the information recorded by addInfo.
Equations
- Plausible.TestResult.addVarInfo var x h r p = Plausible.TestResult.addInfo (toString var ++ toString " := " ++ toString (repr x)) h r p
Instances For
Instances For
A configuration with all the trace options enabled, useful for debugging.
Equations
Instances For
Equations
Instances For
Equations
- One or more equations did not get rendered due to their size.
Instances For
Equations
- One or more equations did not get rendered due to their size.
Equations
- One or more equations did not get rendered due to their size.
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
- Plausible.Testable.addShrinks n (Plausible.TestResult.failure h2 xs n_1) = Plausible.TestResult.failure h2 xs (n_1 + n)
- Plausible.Testable.addShrinks n x✝ = x✝
Instances For
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.
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
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.
Equations
- One or more equations did not get rendered due to their size.
Equations
- One or more equations did not get rendered due to their size.
Equations
- One or more equations did not get rendered due to their size.
Equations
- Plausible.And.printableProp = { printProp := toString (Plausible.printProp x) ++ toString " ∧ " ++ toString (Plausible.printProp y) }
Equations
- Plausible.Or.printableProp = { printProp := toString (Plausible.printProp x) ++ toString " ∨ " ++ toString (Plausible.printProp y) }
Equations
- Plausible.Iff.printableProp = { printProp := toString (Plausible.printProp x) ++ toString " ↔ " ++ toString (Plausible.printProp y) }
Equations
- Plausible.Imp.printableProp = { printProp := toString (Plausible.printProp x) ++ toString " → " ++ toString (Plausible.printProp y) }
Equations
- Plausible.Not.printableProp = { printProp := toString "¬" ++ toString (Plausible.printProp x) }
Equations
- Plausible.True.printableProp = { printProp := "True" }
Equations
- Plausible.False.printableProp = { printProp := "False" }
Execute cmd and repeat every time the result is gaveUp (at most n times).
Equations
- One or more equations did not get rendered due to their size.
- Plausible.retry cmd 0 = pure (Plausible.TestResult.gaveUp 1)
Instances For
Count the number of times the test procedure gave up.
Equations
- Plausible.giveUp x (Plausible.TestResult.success (PSum.inl PUnit.unit)) = Plausible.TestResult.gaveUp x
- Plausible.giveUp x (Plausible.TestResult.success (PSum.inr p_1)) = Plausible.TestResult.success (PSum.inr p_1)
- Plausible.giveUp x (Plausible.TestResult.gaveUp n) = Plausible.TestResult.gaveUp (n + x)
- Plausible.giveUp x (Plausible.TestResult.failure h xs n) = Plausible.TestResult.failure h xs n
Instances For
Try n times to find a counter-example for p.
Equations
- One or more equations did not get rendered due to their size.
- Plausible.Testable.runSuiteAux p cfg x✝ 0 = pure x✝
Instances For
Try to find a counter-example of p.
Equations
- Plausible.Testable.runSuite p cfg = Plausible.Testable.runSuiteAux p cfg (Plausible.TestResult.success (PSum.inl ())) cfg.numInst
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
Traverse the syntax of a proposition to find universal quantifiers
quantifiers and add NamedBinder annotations next to them.
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
- Plausible.Decorations.tacticMk_decorations = Lean.ParserDescr.node `Plausible.Decorations.tacticMk_decorations 1024 (Lean.ParserDescr.nonReservedSymbol "mk_decorations" false)
Instances For
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
Equations
- Plausible.«command#test_» = Lean.ParserDescr.node `Plausible.«command#test_» 1022 (Lean.ParserDescr.binary `andthen (Lean.ParserDescr.symbol "#test ") (Lean.ParserDescr.cat `term 0))