Skip to content

Commit

Permalink
move Assert and check to the stdlib
Browse files Browse the repository at this point in the history
Move the Assert and check function from the local test library to the
stdlib, under the name of `std.test.Assert` and `std.test.assert_all`.

Co-authored-by: Yann Hamdaoui <yann.hamdaoui@gmail.com>
  • Loading branch information
ajbt200128 and yannham committed May 20, 2024
1 parent ed815b1 commit f700849
Show file tree
Hide file tree
Showing 51 changed files with 181 additions and 157 deletions.
15 changes: 7 additions & 8 deletions HACKING.md
Original file line number Diff line number Diff line change
Expand Up @@ -147,14 +147,13 @@ directory. All `.ncl` files in this directory are automatically converted into
Rust integration tests, which run the file and assert that no errors were
raised during evaluation.

Each of these `.ncl` files is structured as an array of `Bool` expressions, which
is ultimately passed to a `check` function defined in
`core/tests/integration/pass/lib/assert.ncl`.
This function applies an `Assert` contract to each value in the array, which
checks that the value it is applied to evaluates to `true`. The benefit of using
a contract for this is that if a test fails we can simply run the file directly
using Nickel, which gives better error messages than the ones we get by default
from `cargo test`.
Each of these `.ncl` files is structured as an array of `Bool` expressions,
which is ultimately passed to `std.contract.check` function defined in the
standard library. This function applies an `Assert` (`std.test.Assert`)
contract to each value in the array, which checks that the value it is applied
to evaluates to `true`. The benefit of using a contract for this is that if a
test fails we can simply run the file directly using Nickel, which gives better
error messages than the ones we get by default from `cargo test`.

Tests which are expected to fail may be written in Rust in `core/tests/integration`.
However, simple failure test cases can make use of the test annotation support
Expand Down
60 changes: 60 additions & 0 deletions core/stdlib/std.ncl
Original file line number Diff line number Diff line change
Expand Up @@ -792,6 +792,28 @@
},

contract = {
Assert
| doc m%"
A contract that checks if its argument is the boolean true.

We could get by just using arrays of boolean tests and `std.array.all`.

However, this contract provides fine-grained error reporting,
pinpointoing the exact expression that failed in an array of tests, as
opposed to the pure boolean solution.

# Examples

```nickel
1 == 2 | std.test.Assert
=> error: contract broken by a value

1 == 1 | std.test.Assert
=> true
```
"%
= fun l x => if x then true else %blame% l,

Equal
| doc m%"
`Equal` is a contract enforcing equality to a given constant.
Expand Down Expand Up @@ -3064,6 +3086,44 @@
= fun s => %enum_from_str% s,
},

test = {
Assert
| doc m%"
A contract that checks if its argument is the boolean true.

# Examples

```nickel
1 == 2 | std.test.Assert
=> error: contract broken by a value

1 == 1 | std.test.Assert
=> true
```
"%
= fun l x => if x then true else %blame% l,

# We statically type `assert_all` because (x | Assert) is not of type bool.
# We could use additional contracts to make it work but it's not worth the
# hassle, given the size of the function.
assert_all
| doc m%"
Asserts that all the elements of an array are equal to true. Applies the
`std.test.Assert` contract on each element of the given array.

Evalutes to `true` if all the elements of the array are equal to true,
or fails with a contract error otherwise.

# Example

```nickel
[ (1 == 2), (1 == 1), (1 == 3) ] |> std.test.assert_all
=> error: contract broken by a value
```
"%
= std.array.fold_left (fun acc test => (test | Assert) && acc) true,
},

is_number
: Dyn -> Bool
| doc m%"
Expand Down
4 changes: 2 additions & 2 deletions core/tests/integration/inputs/adts/enum_primops.ncl
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
# test.type = 'pass'
let {check, ..} = import "../lib/assert.ncl" in


[
%enum_unwrap_variant% ('Left (1+1)) == 2,
Expand All @@ -8,4 +8,4 @@ let {check, ..} = import "../lib/assert.ncl" in
%enum_get_tag% 'Right == 'Right,
%enum_get_tag% ('Right "stuff") == 'Right,
]
|> check
|> std.test.assert_all
4 changes: 2 additions & 2 deletions core/tests/integration/inputs/contracts/contracts.ncl
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
# test.type = 'pass'
let {check, Assert, ..} = import "../lib/assert.ncl" in
let Assert = std.test.Assert in

[
let AlwaysTrue = fun l t =>
Expand Down Expand Up @@ -179,4 +179,4 @@ let {check, Assert, ..} = import "../lib/assert.ncl" in
in
tag == 'some_tag,
]
|> check
|> std.test.assert_all
4 changes: 2 additions & 2 deletions core/tests/integration/inputs/contracts/let_order.ncl
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
# test.type = 'pass'
let { check, Assert, .. } = import "../lib/assert.ncl" in

let ConstantTrue = fun _label value => std.seq value true in
[
let foo | ConstantTrue | Bool = "not a bool" in
Expand All @@ -12,4 +12,4 @@ let ConstantTrue = fun _label value => std.seq value true in
= "still not a bool"
}.foo
]
|> check
|> std.test.assert_all
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
# test.type = 'pass'
let {check, ..} = import "../lib/assert.ncl" in


[
# check that a record type literal is indeed converted to the corresponding
Expand All @@ -21,4 +21,4 @@ let {check, ..} = import "../lib/assert.ncl" in
& {foo | force = false, bar | force = true})
== {foo = false, bar = true},
]
|> check
|> std.test.assert_all
4 changes: 2 additions & 2 deletions core/tests/integration/inputs/core/arrays.ncl
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
# test.type = 'pass'
let {check, ..} = import "../lib/assert.ncl" in


[
# accesses
Expand Down Expand Up @@ -49,4 +49,4 @@ let {check, ..} = import "../lib/assert.ncl" in

std.array.map_with_index (+) [1, 2, 3] == [1, 3, 5],
]
|> check
|> std.test.assert_all
4 changes: 2 additions & 2 deletions core/tests/integration/inputs/core/basics.ncl
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
# test.type = 'pass'
let {check, ..} = import "../lib/assert.ncl" in


[
# basic arithmetic
Expand Down Expand Up @@ -35,4 +35,4 @@ let {check, ..} = import "../lib/assert.ncl" in
# This test checks that the terms of a match are closured
let x = 3 in ((3 + 2) |> match { 'foo => 1, _ => x}) == 3,
]
|> check
|> std.test.assert_all
4 changes: 2 additions & 2 deletions core/tests/integration/inputs/core/builtins.ncl
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
# test.type = 'pass'
let {check, ..} = import "../lib/assert.ncl" in


[
# is_record
Expand Down Expand Up @@ -28,4 +28,4 @@ let {check, ..} = import "../lib/assert.ncl" in
|> std.deserialize 'Json
== [3,4],
]
|> check
|> std.test.assert_all
4 changes: 2 additions & 2 deletions core/tests/integration/inputs/core/curried_dot.ncl
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
# test.type = 'pass'
let {check, ..} = import "../lib/assert.ncl" in


let record = {foo = 1, bar = { baz = 2 }} in
let field = "bar" in
Expand All @@ -9,4 +9,4 @@ let part = "ba" in
(.) record field == { baz = 2 },
let res = (.) record field == {baz = 2} in res,
(.) record "%{part}r" == { baz = 2 },
] |> check
] |> std.test.assert_all
4 changes: 2 additions & 2 deletions core/tests/integration/inputs/core/eq.ncl
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
# test.type = 'pass'
let {check, ..} = import "../lib/assert.ncl" in


[
# basic
Expand Down Expand Up @@ -84,4 +84,4 @@ let {check, ..} = import "../lib/assert.ncl" in
'Left 2 != 'Right 2,
'Up [1,2,3] == 'Up [0+1,1+1,2+1],
]
|> check
|> std.test.assert_all
2 changes: 1 addition & 1 deletion core/tests/integration/inputs/core/fibo.ncl
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
# test.type = 'pass'
let {Assert, ..} = import "../lib/assert.ncl" in
let Assert = std.test.Assert in

let Y | ((Number -> Number) -> Number -> Number) -> Number -> Number = fun f => (fun x => f (x x)) (fun x => f (x x)) in
let dec : Number -> Number = fun x => x + (-1) in
Expand Down
4 changes: 2 additions & 2 deletions core/tests/integration/inputs/core/functions.ncl
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
# test.type = 'pass'
let {check, ..} = import "../lib/assert.ncl" in


[
(fun x => x) 3 == 3,
Expand All @@ -16,4 +16,4 @@ let {check, ..} = import "../lib/assert.ncl" in
g true
== 4,
]
|> check
|> std.test.assert_all
2 changes: 1 addition & 1 deletion core/tests/integration/inputs/core/import.ncl
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
# test.type = 'pass'
let { Assert, .. } = import "../lib/assert.ncl" in
let Assert = std.test.Assert in
((import "../lib/imported.ncl") 3 == 3 | Assert)
4 changes: 2 additions & 2 deletions core/tests/integration/inputs/core/numbers.ncl
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
# test.type = 'pass'
let {check, ..} = import "../lib/assert.ncl" in


[
5 + 5 == 10,
5 * 5 == 25,
1e6 == 1000000,
1e+3 / 2e-3 == 0.5e6,
]
|> check
|> std.test.assert_all
4 changes: 2 additions & 2 deletions core/tests/integration/inputs/core/records.ncl
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
# test.type = 'pass'
let { check, .. } = import "../lib/assert.ncl" in


[
# accesses
Expand Down Expand Up @@ -171,4 +171,4 @@ let { check, .. } = import "../lib/assert.ncl" in
&& r.force == "no"
)
]
|> check
|> std.test.assert_all
4 changes: 2 additions & 2 deletions core/tests/integration/inputs/core/recursive_let.ncl
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
# test.type = 'pass'
let {check, ..} = import "../lib/assert.ncl" in


[
let rec f = fun n => if n == 0 then n else f (n - 1) in f 10 == 0,
let rec fib = fun n => if n == 0 || n == 1 then 1 else fib (n - 1) + fib (n - 2) in fib 5 == 8,
]
|> check
|> std.test.assert_all
4 changes: 2 additions & 2 deletions core/tests/integration/inputs/imports/yaml_import.ncl
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# test.type = 'pass'

let {check, ..} = import "../lib/assert.ncl" in

[
(import "imported/empty.yaml") == null,

Expand All @@ -9,4 +9,4 @@ let {check, ..} = import "../lib/assert.ncl" in
{ type = "event", id = 2 }
],
]
|> check
|> std.test.assert_all
31 changes: 0 additions & 31 deletions core/tests/integration/inputs/lib/assert.ncl

This file was deleted.

4 changes: 2 additions & 2 deletions core/tests/integration/inputs/merging/adts.ncl
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
# test.type = 'pass'
let { check, .. } = import "../lib/assert.ncl" in


[
'Foo true & 'Foo true == 'Foo true,
Expand All @@ -13,4 +13,4 @@ let { check, .. } = import "../lib/assert.ncl" in
& { two.b = 1, one = 'Qux {c = 0} }
== { one = 'Qux { a = 1, b = 1, c = 0 }, two = { a = 1, b = 1 } },
]
|> check
|> std.test.assert_all
4 changes: 2 additions & 2 deletions core/tests/integration/inputs/merging/array-merge.ncl
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
# test.type = 'pass'
let {check, ..} = import "../lib/assert.ncl" in


[
# array pointwise merging
Expand All @@ -25,4 +25,4 @@ let {check, ..} = import "../lib/assert.ncl" in
& ([0 + 0, 1 + 0, 2 + 0] | Array AddOne)
== [1, 2, 3],
]
|> check
|> std.test.assert_all
4 changes: 2 additions & 2 deletions core/tests/integration/inputs/merging/lazy-propagation.ncl
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
# test.type = 'pass'
let {check, Assert, ..} = import "../lib/assert.ncl" in


# tests related to RFC005. Check in particular that the motivating examples of
# RFC005 are indeed fixed by lazy propagation.
Expand Down Expand Up @@ -44,4 +44,4 @@ let {check, Assert, ..} = import "../lib/assert.ncl" in
& {bar = "bar"})
== {foo = 5, bar = "bar"},
]
|> check
|> std.test.assert_all
4 changes: 2 additions & 2 deletions core/tests/integration/inputs/merging/metavalues.ncl
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
# test.type = 'pass'
let {check, Assert, ..} = import "../lib/assert.ncl" in
let Assert = std.test.Assert in

[
{val | default | Number = 10}.val == 10,
Expand Down Expand Up @@ -132,4 +132,4 @@ let {check, Assert, ..} = import "../lib/assert.ncl" in
(%fields% value == ["foo", "opt"] | Assert)
),
]
|> check
|> std.test.assert_all
6 changes: 3 additions & 3 deletions core/tests/integration/inputs/merging/multiple_overrides.ncl
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
# test.type = 'pass'
let {check, ..} = import "../lib/assert.ncl" in


[
# regression test for issue #908 (https://github.com/tweag/nickel/issues/908)
Expand Down Expand Up @@ -121,6 +121,6 @@ let {check, ..} = import "../lib/assert.ncl" in
fst_data = "override",
snd_data = "override",
}
] |> check,
] |> std.test.assert_all,
]
|> check
|> std.test.assert_all
Loading

0 comments on commit f700849

Please sign in to comment.