1 /* Collection of functions useful for debugging
2 broken nix expressions.
4 * `trace`-like functions take two values, print
5 the first to stderr and return the second.
6 * `traceVal`-like functions take one argument
7 which both printed and returned.
8 * `traceSeq`-like functions fully evaluate their
9 traced value before printing (not just to “weak
10 head normal form” like trace does by default).
11 * Functions that end in `-Fn` take an additional
12 function as their first argument, which is applied
13 to the traced value before it is printed.
35 /* Conditionally trace the supplied message, based on a predicate.
37 Type: traceIf :: bool -> string -> a -> a
40 traceIf true "hello" 3
47 # Message that should be traced
50 x: if pred then trace msg x else x;
52 /* Trace the supplied value after applying a function to it, and
53 return the original value.
55 Type: traceValFn :: (a -> b) -> a -> a
58 traceValFn (v: "mystring ${v}") "foo"
65 # Value to trace and return
68 /* Trace the supplied value and return it.
70 Type: traceVal :: a -> a
77 traceVal = traceValFn id;
79 /* `builtins.trace`, but the value is `builtins.deepSeq`ed first.
81 Type: traceSeq :: a -> b -> b
84 trace { a.b.c = 3; } null
85 trace: { a = <CODE>; }
87 traceSeq { a.b.c = 3; } null
88 trace: { a = { b = { c = 3; }; }; }
95 y: trace (builtins.deepSeq x x) y;
97 /* Like `traceSeq`, but only evaluate down to depth n.
98 This is very useful because lots of `traceSeq` usages
99 lead to an infinite recursion.
102 traceSeqN 2 { a.b.c = 3; } null
103 trace: { a = { b = {…}; }; }
106 Type: traceSeqN :: Int -> a -> b -> b
108 traceSeqN = depth: x: y:
109 let snip = v: if isList v then noQuotes "[…]" v
110 else if isAttrs v then noQuotes "{…}" v
112 noQuotes = str: v: { __pretty = const str; val = v; };
113 modify = n: fn: v: if (n == 0) then fn v
114 else if isList v then map (modify (n - 1) fn) v
115 else if isAttrs v then mapAttrs
116 (const (modify (n - 1) fn)) v
118 in trace (generators.toPretty { allowPrettyValues = true; }
119 (modify depth snip x)) y;
121 /* A combination of `traceVal` and `traceSeq` that applies a
122 provided function to the value to be traced after `deepSeq`ing
129 v: traceValFn f (builtins.deepSeq v v);
131 /* A combination of `traceVal` and `traceSeq`. */
132 traceValSeq = traceValSeqFn id;
134 /* A combination of `traceVal` and `traceSeqN` that applies a
135 provided function to the value to be traced. */
141 v: traceSeqN depth (f v) v;
143 /* A combination of `traceVal` and `traceSeqN`. */
144 traceValSeqN = traceValSeqNFn id;
146 /* Trace the input and output of a function `f` named `name`,
147 both down to `depth`.
149 This is useful for adding around a function call,
150 to see the before/after of values as they are transformed.
153 traceFnSeqN 2 "id" (x: x) { a.b.c = 3; }
154 trace: { fn = "id"; from = { a.b = {…}; }; to = { a.b = {…}; }; }
157 traceFnSeqN = depth: name: f: v:
171 /* Evaluates a set of tests.
173 A test is an attribute set `{expr, expected}`,
174 denoting an expression and its expected result.
176 The result is a `list` of __failed tests__, each represented as
177 `{name, expected, result}`,
180 - What was passed as `expected`
182 - The actual `result` of the test
184 Used for regression testing of the functions in lib; see
185 tests.nix for more examples.
187 Important: Only attributes that start with `test` are executed.
189 - If you want to run only a subset of the tests add the attribute `tests = ["testName"];`
195 expr = lib.and true false;
199 expr = lib.and true false;
206 name = "testAndFail";
231 tests: concatLists (attrValues (mapAttrs (name: test:
232 let testsToRun = if tests ? tests then tests.tests else [];
233 in if (substring 0 4 name == "test" || elem name testsToRun)
234 && ((testsToRun == []) || elem name tests.tests)
235 && (test.expr != test.expected)
237 then [ { inherit name; expected = test.expected; result = test.expr; } ]
240 /* Create a test assuming that list elements are `true`.
243 { testX = allTrue [ true ]; }
245 testAllTrue = expr: { inherit expr; expected = map (x: true) expr; };