Skip to content

Commit

Permalink
refactor(code-samples): 📝 Turn code samples into snippets for "Testin…
Browse files Browse the repository at this point in the history
…g" directory
  • Loading branch information
shaedrich committed Apr 21, 2024
1 parent 2464d02 commit 50e60d2
Show file tree
Hide file tree
Showing 8 changed files with 98 additions and 92 deletions.
9 changes: 9 additions & 0 deletions code-samples/ponycheck-ponytest.pony
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
use "pony_test"
use "pony_check"

actor Main is TestList
new create(env: Env) =>
PonyTest(env, this)

fun tag tests(test: PonyTest) =>
test(Property1UnitTest[String](_MyFirstProperty))
14 changes: 14 additions & 0 deletions code-samples/ponycheck-usage-ponytest-for-all.pony
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
class _ListReverseProperties is UnitTest
fun name(): String => "list/properties"

fun apply(h: TestHelper) ? =>
let gen1 = Generators.seq_of[USize, Array[USize]](Generators.usize())
PonyCheck.for_all[Array[USize]](gen1, h)({
(arg1: Array[USize], ph: PropertyHelper) =>
ph.assert_array_eq[USize](arg1, arg1.reverse().reverse())
})
let gen2 = Generators.seq_of[USize, Array[USize]](1, Generators.usize())
PonyCheck.for_all[Array[USize]](gen2, h)({
(arg1: Array[USize], ph: PropertyHelper) =>
ph.assert_array_eq[USize](arg1, arg1.reverse())
})
20 changes: 20 additions & 0 deletions code-samples/ponycheck-usage-quickcheck.pony
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
use "pony_check"
use "collections"

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

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

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

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

fun gen(): Generator[Array[USize]] =>
Generators.seq_of[USize, Array[USize]](Generators.usize() where min = 1, max = 1)

fun property(arg1: Array[USize], ph: PropertyHelper) =>
ph.assert_array_eq[USize](arg1, arg1.reverse())
11 changes: 11 additions & 0 deletions code-samples/ponycheck-usage.pony
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
use "pony_test"

class _MyFirstProperty is Property1[String]
fun name(): String =>
"my_first_property"

fun gen(): Generator[String] =>
Generators.ascii()

fun property(arg1: String, ph: PropertyHelper) =>
ph.assert_eq[String](arg1, arg1)
14 changes: 14 additions & 0 deletions code-samples/ponytest-aggregation.pony
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
use "pony_test"
use foo = "foo"
use bar = "bar"

actor Main is TestList
new create(env: Env) =>
PonyTest(env, this)

new make() =>
None

fun tag tests(test: PonyTest) =>
foo.Main.make().tests(test)
bar.Main.make().tests(test)
24 changes: 24 additions & 0 deletions code-samples/ponytest-example.pony
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
use "pony_test"

actor Main is TestList
new create(env: Env) =>
PonyTest(env, this)

new make() =>
None

fun tag tests(test: PonyTest) =>
test(_TestAdd)
test(_TestSub)

class iso _TestAdd is UnitTest
fun name(): String => "addition"

fun apply(h: TestHelper) =>
h.assert_eq[U32](4, 2 + 2)

class iso _TestSub is UnitTest
fun name(): String => "subtraction"

fun apply(h: TestHelper) =>
h.assert_eq[U32](2, 4 - 2)
58 changes: 4 additions & 54 deletions docs/testing/ponycheck.md
Original file line number Diff line number Diff line change
Expand Up @@ -19,80 +19,30 @@ PonyCheck is heavily inspired by QuickCheck and other great property based testi
Writing property based tests in PonyCheck is done by implementing the trait [`Property1`](https://stdlib.ponylang.io/pony_check-Property1). A [`Property1`](https://stdlib.ponylang.io/pony_check-Property1) needs to define a type parameter for the type of the input sample, a [`Generator`](https://stdlib.ponylang.io/pony_check-Generator) and a property function. Here is a minimal example:

```pony
use "pony_test"
class _MyFirstProperty is Property1[String]
fun name(): String =>
"my_first_property"
fun gen(): Generator[String] =>
Generators.ascii()
fun property(arg1: String, ph: PropertyHelper) =>
ph.assert_eq[String](arg1, arg1)
--8<-- "ponycheck-usage.pony"
```

A `Property1` needs a name for identification in test output. We created a `Generator` by using one of the many convenience factory methods and combinators defined in the [`Generators`](https://stdlib.ponylang.io/pony_check-Generators) primitive and we used [`PropertyHelper`](https://stdlib.ponylang.io/pony_check-PropertyHelper) to assert on a condition that should hold for all samples

Below are two classic list reverse properties from the QuickCheck paper adapted to Pony arrays:

```pony
use "pony_check"
use "collections"
class _ListReverseProperty is Property1[Array[USize]]
fun name(): String => "list/reverse"
fun gen(): Generator[Array[USize]] =>
Generators.seq_of[USize, Array[USize]](Generators.usize())
fun property(arg1: Array[USize], ph: PropertyHelper) =>
ph.assert_array_eq[USize](arg1, arg1.reverse().reverse())
class _ListReverseOneProperty is Property1[Array[USize]]
fun name(): String => "list/reverse/one"
fun gen(): Generator[Array[USize]] =>
Generators.seq_of[USize, Array[USize]](Generators.usize() where min = 1, max = 1)
fun property(arg1: Array[USize], ph: PropertyHelper) =>
ph.assert_array_eq[USize](arg1, arg1.reverse())
--8<-- "ponycheck-usage-quickcheck.pony"
```

## Integration with PonyTest

PonyCheck properties need to be executed. The test runner for PonyCheck is [PonyTest](https://stdlib.ponylang.io/pony_test--index). To integrate [`Property1`](https://stdlib.ponylang.io/pony_check-Property1) into [PonyTest](https://stdlib.ponylang.io/pony_test--index), `Property1` needs to be wrapped inside a [`Property1UnitTest`](https://stdlib.ponylang.io/pony_check-Property1UnitTest) and passed to the PonyTest `apply` method as a regular PonyTest [`UnitTest`](https://stdlib.ponylang.io/pony_test-UnitTest):

```pony
use "pony_test"
use "pony_check"
actor Main is TestList
new create(env: Env) =>
PonyTest(env, this)
fun tag tests(test: PonyTest) =>
test(Property1UnitTest[String](_MyFirstProperty))
--8<-- "ponycheck-usage-ponytest.pony"
```

It is also possible to integrate any number of properties directly into one
[`UnitTest`](https://stdlib.ponylang.io/pony_test-UnitTest) using the [`PonyCheck.for_all`](https://stdlib.ponylang.io/pony_check-PonyCheck) convenience function:

```pony
class _ListReverseProperties is UnitTest
fun name(): String => "list/properties"
fun apply(h: TestHelper) ? =>
let gen1 = Generators.seq_of[USize, Array[USize]](Generators.usize())
PonyCheck.for_all[Array[USize]](gen1, h)({
(arg1: Array[USize], ph: PropertyHelper) =>
ph.assert_array_eq[USize](arg1, arg1.reverse().reverse())
})
let gen2 = Generators.seq_of[USize, Array[USize]](1, Generators.usize())
PonyCheck.for_all[Array[USize]](gen2, h)({
(arg1: Array[USize], ph: PropertyHelper) =>
ph.assert_array_eq[USize](arg1, arg1.reverse())
})
--8<-- "ponycheck-usage-ponytest-for-all.pony"
```

## Additional resources
Expand Down
40 changes: 2 additions & 38 deletions docs/testing/ponytest.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,30 +15,7 @@ To use PonyTest simply write a class for each test and a `TestList` type that te
The following is a complete program with 2 trivial tests.

```pony
use "pony_test"
actor Main is TestList
new create(env: Env) =>
PonyTest(env, this)
new make() =>
None
fun tag tests(test: PonyTest) =>
test(_TestAdd)
test(_TestSub)
class iso _TestAdd is UnitTest
fun name(): String => "addition"
fun apply(h: TestHelper) =>
h.assert_eq[U32](4, 2 + 2)
class iso _TestSub is UnitTest
fun name(): String => "subtraction"
fun apply(h: TestHelper) =>
h.assert_eq[U32](2, 4 - 2)
--8<-- "ponytest-example.pony"
```

The make() constructor is not needed for this example. However, it allows for easy aggregation of tests (see below) so it is recommended that all test Mains provide it.
Expand All @@ -58,20 +35,7 @@ Often it is desirable to run a collection of unit tests from multiple different
This can be achieved by writing an aggregate test list class, which calls the list function for each package. The following is an example that aggregates the tests from packages `foo` and `bar`.

```pony
use "pony_test"
use foo = "foo"
use bar = "bar"
actor Main is TestList
new create(env: Env) =>
PonyTest(env, this)
new make() =>
None
fun tag tests(test: PonyTest) =>
foo.Main.make().tests(test)
bar.Main.make().tests(test)
--8<-- "ponytest-aggregation.pony"
```

Aggregate test classes may themselves be aggregated. Every test list class may contain any combination of its own tests and aggregated lists.
Expand Down

0 comments on commit 50e60d2

Please sign in to comment.