mirror of
https://github.com/NixOS/nixpkgs.git
synced 2024-11-17 11:10:03 +00:00
doc: migrate lib.debug to doc-comment format
This commit is contained in:
parent
cab94ab46e
commit
dfffdf1426
470
lib/debug.nix
470
lib/debug.nix
|
@ -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
|
||||
the first to stderr and return the second.
|
||||
* `traceVal`-like functions take one argument
|
||||
which both printed and returned.
|
||||
* `traceSeq`-like functions fully evaluate their
|
||||
traced value before printing (not just to “weak
|
||||
head normal form” like trace does by default).
|
||||
* Functions that end in `-Fn` take an additional
|
||||
function as their first argument, which is applied
|
||||
to the traced value before it is printed.
|
||||
* `trace`-like functions take two values, print
|
||||
the first to stderr and return the second.
|
||||
* `traceVal`-like functions take one argument
|
||||
which both printed and returned.
|
||||
* `traceSeq`-like functions fully evaluate their
|
||||
traced value before printing (not just to “weak
|
||||
head normal form” like trace does by default).
|
||||
* Functions that end in `-Fn` take an additional
|
||||
function as their first argument, which is applied
|
||||
to the traced value before it is printed.
|
||||
*/
|
||||
{ lib }:
|
||||
let
|
||||
|
@ -32,79 +33,190 @@ rec {
|
|||
|
||||
# -- 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:
|
||||
traceIf true "hello" 3
|
||||
trace: hello
|
||||
=> 3
|
||||
# Inputs
|
||||
|
||||
`pred`
|
||||
|
||||
: 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 =
|
||||
# Predicate to check
|
||||
pred:
|
||||
# Message that should be traced
|
||||
msg:
|
||||
# Value to return
|
||||
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:
|
||||
traceValFn (v: "mystring ${v}") "foo"
|
||||
trace: mystring foo
|
||||
=> "foo"
|
||||
# Inputs
|
||||
|
||||
`f`
|
||||
|
||||
: 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 =
|
||||
# Function to apply
|
||||
f:
|
||||
# Value to trace and return
|
||||
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:
|
||||
traceVal 42
|
||||
# trace: 42
|
||||
=> 42
|
||||
`x`
|
||||
|
||||
: Value to trace and return
|
||||
|
||||
# Type
|
||||
|
||||
```
|
||||
traceVal :: a -> a
|
||||
```
|
||||
|
||||
# Examples
|
||||
:::{.example}
|
||||
## `lib.debug.traceVal` usage example
|
||||
|
||||
```nix
|
||||
traceVal 42
|
||||
# trace: 42
|
||||
=> 42
|
||||
```
|
||||
|
||||
:::
|
||||
*/
|
||||
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:
|
||||
trace { a.b.c = 3; } null
|
||||
trace: { a = <CODE>; }
|
||||
=> null
|
||||
traceSeq { a.b.c = 3; } null
|
||||
trace: { a = { b = { c = 3; }; }; }
|
||||
=> null
|
||||
# Inputs
|
||||
|
||||
`x`
|
||||
|
||||
: The value to trace
|
||||
|
||||
`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 =
|
||||
# The value to trace
|
||||
x:
|
||||
# The value to return
|
||||
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
|
||||
lead to an infinite recursion.
|
||||
/**
|
||||
Like `traceSeq`, but only evaluate down to depth n.
|
||||
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:
|
||||
let snip = v: if isList v then noQuotes "[…]" v
|
||||
else if isAttrs v then noQuotes "{…}" v
|
||||
|
@ -118,41 +230,115 @@ rec {
|
|||
in trace (generators.toPretty { allowPrettyValues = true; }
|
||||
(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
|
||||
it.
|
||||
/**
|
||||
A combination of `traceVal` and `traceSeq` that applies a
|
||||
provided function to the value to be traced after `deepSeq`ing
|
||||
it.
|
||||
|
||||
|
||||
# Inputs
|
||||
|
||||
`f`
|
||||
|
||||
: Function to apply
|
||||
|
||||
`v`
|
||||
|
||||
: Value to trace
|
||||
*/
|
||||
traceValSeqFn =
|
||||
# Function to apply
|
||||
f:
|
||||
# Value to trace
|
||||
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;
|
||||
|
||||
/* 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 =
|
||||
# Function to apply
|
||||
f:
|
||||
depth:
|
||||
# Value to trace
|
||||
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;
|
||||
|
||||
/* 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,
|
||||
to see the before/after of values as they are transformed.
|
||||
This is useful for adding around a function call,
|
||||
to see the before/after of values as they are transformed.
|
||||
|
||||
Example:
|
||||
traceFnSeqN 2 "id" (x: x) { a.b.c = 3; }
|
||||
trace: { fn = "id"; from = { a.b = {…}; }; to = { a.b = {…}; }; }
|
||||
=> { a.b.c = 3; }
|
||||
|
||||
# Inputs
|
||||
|
||||
`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:
|
||||
let res = f v;
|
||||
|
@ -168,66 +354,82 @@ rec {
|
|||
|
||||
# -- TESTING --
|
||||
|
||||
/* Evaluates a set of tests.
|
||||
/**
|
||||
Evaluates a set of tests.
|
||||
|
||||
A test is an attribute set `{expr, expected}`,
|
||||
denoting an expression and its expected result.
|
||||
A test is an attribute set `{expr, expected}`,
|
||||
denoting an expression and its expected result.
|
||||
|
||||
The result is a `list` of __failed tests__, each represented as
|
||||
`{name, expected, result}`,
|
||||
The result is a `list` of __failed tests__, each represented as
|
||||
`{name, expected, result}`,
|
||||
|
||||
- expected
|
||||
- What was passed as `expected`
|
||||
- result
|
||||
- The actual `result` of the test
|
||||
- expected
|
||||
- What was passed as `expected`
|
||||
- result
|
||||
- The actual `result` of the test
|
||||
|
||||
Used for regression testing of the functions in lib; see
|
||||
tests.nix for more examples.
|
||||
Used for regression testing of the functions in lib; see
|
||||
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 {
|
||||
testAndOk = {
|
||||
expr = lib.and true false;
|
||||
expected = false;
|
||||
};
|
||||
testAndFail = {
|
||||
expr = lib.and true false;
|
||||
expected = true;
|
||||
};
|
||||
}
|
||||
->
|
||||
[
|
||||
{
|
||||
name = "testAndFail";
|
||||
expected = true;
|
||||
result = false;
|
||||
}
|
||||
]
|
||||
# Inputs
|
||||
|
||||
Type:
|
||||
runTests :: {
|
||||
tests = [ String ];
|
||||
${testName} :: {
|
||||
expr :: a;
|
||||
expected :: a;
|
||||
};
|
||||
`tests`
|
||||
|
||||
: Tests to run
|
||||
|
||||
# Type
|
||||
|
||||
```
|
||||
runTests :: {
|
||||
tests = [ String ];
|
||||
${testName} :: {
|
||||
expr :: a;
|
||||
expected :: a;
|
||||
};
|
||||
}
|
||||
->
|
||||
[
|
||||
{
|
||||
name :: String;
|
||||
expected :: a;
|
||||
result :: a;
|
||||
}
|
||||
->
|
||||
[
|
||||
{
|
||||
name :: String;
|
||||
expected :: a;
|
||||
result :: a;
|
||||
}
|
||||
]
|
||||
]
|
||||
```
|
||||
|
||||
# Examples
|
||||
:::{.example}
|
||||
## `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 =
|
||||
# Tests to run
|
||||
tests: concatLists (attrValues (mapAttrs (name: test:
|
||||
let testsToRun = if tests ? tests then tests.tests else [];
|
||||
in if (substring 0 4 name == "test" || elem name testsToRun)
|
||||
|
@ -237,10 +439,26 @@ rec {
|
|||
then [ { inherit name; expected = test.expected; result = test.expr; } ]
|
||||
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; };
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue