nixfiles/libs/core/lib/check/default.nix
Sebastian Walz 860d31cee1
Tohu vaBohu
2023-04-21 00:22:52 +02:00

277 lines
8.1 KiB
Nix

{ ansi, context, debug, derivation, expression, library, list, path, set, string, target, type, ... }:
let
TestCase
= type "TestCase"
{
from
= { success, value } @ result:
TestCase.instanciate result;
};
TestResult
= type "TestResult"
{
from
= variant:
{ success, value } @ result:
TestResult.instanciateAs variant result;
};
check
= value:
arguments:
let
result = expression.tryEval value;
in
type.matchPrimitiveOrDefault result.value
{
list = checkList result.value;
set = checkTests arguments result.value;
lambda = checkValue (result.value arguments);
}
(TestResult "Value" result);
checkList
= list.fold
(
{ success, value, ... } @ state:
entry:
let
result = checkValue entry;
in
state
// {
success = success && result.success;
value = value ++ [ entry ];
}
)
(
TestResult "List"
{
success = true;
value = [];
}
);
checkSet
= set.fold
(
{ success, value, ... } @ state:
name:
entry:
let
result = checkValue entry;
in
debug.info "checkSet"
{
text = "Entry ${name} failed:";
data = entry;
when = !result.success;
}
state
// {
success = success && result.success;
value = value // { ${name} = entry; };
}
)
(
TestResult "Set"
{
success = true;
value = {};
}
);
checkTests
= arguments:
set.fold
(
{ success, value, ... } @ state:
name:
entry:
let
result = check entry arguments;
in
state
// {
success = success && result.success;
value = value // { ${name} = result; };
}
)
(
TestCase
{
success = true;
value = {};
}
);
checkValue
= value:
let
result = expression.tryEval value;
in
type.matchPrimitiveOrDefault result.value
{
list = checkList result.value;
set
= if !(string.DoNotFollow.isInstanceOf result.value)
then
checkSet result.value
else
result;
}
(TestResult "Value" result);
format
= system:
fullName:
{ success, value, ... } @ this:
if !(TestResult.isInstanceOf this)
then
string.concatLines
(
set.mapToList
(
name:
testCases:
let
fullName'
= if fullName != null
then
"${fullName} ${name}"
else
name;
in
format system fullName' testCases
)
value
)
else
let
inherit(ansi) foreground;
fullName'
= if fullName != null
then
" ${fullName}"
else
"";
value'
= string.from
{
legacy = false;
display = true;
maxDepth = null;
nice = true;
showType = true;
}
value;
verdict
= if success
then
"${foreground.green}[passed]"
else
"${foreground.red}[failed]";
formatLine
= line:
"echo -e \"${verdict}${fullName'} @ ${system}${line}${ansi.reset}\"";
in
if success && true
then
formatLine ""
else
string.concatMappedLines
(
line:
let
line'
= let
inherit(string.char) escape;
in
string.replace'
{
"\"" = ''\"'';
"\\" = ''\\'';
"$" = ''\$'';
"`" = ''\`'';
${escape} = "\\e";
}
line;
in
formatLine ": ${line'}"
)
(string.splitLines value');
testsToChecks
= { fileName, lib, source, tests }:
buildSystem:
arguments:
let
lib' = library.initialise lib (arguments' // { inherit fileName source; });
arguments' = arguments // { inherit buildSystem; };
tests' = check (tests lib') arguments';
builder
= path.toFile "builder.sh"
''
#!/usr/bin/env sh
${format buildSystem null tests'}
${
if tests'.success
then
''
echo -e "\e[32mall tests were successful!\e[0m"
echo "1" > $out
exit 0
''
else
''
echo -e "\e[31msome tests failed!\e[0m"
exit 1
''
}
'';
in
debug.debug []
{
text = "Builder for ${buildSystem}";
data = builder;
}
derivation
{
args = [ builder ];
builder = "/bin/sh";
name = "libcore-test";
system = "${buildSystem}";
};
in
{
load
= fileName:
{ ... } @ env:
{ ... } @ lib:
{
inherit fileName lib;
tests = path.import fileName env;
source = context "tests" fileName;
};
__functor
= { ... }:
{ ... } @ tests:
arguments:
if false
then
target.System.mapAll
(
buildSystem:
{
default = testsToChecks tests buildSystem arguments;
}
)
else
{
x86_64-linux.default = testsToChecks tests "x86_64-linux" arguments;
};
}