Merge pull request #312215 from hsjobeki/doc/lib-debug

doc: migrate lib.debug to doc-comment format
This commit is contained in:
Daniel Sidhion 2024-05-20 23:20:36 -07:00 committed by GitHub
commit f452bb946c
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194

View File

@ -1,16 +1,17 @@
/* Collection of functions useful for debugging /**
broken nix expressions. Collection of functions useful for debugging
broken nix expressions.
* `trace`-like functions take two values, print * `trace`-like functions take two values, print
the first to stderr and return the second. the first to stderr and return the second.
* `traceVal`-like functions take one argument * `traceVal`-like functions take one argument
which both printed and returned. which both printed and returned.
* `traceSeq`-like functions fully evaluate their * `traceSeq`-like functions fully evaluate their
traced value before printing (not just to weak traced value before printing (not just to weak
head normal form like trace does by default). head normal form like trace does by default).
* Functions that end in `-Fn` take an additional * Functions that end in `-Fn` take an additional
function as their first argument, which is applied function as their first argument, which is applied
to the traced value before it is printed. to the traced value before it is printed.
*/ */
{ lib }: { lib }:
let let
@ -32,79 +33,190 @@ rec {
# -- TRACING -- # -- TRACING --
/* Conditionally trace the supplied message, based on a predicate. /**
Conditionally trace the supplied message, based on a predicate.
Type: traceIf :: bool -> string -> a -> a
Example: # Inputs
traceIf true "hello" 3
trace: hello `pred`
=> 3
: Predicate to check
`msg`
: Message that should be traced
`x`
: Value to return
# Type
```
traceIf :: bool -> string -> a -> a
```
# Examples
:::{.example}
## `lib.debug.traceIf` usage example
```nix
traceIf true "hello" 3
trace: hello
=> 3
```
:::
*/ */
traceIf = traceIf =
# Predicate to check
pred: pred:
# Message that should be traced
msg: msg:
# Value to return
x: if pred then trace msg x else x; x: if pred then trace msg x else x;
/* Trace the supplied value after applying a function to it, and /**
return the original value. Trace the supplied value after applying a function to it, and
return the original value.
Type: traceValFn :: (a -> b) -> a -> a
Example: # Inputs
traceValFn (v: "mystring ${v}") "foo"
trace: mystring foo `f`
=> "foo"
: Function to apply
`x`
: Value to trace and return
# Type
```
traceValFn :: (a -> b) -> a -> a
```
# Examples
:::{.example}
## `lib.debug.traceValFn` usage example
```nix
traceValFn (v: "mystring ${v}") "foo"
trace: mystring foo
=> "foo"
```
:::
*/ */
traceValFn = traceValFn =
# Function to apply
f: f:
# Value to trace and return
x: trace (f x) x; x: trace (f x) x;
/* Trace the supplied value and return it. /**
Trace the supplied value and return it.
Type: traceVal :: a -> a # Inputs
Example: `x`
traceVal 42
# trace: 42 : Value to trace and return
=> 42
# Type
```
traceVal :: a -> a
```
# Examples
:::{.example}
## `lib.debug.traceVal` usage example
```nix
traceVal 42
# trace: 42
=> 42
```
:::
*/ */
traceVal = traceValFn id; traceVal = traceValFn id;
/* `builtins.trace`, but the value is `builtins.deepSeq`ed first. /**
`builtins.trace`, but the value is `builtins.deepSeq`ed first.
Type: traceSeq :: a -> b -> b
Example: # Inputs
trace { a.b.c = 3; } null
trace: { a = <CODE>; } `x`
=> null
traceSeq { a.b.c = 3; } null : The value to trace
trace: { a = { b = { c = 3; }; }; }
=> null `y`
: The value to return
# Type
```
traceSeq :: a -> b -> b
```
# Examples
:::{.example}
## `lib.debug.traceSeq` usage example
```nix
trace { a.b.c = 3; } null
trace: { a = <CODE>; }
=> null
traceSeq { a.b.c = 3; } null
trace: { a = { b = { c = 3; }; }; }
=> null
```
:::
*/ */
traceSeq = traceSeq =
# The value to trace
x: x:
# The value to return
y: trace (builtins.deepSeq x x) y; y: trace (builtins.deepSeq x x) y;
/* Like `traceSeq`, but only evaluate down to depth n. /**
This is very useful because lots of `traceSeq` usages Like `traceSeq`, but only evaluate down to depth n.
lead to an infinite recursion. This is very useful because lots of `traceSeq` usages
lead to an infinite recursion.
Example:
traceSeqN 2 { a.b.c = 3; } null
trace: { a = { b = {}; }; }
=> null
Type: traceSeqN :: Int -> a -> b -> b # Inputs
*/
`depth`
: 1\. Function argument
`x`
: 2\. Function argument
`y`
: 3\. Function argument
# Type
```
traceSeqN :: Int -> a -> b -> b
```
# Examples
:::{.example}
## `lib.debug.traceSeqN` usage example
```nix
traceSeqN 2 { a.b.c = 3; } null
trace: { a = { b = {}; }; }
=> null
```
:::
*/
traceSeqN = depth: x: y: traceSeqN = depth: x: y:
let snip = v: if isList v then noQuotes "[]" v let snip = v: if isList v then noQuotes "[]" v
else if isAttrs v then noQuotes "{}" v else if isAttrs v then noQuotes "{}" v
@ -118,41 +230,115 @@ rec {
in trace (generators.toPretty { allowPrettyValues = true; } in trace (generators.toPretty { allowPrettyValues = true; }
(modify depth snip x)) y; (modify depth snip x)) y;
/* A combination of `traceVal` and `traceSeq` that applies a /**
provided function to the value to be traced after `deepSeq`ing A combination of `traceVal` and `traceSeq` that applies a
it. provided function to the value to be traced after `deepSeq`ing
it.
# Inputs
`f`
: Function to apply
`v`
: Value to trace
*/ */
traceValSeqFn = traceValSeqFn =
# Function to apply
f: f:
# Value to trace
v: traceValFn f (builtins.deepSeq v v); v: traceValFn f (builtins.deepSeq v v);
/* A combination of `traceVal` and `traceSeq`. */ /**
A combination of `traceVal` and `traceSeq`.
# Inputs
`v`
: Value to trace
*/
traceValSeq = traceValSeqFn id; traceValSeq = traceValSeqFn id;
/* A combination of `traceVal` and `traceSeqN` that applies a /**
provided function to the value to be traced. */ A combination of `traceVal` and `traceSeqN` that applies a
provided function to the value to be traced.
# Inputs
`f`
: Function to apply
`depth`
: 2\. Function argument
`v`
: Value to trace
*/
traceValSeqNFn = traceValSeqNFn =
# Function to apply
f: f:
depth: depth:
# Value to trace
v: traceSeqN depth (f v) v; v: traceSeqN depth (f v) v;
/* A combination of `traceVal` and `traceSeqN`. */ /**
A combination of `traceVal` and `traceSeqN`.
# Inputs
`depth`
: 1\. Function argument
`v`
: Value to trace
*/
traceValSeqN = traceValSeqNFn id; traceValSeqN = traceValSeqNFn id;
/* Trace the input and output of a function `f` named `name`, /**
both down to `depth`. Trace the input and output of a function `f` named `name`,
both down to `depth`.
This is useful for adding around a function call, This is useful for adding around a function call,
to see the before/after of values as they are transformed. to see the before/after of values as they are transformed.
Example:
traceFnSeqN 2 "id" (x: x) { a.b.c = 3; } # Inputs
trace: { fn = "id"; from = { a.b = {}; }; to = { a.b = {}; }; }
=> { a.b.c = 3; } `depth`
: 1\. Function argument
`name`
: 2\. Function argument
`f`
: 3\. Function argument
`v`
: 4\. Function argument
# Examples
:::{.example}
## `lib.debug.traceFnSeqN` usage example
```nix
traceFnSeqN 2 "id" (x: x) { a.b.c = 3; }
trace: { fn = "id"; from = { a.b = {}; }; to = { a.b = {}; }; }
=> { a.b.c = 3; }
```
:::
*/ */
traceFnSeqN = depth: name: f: v: traceFnSeqN = depth: name: f: v:
let res = f v; let res = f v;
@ -168,66 +354,82 @@ rec {
# -- TESTING -- # -- TESTING --
/* Evaluates a set of tests. /**
Evaluates a set of tests.
A test is an attribute set `{expr, expected}`, A test is an attribute set `{expr, expected}`,
denoting an expression and its expected result. denoting an expression and its expected result.
The result is a `list` of __failed tests__, each represented as The result is a `list` of __failed tests__, each represented as
`{name, expected, result}`, `{name, expected, result}`,
- expected - expected
- What was passed as `expected` - What was passed as `expected`
- result - result
- The actual `result` of the test - The actual `result` of the test
Used for regression testing of the functions in lib; see Used for regression testing of the functions in lib; see
tests.nix for more examples. tests.nix for more examples.
Important: Only attributes that start with `test` are executed. Important: Only attributes that start with `test` are executed.
- If you want to run only a subset of the tests add the attribute `tests = ["testName"];` - If you want to run only a subset of the tests add the attribute `tests = ["testName"];`
Example:
runTests { # Inputs
testAndOk = {
expr = lib.and true false;
expected = false;
};
testAndFail = {
expr = lib.and true false;
expected = true;
};
}
->
[
{
name = "testAndFail";
expected = true;
result = false;
}
]
Type: `tests`
runTests :: {
tests = [ String ]; : Tests to run
${testName} :: {
expr :: a; # Type
expected :: a;
}; ```
runTests :: {
tests = [ String ];
${testName} :: {
expr :: a;
expected :: a;
};
}
->
[
{
name :: String;
expected :: a;
result :: a;
} }
-> ]
[ ```
{
name :: String; # Examples
expected :: a; :::{.example}
result :: a; ## `lib.debug.runTests` usage example
}
] ```nix
runTests {
testAndOk = {
expr = lib.and true false;
expected = false;
};
testAndFail = {
expr = lib.and true false;
expected = true;
};
}
->
[
{
name = "testAndFail";
expected = true;
result = false;
}
]
```
:::
*/ */
runTests = runTests =
# Tests to run
tests: concatLists (attrValues (mapAttrs (name: test: tests: concatLists (attrValues (mapAttrs (name: test:
let testsToRun = if tests ? tests then tests.tests else []; let testsToRun = if tests ? tests then tests.tests else [];
in if (substring 0 4 name == "test" || elem name testsToRun) in if (substring 0 4 name == "test" || elem name testsToRun)
@ -237,10 +439,26 @@ rec {
then [ { inherit name; expected = test.expected; result = test.expr; } ] then [ { inherit name; expected = test.expected; result = test.expr; } ]
else [] ) tests)); else [] ) tests));
/* Create a test assuming that list elements are `true`. /**
Create a test assuming that list elements are `true`.
Example:
{ testX = allTrue [ true ]; } # Inputs
`expr`
: 1\. Function argument
# Examples
:::{.example}
## `lib.debug.testAllTrue` usage example
```nix
{ testX = allTrue [ true ]; }
```
:::
*/ */
testAllTrue = expr: { inherit expr; expected = map (x: true) expr; }; testAllTrue = expr: { inherit expr; expected = map (x: true) expr; };
} }