Rework unit test report to leverage new reification
And also provide slightly better errors when traces, or trace-if-false operators are present.
This commit is contained in:
parent
59996850c1
commit
bff822ea7f
|
@ -8,11 +8,13 @@
|
||||||
- **aiken-lang**: New types `PRNG` and `Fuzzer` in the prelude. @KtorZ
|
- **aiken-lang**: New types `PRNG` and `Fuzzer` in the prelude. @KtorZ
|
||||||
- **aiken-lang**: Test definitions now accept an (optional) argument alongside a new keyword `via` to specify fuzzers. @KtorZ
|
- **aiken-lang**: Test definitions now accept an (optional) argument alongside a new keyword `via` to specify fuzzers. @KtorZ
|
||||||
- **aiken-project**: Property-based testing framework with integrated shrinking. @KtorZ
|
- **aiken-project**: Property-based testing framework with integrated shrinking. @KtorZ
|
||||||
|
- **aiken-project**: Unit tests now show assertion operands as Aiken expression instead of raw UPLC . @KtorZ
|
||||||
- **aiken**: The `check` command now accept an extra arg `--seed` to provide an initial seed for the pseudo-random generator of properties. @KtorZ
|
- **aiken**: The `check` command now accept an extra arg `--seed` to provide an initial seed for the pseudo-random generator of properties. @KtorZ
|
||||||
|
|
||||||
### Fixed
|
### Fixed
|
||||||
|
|
||||||
- **uplc**: `serialise_data` builtin wrongly encoding some larger ints as tagged CBOR bigints, instead of plain integers over 9 bytes. @KtorZ
|
- **uplc**: `serialise_data` builtin wrongly encoding some larger ints as tagged CBOR bigints, instead of plain integers over 9 bytes. @KtorZ
|
||||||
|
- **aiken-project**: Unit tests reports are now inline with the test with less noise. @KtorZ
|
||||||
|
|
||||||
### Changed
|
### Changed
|
||||||
|
|
||||||
|
|
|
@ -30,9 +30,9 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "ahash"
|
name = "ahash"
|
||||||
version = "0.8.10"
|
version = "0.8.11"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "8b79b82693f705137f8fb9b37871d99e4f9a7df12b917eed79c3d3954830a60b"
|
checksum = "e89da841a80418a9b391ebaea17f5c112ffaaa96f621d2c285b5174da76b9011"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"cfg-if",
|
"cfg-if",
|
||||||
"once_cell",
|
"once_cell",
|
||||||
|
@ -156,6 +156,7 @@ dependencies = [
|
||||||
"tokio",
|
"tokio",
|
||||||
"toml",
|
"toml",
|
||||||
"uplc",
|
"uplc",
|
||||||
|
"vec1",
|
||||||
"walkdir",
|
"walkdir",
|
||||||
"zip",
|
"zip",
|
||||||
]
|
]
|
||||||
|
@ -520,10 +521,11 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "cc"
|
name = "cc"
|
||||||
version = "1.0.88"
|
version = "1.0.90"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "02f341c093d19155a6e41631ce5971aac4e9a868262212153124c15fa22d1cdc"
|
checksum = "8cd6604a82acf3039f1144f54b8eb34e91ffba622051189e71b781822d5ee1f5"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
|
"jobserver",
|
||||||
"libc",
|
"libc",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
@ -535,9 +537,9 @@ checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "chrono"
|
name = "chrono"
|
||||||
version = "0.4.34"
|
version = "0.4.35"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "5bc015644b92d5890fab7489e49d21f879d5c990186827d42ec511919404f38b"
|
checksum = "8eaf5903dcbc0a39312feb77df2ff4c76387d591b9fc7b04a238dcf8bb62639a"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"num-traits",
|
"num-traits",
|
||||||
]
|
]
|
||||||
|
@ -564,9 +566,9 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "clap"
|
name = "clap"
|
||||||
version = "4.5.1"
|
version = "4.5.2"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "c918d541ef2913577a0f9566e9ce27cb35b6df072075769e0b26cb5a554520da"
|
checksum = "b230ab84b0ffdf890d5a10abdbc8b83ae1c4918275daea1ab8801f71536b2651"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"clap_builder",
|
"clap_builder",
|
||||||
"clap_derive",
|
"clap_derive",
|
||||||
|
@ -574,9 +576,9 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "clap_builder"
|
name = "clap_builder"
|
||||||
version = "4.5.1"
|
version = "4.5.2"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "9f3e7391dad68afb0c2ede1bf619f579a3dc9c2ec67f089baa397123a2f3d1eb"
|
checksum = "ae129e2e766ae0ec03484e609954119f123cc1fe650337e155d03b022f24f7b4"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"anstream",
|
"anstream",
|
||||||
"anstyle",
|
"anstyle",
|
||||||
|
@ -1254,9 +1256,9 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "http"
|
name = "http"
|
||||||
version = "0.2.11"
|
version = "0.2.12"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "8947b1a6fad4393052c7ba1f4cd97bed3e953a95c79c92ad9b051a04611d9fbb"
|
checksum = "601cbb57e577e2f5ef5be8e7b83f0f63994f25aa94d673e54a92d5c516d101f1"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"bytes",
|
"bytes",
|
||||||
"fnv",
|
"fnv",
|
||||||
|
@ -1443,9 +1445,9 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "insta"
|
name = "insta"
|
||||||
version = "1.35.1"
|
version = "1.36.1"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "7c985c1bef99cf13c58fade470483d81a2bfe846ebde60ed28cc2dddec2df9e2"
|
checksum = "0a7c22c4d34ef4788c351e971c52bfdfe7ea2766f8c5466bc175dd46e52ac22e"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"console",
|
"console",
|
||||||
"lazy_static",
|
"lazy_static",
|
||||||
|
@ -1494,10 +1496,19 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "b1a46d1a171d865aa5f83f92695765caa047a9b4cbae2cbf37dbd613a793fd4c"
|
checksum = "b1a46d1a171d865aa5f83f92695765caa047a9b4cbae2cbf37dbd613a793fd4c"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "js-sys"
|
name = "jobserver"
|
||||||
version = "0.3.68"
|
version = "0.1.28"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "406cda4b368d531c842222cf9d2600a9a4acce8d29423695379c6868a143a9ee"
|
checksum = "ab46a6e9526ddef3ae7f787c06f0f2600639ba80ea3eade3d8e670a2230f51d6"
|
||||||
|
dependencies = [
|
||||||
|
"libc",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "js-sys"
|
||||||
|
version = "0.3.69"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "29c15563dc2726973df627357ce0c9ddddbea194836909d655df6a75d2cf296d"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"wasm-bindgen",
|
"wasm-bindgen",
|
||||||
]
|
]
|
||||||
|
@ -2230,18 +2241,18 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "pin-project"
|
name = "pin-project"
|
||||||
version = "1.1.4"
|
version = "1.1.5"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "0302c4a0442c456bd56f841aee5c3bfd17967563f6fadc9ceb9f9c23cf3807e0"
|
checksum = "b6bf43b791c5b9e34c3d182969b4abb522f9343702850a2e57f460d00d09b4b3"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"pin-project-internal",
|
"pin-project-internal",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "pin-project-internal"
|
name = "pin-project-internal"
|
||||||
version = "1.1.4"
|
version = "1.1.5"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "266c042b60c9c76b8d53061e52b2e0d1116abc57cefc8c5cd671619a56ac3690"
|
checksum = "2f38a4412a78282e09a2cf38d195ea5420d15ba0602cb375210efbc877243965"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"quote",
|
"quote",
|
||||||
|
@ -2531,9 +2542,9 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "regex-automata"
|
name = "regex-automata"
|
||||||
version = "0.4.5"
|
version = "0.4.6"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "5bb987efffd3c6d0d8f5f89510bb458559eab11e4f869acb20bf845e016259cd"
|
checksum = "86b83b8b9847f9bf95ef68afb0b8e6cdb80f498442f5179a29fad448fcc1eaea"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"aho-corasick",
|
"aho-corasick",
|
||||||
"memchr",
|
"memchr",
|
||||||
|
@ -3570,9 +3581,9 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "walkdir"
|
name = "walkdir"
|
||||||
version = "2.4.0"
|
version = "2.5.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "d71d857dc86794ca4c280d616f7da00d2dbfd8cd788846559a6813e6aa4b54ee"
|
checksum = "29790946404f91d9c5d06f9874efddea1dc06c5efe94541a7d6863108e3a5e4b"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"same-file",
|
"same-file",
|
||||||
"winapi-util",
|
"winapi-util",
|
||||||
|
@ -3595,9 +3606,9 @@ checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "wasm-bindgen"
|
name = "wasm-bindgen"
|
||||||
version = "0.2.91"
|
version = "0.2.92"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "c1e124130aee3fb58c5bdd6b639a0509486b0338acaaae0c84a5124b0f588b7f"
|
checksum = "4be2531df63900aeb2bca0daaaddec08491ee64ceecbee5076636a3b026795a8"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"cfg-if",
|
"cfg-if",
|
||||||
"wasm-bindgen-macro",
|
"wasm-bindgen-macro",
|
||||||
|
@ -3605,9 +3616,9 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "wasm-bindgen-backend"
|
name = "wasm-bindgen-backend"
|
||||||
version = "0.2.91"
|
version = "0.2.92"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "c9e7e1900c352b609c8488ad12639a311045f40a35491fb69ba8c12f758af70b"
|
checksum = "614d787b966d3989fa7bb98a654e369c762374fd3213d212cfc0251257e747da"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"bumpalo",
|
"bumpalo",
|
||||||
"log",
|
"log",
|
||||||
|
@ -3620,9 +3631,9 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "wasm-bindgen-futures"
|
name = "wasm-bindgen-futures"
|
||||||
version = "0.4.41"
|
version = "0.4.42"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "877b9c3f61ceea0e56331985743b13f3d25c406a7098d45180fb5f09bc19ed97"
|
checksum = "76bc14366121efc8dbb487ab05bcc9d346b3b5ec0eaa76e46594cabbe51762c0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"cfg-if",
|
"cfg-if",
|
||||||
"js-sys",
|
"js-sys",
|
||||||
|
@ -3632,9 +3643,9 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "wasm-bindgen-macro"
|
name = "wasm-bindgen-macro"
|
||||||
version = "0.2.91"
|
version = "0.2.92"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "b30af9e2d358182b5c7449424f017eba305ed32a7010509ede96cdc4696c46ed"
|
checksum = "a1f8823de937b71b9460c0c34e25f3da88250760bec0ebac694b49997550d726"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"quote",
|
"quote",
|
||||||
"wasm-bindgen-macro-support",
|
"wasm-bindgen-macro-support",
|
||||||
|
@ -3642,9 +3653,9 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "wasm-bindgen-macro-support"
|
name = "wasm-bindgen-macro-support"
|
||||||
version = "0.2.91"
|
version = "0.2.92"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "642f325be6301eb8107a83d12a8ac6c1e1c54345a7ef1a9261962dfefda09e66"
|
checksum = "e94f17b526d0a461a191c78ea52bbce64071ed5c04c9ffe424dcb38f74171bb7"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"quote",
|
"quote",
|
||||||
|
@ -3655,15 +3666,15 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "wasm-bindgen-shared"
|
name = "wasm-bindgen-shared"
|
||||||
version = "0.2.91"
|
version = "0.2.92"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "4f186bd2dcf04330886ce82d6f33dd75a7bfcf69ecf5763b89fcde53b6ac9838"
|
checksum = "af190c94f2773fdb3729c55b007a722abb5384da03bc0986df4c289bf5567e96"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "web-sys"
|
name = "web-sys"
|
||||||
version = "0.3.68"
|
version = "0.3.69"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "96565907687f7aceb35bc5fc03770a8a0471d82e479f25832f54a0e3f4b28446"
|
checksum = "77afa9a11836342370f4817622a2f0f418b134426d91a82dfb48f532d2ec13ef"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"js-sys",
|
"js-sys",
|
||||||
"wasm-bindgen",
|
"wasm-bindgen",
|
||||||
|
|
|
@ -273,56 +273,6 @@ impl From<TypedTest> for TypedFunction {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl TypedTest {
|
|
||||||
pub fn test_hint(&self) -> Option<(BinOp, Box<TypedExpr>, Box<TypedExpr>)> {
|
|
||||||
if self.arguments.is_empty() {
|
|
||||||
do_test_hint(&self.body)
|
|
||||||
} else {
|
|
||||||
None
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn do_test_hint(body: &TypedExpr) -> Option<(BinOp, Box<TypedExpr>, Box<TypedExpr>)> {
|
|
||||||
match body {
|
|
||||||
TypedExpr::BinOp {
|
|
||||||
name,
|
|
||||||
tipo,
|
|
||||||
left,
|
|
||||||
right,
|
|
||||||
..
|
|
||||||
} if tipo == &bool() => Some((*name, left.clone(), right.clone())),
|
|
||||||
TypedExpr::Sequence { expressions, .. } | TypedExpr::Pipeline { expressions, .. } => {
|
|
||||||
if let Some((binop, left, right)) = do_test_hint(&expressions[expressions.len() - 1]) {
|
|
||||||
let mut new_left_expressions = expressions.clone();
|
|
||||||
new_left_expressions.pop();
|
|
||||||
new_left_expressions.push(*left);
|
|
||||||
|
|
||||||
let mut new_right_expressions = expressions.clone();
|
|
||||||
new_right_expressions.pop();
|
|
||||||
new_right_expressions.push(*right);
|
|
||||||
|
|
||||||
Some((
|
|
||||||
binop,
|
|
||||||
TypedExpr::Sequence {
|
|
||||||
expressions: new_left_expressions,
|
|
||||||
location: Span::empty(),
|
|
||||||
}
|
|
||||||
.into(),
|
|
||||||
TypedExpr::Sequence {
|
|
||||||
expressions: new_right_expressions,
|
|
||||||
location: Span::empty(),
|
|
||||||
}
|
|
||||||
.into(),
|
|
||||||
))
|
|
||||||
} else {
|
|
||||||
None
|
|
||||||
}
|
|
||||||
}
|
|
||||||
_ => None,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug, Clone, PartialEq)]
|
#[derive(Debug, Clone, PartialEq)]
|
||||||
pub struct TypeAlias<T> {
|
pub struct TypeAlias<T> {
|
||||||
pub alias: String,
|
pub alias: String,
|
||||||
|
|
|
@ -45,6 +45,7 @@ aiken-lang = { path = "../aiken-lang", version = "1.0.24-alpha" }
|
||||||
uplc = { path = '../uplc', version = "1.0.24-alpha" }
|
uplc = { path = '../uplc', version = "1.0.24-alpha" }
|
||||||
num-bigint = "0.4.4"
|
num-bigint = "0.4.4"
|
||||||
cryptoxide = "0.4.4"
|
cryptoxide = "0.4.4"
|
||||||
|
vec1 = "1.10.1"
|
||||||
|
|
||||||
[dev-dependencies]
|
[dev-dependencies]
|
||||||
blst = "0.3.11"
|
blst = "0.3.11"
|
||||||
|
|
|
@ -93,7 +93,6 @@ pub enum Error {
|
||||||
path: PathBuf,
|
path: PathBuf,
|
||||||
verbose: bool,
|
verbose: bool,
|
||||||
src: String,
|
src: String,
|
||||||
assertion: Option<String>,
|
|
||||||
},
|
},
|
||||||
|
|
||||||
#[error(
|
#[error(
|
||||||
|
@ -331,10 +330,7 @@ impl Diagnostic for Error {
|
||||||
)),
|
)),
|
||||||
Error::TomlLoading { .. } => None,
|
Error::TomlLoading { .. } => None,
|
||||||
Error::Format { .. } => None,
|
Error::Format { .. } => None,
|
||||||
Error::TestFailure { assertion, .. } => match assertion {
|
Error::TestFailure { .. } => None,
|
||||||
None => None,
|
|
||||||
Some(hint) => Some(Box::new(hint.to_string())),
|
|
||||||
},
|
|
||||||
Error::Http(_) => None,
|
Error::Http(_) => None,
|
||||||
Error::ZipExtract(_) => None,
|
Error::ZipExtract(_) => None,
|
||||||
Error::JoinError(_) => None,
|
Error::JoinError(_) => None,
|
||||||
|
|
|
@ -843,8 +843,6 @@ where
|
||||||
.into_par_iter()
|
.into_par_iter()
|
||||||
.map(|test| match test {
|
.map(|test| match test {
|
||||||
Test::UnitTest(unit_test) => unit_test.run(),
|
Test::UnitTest(unit_test) => unit_test.run(),
|
||||||
// TODO: Get the seed from the command-line, defaulting to a random one when not
|
|
||||||
// provided.
|
|
||||||
Test::PropertyTest(property_test) => property_test.run(seed),
|
Test::PropertyTest(property_test) => property_test.run(seed),
|
||||||
})
|
})
|
||||||
.collect::<Vec<TestResult<PlutusData>>>()
|
.collect::<Vec<TestResult<PlutusData>>>()
|
||||||
|
|
|
@ -305,14 +305,10 @@ fn fmt_test(
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
TestResult::PropertyTestResult(PropertyTestResult { iterations, .. }) => {
|
TestResult::PropertyTestResult(PropertyTestResult { iterations, .. }) => {
|
||||||
test = pretty::pad_right(
|
test = format!(
|
||||||
format!(
|
"{test} [after {} test{}]",
|
||||||
"{test} [after {} test{}]",
|
pretty::pad_left(iterations.to_string(), max_iter, " "),
|
||||||
pretty::pad_left(iterations.to_string(), max_iter, " "),
|
if *iterations > 1 { "s" } else { "" }
|
||||||
if *iterations > 1 { "s" } else { "" }
|
|
||||||
),
|
|
||||||
18 + max_mem + max_cpu + max_iter,
|
|
||||||
" ",
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -325,6 +321,22 @@ fn fmt_test(
|
||||||
.to_string())
|
.to_string())
|
||||||
);
|
);
|
||||||
|
|
||||||
|
// Annotations
|
||||||
|
match result {
|
||||||
|
TestResult::UnitTestResult(UnitTestResult {
|
||||||
|
test: unit_test, ..
|
||||||
|
}) if !result.is_success() => {
|
||||||
|
if let Some(ref assertion) = unit_test.assertion {
|
||||||
|
test = format!(
|
||||||
|
"{test}\n{}{new_line}",
|
||||||
|
assertion.to_string(Stderr, unit_test.can_error),
|
||||||
|
new_line = if result.logs().is_empty() { "\n" } else { "" },
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
_ => (),
|
||||||
|
}
|
||||||
|
|
||||||
// CounterExample
|
// CounterExample
|
||||||
if let TestResult::PropertyTestResult(PropertyTestResult {
|
if let TestResult::PropertyTestResult(PropertyTestResult {
|
||||||
counterexample: Some(counterexample),
|
counterexample: Some(counterexample),
|
||||||
|
@ -334,7 +346,7 @@ fn fmt_test(
|
||||||
let is_expected_failure = result.is_success();
|
let is_expected_failure = result.is_success();
|
||||||
|
|
||||||
test = format!(
|
test = format!(
|
||||||
"{test}\n{}\n{}\n",
|
"{test}\n{}\n{}{new_line}",
|
||||||
if is_expected_failure {
|
if is_expected_failure {
|
||||||
"★ counterexample"
|
"★ counterexample"
|
||||||
.if_supports_color(Stderr, |s| s.green())
|
.if_supports_color(Stderr, |s| s.green())
|
||||||
|
@ -362,31 +374,20 @@ fn fmt_test(
|
||||||
)
|
)
|
||||||
})
|
})
|
||||||
.collect::<Vec<String>>()
|
.collect::<Vec<String>>()
|
||||||
.join("\n")
|
.join("\n"),
|
||||||
|
new_line = if result.logs().is_empty() { "\n" } else { "" },
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Traces
|
// Traces
|
||||||
if !result.logs().is_empty() {
|
if !result.logs().is_empty() {
|
||||||
test = format!(
|
test = format!(
|
||||||
"{test}\n{logs}",
|
"{test}\n{title}\n{logs}\n",
|
||||||
|
title = "· with traces".if_supports_color(Stderr, |s| s.bold()),
|
||||||
logs = result
|
logs = result
|
||||||
.logs()
|
.logs()
|
||||||
.iter()
|
.iter()
|
||||||
.map(|line| {
|
.map(|line| { format!("| {line}",) })
|
||||||
format!(
|
|
||||||
"{arrow} {styled_line}",
|
|
||||||
arrow = "↳".if_supports_color(Stderr, |s| s.bright_yellow()),
|
|
||||||
styled_line = line
|
|
||||||
.split('\n')
|
|
||||||
.map(|l| format!(
|
|
||||||
"{}",
|
|
||||||
l.if_supports_color(Stderr, |s| s.bright_black())
|
|
||||||
))
|
|
||||||
.collect::<Vec<_>>()
|
|
||||||
.join("\n")
|
|
||||||
)
|
|
||||||
})
|
|
||||||
.collect::<Vec<_>>()
|
.collect::<Vec<_>>()
|
||||||
.join("\n")
|
.join("\n")
|
||||||
);
|
);
|
||||||
|
|
|
@ -1,23 +1,21 @@
|
||||||
use crate::pretty;
|
|
||||||
use aiken_lang::{
|
use aiken_lang::{
|
||||||
ast::{Arg, BinOp, DataTypeKey, TypedDataType, TypedTest},
|
ast::{Arg, BinOp, DataTypeKey, IfBranch, Span, TypedDataType, TypedTest},
|
||||||
expr::UntypedExpr,
|
builtins::bool,
|
||||||
|
expr::{TypedExpr, UntypedExpr},
|
||||||
|
format::Formatter,
|
||||||
gen_uplc::{builder::convert_opaque_type, CodeGenerator},
|
gen_uplc::{builder::convert_opaque_type, CodeGenerator},
|
||||||
tipo::Type,
|
tipo::Type,
|
||||||
};
|
};
|
||||||
use cryptoxide::{blake2b::Blake2b, digest::Digest};
|
use cryptoxide::{blake2b::Blake2b, digest::Digest};
|
||||||
use indexmap::IndexMap;
|
use indexmap::IndexMap;
|
||||||
|
use owo_colors::{OwoColorize, Stream};
|
||||||
use pallas::ledger::primitives::alonzo::{Constr, PlutusData};
|
use pallas::ledger::primitives::alonzo::{Constr, PlutusData};
|
||||||
use std::{
|
use std::{borrow::Borrow, convert::TryFrom, path::PathBuf, rc::Rc};
|
||||||
borrow::Borrow,
|
|
||||||
fmt::{self, Display},
|
|
||||||
path::PathBuf,
|
|
||||||
rc::Rc,
|
|
||||||
};
|
|
||||||
use uplc::{
|
use uplc::{
|
||||||
ast::{Constant, Data, Name, NamedDeBruijn, Program, Term},
|
ast::{Constant, Data, Name, NamedDeBruijn, Program, Term},
|
||||||
machine::{cost_model::ExBudget, eval_result::EvalResult},
|
machine::{cost_model::ExBudget, eval_result::EvalResult},
|
||||||
};
|
};
|
||||||
|
use vec1::{vec1, Vec1};
|
||||||
|
|
||||||
/// ----- Test -----------------------------------------------------------------
|
/// ----- Test -----------------------------------------------------------------
|
||||||
///
|
///
|
||||||
|
@ -46,20 +44,50 @@ unsafe impl Send for Test {}
|
||||||
|
|
||||||
impl Test {
|
impl Test {
|
||||||
pub fn unit_test(
|
pub fn unit_test(
|
||||||
|
generator: &mut CodeGenerator<'_>,
|
||||||
|
test: TypedTest,
|
||||||
|
module_name: String,
|
||||||
input_path: PathBuf,
|
input_path: PathBuf,
|
||||||
module: String,
|
|
||||||
name: String,
|
|
||||||
can_error: bool,
|
|
||||||
program: Program<NamedDeBruijn>,
|
|
||||||
assertion: Option<Assertion>,
|
|
||||||
) -> Test {
|
) -> Test {
|
||||||
|
let data_types = generator.data_types().clone();
|
||||||
|
|
||||||
|
let program = generator.generate_raw(&test.body, &[], &module_name);
|
||||||
|
|
||||||
|
let assertion = match test.body.try_into() {
|
||||||
|
Err(..) => None,
|
||||||
|
Ok(Assertion { bin_op, head, tail }) => {
|
||||||
|
let as_constant = |generator: &mut CodeGenerator<'_>, side| {
|
||||||
|
Program::<NamedDeBruijn>::try_from(generator.generate_raw(
|
||||||
|
&side,
|
||||||
|
&[],
|
||||||
|
&module_name,
|
||||||
|
))
|
||||||
|
.expect("failed to convert assertion operaand to NamedDeBruijn")
|
||||||
|
.eval(ExBudget::max())
|
||||||
|
.unwrap_constant()
|
||||||
|
.map(|cst| {
|
||||||
|
UntypedExpr::reify_constant(&data_types, cst, &side.tipo())
|
||||||
|
.expect("failed to reify assertion operand?")
|
||||||
|
})
|
||||||
|
};
|
||||||
|
|
||||||
|
Some(Assertion {
|
||||||
|
bin_op,
|
||||||
|
head: as_constant(generator, head.expect("cannot be Err at this point")),
|
||||||
|
tail: tail
|
||||||
|
.expect("cannot be Err at this point")
|
||||||
|
.try_mapped(|e| as_constant(generator, e)),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
Test::UnitTest(UnitTest {
|
Test::UnitTest(UnitTest {
|
||||||
input_path,
|
input_path,
|
||||||
module,
|
module: module_name,
|
||||||
name,
|
name: test.name,
|
||||||
program,
|
program,
|
||||||
can_error,
|
|
||||||
assertion,
|
assertion,
|
||||||
|
can_error: test.can_error,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -88,39 +116,7 @@ impl Test {
|
||||||
input_path: PathBuf,
|
input_path: PathBuf,
|
||||||
) -> Test {
|
) -> Test {
|
||||||
if test.arguments.is_empty() {
|
if test.arguments.is_empty() {
|
||||||
let program = generator.generate_raw(&test.body, &[], &module_name);
|
Self::unit_test(generator, test, module_name, input_path)
|
||||||
|
|
||||||
// TODO: Check whether we really need to clone the _entire_ generator, or whether we
|
|
||||||
// can mostly copy the generator and only clone parts that matters.
|
|
||||||
let assertion = test.test_hint().map(|(bin_op, left_src, right_src)| {
|
|
||||||
let left = generator
|
|
||||||
.clone()
|
|
||||||
.generate_raw(&left_src, &[], &module_name)
|
|
||||||
.try_into()
|
|
||||||
.unwrap();
|
|
||||||
|
|
||||||
let right = generator
|
|
||||||
.clone()
|
|
||||||
.generate_raw(&right_src, &[], &module_name)
|
|
||||||
.try_into()
|
|
||||||
.unwrap();
|
|
||||||
|
|
||||||
Assertion {
|
|
||||||
bin_op,
|
|
||||||
left,
|
|
||||||
right,
|
|
||||||
can_error: test.can_error,
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
Self::unit_test(
|
|
||||||
input_path,
|
|
||||||
module_name,
|
|
||||||
test.name,
|
|
||||||
test.can_error,
|
|
||||||
program.try_into().unwrap(),
|
|
||||||
assertion,
|
|
||||||
)
|
|
||||||
} else {
|
} else {
|
||||||
let parameter = test.arguments.first().unwrap().to_owned();
|
let parameter = test.arguments.first().unwrap().to_owned();
|
||||||
|
|
||||||
|
@ -168,18 +164,23 @@ pub struct UnitTest {
|
||||||
pub module: String,
|
pub module: String,
|
||||||
pub name: String,
|
pub name: String,
|
||||||
pub can_error: bool,
|
pub can_error: bool,
|
||||||
pub program: Program<NamedDeBruijn>,
|
pub program: Program<Name>,
|
||||||
pub assertion: Option<Assertion>,
|
pub assertion: Option<Assertion<UntypedExpr>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
unsafe impl Send for UnitTest {}
|
unsafe impl Send for UnitTest {}
|
||||||
|
|
||||||
impl UnitTest {
|
impl UnitTest {
|
||||||
pub fn run<T>(self) -> TestResult<T> {
|
pub fn run<T>(self) -> TestResult<T> {
|
||||||
let mut eval_result = self.program.clone().eval(ExBudget::max());
|
let mut eval_result = Program::<NamedDeBruijn>::try_from(self.program.clone())
|
||||||
|
.unwrap()
|
||||||
|
.eval(ExBudget::max());
|
||||||
|
|
||||||
|
let success = !eval_result.failed(self.can_error);
|
||||||
|
|
||||||
TestResult::UnitTestResult(UnitTestResult {
|
TestResult::UnitTestResult(UnitTestResult {
|
||||||
|
success,
|
||||||
test: self.to_owned(),
|
test: self.to_owned(),
|
||||||
success: !eval_result.failed(self.can_error),
|
|
||||||
spent_budget: eval_result.cost(),
|
spent_budget: eval_result.cost(),
|
||||||
logs: eval_result.logs(),
|
logs: eval_result.logs(),
|
||||||
output: eval_result.result().ok(),
|
output: eval_result.result().ok(),
|
||||||
|
@ -399,8 +400,10 @@ impl Prng {
|
||||||
fn as_prng(cst: &PlutusData) -> Prng {
|
fn as_prng(cst: &PlutusData) -> Prng {
|
||||||
if let PlutusData::Constr(Constr { tag, fields, .. }) = cst {
|
if let PlutusData::Constr(Constr { tag, fields, .. }) = cst {
|
||||||
if *tag == 121 + Prng::SEEDED {
|
if *tag == 121 + Prng::SEEDED {
|
||||||
if let [PlutusData::BoundedBytes(bytes), PlutusData::BoundedBytes(choices)] =
|
if let [
|
||||||
&fields[..]
|
PlutusData::BoundedBytes(bytes),
|
||||||
|
PlutusData::BoundedBytes(choices),
|
||||||
|
] = &fields[..]
|
||||||
{
|
{
|
||||||
return Prng::Seeded {
|
return Prng::Seeded {
|
||||||
choices: choices.to_vec(),
|
choices: choices.to_vec(),
|
||||||
|
@ -741,24 +744,21 @@ impl<T> TestResult<T> {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn into_error(&self, verbose: bool) -> crate::Error {
|
pub fn into_error(&self, verbose: bool) -> crate::Error {
|
||||||
let (name, path, assertion, src) = match self {
|
let (name, path, src) = match self {
|
||||||
TestResult::UnitTestResult(UnitTestResult { test, .. }) => (
|
TestResult::UnitTestResult(UnitTestResult { test, .. }) => (
|
||||||
test.name.to_string(),
|
test.name.to_string(),
|
||||||
test.input_path.to_path_buf(),
|
test.input_path.to_path_buf(),
|
||||||
test.assertion.as_ref().map(|hint| hint.to_string()),
|
|
||||||
test.program.to_pretty(),
|
test.program.to_pretty(),
|
||||||
),
|
),
|
||||||
TestResult::PropertyTestResult(PropertyTestResult { test, .. }) => (
|
TestResult::PropertyTestResult(PropertyTestResult { test, .. }) => (
|
||||||
test.name.to_string(),
|
test.name.to_string(),
|
||||||
test.input_path.to_path_buf(),
|
test.input_path.to_path_buf(),
|
||||||
None,
|
|
||||||
test.program.to_pretty(),
|
test.program.to_pretty(),
|
||||||
),
|
),
|
||||||
};
|
};
|
||||||
crate::Error::TestFailure {
|
crate::Error::TestFailure {
|
||||||
name,
|
name,
|
||||||
path,
|
path,
|
||||||
assertion,
|
|
||||||
src,
|
src,
|
||||||
verbose,
|
verbose,
|
||||||
}
|
}
|
||||||
|
@ -809,74 +809,233 @@ impl PropertyTestResult<PlutusData> {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
pub struct Assertion {
|
pub struct Assertion<T> {
|
||||||
pub bin_op: BinOp,
|
pub bin_op: BinOp,
|
||||||
pub left: Program<NamedDeBruijn>,
|
pub head: Result<T, ()>,
|
||||||
pub right: Program<NamedDeBruijn>,
|
pub tail: Result<Vec1<T>, ()>,
|
||||||
pub can_error: bool,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Display for Assertion {
|
impl TryFrom<TypedExpr> for Assertion<TypedExpr> {
|
||||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
type Error = ();
|
||||||
let unlimited_budget = ExBudget {
|
|
||||||
mem: i64::MAX,
|
fn try_from(body: TypedExpr) -> Result<Self, Self::Error> {
|
||||||
cpu: i64::MAX,
|
match body {
|
||||||
|
TypedExpr::BinOp {
|
||||||
|
name,
|
||||||
|
tipo,
|
||||||
|
left,
|
||||||
|
right,
|
||||||
|
..
|
||||||
|
} if tipo == bool() => {
|
||||||
|
// 'and' and 'or' are left-associative operators.
|
||||||
|
match (*right).clone().try_into() {
|
||||||
|
Ok(Assertion {
|
||||||
|
bin_op,
|
||||||
|
head: Ok(head),
|
||||||
|
tail: Ok(tail),
|
||||||
|
..
|
||||||
|
}) if bin_op == name => {
|
||||||
|
let mut both = vec1![head];
|
||||||
|
both.extend(tail);
|
||||||
|
Ok(Assertion {
|
||||||
|
bin_op: name,
|
||||||
|
head: Ok(*left),
|
||||||
|
tail: Ok(both),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
_ => Ok(Assertion {
|
||||||
|
bin_op: name,
|
||||||
|
head: Ok(*left),
|
||||||
|
tail: Ok(vec1![*right]),
|
||||||
|
}),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// NOTE drill through trace-if-false operators for better errors.
|
||||||
|
TypedExpr::If {
|
||||||
|
branches,
|
||||||
|
final_else,
|
||||||
|
..
|
||||||
|
} => {
|
||||||
|
if let [
|
||||||
|
IfBranch {
|
||||||
|
condition, body, ..
|
||||||
|
},
|
||||||
|
] = &branches[..]
|
||||||
|
{
|
||||||
|
let then_is_true = match body {
|
||||||
|
TypedExpr::Var {
|
||||||
|
name, constructor, ..
|
||||||
|
} => name == "True" && constructor.tipo == bool(),
|
||||||
|
_ => false,
|
||||||
|
};
|
||||||
|
|
||||||
|
let else_is_wrapped_false = match *final_else {
|
||||||
|
TypedExpr::Trace { then, .. } => match *then {
|
||||||
|
TypedExpr::Var {
|
||||||
|
name, constructor, ..
|
||||||
|
} => name == "False" && constructor.tipo == bool(),
|
||||||
|
_ => false,
|
||||||
|
},
|
||||||
|
_ => false,
|
||||||
|
};
|
||||||
|
|
||||||
|
if then_is_true && else_is_wrapped_false {
|
||||||
|
return condition.to_owned().try_into();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Err(())
|
||||||
|
}
|
||||||
|
|
||||||
|
TypedExpr::Trace { then, .. } => (*then).try_into(),
|
||||||
|
|
||||||
|
TypedExpr::Sequence { expressions, .. } | TypedExpr::Pipeline { expressions, .. } => {
|
||||||
|
if let Ok(Assertion {
|
||||||
|
bin_op,
|
||||||
|
head: Ok(head),
|
||||||
|
tail: Ok(tail),
|
||||||
|
}) = expressions.last().unwrap().to_owned().try_into()
|
||||||
|
{
|
||||||
|
let replace = |expr| {
|
||||||
|
let mut expressions = expressions.clone();
|
||||||
|
expressions.pop();
|
||||||
|
expressions.push(expr);
|
||||||
|
TypedExpr::Sequence {
|
||||||
|
expressions,
|
||||||
|
location: Span::empty(),
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
Ok(Assertion {
|
||||||
|
bin_op,
|
||||||
|
head: Ok(replace(head)),
|
||||||
|
tail: Ok(tail.mapped(replace)),
|
||||||
|
})
|
||||||
|
} else {
|
||||||
|
Err(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
_ => Err(()),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Assertion<UntypedExpr> {
|
||||||
|
#[allow(clippy::just_underscores_and_digits)]
|
||||||
|
pub fn to_string(&self, stream: Stream, expect_failure: bool) -> String {
|
||||||
|
let red = |s: &str| {
|
||||||
|
format!("× {s}")
|
||||||
|
.if_supports_color(stream, |s| s.red())
|
||||||
|
.if_supports_color(stream, |s| s.bold())
|
||||||
|
.to_string()
|
||||||
};
|
};
|
||||||
|
|
||||||
let left = pretty::boxed(
|
if self.head.is_err() {
|
||||||
"left",
|
return red("program failed");
|
||||||
&match self.left.clone().eval(unlimited_budget).result() {
|
|
||||||
Ok(term) => format!("{term}"),
|
|
||||||
Err(err) => format!("{err}"),
|
|
||||||
},
|
|
||||||
);
|
|
||||||
let right = pretty::boxed(
|
|
||||||
"right",
|
|
||||||
&match self.right.clone().eval(unlimited_budget).result() {
|
|
||||||
Ok(term) => format!("{term}"),
|
|
||||||
Err(err) => format!("{err}"),
|
|
||||||
},
|
|
||||||
);
|
|
||||||
let msg = if self.can_error {
|
|
||||||
match self.bin_op {
|
|
||||||
BinOp::And => Some(format!(
|
|
||||||
"{left}\n\nand\n\n{right}\n\nare both true but shouldn't."
|
|
||||||
)),
|
|
||||||
BinOp::Or => Some(format!(
|
|
||||||
"neither\n\n{left}\n\nnor\n\n{right}\n\nshould be true."
|
|
||||||
)),
|
|
||||||
BinOp::Eq => Some(format!("{left}\n\nshould not be equal to\n\n{right}")),
|
|
||||||
BinOp::NotEq => Some(format!("{left}\n\nshould be equal to\n\n{right}")),
|
|
||||||
BinOp::LtInt => Some(format!(
|
|
||||||
"{left}\n\nshould be greater than or equal to\n\n{right}"
|
|
||||||
)),
|
|
||||||
BinOp::LtEqInt => Some(format!("{left}\n\nshould be greater than\n\n{right}")),
|
|
||||||
BinOp::GtEqInt => Some(format!(
|
|
||||||
"{left}\n\nshould be lower than or equal\n\n{right}"
|
|
||||||
)),
|
|
||||||
BinOp::GtInt => Some(format!("{left}\n\nshould be lower than\n\n{right}")),
|
|
||||||
_ => None,
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
match self.bin_op {
|
|
||||||
BinOp::And => Some(format!("{left}\n\nand\n\n{right}\n\nshould both be true.")),
|
|
||||||
BinOp::Or => Some(format!("{left}\n\nor\n\n{right}\n\nshould be true.")),
|
|
||||||
BinOp::Eq => Some(format!("{left}\n\nshould be equal to\n\n{right}")),
|
|
||||||
BinOp::NotEq => Some(format!("{left}\n\nshould not be equal to\n\n{right}")),
|
|
||||||
BinOp::LtInt => Some(format!("{left}\n\nshould be lower than\n\n{right}")),
|
|
||||||
BinOp::LtEqInt => Some(format!(
|
|
||||||
"{left}\n\nshould be lower than or equal to\n\n{right}"
|
|
||||||
)),
|
|
||||||
BinOp::GtEqInt => Some(format!("{left}\n\nshould be greater than\n\n{right}")),
|
|
||||||
BinOp::GtInt => Some(format!(
|
|
||||||
"{left}\n\nshould be greater than or equal to\n\n{right}"
|
|
||||||
)),
|
|
||||||
_ => None,
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
.ok_or(fmt::Error)?;
|
|
||||||
|
|
||||||
f.write_str(&msg)
|
fn fmt_side(side: &UntypedExpr, stream: Stream) -> String {
|
||||||
|
let __ = "│".if_supports_color(stream, |s| s.red());
|
||||||
|
|
||||||
|
Formatter::new()
|
||||||
|
.expr(side, false)
|
||||||
|
.to_pretty_string(60)
|
||||||
|
.lines()
|
||||||
|
.map(|line| format!("{__} {line}"))
|
||||||
|
.collect::<Vec<String>>()
|
||||||
|
.join("\n")
|
||||||
|
}
|
||||||
|
|
||||||
|
let left = fmt_side(self.head.as_ref().unwrap(), stream);
|
||||||
|
|
||||||
|
let tail = self.tail.as_ref().unwrap();
|
||||||
|
|
||||||
|
let right = fmt_side(tail.first(), stream);
|
||||||
|
|
||||||
|
format!(
|
||||||
|
"{}{}{}",
|
||||||
|
red("expected"),
|
||||||
|
if expect_failure && self.bin_op == BinOp::Or {
|
||||||
|
" neither\n"
|
||||||
|
.if_supports_color(stream, |s| s.red())
|
||||||
|
.if_supports_color(stream, |s| s.bold())
|
||||||
|
.to_string()
|
||||||
|
} else {
|
||||||
|
"\n".to_string()
|
||||||
|
},
|
||||||
|
if expect_failure {
|
||||||
|
match self.bin_op {
|
||||||
|
BinOp::And => [
|
||||||
|
left,
|
||||||
|
red("and"),
|
||||||
|
[
|
||||||
|
tail.mapped_ref(|s| fmt_side(s, stream))
|
||||||
|
.join(format!("\n{}\n", red("and")).as_str()),
|
||||||
|
if tail.len() > 1 {
|
||||||
|
red("to not all be true")
|
||||||
|
} else {
|
||||||
|
red("to not both be true")
|
||||||
|
},
|
||||||
|
]
|
||||||
|
.join("\n"),
|
||||||
|
],
|
||||||
|
BinOp::Or => [
|
||||||
|
left,
|
||||||
|
red("nor"),
|
||||||
|
[
|
||||||
|
tail.mapped_ref(|s| fmt_side(s, stream))
|
||||||
|
.join(format!("\n{}\n", red("nor")).as_str()),
|
||||||
|
red("to be true"),
|
||||||
|
]
|
||||||
|
.join("\n"),
|
||||||
|
],
|
||||||
|
BinOp::Eq => [left, red("to not equal"), right],
|
||||||
|
BinOp::NotEq => [left, red("to not be different"), right],
|
||||||
|
BinOp::LtInt => [left, red("to not be lower than"), right],
|
||||||
|
BinOp::LtEqInt => [left, red("to not be lower than or equal to"), right],
|
||||||
|
BinOp::GtInt => [left, red("to not be greater than"), right],
|
||||||
|
BinOp::GtEqInt => [left, red("to not be greater than or equal to"), right],
|
||||||
|
_ => unreachable!("unexpected non-boolean binary operator in assertion?"),
|
||||||
|
}
|
||||||
|
.join("\n")
|
||||||
|
} else {
|
||||||
|
match self.bin_op {
|
||||||
|
BinOp::And => [
|
||||||
|
left,
|
||||||
|
red("and"),
|
||||||
|
[
|
||||||
|
tail.mapped_ref(|s| fmt_side(s, stream))
|
||||||
|
.join(format!("\n{}\n", red("and")).as_str()),
|
||||||
|
if tail.len() > 1 {
|
||||||
|
red("to all be true")
|
||||||
|
} else {
|
||||||
|
red("to both be true")
|
||||||
|
},
|
||||||
|
]
|
||||||
|
.join("\n"),
|
||||||
|
],
|
||||||
|
BinOp::Or => [
|
||||||
|
left,
|
||||||
|
red("or"),
|
||||||
|
[
|
||||||
|
tail.mapped_ref(|s| fmt_side(s, stream))
|
||||||
|
.join(format!("\n{}\n", red("or")).as_str()),
|
||||||
|
red("to be true"),
|
||||||
|
]
|
||||||
|
.join("\n"),
|
||||||
|
],
|
||||||
|
BinOp::Eq => [left, red("to equal"), right],
|
||||||
|
BinOp::NotEq => [left, red("to not equal"), right],
|
||||||
|
BinOp::LtInt => [left, red("to be lower than"), right],
|
||||||
|
BinOp::LtEqInt => [left, red("to be lower than or equal to"), right],
|
||||||
|
BinOp::GtInt => [left, red("to be greater than"), right],
|
||||||
|
BinOp::GtEqInt => [left, red("to be greater than or equal to"), right],
|
||||||
|
_ => unreachable!("unexpected non-boolean binary operator in assertion?"),
|
||||||
|
}
|
||||||
|
.join("\n")
|
||||||
|
}
|
||||||
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
use crate::{telemetry::Terminal, Error, Project};
|
use crate::{telemetry::Terminal, Project};
|
||||||
use miette::{Diagnostic, IntoDiagnostic};
|
use miette::{Diagnostic, IntoDiagnostic};
|
||||||
use notify::{Event, RecursiveMode, Watcher};
|
use notify::{Event, RecursiveMode, Watcher};
|
||||||
use owo_colors::{OwoColorize, Stream::Stderr};
|
use owo_colors::{OwoColorize, Stream::Stderr};
|
||||||
|
@ -108,15 +108,13 @@ where
|
||||||
err.report()
|
err.report()
|
||||||
}
|
}
|
||||||
|
|
||||||
if !errs.iter().any(|e| matches!(e, Error::TestFailure { .. })) {
|
eprintln!(
|
||||||
eprintln!(
|
"{}",
|
||||||
"{}",
|
Summary {
|
||||||
Summary {
|
warning_count,
|
||||||
warning_count,
|
error_count: errs.len(),
|
||||||
error_count: errs.len(),
|
}
|
||||||
}
|
);
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
return Err(ExitFailure::into_report());
|
return Err(ExitFailure::into_report());
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,6 +1,5 @@
|
||||||
use crate::ast::{Constant, NamedDeBruijn, Term};
|
|
||||||
|
|
||||||
use super::{cost_model::ExBudget, Error};
|
use super::{cost_model::ExBudget, Error};
|
||||||
|
use crate::ast::{Constant, NamedDeBruijn, Term};
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct EvalResult {
|
pub struct EvalResult {
|
||||||
|
@ -44,6 +43,14 @@ impl EvalResult {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[allow(clippy::result_unit_err)]
|
||||||
|
pub fn unwrap_constant(self) -> Result<Constant, ()> {
|
||||||
|
match self.result {
|
||||||
|
Ok(Term::Constant(cst)) => Ok(cst.as_ref().to_owned()),
|
||||||
|
_ => Err(()),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub fn result(&self) -> Result<Term<NamedDeBruijn>, Error> {
|
pub fn result(&self) -> Result<Term<NamedDeBruijn>, Error> {
|
||||||
self.result.clone()
|
self.result.clone()
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue