diff --git a/lib/debug.nix b/lib/debug.nix index 97e87acccf0e..b10023d02616 100644 --- a/lib/debug.nix +++ b/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 = ; } - => 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 = ; } + => 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; }; }