diff options
Diffstat (limited to 'lib/tests')
-rw-r--r-- | lib/tests/misc.nix | 81 | ||||
-rwxr-xr-x | lib/tests/modules.sh | 23 | ||||
-rw-r--r-- | lib/tests/modules/declaration-positions.nix | 49 | ||||
-rw-r--r-- | lib/tests/modules/gvariant.nix | 142 |
4 files changed, 205 insertions, 90 deletions
diff --git a/lib/tests/misc.nix b/lib/tests/misc.nix index 702be9529b4..6527c31e49c 100644 --- a/lib/tests/misc.nix +++ b/lib/tests/misc.nix @@ -509,6 +509,38 @@ runTests { }; }; + testFoldl'Empty = { + expr = foldl' (acc: el: abort "operation not called") 0 [ ]; + expected = 0; + }; + + testFoldl'IntegerAdding = { + expr = foldl' (acc: el: acc + el) 0 [ 1 2 3 ]; + expected = 6; + }; + + # The accumulator isn't forced deeply + testFoldl'NonDeep = { + expr = take 3 (foldl' + (acc: el: [ el ] ++ acc) + [ (abort "unevaluated list entry") ] + [ 1 2 3 ]); + expected = [ 3 2 1 ]; + }; + + # Compared to builtins.foldl', lib.foldl' evaluates the first accumulator strictly too + testFoldl'StrictInitial = { + expr = (builtins.tryEval (foldl' (acc: el: el) (throw "hello") [])).success; + expected = false; + }; + + # Make sure we don't get a stack overflow for large lists + # This number of elements would notably cause a stack overflow if it was implemented without the `foldl'` builtin + testFoldl'Large = { + expr = foldl' (acc: el: acc + el) 0 (range 0 100000); + expected = 5000050000; + }; + testTake = testAllTrue [ ([] == (take 0 [ 1 2 3 ])) ([1] == (take 1 [ 1 2 3 ])) @@ -712,7 +744,7 @@ runTests { # should just return the initial value emptySet = foldlAttrs (throw "function not needed") 123 { }; # should just evaluate to the last value - accNotNeeded = foldlAttrs (_acc: _name: v: v) (throw "accumulator not needed") { z = 3; a = 2; }; + valuesNotNeeded = foldlAttrs (acc: _name: _v: acc) 3 { z = throw "value z not needed"; a = throw "value a not needed"; }; # the accumulator doesnt have to be an attrset it can be as trivial as being just a number or string trivialAcc = foldlAttrs (acc: _name: v: acc * 10 + v) 1 { z = 1; a = 2; }; }; @@ -722,7 +754,7 @@ runTests { names = [ "bar" "foo" ]; }; emptySet = 123; - accNotNeeded = 3; + valuesNotNeeded = 3; trivialAcc = 121; }; }; @@ -972,6 +1004,51 @@ runTests { ''; }; + testToGitINI = { + expr = generators.toGitINI { + user = { + email = "user@example.org"; + name = "John Doe"; + signingKey = "00112233445566778899AABBCCDDEEFF"; + }; + gpg.program = "path-to-gpg"; + tag.gpgSign = true; + include.path = "~/path/to/config.inc"; + includeIf."gitdif:~/src/dir".path = "~/path/to/conditional.inc"; + extra = { + boolean = true; + integer = 38; + name = "value"; + subsection.value = "test"; + };}; + expected = '' + [extra] + ${"\t"}boolean = true + ${"\t"}integer = 38 + ${"\t"}name = "value" + + [extra "subsection"] + ${"\t"}value = "test" + + [gpg] + ${"\t"}program = "path-to-gpg" + + [include] + ${"\t"}path = "~/path/to/config.inc" + + [includeIf "gitdif:~/src/dir"] + ${"\t"}path = "~/path/to/conditional.inc" + + [tag] + ${"\t"}gpgSign = true + + [user] + ${"\t"}email = "user@example.org" + ${"\t"}name = "John Doe" + ${"\t"}signingKey = "00112233445566778899AABBCCDDEEFF" + ''; + }; + /* right now only invocation check */ testToJSONSimple = let val = { diff --git a/lib/tests/modules.sh b/lib/tests/modules.sh index 2c5e4cdbcec..05c99e6de83 100755 --- a/lib/tests/modules.sh +++ b/lib/tests/modules.sh @@ -39,7 +39,7 @@ reportFailure() { checkConfigOutput() { local outputContains=$1 shift - if evalConfig "$@" 2>/dev/null | grep --silent "$outputContains" ; then + if evalConfig "$@" 2>/dev/null | grep -E --silent "$outputContains" ; then ((++pass)) else echo 2>&1 "error: Expected result matching '$outputContains', while evaluating" @@ -91,6 +91,9 @@ checkConfigOutput '^true$' config.result ./test-mergeAttrDefinitionsWithPrio.nix # is the option. checkConfigOutput '^true$' config.result ./module-argument-default.nix +# gvariant +checkConfigOutput '^true$' config.assertion ./gvariant.nix + # types.pathInStore checkConfigOutput '".*/store/0lz9p8xhf89kb1c1kk6jxrzskaiygnlh-bash-5.2-p15.drv"' config.pathInStore.ok1 ./types.nix checkConfigOutput '".*/store/0fb3ykw9r5hpayd05sr0cizwadzq1d8q-bash-5.2-p15"' config.pathInStore.ok2 ./types.nix @@ -444,6 +447,24 @@ checkConfigOutput '^"The option `a\.b. defined in `.*/doRename-warnings\.nix. ha checkConfigOutput '^"pear"$' config.once.raw ./merge-module-with-key.nix checkConfigOutput '^"pear\\npear"$' config.twice.raw ./merge-module-with-key.nix +# Declaration positions +# Line should be present for direct options +checkConfigOutput '^10$' options.imported.line10.declarationPositions.0.line ./declaration-positions.nix +checkConfigOutput '/declaration-positions.nix"$' options.imported.line10.declarationPositions.0.file ./declaration-positions.nix +# Generated options may not have line numbers but they will at least get the +# right file +checkConfigOutput '/declaration-positions.nix"$' options.generated.line18.declarationPositions.0.file ./declaration-positions.nix +checkConfigOutput '^null$' options.generated.line18.declarationPositions.0.line ./declaration-positions.nix +# Submodules don't break it +checkConfigOutput '^39$' config.submoduleLine34.submodDeclLine39.0.line ./declaration-positions.nix +checkConfigOutput '/declaration-positions.nix"$' config.submoduleLine34.submodDeclLine39.0.file ./declaration-positions.nix +# New options under freeform submodules get collected into the parent submodule +# (consistent with .declarations behaviour, but weird; notably appears in system.build) +checkConfigOutput '^34|23$' options.submoduleLine34.declarationPositions.0.line ./declaration-positions.nix +checkConfigOutput '^34|23$' options.submoduleLine34.declarationPositions.1.line ./declaration-positions.nix +# nested options work +checkConfigOutput '^30$' options.nested.nestedLine30.declarationPositions.0.line ./declaration-positions.nix + cat <<EOF ====== module tests ====== $pass Pass diff --git a/lib/tests/modules/declaration-positions.nix b/lib/tests/modules/declaration-positions.nix new file mode 100644 index 00000000000..cefd3b4e516 --- /dev/null +++ b/lib/tests/modules/declaration-positions.nix @@ -0,0 +1,49 @@ +{ lib, options, ... }: +let discardPositions = lib.mapAttrs (k: v: v); +in +# unsafeGetAttrPos is unspecified best-effort behavior, so we only want to consider this test on an evaluator that satisfies some basic assumptions about this function. +assert builtins.unsafeGetAttrPos "a" { a = true; } != null; +assert builtins.unsafeGetAttrPos "a" (discardPositions { a = true; }) == null; +{ + imports = [ + { + options.imported.line10 = lib.mkOption { + type = lib.types.int; + }; + + # Simulates various patterns of generating modules such as + # programs.firefox.nativeMessagingHosts.ff2mpv. We don't expect to get + # line numbers for these, but we can fall back on knowing the file. + options.generated = discardPositions { + line18 = lib.mkOption { + type = lib.types.int; + }; + }; + + options.submoduleLine34.extraOptLine23 = lib.mkOption { + default = 1; + type = lib.types.int; + }; + } + ]; + + options.nested.nestedLine30 = lib.mkOption { + type = lib.types.int; + }; + + options.submoduleLine34 = lib.mkOption { + default = { }; + type = lib.types.submoduleWith { + modules = [ + ({ options, ... }: { + options.submodDeclLine39 = lib.mkOption { }; + }) + { freeformType = with lib.types; lazyAttrsOf (uniq unspecified); } + ]; + }; + }; + + config = { + submoduleLine34.submodDeclLine39 = (options.submoduleLine34.type.getSubOptions [ ]).submodDeclLine39.declarationPositions; + }; +} diff --git a/lib/tests/modules/gvariant.nix b/lib/tests/modules/gvariant.nix index a792ebf85b7..ba452c0287a 100644 --- a/lib/tests/modules/gvariant.nix +++ b/lib/tests/modules/gvariant.nix @@ -1,93 +1,61 @@ { config, lib, ... }: -let inherit (lib) concatStringsSep mapAttrsToList mkMerge mkOption types gvariant; -in { - options.examples = mkOption { type = types.attrsOf gvariant; }; +{ + options = { + examples = lib.mkOption { type = lib.types.attrs; }; + assertion = lib.mkOption { type = lib.types.bool; }; + }; config = { - examples = with gvariant; - mkMerge [ - { bool = true; } - { bool = true; } - - { float = 3.14; } - - { int32 = mkInt32 (- 42); } - { int32 = mkInt32 (- 42); } - - { uint32 = mkUint32 42; } - { uint32 = mkUint32 42; } - - { int16 = mkInt16 (-42); } - { int16 = mkInt16 (-42); } - - { uint16 = mkUint16 42; } - { uint16 = mkUint16 42; } - - { int64 = mkInt64 (-42); } - { int64 = mkInt64 (-42); } - - { uint64 = mkUint64 42; } - { uint64 = mkUint64 42; } - - { array1 = [ "one" ]; } - { array1 = mkArray [ "two" ]; } - { array2 = mkArray [ (mkInt32 1) ]; } - { array2 = mkArray [ (nkUint32 2) ]; } - - { emptyArray1 = [ ]; } - { emptyArray2 = mkEmptyArray type.uint32; } - - { string = "foo"; } - { string = "foo"; } - { - escapedString = '' - '\ - ''; - } - - { tuple = mkTuple [ (mkInt32 1) [ "foo" ] ]; } - - { maybe1 = mkNothing type.string; } - { maybe2 = mkJust (mkUint32 4); } - - { variant1 = mkVariant "foo"; } - { variant2 = mkVariant 42; } - - { dictionaryEntry = mkDictionaryEntry (mkInt32 1) [ "foo" ]; } - ]; - - assertions = [ - { - assertion = ( - let - mkLine = n: v: "${n} = ${toString (gvariant.mkValue v)}"; - result = concatStringsSep "\n" (mapAttrsToList mkLine config.examples); - in - result + "\n" - ) == '' - array1 = @as ['one','two'] - array2 = @au [1,2] - bool = true - dictionaryEntry = @{ias} {1,@as ['foo']} - emptyArray1 = @as [] - emptyArray2 = @au [] - escapedString = '\'\\\n' - float = 3.140000 - int = -42 - int16 = @n -42 - int64 = @x -42 - maybe1 = @ms nothing - maybe2 = just @u 4 - string = 'foo' - tuple = @(ias) (1,@as ['foo']) - uint16 = @q 42 - uint32 = @u 42 - uint64 = @t 42 - variant1 = @v <'foo'> - variant2 = @v <42> - ''; - } - ]; + examples = with lib.gvariant; { + bool = true; + float = 3.14; + int32 = mkInt32 (- 42); + uint32 = mkUint32 42; + int16 = mkInt16 (-42); + uint16 = mkUint16 42; + int64 = mkInt64 (-42); + uint64 = mkUint64 42; + array1 = [ "one" ]; + array2 = mkArray [ (mkInt32 1) ]; + array3 = mkArray [ (mkUint32 2) ]; + emptyArray = mkEmptyArray type.uint32; + string = "foo"; + escapedString = '' + '\ + ''; + tuple = mkTuple [ (mkInt32 1) [ "foo" ] ]; + maybe1 = mkNothing type.string; + maybe2 = mkJust (mkUint32 4); + variant = mkVariant "foo"; + dictionaryEntry = mkDictionaryEntry (mkInt32 1) [ "foo" ]; + }; + + assertion = + let + mkLine = n: v: "${n} = ${toString (lib.gvariant.mkValue v)}"; + result = lib.concatStringsSep "\n" (lib.mapAttrsToList mkLine config.examples); + in + (result + "\n") == '' + array1 = @as ['one'] + array2 = @ai [1] + array3 = @au [@u 2] + bool = true + dictionaryEntry = @{ias} {1,@as ['foo']} + emptyArray = @au [] + escapedString = '\'\\\n' + float = 3.140000 + int16 = @n -42 + int32 = -42 + int64 = @x -42 + maybe1 = @ms nothing + maybe2 = just @u 4 + string = 'foo' + tuple = @(ias) (1,@as ['foo']) + uint16 = @q 42 + uint32 = @u 42 + uint64 = @t 42 + variant = <'foo'> + ''; }; } |