Skip to content
This repository has been archived by the owner on Mar 9, 2022. It is now read-only.

Commit

Permalink
fix examples
Browse files Browse the repository at this point in the history
  • Loading branch information
Theodus authored and mfelsche committed Aug 5, 2017
1 parent 84f0570 commit 94c9173
Show file tree
Hide file tree
Showing 5 changed files with 81 additions and 77 deletions.
34 changes: 17 additions & 17 deletions examples/list_reverse.pony
Original file line number Diff line number Diff line change
Expand Up @@ -13,36 +13,36 @@ actor Main is TestList
test(_ListReverseOneProperty)
test(_ListReverseMultipleProperties)

class _ListReverseProperty is Property1[List[USize]]
class _ListReverseProperty is Property1[Array[USize]]
fun name(): String => "list/reverse"

fun gen(): Generator[List[USize]] =>
Generators.listOf[USize](Generators.uSize())
fun gen(): Generator[Array[USize]] =>
Generators.seq_of[USize, Array[USize]](Generators.usize())

fun property(arg1: List[USize], ph: PropertyHelper) =>
fun property(arg1: Array[USize], ph: PropertyHelper) =>
ph.assert_array_eq[USize](arg1, arg1.reverse().reverse())


class _ListReverseOneProperty is Property1[List[USize]]
class _ListReverseOneProperty is Property1[Array[USize]]
fun name(): String => "list/reverse/one"

fun gen(): Generator[List[USize]] =>
Generators.listOfN[USize](1, Generators.uSize())
fun gen(): Generator[Array[USize]] =>
Generators.seq_of[USize, Array[USize]](Generators.usize(), 1, 1)

fun property(arg1: List[USize], ph: PropertyHelper) =>
fun property(arg1: Array[USize], ph: PropertyHelper) =>
ph.assert_eq[USize](arg1.size(), 1)
ph.assert_array_eq[USize](arg1, arg1.reverse())

class _ListReverseMultipleProperties is UnitTest
fun name(): String => "list/properties"

fun apply(h: TestHelper) ? =>
let gen1 = Generators.listOf[USize](Generators.uSize())
Ponycheck.forAll[List[USize]](gen1, h)({
(arg1: List[USize], ph: PropertyHelper) =>
let gen1 = Generators.seq_of[USize, Array[USize]](Generators.usize())
Ponycheck.forAll[Array[USize]](gen1, h)(
{(arg1: Array[USize], ph: PropertyHelper) =>
ph.assert_array_eq[USize](arg1, arg1.reverse().reverse())
})?
let gen2 = Generators.listOfN[USize](1, Generators.uSize())
Ponycheck.forAll[List[USize]](gen2, h)({
(arg1: List[USize], ph: PropertyHelper) =>
})?
let gen2 = Generators.seq_of[USize, Array[USize]](Generators.usize(), 1, 1)
Ponycheck.forAll[Array[USize]](gen2, h)(
{(arg1: Array[USize], ph: PropertyHelper) =>
ph.assert_array_eq[USize](arg1, arg1.reverse())
})?
})?
25 changes: 13 additions & 12 deletions ponycheck/generator.pony
Original file line number Diff line number Diff line change
Expand Up @@ -71,22 +71,23 @@ primitive Generators
f()
end)

fun seq_of[T, S: Seq[T] ref = Array[T]](
fun seq_of[T, S: Seq[T] ref](
gen: Generator[T],
min: USize = 0,
max: USize = 100)
: Generator[Seq[T]]
: Generator[S]
=>
"""
Create a list from the given Generator with an optional minimum and
maximum size, defaults are 0 and 100 respectively.
"""
Generator[Seq[T]](
object is GenObj[Seq[T]]
fun generate(rnd: Randomness): Seq[T]^ =>
Generator[S](
object is GenObj[S]
fun generate(rnd: Randomness): S^ =>
let size = rnd.usize(min, max)
Iter[T^](gen.iter(rnd))
.take(rnd.usize(min, max))
.collect[S](S(rnd.usize(0, max)))
.take(size)
.collect[S](S.create(size))
end)

fun one_of[T](xs: ReadSeq[T]): Generator[box->T] ? =>
Expand All @@ -113,8 +114,8 @@ primitive Generators
let filtered =
Iter[WeightedGenerator[T]](weighted_generators.values())
.filter(
{(weightedGen: WeightedGenerator[T]): Bool =>
weightedGen._1 > 0
{(weighted_gen: WeightedGenerator[T]): Bool =>
weighted_gen._1 > 0
})
.collect(Array[WeightedGenerator[T]])

Expand All @@ -129,16 +130,16 @@ primitive Generators
try
Iter[WeightedGenerator[T]](filtered.values())
.fold[USize](
{(acc: USize, weightedGen: WeightedGenerator[T]): USize =>
weightedGen._1 + acc
{(acc: USize, weighted_gen: WeightedGenerator[T]): USize =>
weighted_gen._1 + acc
},
0)?
else
0
end
let desired_sum = rnd.usize(0, weight_sum)
var running_sum: USize = 0
var chosen: (Generator[T] box| None) = None
var chosen: (Generator[T] | None) = None
for weighted_gen in filtered.values() do
let new_sum = running_sum + weighted_gen._1
if (running_sum < desired_sum) and (desired_sum <= new_sum) then
Expand Down
16 changes: 8 additions & 8 deletions ponycheck/ponycheck.pony
Original file line number Diff line number Diff line change
Expand Up @@ -8,14 +8,13 @@ use "collections"
use "ponycheck"
class ListReverseProperty is Property1[List[USize]]
fun name(): String => "list/reverse"
fun gen(): Generator[List[USize]] => Generators.listOf[USize](Generators.uSize())
fun gen(): Generator[List[USize]] =>
Generators.list_of[USize](Generators.usize())
fun property(arg1: List[USize], ph: PropertyHelper) =>
ph.array_eq[Usize](arg1, arg1.reverse().reverse())
ph.array_eq[USize](arg1, arg1.reverse().reverse())
```
A property based test in ponytest consists of the following:
Expand All @@ -37,10 +36,11 @@ class ListReversePropertyWithinAUnitTest is UnitTest
fun apply(h: TestHelper) =>
let gen = Generators.listOf[USize](Generators.uSize())
Ponycheck.forAll[List[USize]](gen, h)({(sample: List[USize], ph: PropertyHelper) =>
ph.array_eq[Usize](arg1, arg1.reverse().reverse())
})
// ... possibly more properties, using ``Ponycheck.forAll``
Ponycheck.forAll[List[USize]](gen, h)(
{(sample: List[USize], ph: PropertyHelper) =>
ph.array_eq[Usize](arg1, arg1.reverse().reverse())
})
// ... possibly more properties, using ``Ponycheck.for_all``
```
Expand Down
63 changes: 33 additions & 30 deletions ponycheck/property.pony
Original file line number Diff line number Diff line change
Expand Up @@ -6,23 +6,23 @@ class PropertyParams
parameters for Property Execution
* seed: the seed for the source of Randomness
* numSamples: the number of samples to produce from the property generator
* maxShrinkRounds: the maximum rounds of shrinking to perform
* maxShrinkSamples: the maximum number of shrunken samples to consider in 1 shrink round
* num_samples: the number of samples to produce from the property generator
* max_shrink_rounds: the maximum rounds of shrinking to perform
* max_shrink_samples: the maximum number of shrunken samples to consider in 1 shrink round
"""
let seed: U64
let numSamples: USize
let maxShrinkRounds: USize
let maxShrinkSamples: USize
let num_samples: USize
let max_shrink_rounds: USize
let max_shrink_samples: USize

new create(numSamples': USize = 100,
new create(num_samples': USize = 100,
seed': U64 = 42,
maxShrinkRounds': USize = 10,
maxShrinkSamples': USize = 100) =>
numSamples = numSamples'
max_shrink_rounds': USize = 10,
max_shrink_samples': USize = 100) =>
num_samples = num_samples'
seed = seed'
maxShrinkRounds = maxShrinkRounds'
maxShrinkSamples = maxShrinkSamples'
max_shrink_rounds = max_shrink_rounds'
max_shrink_samples = max_shrink_samples'


trait Property1[T] is UnitTest
Expand All @@ -45,7 +45,7 @@ trait Property1[T] is UnitTest
from the ``params()`` method.
The ``gen()`` method is called exactly once to instantiate the generator.
The generator produces ``PropertyParams.numSamples`` samples and each is
The generator produces ``PropertyParams.num_samples`` samples and each is
passed to the ``property`` method for verification.
If the property did not verify, the given sample is shrunken, if the generator
Expand All @@ -71,59 +71,62 @@ trait Property1[T] is UnitTest
let helper: PropertyHelper ref = PropertyHelper(parameters, h)
let generator: Generator[T] = gen()
let me: Property1[T] = this
for i in Range[USize].create(0, parameters.numSamples) do
for i in Range[USize].create(0, parameters.num_samples) do
var sample: T = generator.generate(rnd)

// create a string representation before consuming ``sample`` with property
(sample, var sampleRepr: String) = _toString(consume sample)
(sample, var sample_repr: String) = _to_string(consume sample)
// shrink before consuming ``sample`` with property
(sample, var shrinks: Seq[T]) = _shrink(consume sample, generator)
try
me.property(consume sample, helper)?
else
// report error with given sample
helper.reportError(sampleRepr, 0)
helper.reportError(sample_repr, 0)
error
end
if helper.failed() then
var shrinkRounds: USize = 0
let numShrinks = shrinks.size()
var shrink_rounds: USize = 0
let num_shrinks = shrinks.size()

// safeguard against generators that generate huge or even infinite shrink seqs
let shrinksToIgnore =
if numShrinks > parameters.maxShrinkSamples then
numShrinks - parameters.maxShrinkSamples
let shrinks_to_ignore =
if num_shrinks > parameters.max_shrink_samples then
num_shrinks - parameters.max_shrink_samples
else
0
end
while (shrinks.size() > shrinksToIgnore) and (shrinkRounds < parameters.maxShrinkRounds) do
while
(shrinks.size() > shrinks_to_ignore)
and (shrink_rounds < parameters.max_shrink_rounds)
do
var failedShrink: T = shrinks.pop()?
(failedShrink, let shrinkRepr: String) = _toString(consume failedShrink)
(failedShrink, let nextShrinks: Seq[T]) = _shrink(consume failedShrink, generator)
(failedShrink, let shrink_repr: String) = _to_string(consume failedShrink)
(failedShrink, let next_shrinks: Seq[T]) = _shrink(consume failedShrink, generator)
helper.reset()
try
me.property(consume failedShrink, helper)?
else
helper.reportError(shrinkRepr, shrinkRounds)
helper.reportError(shrink_repr, shrink_rounds)
error
end
if helper.failed() then
// we have a failing shrink sample
shrinkRounds = shrinkRounds + 1
shrinks = consume nextShrinks
sampleRepr = shrinkRepr
shrink_rounds = shrink_rounds + 1
shrinks = consume next_shrinks
sample_repr = shrink_repr
continue
end
end
helper.reportFailed[T](sampleRepr, shrinkRounds)
helper.reportFailed[T](sample_repr, shrink_rounds)
break
end
end
if not helper.failed() then
helper.reportSuccess()
end

fun ref _toString(sample: T): (T^, String) =>
fun ref _to_string(sample: T): (T^, String) =>
"""
format the given sample to a string representation,
use digestof if nothing else is available
Expand Down
20 changes: 10 additions & 10 deletions ponycheck/property_helper.pony
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
use "ponytest"

// TODO append strings instead of add

interface FailureCallback
"""something to call in case of error"""
fun fail(msg: String)
Expand Down Expand Up @@ -324,15 +326,13 @@ class ref PropertyHelper
fun tag _format_params(params: PropertyParams): String =>
"Params(seed=" + params.seed.string() + ")"


fun reportSuccess() =>
"""
report success to the property test runner
"""


fun reportError(sampleRepr: String,
shrinkRounds: USize = 0,
fun reportError(sample_repr: String,
shrink_rounds: USize = 0,
loc: SourceLoc = __loc) =>
"""
report an error that happened during property evaluation
Expand All @@ -341,16 +341,16 @@ class ref PropertyHelper
_fmt_msg(
loc,
"Property errored for sample "
+ sampleRepr
+ sample_repr
+ " (after "
+ shrinkRounds.string()
+ shrink_rounds.string()
+ " shrinks)"
),
false
)

fun reportFailed[T](sampleRepr: String,
shrinkRounds: USize = 0,
fun reportFailed[T](sample_repr: String,
shrink_rounds: USize = 0,
loc: SourceLoc = __loc) =>
"""
report a failed property
Expand All @@ -359,9 +359,9 @@ class ref PropertyHelper
_fmt_msg(
loc,
"Property failed for sample "
+ sampleRepr
+ sample_repr
+ " (after "
+ shrinkRounds.string()
+ shrink_rounds.string()
+ " shrinks)"
)
)
Expand Down

0 comments on commit 94c9173

Please sign in to comment.