2 # nix-build -A tests.stdenv
11 # early enough not to rebuild gcc but late enough to have patchelf
12 earlyPkgs = stdenv.__bootPackages.stdenv.__bootPackages;
13 earlierPkgs = stdenv.__bootPackages.stdenv.__bootPackages.stdenv.__bootPackages.stdenv.__bootPackages.stdenv.__bootPackages;
14 # use a early stdenv so when hacking on stdenv this test can be run quickly
15 bootStdenv = stdenv.__bootPackages.stdenv.__bootPackages.stdenv.__bootPackages.stdenv.__bootPackages.stdenv;
16 pkgsStructured = import pkgs.path { config = { structuredAttrsByDefault = true; }; inherit (stdenv.hostPlatform) system; };
17 bootStdenvStructuredAttrsByDefault = pkgsStructured.stdenv.__bootPackages.stdenv.__bootPackages.stdenv.__bootPackages.stdenv.__bootPackages.stdenv;
19 runCommand = earlierPkgs.runCommand;
22 ccWrapperSubstitutionsTest = { name, stdenv', extraAttrs ? { } }:
24 stdenv'.cc.overrideAttrs (previousAttrs: ({
27 postFixup = previousAttrs.postFixup + ''
28 declare -p wrapperName
29 echo "env.wrapperName = $wrapperName"
30 [[ $wrapperName == "CC_WRAPPER" ]] || (echo "'\$wrapperName' was not 'CC_WRAPPER'" && false)
32 echo "env.suffixSalt = $suffixSalt"
33 [[ $suffixSalt == "${stdenv'.cc.suffixSalt}" ]] || (echo "'\$suffxSalt' was not '${stdenv'.cc.suffixSalt}'" && false)
35 grep -q "@out@" $out/bin/cc || echo "@out@ in $out/bin/cc was substituted"
36 grep -q "@suffixSalt@" $out/bin/cc && (echo "$out/bin/cc contains unsubstituted variables" && false)
42 testEnvAttrset = { name, stdenv', extraAttrs ? { } }:
47 string = "testing-string";
50 passAsFile = [ "buildCommand" ];
53 echo "env.string = $string"
54 [[ $string == "testing-string" ]] || (echo "'\$string' was not 'testing-string'" && false)
55 [[ "$(declare -p string)" == 'declare -x string="testing-string"' ]] || (echo "'\$string' was not exported" && false)
60 testPrependAndAppendToVar = { name, stdenv', extraAttrs ? { } }:
65 string = "testing-string";
68 passAsFile = [ "buildCommand" ] ++ lib.optionals (extraAttrs ? extraTest) [ "extraTest" ];
71 appendToVar string hello
72 # test that quoted strings work
73 prependToVar string "world"
76 declare -A associativeArray=(["X"]="Y")
77 [[ $(appendToVar associativeArray "fail" 2>&1) =~ "trying to use" ]] || (echo "prependToVar did not catch prepending associativeArray" && false)
78 [[ $(prependToVar associativeArray "fail" 2>&1) =~ "trying to use" ]] || (echo "prependToVar did not catch prepending associativeArray" && false)
80 [[ $string == "world testing-string hello" ]] || (echo "'\$string' was not 'world testing-string hello'" && false)
82 # test appending to a unset variable
83 appendToVar nonExistant created hello
84 typeset -p nonExistant
85 if [[ -n $__structuredAttrs ]]; then
86 [[ "''${nonExistant[@]}" == "created hello" ]]
88 # there's a extra " " in front here and a extra " " in the end of prependToVar
89 # shouldn't matter because these functions will mostly be used for $*Flags and the Flag variable will in most cases already exit
90 [[ "$nonExistant" == " created hello" ]]
102 # tests for hooks in `stdenv.defaultNativeBuildInputs`
103 hooks = lib.recurseIntoAttrs (import ./hooks.nix { stdenv = bootStdenv; pkgs = earlyPkgs; inherit lib; });
105 outputs-no-out = runCommand "outputs-no-out-assert" {
106 result = earlierPkgs.testers.testBuildFailure (bootStdenv.mkDerivation {
108 name = "outputs-no-out";
116 # Assumption: the first output* variable to be configured is
117 # _overrideFirst outputDev "dev" "out"
118 expectedMsg = "error: _assignFirst: could not find a non-empty variable whose name to assign to outputDev.\n The following variables were all unset or empty:\n dev out";
120 grep -F "$expectedMsg" $result/testBuildFailure.log >/dev/null
124 test-env-attrset = testEnvAttrset { name = "test-env-attrset"; stdenv' = bootStdenv; };
126 # Test compatibility with derivations using `env` as a regular variable.
127 test-env-derivation = bootStdenv.mkDerivation rec {
128 name = "test-env-derivation";
129 env = bootStdenv.mkDerivation {
137 passAsFile = [ "buildCommand" ];
140 [[ $env == "${env}" ]]
145 # Check that mkDerivation rejects MD5 hashes
146 rejectedHashes = lib.recurseIntoAttrs {
148 let drv = runCommand "md5 outputHash rejected" {
149 outputHash = "md5-fPt7dxVVP7ffY3MxkQdwVw==";
151 in assert !(builtins.tryEval drv).success; {};
154 test-inputDerivation = let
155 inherit (stdenv.mkDerivation {
156 dep1 = derivation { name = "dep1"; builder = "/bin/sh"; args = [ "-c" ": > $out" ]; system = builtins.currentSystem; };
157 dep2 = derivation { name = "dep2"; builder = "/bin/sh"; args = [ "-c" ": > $out" ]; system = builtins.currentSystem; };
158 passAsFile = [ "dep2" ];
161 runCommand "test-inputDerivation" {
162 exportReferencesGraph = [ "graph" inputDerivation ];
164 grep ${inputDerivation.dep1} graph
165 grep ${inputDerivation.dep2} graph
169 test-prepend-append-to-var = testPrependAndAppendToVar {
170 name = "test-prepend-append-to-var";
171 stdenv' = bootStdenv;
174 test-structured-env-attrset = testEnvAttrset {
175 name = "test-structured-env-attrset";
176 stdenv' = bootStdenv;
177 extraAttrs = { __structuredAttrs = true; };
180 test-cc-wrapper-substitutions = ccWrapperSubstitutionsTest {
181 name = "test-cc-wrapper-substitutions";
182 stdenv' = bootStdenv;
185 structuredAttrsByDefault = lib.recurseIntoAttrs {
187 hooks = lib.recurseIntoAttrs (import ./hooks.nix { stdenv = bootStdenvStructuredAttrsByDefault; pkgs = earlyPkgs; inherit lib; });
189 test-cc-wrapper-substitutions = ccWrapperSubstitutionsTest {
190 name = "test-cc-wrapper-substitutions-structuredAttrsByDefault";
191 stdenv' = bootStdenvStructuredAttrsByDefault;
194 test-structured-env-attrset = testEnvAttrset {
195 name = "test-structured-env-attrset-structuredAttrsByDefault";
196 stdenv' = bootStdenvStructuredAttrsByDefault;
199 test-prepend-append-to-var = testPrependAndAppendToVar {
200 name = "test-prepend-append-to-var-structuredAttrsByDefault";
201 stdenv' = bootStdenvStructuredAttrsByDefault;
203 # will be a bash indexed array in attrs.sh
204 # declare -a list=('a' 'b' )
205 # and a json array in attrs.json
208 # will be a bash associative array(dictionary) in attrs.sh
209 # declare -A array=(['a']='1' ['b']='2' )
210 # and a json object in attrs.json
211 # {"array":{"a":"1","b":"2"}
212 array = { a = "1"; b = "2"; };
218 [[ "''${array[c]}" == "3" ]] || (echo "c element of '\$array' was not '3'" && false)
221 prependToVar list hello
222 # test that quoted strings work
223 appendToVar list "world"
226 [[ "''${list[0]}" == "hello" ]] || (echo "first element of '\$list' was not 'hello'" && false)
227 [[ "''${list[1]}" == "a" ]] || (echo "first element of '\$list' was not 'a'" && false)
228 [[ "''${list[-1]}" == "world" ]] || (echo "last element of '\$list' was not 'world'" && false)
233 test-golden-example-structuredAttrs =
235 goldenSh = earlyPkgs.writeText "goldenSh" ''
236 declare -A EXAMPLE_ATTRS=(['foo']='bar' )
237 declare EXAMPLE_BOOL_FALSE=
238 declare EXAMPLE_BOOL_TRUE=1
239 declare EXAMPLE_INT=123
240 declare EXAMPLE_INT_NEG=-123
241 declare -a EXAMPLE_LIST=('foo' 'bar' )
242 declare EXAMPLE_STR='foo bar'
244 goldenJson = earlyPkgs.writeText "goldenSh" ''
249 "EXAMPLE_BOOL_FALSE": false,
250 "EXAMPLE_BOOL_TRUE": true,
252 "EXAMPLE_INT_NEG": -123,
257 "EXAMPLE_NESTED_ATTRS": {
262 "EXAMPLE_NESTED_LIST": [
271 "EXAMPLE_STR": "foo bar"
275 bootStdenvStructuredAttrsByDefault.mkDerivation {
276 name = "test-golden-example-structuredAttrsByDefault";
277 nativeBuildInputs = [ earlyPkgs.jq ];
279 EXAMPLE_BOOL_TRUE = true;
280 EXAMPLE_BOOL_FALSE = false;
282 EXAMPLE_INT_NEG = -123;
283 EXAMPLE_STR = "foo bar";
284 EXAMPLE_LIST = [ "foo" "bar" ];
285 EXAMPLE_NESTED_LIST = [ [ "foo" "bar" ] [ "baz" ] ];
286 EXAMPLE_ATTRS = { foo = "bar"; };
287 EXAMPLE_NESTED_ATTRS = { foo.bar = "baz"; };
294 cat $NIX_ATTRS_SH_FILE | grep "EXAMPLE" | grep -v -E 'installPhase|jq' > $out/sh
295 jq 'with_entries(select(.key|match("EXAMPLE")))' $NIX_ATTRS_JSON_FILE > $out/json
296 diff $out/sh $goldenSh
297 diff $out/json $goldenJson