Merge pull request #268619 from tweag/lib-descriptions
[NixPkgs.git] / pkgs / test / stdenv / default.nix
blob3882eb2b625c5a96a459d4e4e76ec63809d5fabb
1 # To run these tests:
2 # nix-build -A tests.stdenv
4 { stdenv
5 , pkgs
6 , lib
7 , testers
8 }:
10 let
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: ({
25       inherit name;
27       postFixup = previousAttrs.postFixup + ''
28         declare -p wrapperName
29         echo "env.wrapperName = $wrapperName"
30         [[ $wrapperName == "CC_WRAPPER" ]] || (echo "'\$wrapperName' was not 'CC_WRAPPER'" && false)
31         declare -p suffixSalt
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)
38         touch $out
39       '';
40     } // extraAttrs));
42   testEnvAttrset = { name, stdenv', extraAttrs ? { } }:
43     stdenv'.mkDerivation
44       ({
45         inherit name;
46         env = {
47           string = "testing-string";
48         };
50         passAsFile = [ "buildCommand" ];
51         buildCommand = ''
52           declare -p string
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)
56           touch $out
57         '';
58       } // extraAttrs);
60   testPrependAndAppendToVar = { name, stdenv', extraAttrs ? { } }:
61     stdenv'.mkDerivation
62       ({
63         inherit name;
64         env = {
65           string = "testing-string";
66         };
68         passAsFile = [ "buildCommand" ] ++ lib.optionals (extraAttrs ? extraTest) [ "extraTest" ];
69         buildCommand = ''
70           declare -p string
71           appendToVar string hello
72           # test that quoted strings work
73           prependToVar string "world"
74           declare -p string
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" ]]
87           else
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" ]]
91           fi
93           eval "$extraTest"
95           touch $out
96         '';
97       } // extraAttrs);
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 {
107       NIX_DEBUG = 1;
108       name = "outputs-no-out";
109       outputs = ["foo"];
110       buildPhase = ":";
111       installPhase = ''
112         touch $foo
113       '';
114     });
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";
119   } ''
120     grep -F "$expectedMsg" $result/testBuildFailure.log >/dev/null
121     touch $out
122   '';
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 {
130       name = "foo";
131       buildCommand = ''
132         mkdir "$out"
133         touch "$out/bar"
134       '';
135     };
137     passAsFile = [ "buildCommand" ];
138     buildCommand = ''
139       declare -p env
140       [[ $env == "${env}" ]]
141       touch "$out"
142     '';
143   };
145   # Check that mkDerivation rejects MD5 hashes
146   rejectedHashes = lib.recurseIntoAttrs {
147     md5 =
148       let drv = runCommand "md5 outputHash rejected" {
149         outputHash = "md5-fPt7dxVVP7ffY3MxkQdwVw==";
150       } "true";
151       in assert !(builtins.tryEval drv).success; {};
152   };
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" ];
159     }) inputDerivation;
160   in
161     runCommand "test-inputDerivation" {
162       exportReferencesGraph = [ "graph" inputDerivation ];
163     } ''
164       grep ${inputDerivation.dep1} graph
165       grep ${inputDerivation.dep2} graph
166       touch $out
167     '';
169   test-prepend-append-to-var = testPrependAndAppendToVar {
170     name = "test-prepend-append-to-var";
171     stdenv' = bootStdenv;
172   };
174   test-structured-env-attrset = testEnvAttrset {
175     name = "test-structured-env-attrset";
176     stdenv' = bootStdenv;
177     extraAttrs = { __structuredAttrs = true; };
178   };
180   test-cc-wrapper-substitutions = ccWrapperSubstitutionsTest {
181     name = "test-cc-wrapper-substitutions";
182     stdenv' = bootStdenv;
183   };
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;
192     };
194     test-structured-env-attrset = testEnvAttrset {
195       name = "test-structured-env-attrset-structuredAttrsByDefault";
196       stdenv' = bootStdenvStructuredAttrsByDefault;
197     };
199     test-prepend-append-to-var = testPrependAndAppendToVar {
200       name = "test-prepend-append-to-var-structuredAttrsByDefault";
201       stdenv' = bootStdenvStructuredAttrsByDefault;
202       extraAttrs = {
203         # will be a bash indexed array in attrs.sh
204         # declare -a list=('a' 'b' )
205         # and a json array in attrs.json
206         # "list":["a","b"]
207         list = [ "a" "b" ];
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"; };
213         extraTest = ''
214           declare -p array
215           array+=(["c"]="3")
216           declare -p array
218           [[ "''${array[c]}" == "3" ]] || (echo "c element of '\$array' was not '3'" && false)
220           declare -p list
221           prependToVar list hello
222           # test that quoted strings work
223           appendToVar list "world"
224           declare -p list
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)
229         '';
230       };
231     };
233     test-golden-example-structuredAttrs =
234       let
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'
243         '';
244         goldenJson = earlyPkgs.writeText "goldenSh" ''
245           {
246             "EXAMPLE_ATTRS": {
247               "foo": "bar"
248             },
249             "EXAMPLE_BOOL_FALSE": false,
250             "EXAMPLE_BOOL_TRUE": true,
251             "EXAMPLE_INT": 123,
252             "EXAMPLE_INT_NEG": -123,
253             "EXAMPLE_LIST": [
254               "foo",
255               "bar"
256             ],
257             "EXAMPLE_NESTED_ATTRS": {
258               "foo": {
259                 "bar": "baz"
260               }
261             },
262             "EXAMPLE_NESTED_LIST": [
263               [
264                 "foo",
265                 "bar"
266               ],
267               [
268                 "baz"
269               ]
270             ],
271             "EXAMPLE_STR": "foo bar"
272           }
273         '';
274       in
275       bootStdenvStructuredAttrsByDefault.mkDerivation {
276         name = "test-golden-example-structuredAttrsByDefault";
277         nativeBuildInputs = [ earlyPkgs.jq ];
279         EXAMPLE_BOOL_TRUE = true;
280         EXAMPLE_BOOL_FALSE = false;
281         EXAMPLE_INT = 123;
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"; };
289         inherit goldenSh;
290         inherit goldenJson;
292         buildCommand = ''
293           mkdir -p $out
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
298         '';
299       };
301   };