Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

chore: add assert to the stdlib #1914

Merged
merged 1 commit into from
May 24, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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
38 changes: 38 additions & 0 deletions core/stdlib/std.ncl
Original file line number Diff line number Diff line change
Expand Up @@ -3064,6 +3064,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 label value => if value then true else %blame% label,

assert_all
| Array Assert -> Bool
| 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
```
"%
# We mostly rely on the contracts to do the work here. We just need to
# make sure each element of the array is properly forced.
= std.array.all (fun x => x),
},

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
4 changes: 2 additions & 2 deletions core/tests/integration/inputs/merging/overriding.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 | default = 1} & {foo = 2} == {foo = 2},
Expand Down Expand Up @@ -72,4 +72,4 @@ let {check, ..} = import "../lib/assert.ncl" in
({foo | default = 1, bar = foo} & {foo = 2}).bar == 2,
({foo | default = 1, bar = foo, baz = bar} & {foo = 2}).baz == 2,
]
|> check
|> std.test.assert_all
4 changes: 2 additions & 2 deletions core/tests/integration/inputs/merging/priorities.ncl
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
# test.type = 'pass'
let {Assert, check, ..} = import "../lib/assert.ncl" in
let Assert = std.test.Assert in

[
let block1 = {
Expand Down Expand Up @@ -83,4 +83,4 @@ let {Assert, check, ..} = import "../lib/assert.ncl" in
# } in
# {val | rec force = x } & {val = {foo = 0, bar = 10}}
# == {val = {bar = 10, foo = 1 + 2 + 10}} | Assert,
] |> check
] |> std.test.assert_all
Loading
Loading