2 Collection of functions useful for debugging
3 broken nix expressions.
5 * `trace`-like functions take two values, print
6 the first to stderr and return the second.
7 * `traceVal`-like functions take one argument
8 which both printed and returned.
9 * `traceSeq`-like functions fully evaluate their
10 traced value before printing (not just to “weak
11 head normal form” like trace does by default).
12 * Functions that end in `-Fn` take an additional
13 function as their first argument, which is applied
14 to the traced value before it is printed.
37 Conditionally trace the supplied message, based on a predicate.
48 : Message that should be traced
57 traceIf :: bool -> string -> a -> a
62 ## `lib.debug.traceIf` usage example
65 traceIf true "hello" 3
75 x: if pred then trace msg x else x;
78 Trace the supplied value after applying a function to it, and
79 return the original value.
90 : Value to trace and return
95 traceValFn :: (a -> b) -> a -> a
100 ## `lib.debug.traceValFn` usage example
103 traceValFn (v: "mystring ${v}") "foo"
115 Trace the supplied value and return it.
121 : Value to trace and return
131 ## `lib.debug.traceVal` usage example
141 traceVal = traceValFn id;
144 `builtins.trace`, but the value is `builtins.deepSeq`ed first.
155 : The value to return
160 traceSeq :: a -> b -> b
165 ## `lib.debug.traceSeq` usage example
168 trace { a.b.c = 3; } null
169 trace: { a = <CODE>; }
171 traceSeq { a.b.c = 3; } null
172 trace: { a = { b = { c = 3; }; }; }
180 y: trace (builtins.deepSeq x x) y;
183 Like `traceSeq`, but only evaluate down to depth n.
184 This is very useful because lots of `traceSeq` usages
185 lead to an infinite recursion.
192 : 1\. Function argument
196 : 2\. Function argument
200 : 3\. Function argument
205 traceSeqN :: Int -> a -> b -> b
210 ## `lib.debug.traceSeqN` usage example
213 traceSeqN 2 { a.b.c = 3; } null
214 trace: { a = { b = {…}; }; }
220 traceSeqN = depth: x: y:
221 let snip = v: if isList v then noQuotes "[…]" v
222 else if isAttrs v then noQuotes "{…}" v
224 noQuotes = str: v: { __pretty = const str; val = v; };
225 modify = n: fn: v: if (n == 0) then fn v
226 else if isList v then map (modify (n - 1) fn) v
227 else if isAttrs v then mapAttrs
228 (const (modify (n - 1) fn)) v
230 in trace (generators.toPretty { allowPrettyValues = true; }
231 (modify depth snip x)) y;
234 A combination of `traceVal` and `traceSeq` that applies a
235 provided function to the value to be traced after `deepSeq`ing
251 v: traceValFn f (builtins.deepSeq v v);
254 A combination of `traceVal` and `traceSeq`.
263 traceValSeq = traceValSeqFn id;
266 A combination of `traceVal` and `traceSeqN` that applies a
267 provided function to the value to be traced.
278 : 2\. Function argument
287 v: traceSeqN depth (f v) v;
290 A combination of `traceVal` and `traceSeqN`.
296 : 1\. Function argument
302 traceValSeqN = traceValSeqNFn id;
305 Trace the input and output of a function `f` named `name`,
306 both down to `depth`.
308 This is useful for adding around a function call,
309 to see the before/after of values as they are transformed.
316 : 1\. Function argument
320 : 2\. Function argument
324 : 3\. Function argument
328 : 4\. Function argument
333 ## `lib.debug.traceFnSeqN` usage example
336 traceFnSeqN 2 "id" (x: x) { a.b.c = 3; }
337 trace: { fn = "id"; from = { a.b = {…}; }; to = { a.b = {…}; }; }
343 traceFnSeqN = depth: name: f: v:
358 Evaluates a set of tests.
360 A test is an attribute set `{expr, expected}`,
361 denoting an expression and its expected result.
363 The result is a `list` of __failed tests__, each represented as
364 `{name, expected, result}`,
367 - What was passed as `expected`
369 - The actual `result` of the test
371 Used for regression testing of the functions in lib; see
372 tests.nix for more examples.
374 Important: Only attributes that start with `test` are executed.
376 - If you want to run only a subset of the tests add the attribute `tests = ["testName"];`
407 ## `lib.debug.runTests` usage example
412 expr = lib.and true false;
416 expr = lib.and true false;
423 name = "testAndFail";
433 tests: concatLists (attrValues (mapAttrs (name: test:
434 let testsToRun = if tests ? tests then tests.tests else [];
435 in if (substring 0 4 name == "test" || elem name testsToRun)
436 && ((testsToRun == []) || elem name tests.tests)
437 && (test.expr != test.expected)
439 then [ { inherit name; expected = test.expected; result = test.expr; } ]
443 Create a test assuming that list elements are `true`.
450 : 1\. Function argument
455 ## `lib.debug.testAllTrue` usage example
458 { testX = allTrue [ true ]; }
463 testAllTrue = expr: { inherit expr; expected = map (x: true) expr; };