From e5a794b77d9878fb8c6566b56f0958af16ba3a20 Mon Sep 17 00:00:00 2001 From: Silvan Mosberger Date: Tue, 7 Feb 2023 18:41:52 +0100 Subject: [PATCH] lib.asserts.assertAll: init --- lib/asserts.nix | 39 +++++++++++++++++++++++++++++++++++++++ lib/default.nix | 2 +- lib/tests/misc.nix | 11 +++++++++++ 3 files changed, 51 insertions(+), 1 deletion(-) diff --git a/lib/asserts.nix b/lib/asserts.nix index 98e0b490acf29..fc325c7080b53 100644 --- a/lib/asserts.nix +++ b/lib/asserts.nix @@ -1,5 +1,12 @@ { lib }: +let + inherit (lib.lists) + all + foldl' + ; +in + rec { /* Throw if pred is false, else return pred. @@ -50,4 +57,36 @@ rec { lib.generators.toPretty {} xs}, but is: ${ lib.generators.toPretty {} val}"; + /* + Assert that a condition holds for all elements of a list. If it doesn't, + the first element violating the condition and its index will be given to + construct an error message. + + Type: + assertAll :: (a -> Bool) -> [a] -> (Int -> a -> String) -> Bool + + Example: + assert assertAll (n: n != 2) [ 1 3 5 ] (i: n: "Number ${toString n} at index ${toString i} is two!") + => true + assert assertAll (n: n != 2) [ 1 2 3 ] (i: n: "Number ${toString n} at index ${toString i} is two!") + => error: Number 2 at index 1 is two! + */ + assertAll = + # The condition to check on the list elements + cond: + # The list whose elements to check the condition on + list: + # In case an element violates the condition, this function gets called + # with the element index and value, it should return an error message string + msg: + # Fast successful path + if all cond list + then true + # Slower unsuccessful path + else foldl' (i: elem: + if cond elem + then i + 1 + else throw (msg i elem) + ) 0 list; + } diff --git a/lib/default.nix b/lib/default.nix index dc4df95754186..f4556679116bb 100644 --- a/lib/default.nix +++ b/lib/default.nix @@ -144,7 +144,7 @@ let inherit (self.types) isType setType defaultTypeMerge defaultFunctor isOptionType mkOptionType; inherit (self.asserts) - assertMsg assertOneOf; + assertMsg assertOneOf assertAll; inherit (self.debug) addErrorContextToAttrs traceIf traceVal traceValFn traceXMLVal traceXMLValMarked traceSeq traceSeqN traceValSeq traceValSeqFn traceValSeqN traceValSeqNFn traceFnSeqN traceShowVal diff --git a/lib/tests/misc.nix b/lib/tests/misc.nix index 406656dac1a92..d40263e1e2d5e 100644 --- a/lib/tests/misc.nix +++ b/lib/tests/misc.nix @@ -504,6 +504,17 @@ runTests { expected = false; }; +# ASSERTS + + testAssertAllExample1 = { + expr = asserts.assertAll (n: n != 2) [ 1 3 5 ] (abort "unused"); + expected = true; + }; + testAssertAllExample2 = { + expr = (builtins.tryEval (asserts.assertAll (n: n != 2) [ 1 2 3 ] (i: n: + throw "Number ${toString n} at index ${toString i} is two!"))).success; + expected = false; + }; # ATTRSETS