refactor(nix/runTestsuite): implement in terms of generic assertBool

Refactor assertEq and assertThrows to be implemented in terms of a more
generic assertBool to reduce code duplication and ease adding new assert
types.

To preserve meaningful error messages AssertResult is changed slightly:
nope-eq and nope-throw have been replaced by a single nope branch which
contains an AssertErrorContext which contains error information. To
implement an assert assertBoolContext (which is not exposed) can be
used: It takes an AssertErrorContext which is returned in case of an
error and a boolean determining whether the assert was successful.

The currently possible AssertErrorContext are:

* should-throw: error result of assertThrows, formerly nope-throw
* not-equal: error result of assertEq, formerly nope-eq

Change-Id: Ifd6b3aa4187c90c3add2df63fa7c906c8f03fd2d
Reviewed-on: https://cl.tvl.fyi/c/depot/+/2473
Tested-by: BuildkiteCI
Reviewed-by: Profpatsch <mail@profpatsch.de>
This commit is contained in:
sterni 2021-01-31 13:41:32 +01:00
parent 03f1fefc72
commit 00f79da358

View file

@ -34,10 +34,15 @@ let
defun
list
drv
bool
;
bins = depot.nix.getBins pkgs.coreutils [ "printf" "touch" ];
# Returns true if the given expression throws when `deepSeq`-ed
throws = expr:
!(builtins.tryEval (builtins.deepSeq expr {})).success;
# rewrite the builtins.partition result
# to use `ok` and `err` instead of `right` and `wrong`.
partitionTests = pred: xs:
@ -47,23 +52,30 @@ let
err = res.wrong;
};
AssertErrorContext =
sum "AssertErrorContext" {
not-equal = struct "not-equal" {
left = any;
right = any;
};
should-throw = struct "should-throw" {
expr = any;
};
};
# The result of an assert,
# either its true (yep) or false (nope).
# If its nope, we return the left and right
# side of the assert, together with the description.
# If it's nope we return an additional context
# attribute which gives details on the failure
# depending on the type of assert performed.
AssertResult =
sum "AssertResult" {
yep = struct "yep" {
test = string;
};
nope-eq = struct "nope-eq" {
nope = struct "nope" {
test = string;
left = any;
right = any;
};
nope-throw = struct "nope-throw" {
test = string;
expr = any;
context = AssertErrorContext;
};
};
@ -75,27 +87,37 @@ let
asserts = list AssertResult;
};
# If the given boolean is true return a positive AssertResult.
# If the given boolean is false return a negative AssertResult
# with the provided AssertErrorContext describing the failure.
#
# This function is intended as a generic assert to implement
# more assert types and is not exposed to the user.
assertBoolContext = defun [ AssertErrorContext string bool AssertResult ]
(context: desc: res:
if res
then { yep = { test = desc; }; }
else { nope = {
test = desc;
inherit context;
};
});
# assert that left and right values are equal
assertEq = defun [ string any any AssertResult ]
(desc: left: right:
if left == right
then { yep = { test = desc; }; }
else { nope-eq = {
test = desc;
inherit left right;
};
});
let
context = { not-equal = { inherit left right; }; };
in
assertBoolContext context desc (left == right));
# assert that the expression throws when `deepSeq`-ed
assertThrows = defun [ string any AssertResult ]
(desc: expr:
if ! (builtins.tryEval (builtins.deepSeq expr {})).success
then { yep = { test = desc; }; }
else { nope-throw = {
test = desc;
inherit expr;
};
});
let
context = { should-throw = { inherit expr; }; };
in
assertBoolContext context desc (throws expr));
# Annotate a bunch of asserts with a descriptive name
it = desc: asserts: {
@ -114,8 +136,7 @@ let
goodAss = ass: {
good = AssertResult.match ass {
yep = _: true;
nope-eq = _: false;
nope-throw = _: false;
nope = _: false;
};
x = ass;
};
@ -124,8 +145,7 @@ let
asserts = partitionTests (ass:
AssertResult.match ass {
yep = _: true;
nope-eq = _: false;
nope-throw = _: false;
nope = _: false;
}) it.asserts;
};
goodIts = partitionTests (it: (goodIt it).asserts.err == []);