initial thoughts
This commit is contained in:
parent
982eff449e
commit
c03d12b98c
|
@ -3,7 +3,7 @@ use chumsky::prelude::*;
|
||||||
use crate::{
|
use crate::{
|
||||||
ast,
|
ast,
|
||||||
expr::UntypedExpr,
|
expr::UntypedExpr,
|
||||||
parser::{error::ParseError, expr, token::Token},
|
parser::{error::ParseError, expr, token::Token, definition::function::param},
|
||||||
};
|
};
|
||||||
|
|
||||||
pub fn parser() -> impl Parser<Token, ast::UntypedDefinition, Error = ParseError> {
|
pub fn parser() -> impl Parser<Token, ast::UntypedDefinition, Error = ParseError> {
|
||||||
|
@ -13,7 +13,15 @@ pub fn parser() -> impl Parser<Token, ast::UntypedDefinition, Error = ParseError
|
||||||
.or_not()
|
.or_not()
|
||||||
.then_ignore(just(Token::Test))
|
.then_ignore(just(Token::Test))
|
||||||
.then(select! {Token::Name {name} => name})
|
.then(select! {Token::Name {name} => name})
|
||||||
|
.then(
|
||||||
|
param(false)
|
||||||
|
.separated_by(just(Token::Comma))
|
||||||
|
.allow_trailing()
|
||||||
|
.delimited_by(just(Token::LeftParen), just(Token::RightParen))
|
||||||
|
.map_with_span(|arguments, span| (arguments, span)),
|
||||||
|
)
|
||||||
.then_ignore(just(Token::LeftParen))
|
.then_ignore(just(Token::LeftParen))
|
||||||
|
|
||||||
.then_ignore(just(Token::RightParen))
|
.then_ignore(just(Token::RightParen))
|
||||||
.then(just(Token::Fail).ignored().or_not())
|
.then(just(Token::Fail).ignored().or_not())
|
||||||
.map_with_span(|name, span| (name, span))
|
.map_with_span(|name, span| (name, span))
|
||||||
|
|
|
@ -0,0 +1 @@
|
||||||
|
build
|
|
@ -0,0 +1,114 @@
|
||||||
|
# Moonrat
|
||||||
|
|
||||||
|
> Hedgehog's spineless cousin
|
||||||
|
|
||||||
|
## Aims
|
||||||
|
|
||||||
|
Property based testing for aiken inspired by hedgehog and elm-test.
|
||||||
|
|
||||||
|
Aims:
|
||||||
|
|
||||||
|
- Default gen and shrinking auto derived for any types
|
||||||
|
- Support custom gen/shrinking
|
||||||
|
- Friendly output (progress, sensible feedback such as diffs on large data)
|
||||||
|
- Reasonably speedy
|
||||||
|
|
||||||
|
Non-aims:
|
||||||
|
|
||||||
|
- e2e testing.
|
||||||
|
This is intended for functions rather than testing full txs against validators.
|
||||||
|
Although it should still be possible, it is not our aim here to make writing and testing txs ergonomic.
|
||||||
|
|
||||||
|
|
||||||
|
## Interface
|
||||||
|
|
||||||
|
An aiken file
|
||||||
|
|
||||||
|
```aiken
|
||||||
|
// my_tests.ak
|
||||||
|
|
||||||
|
type T0 {
|
||||||
|
f0 : Int,
|
||||||
|
...
|
||||||
|
}
|
||||||
|
|
||||||
|
fn gen_t0(seed : Int, complexity : Int) -> T0 {
|
||||||
|
...
|
||||||
|
}
|
||||||
|
|
||||||
|
fn shrink_t0(x : T0) -> List<T0> {
|
||||||
|
// TODO : what should the signature of this be?!
|
||||||
|
...
|
||||||
|
}
|
||||||
|
|
||||||
|
type T1 {
|
||||||
|
f0 : Int,
|
||||||
|
...
|
||||||
|
}
|
||||||
|
|
||||||
|
test prop_x (
|
||||||
|
a0 : T0 via (gen_t0(0), shrink_t0),
|
||||||
|
a1 : T0 via (gen_t0(1), shrink_t0),
|
||||||
|
a2 : T0,
|
||||||
|
a2 : T1,
|
||||||
|
) {
|
||||||
|
todo!
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
Comments on the sample.
|
||||||
|
`prop_x` is our test - now supporting arguments.
|
||||||
|
There is new syntax `via`.
|
||||||
|
We have a custom generator and shrinker for `T0` which we may or may not use.
|
||||||
|
In the absence of a specified gen/shrink pair, the default, autoderived one is used.
|
||||||
|
|
||||||
|
Run 100 times
|
||||||
|
```
|
||||||
|
aiken check -m "my_lib/my_test.{prop_x}"
|
||||||
|
```
|
||||||
|
|
||||||
|
Run 1000 cases with a specified seed and shrink limit
|
||||||
|
```
|
||||||
|
aiken check --repeat 1000 --seed 123212123 --shrink-limit 5
|
||||||
|
```
|
||||||
|
|
||||||
|
Reporting:
|
||||||
|
```sample
|
||||||
|
Testing ...
|
||||||
|
|
||||||
|
my_test
|
||||||
|
prop_x PASS [100/100]
|
||||||
|
```
|
||||||
|
|
||||||
|
```sample
|
||||||
|
Testing ...
|
||||||
|
|
||||||
|
my_test
|
||||||
|
prop_x FAIL (after 16 tests and 5 shrinks):
|
||||||
|
a0 = T0 { f0 : 120201, ... }
|
||||||
|
a1 = T0 { ... }
|
||||||
|
...
|
||||||
|
|
||||||
|
RHS = True
|
||||||
|
LHS = False
|
||||||
|
|
||||||
|
seed = 123212123
|
||||||
|
|
||||||
|
Rerun with
|
||||||
|
aiken check -m "my_lib/my_test.{prop_x}" --args " [ T0 { }] ... "
|
||||||
|
```
|
||||||
|
|
||||||
|
## Functionality
|
||||||
|
|
||||||
|
Aiken compiler finds all tests.
|
||||||
|
Any tests with args are assumed subject to property based testing.
|
||||||
|
|
||||||
|
[Property config](https://hackage.haskell.org/package/hedgehog-1.4/docs/Hedgehog-Internal-Property.html#t:PropertyConfig) is global, rather than local.
|
||||||
|
|
||||||
|
The test is compiled as if it were a parametrized validator.
|
||||||
|
Separate gen and shrink functions are also compiled.
|
||||||
|
|
||||||
|
To evaluate the test, the generator(s) are run to generate input for the test.
|
||||||
|
Then the args are applied, and the code evaluated.
|
||||||
|
On success this is repeated until `repeat` number of successes.
|
||||||
|
On failure, the shrinker is employed to seek a simpler failure case.
|
|
@ -0,0 +1,16 @@
|
||||||
|
# This file was generated by Aiken
|
||||||
|
# You typically do not need to edit this file
|
||||||
|
|
||||||
|
[[requirements]]
|
||||||
|
name = "aiken-lang/stdlib"
|
||||||
|
version = "main"
|
||||||
|
source = "github"
|
||||||
|
|
||||||
|
[[packages]]
|
||||||
|
name = "aiken-lang/stdlib"
|
||||||
|
version = "main"
|
||||||
|
requirements = []
|
||||||
|
source = "github"
|
||||||
|
|
||||||
|
[etags]
|
||||||
|
"aiken-lang/stdlib@main" = [{ secs_since_epoch = 1707160390, nanos_since_epoch = 895305443 }, "cf946239d3dd481ed41f20e56bf24910b5229ea35aa171a708edc2a47fc20a7b"]
|
|
@ -0,0 +1,8 @@
|
||||||
|
name = "aiken-lang/moonrat"
|
||||||
|
version = "0.0.0"
|
||||||
|
description = ""
|
||||||
|
|
||||||
|
[[dependencies]]
|
||||||
|
name = 'aiken-lang/stdlib'
|
||||||
|
version = 'main'
|
||||||
|
source = 'github'
|
|
@ -0,0 +1,4 @@
|
||||||
|
|
||||||
|
test test_with_arg(x : Int) {
|
||||||
|
x - x == 0
|
||||||
|
}
|
|
@ -0,0 +1,89 @@
|
||||||
|
{
|
||||||
|
"preamble": {
|
||||||
|
"title": "aiken-lang/acceptance_test_089",
|
||||||
|
"version": "0.0.0",
|
||||||
|
"plutusVersion": "v2",
|
||||||
|
"compiler": {
|
||||||
|
"name": "Aiken",
|
||||||
|
"version": "v1.0.24-alpha+982eff4"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"validators": [
|
||||||
|
{
|
||||||
|
"title": "test2.simple_oneshot",
|
||||||
|
"redeemer": {
|
||||||
|
"title": "_r",
|
||||||
|
"schema": {
|
||||||
|
"$ref": "#/definitions/Void"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"parameters": [
|
||||||
|
{
|
||||||
|
"title": "utxo_ref",
|
||||||
|
"schema": {
|
||||||
|
"$ref": "#/definitions/aiken~1transaction~1OutputReference"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"compiledCode": "58d40100003232323232323232322225333006323232323232533300c3370e900018058018991919299980799b8748000c0380044c8c94ccc044cdc3a40000022944528180780099801002119baf3004300e00100d163300100323375e6006601a00201844646600200200644a6660280022980103d87a8000132325333013300500213374a90001980b80125eb804cc010010004c060008c0580048c04800458dd61808000980400198070009807001180600098020008a4c26cac4600a6ea80048c00cdd5000ab9a5573aaae7955cfaba05742ae89",
|
||||||
|
"hash": "dd850cc95e173d7dbb3357a4a021afc350f405a3cc2e85ace58bfe8d"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"definitions": {
|
||||||
|
"ByteArray": {
|
||||||
|
"dataType": "bytes"
|
||||||
|
},
|
||||||
|
"Int": {
|
||||||
|
"dataType": "integer"
|
||||||
|
},
|
||||||
|
"Void": {
|
||||||
|
"title": "Unit",
|
||||||
|
"description": "The nullary constructor.",
|
||||||
|
"anyOf": [
|
||||||
|
{
|
||||||
|
"dataType": "constructor",
|
||||||
|
"index": 0,
|
||||||
|
"fields": []
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"aiken/transaction/OutputReference": {
|
||||||
|
"title": "OutputReference",
|
||||||
|
"description": "An `OutputReference` is a unique reference to an output on-chain. The `output_index`\n corresponds to the position in the output list of the transaction (identified by its id)\n that produced that output",
|
||||||
|
"anyOf": [
|
||||||
|
{
|
||||||
|
"title": "OutputReference",
|
||||||
|
"dataType": "constructor",
|
||||||
|
"index": 0,
|
||||||
|
"fields": [
|
||||||
|
{
|
||||||
|
"title": "transaction_id",
|
||||||
|
"$ref": "#/definitions/aiken~1transaction~1TransactionId"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"title": "output_index",
|
||||||
|
"$ref": "#/definitions/Int"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"aiken/transaction/TransactionId": {
|
||||||
|
"title": "TransactionId",
|
||||||
|
"description": "A unique transaction identifier, as the hash of a transaction body. Note that the transaction id\n isn't a direct hash of the `Transaction` as visible on-chain. Rather, they correspond to hash\n digests of transaction body as they are serialized on the network.",
|
||||||
|
"anyOf": [
|
||||||
|
{
|
||||||
|
"title": "TransactionId",
|
||||||
|
"dataType": "constructor",
|
||||||
|
"index": 0,
|
||||||
|
"fields": [
|
||||||
|
{
|
||||||
|
"title": "hash",
|
||||||
|
"$ref": "#/definitions/ByteArray"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -79,8 +79,9 @@
|
||||||
|
|
||||||
cargo-insta
|
cargo-insta
|
||||||
|
|
||||||
|
|
||||||
(pkgs.rust-bin.stable.latest.default.override {
|
(pkgs.rust-bin.stable.latest.default.override {
|
||||||
extensions = [ "rust-src" "clippy" "rustfmt" ];
|
extensions = [ "rust-src" "clippy" "rustfmt" "rust-analyzer" ];
|
||||||
})
|
})
|
||||||
] ++ osxDependencies;
|
] ++ osxDependencies;
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue