feat(nix/runTestsuite): add runTestsuite
This is a very simple test suite for nix expressions. It should help us set up a good suite of unit tests for our nix-based stuff. Since we allow import from derivation, these tests can also depend on derivations and e.g. use `builtins.readFile` to check outputs. This is a first PoC to get us going, we can always replace it by something different in the future if we don’t like it. Change-Id: I206c7b624db2b1dabd9c73ffce4f87e658919958 Reviewed-on: https://cl.tvl.fyi/c/depot/+/662 Reviewed-by: tazjin <mail@tazj.in> Tested-by: tazjin <mail@tazj.in>
This commit is contained in:
parent
e2c7e38934
commit
c8e888c1d2
1 changed files with 121 additions and 0 deletions
121
nix/runTestsuite/default.nix
Normal file
121
nix/runTestsuite/default.nix
Normal file
|
@ -0,0 +1,121 @@
|
||||||
|
{ lib, pkgs, depot, ... }:
|
||||||
|
|
||||||
|
# Run a nix testsuite.
|
||||||
|
#
|
||||||
|
# The tests are simple assertions on the nix level,
|
||||||
|
# and can use derivation outputs if IfD is enabled.
|
||||||
|
#
|
||||||
|
# You build a testsuite by bundling assertions into
|
||||||
|
# “it”s and then bundling the “it”s into a testsuite.
|
||||||
|
#
|
||||||
|
# Running the testsuite will abort evaluation if
|
||||||
|
# any assertion fails.
|
||||||
|
#
|
||||||
|
# Example:
|
||||||
|
#
|
||||||
|
# runTestsuite "myFancyTestsuite" [
|
||||||
|
# (it "does an assertion" [
|
||||||
|
# (assertEq "42 is equal to 42" "42" "42")
|
||||||
|
# (assertEq "also 23" 23 23)
|
||||||
|
# ])
|
||||||
|
# (it "frmbls the brlbr" [
|
||||||
|
# (assertEq true false)
|
||||||
|
# ])
|
||||||
|
# ]
|
||||||
|
#
|
||||||
|
# will fail the second it group because true is not false.
|
||||||
|
|
||||||
|
let
|
||||||
|
inherit (depot.nix.yants) sum struct string any unit defun list;
|
||||||
|
|
||||||
|
# rewrite the builtins.partition result
|
||||||
|
# to use `ok` and `err` instead of `right` and `wrong`.
|
||||||
|
partitionTests = pred: xs:
|
||||||
|
let res = builtins.partition pred xs;
|
||||||
|
in {
|
||||||
|
ok = res.right;
|
||||||
|
err = res.wrong;
|
||||||
|
};
|
||||||
|
|
||||||
|
# The result of an assert,
|
||||||
|
# either it’s true (yep) or false (nope).
|
||||||
|
# If it’s nope, we return the left and right
|
||||||
|
# side of the assert, together with the description.
|
||||||
|
AssertResult =
|
||||||
|
sum "AssertResult" {
|
||||||
|
yep = struct "yep" {
|
||||||
|
test = string;
|
||||||
|
};
|
||||||
|
nope = struct "nope" {
|
||||||
|
test = string;
|
||||||
|
left = any;
|
||||||
|
right = any;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
# Result of an it. An it is a bunch of asserts
|
||||||
|
# bundled up with a good description of what is tested.
|
||||||
|
ItResult =
|
||||||
|
struct "ItResult" {
|
||||||
|
it-desc = string;
|
||||||
|
asserts = list AssertResult;
|
||||||
|
};
|
||||||
|
|
||||||
|
# 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 = {
|
||||||
|
test = desc;
|
||||||
|
inherit left right;
|
||||||
|
};
|
||||||
|
});
|
||||||
|
|
||||||
|
# Annotate a bunch of asserts with a descriptive name
|
||||||
|
it = desc: asserts: {
|
||||||
|
it-desc = desc;
|
||||||
|
inherit asserts;
|
||||||
|
};
|
||||||
|
|
||||||
|
# Run a bunch of its and check whether all asserts are yep.
|
||||||
|
# If not, abort evaluation with `throw`
|
||||||
|
# and print the result of the test suite.
|
||||||
|
#
|
||||||
|
# Takes a test suite name as first argument.
|
||||||
|
runTestsuite = defun [ string (list ItResult) unit ]
|
||||||
|
(name: itResults:
|
||||||
|
let
|
||||||
|
goodAss = ass: {
|
||||||
|
good = AssertResult.match ass {
|
||||||
|
yep = _: true;
|
||||||
|
nope = _: false;
|
||||||
|
};
|
||||||
|
x = ass;
|
||||||
|
};
|
||||||
|
goodIt = it: {
|
||||||
|
inherit (it) it-desc;
|
||||||
|
asserts = partitionTests (ass:
|
||||||
|
AssertResult.match ass {
|
||||||
|
yep = _: true;
|
||||||
|
nope = _: false;
|
||||||
|
}) it.asserts;
|
||||||
|
};
|
||||||
|
goodIts = partitionTests (it: (goodIt it).asserts.err == []);
|
||||||
|
res = goodIts itResults;
|
||||||
|
in
|
||||||
|
if res.err == []
|
||||||
|
then {}
|
||||||
|
# TODO(Profpatsch): pretty printing of results
|
||||||
|
# and probably also somewhat easier to read output
|
||||||
|
else throw
|
||||||
|
( "testsuite ${name} failed!\n"
|
||||||
|
+ lib.generators.toPretty {} res));
|
||||||
|
|
||||||
|
in {
|
||||||
|
inherit
|
||||||
|
assertEq
|
||||||
|
it
|
||||||
|
runTestsuite
|
||||||
|
;
|
||||||
|
}
|
Loading…
Reference in a new issue