1# Run with:
2# cd nixpkgs
3# ./lib/tests/modules.sh
4{ lib, ... }:
5let
6 inherit (builtins)
7 storeDir
8 ;
9 inherit (lib)
10 types
11 mkOption
12 ;
13
14in
15{
16 options = {
17 pathInStore = mkOption { type = types.lazyAttrsOf types.pathInStore; };
18 assertions = mkOption { };
19 };
20 config = {
21 pathInStore.ok1 = "${storeDir}/0lz9p8xhf89kb1c1kk6jxrzskaiygnlh-bash-5.2-p15.drv";
22 pathInStore.ok2 = "${storeDir}/0fb3ykw9r5hpayd05sr0cizwadzq1d8q-bash-5.2-p15";
23 pathInStore.ok3 = "${storeDir}/0fb3ykw9r5hpayd05sr0cizwadzq1d8q-bash-5.2-p15/bin/bash";
24 pathInStore.bad1 = "";
25 pathInStore.bad2 = "${storeDir}";
26 pathInStore.bad3 = "${storeDir}/";
27 pathInStore.bad4 = "${storeDir}/.links"; # technically true, but not reasonable
28 pathInStore.bad5 = "/foo/bar";
29
30 assertions =
31 with lib.types;
32
33 assert str.description == "string";
34 assert int.description == "signed integer";
35 assert (attrsOf str).description == "attribute set of string";
36 assert (attrsOf (attrsOf str)).description == "attribute set of attribute set of string";
37 assert
38 (oneOf [
39 (attrsOf str)
40 int
41 bool
42 ]).description == "(attribute set of string) or signed integer or boolean";
43 assert
44 (enum [
45 true
46 null
47 false
48 ]).description == "one of true, <null>, false";
49 assert
50 (submodule { freeformType = attrsOf str; }).description
51 == "open submodule of attribute set of string";
52 # Comprehensive type constructor description tests
53 assert (attrsOf int).description == "attribute set of signed integer";
54 assert (attrsOf bool).description == "attribute set of boolean";
55 assert (attrsOf (either int str)).description == "attribute set of (signed integer or string)";
56 assert (attrsOf (nullOr str)).description == "attribute set of (null or string)";
57 assert (attrsOf (listOf str)).description == "attribute set of list of string";
58 assert (attrsOf (attrsOf int)).description == "attribute set of attribute set of signed integer";
59 assert (attrsOf ints.positive).description == "attribute set of (positive integer, meaning >0)";
60
61 # Test type constructors as attrsOf item types
62 assert
63 (attrsOf (enum [
64 "a"
65 "b"
66 ])).description == "attribute set of (one of \"a\", \"b\")";
67 assert
68 (attrsOf (strMatching "[0-9]+")).description
69 == "attribute set of string matching the pattern [0-9]+";
70 assert (attrsOf (nonEmptyListOf str)).description == "attribute set of non-empty (list of string)"; # TODO: reduce parentheses?
71 assert
72 (attrsOf (oneOf [
73 str
74 int
75 ])).description == "attribute set of (string or signed integer)";
76 assert
77 (attrsOf (coercedTo str abort int)).description
78 == "attribute set of (signed integer or string convertible to it)";
79 assert
80 (attrsOf (functionTo str)).description == "attribute set of function that evaluates to a(n) string";
81 assert
82 (attrsOf (passwdEntry str)).description
83 == "attribute set of (string, not containing newlines or colons)";
84 assert (attrsOf (uniq str)).description == "attribute set of string";
85 assert (attrsOf (unique { message = "test"; } str)).description == "attribute set of string";
86 assert
87 (attrsOf (pathWith {
88 absolute = true;
89 })).description == "attribute set of absolute path";
90 assert
91 (attrsOf (separatedString ",")).description == "attribute set of strings concatenated with \",\"";
92 assert (attrsOf (loaOf str)).description == "attribute set of attribute set of string";
93 assert (attrsOf (lazyAttrsOf str)).description == "attribute set of lazy attribute set of string";
94 assert (attrsOf (submodule { })).description == "attribute set of (submodule)"; # FIXME: extra parentheses around submodule
95 assert
96 (attrsOf (submodule {
97 freeformType = attrsOf str;
98 })).description == "attribute set of (open submodule of attribute set of string)";
99 assert (attrsOf (addCheck str (x: true))).description == "attribute set of string";
100 assert (attrsOf (enum [ ])).description == "attribute set of impossible (empty enum)";
101 assert
102 (attrsOf ints.u32).description
103 == "attribute set of 32 bit unsigned integer; between 0 and 4294967295 (both inclusive)";
104 assert
105 (attrsOf numbers.positive).description
106 == "attribute set of (positive integer or floating point number, meaning >0)";
107
108 assert (attrsWith { elemType = str; }).description == "attribute set of string";
109 assert (attrsWith { elemType = int; }).description == "attribute set of signed integer";
110 assert (attrsWith { elemType = bool; }).description == "attribute set of boolean";
111 assert
112 (attrsWith { elemType = either int str; }).description
113 == "attribute set of (signed integer or string)";
114 assert (attrsWith { elemType = nullOr str; }).description == "attribute set of (null or string)";
115 assert (attrsWith { elemType = listOf str; }).description == "attribute set of list of string";
116 assert
117 (attrsWith { elemType = attrsOf int; }).description
118 == "attribute set of attribute set of signed integer";
119 assert
120 (attrsWith { elemType = ints.positive; }).description
121 == "attribute set of (positive integer, meaning >0)";
122 assert
123 (attrsWith {
124 elemType = str;
125 lazy = true;
126 }).description == "lazy attribute set of string";
127 # Additional attrsWith tests are covered above
128 assert
129 (attrsWith {
130 elemType = str;
131 lazy = false;
132 }).description == "attribute set of string";
133 assert (coercedTo str abort int).description == "signed integer or string convertible to it";
134 assert (coercedTo int abort str).description == "string or signed integer convertible to it";
135 assert (coercedTo bool abort str).description == "string or boolean convertible to it";
136 assert
137 (coercedTo (either int str) abort str).description
138 == "string or (signed integer or string) convertible to it";
139 assert
140 (coercedTo (nullOr str) abort str).description == "string or (null or string) convertible to it";
141 assert
142 (coercedTo (listOf str) abort str).description == "string or (list of string) convertible to it";
143 assert
144 (coercedTo (attrsOf int) abort str).description
145 == "string or (attribute set of signed integer) convertible to it";
146 assert
147 (coercedTo ints.positive abort str).description
148 == "string or (positive integer, meaning >0) convertible to it";
149 assert
150 (coercedTo (listOf str) abort (attrsOf str)).description
151 == "(attribute set of string) or (list of string) convertible to it";
152 # Additional coercedTo tests covered above
153 assert (either str int).description == "string or signed integer";
154 assert (either int str).description == "signed integer or string";
155 assert (either bool str).description == "boolean or string";
156 assert (either (either int str) bool).description == "signed integer or string or boolean";
157 assert (either (nullOr str) int).description == "null or string or signed integer";
158 assert (either (listOf str) int).description == "(list of string) or signed integer";
159 assert (either (attrsOf int) str).description == "(attribute set of signed integer) or string";
160 assert (either ints.positive str).description == "positive integer, meaning >0, or string";
161 assert (either (either bool str) int).description == "boolean or string or signed integer";
162
163 # Test type constructors as either bool t
164 assert (either bool str).description == "boolean or string";
165 assert (either bool int).description == "boolean or signed integer";
166 assert
167 (either bool (enum [
168 "a"
169 "b"
170 ])).description == "boolean or one of \"a\", \"b\"";
171 assert
172 (either bool (strMatching "[0-9]+")).description == "boolean or string matching the pattern [0-9]+";
173 assert (either bool (nonEmptyListOf str)).description == "boolean or non-empty (list of string)"; # TODO: reduce parentheses?
174 assert
175 (either bool (oneOf [
176 str
177 int
178 ])).description == "boolean or string or signed integer";
179 assert
180 (either bool (coercedTo str abort int)).description
181 == "boolean or (signed integer or string convertible to it)";
182 assert
183 (either bool (functionTo str)).description == "boolean or function that evaluates to a(n) string";
184 assert
185 (either bool (passwdEntry str)).description
186 == "boolean or (string, not containing newlines or colons)";
187 assert (either bool (uniq str)).description == "boolean or string";
188 assert (either bool (unique { message = "test"; } str)).description == "boolean or string";
189 assert
190 (either bool (pathWith {
191 absolute = true;
192 })).description == "boolean or absolute path";
193 assert
194 (either bool (separatedString ",")).description == "boolean or strings concatenated with \",\"";
195 assert (either bool (attrsOf str)).description == "boolean or attribute set of string";
196 assert (either bool (listOf str)).description == "boolean or list of string";
197 assert (either bool (nullOr str)).description == "boolean or null or string";
198 assert (either bool (lazyAttrsOf str)).description == "boolean or lazy attribute set of string";
199 assert (either bool (submodule { })).description == "boolean or (submodule)"; # FIXME: extra parentheses around submodule
200 assert (either bool ints.positive).description == "boolean or (positive integer, meaning >0)";
201 assert
202 (either bool numbers.positive).description
203 == "boolean or (positive integer or floating point number, meaning >0)";
204
205 # Test type constructors as either t bool
206 assert (either str bool).description == "string or boolean";
207 assert (either int bool).description == "signed integer or boolean";
208 assert
209 (either (enum [
210 "a"
211 "b"
212 ]) bool).description == "one of \"a\", \"b\" or boolean";
213 assert
214 (either (strMatching "[0-9]+") bool).description == "string matching the pattern [0-9]+ or boolean";
215 assert (either (nonEmptyListOf str) bool).description == "(non-empty (list of string)) or boolean"; # TODO: reduce parentheses?
216 assert
217 (either (oneOf [
218 str
219 int
220 ]) bool).description == "string or signed integer or boolean";
221 assert
222 (either (coercedTo str abort int) bool).description
223 == "(signed integer or string convertible to it) or boolean";
224 assert
225 (either (functionTo str) bool).description == "(function that evaluates to a(n) string) or boolean";
226 assert
227 (either (passwdEntry str) bool).description
228 == "string, not containing newlines or colons, or boolean";
229 assert (either (uniq str) bool).description == "string or boolean";
230 assert (either (unique { message = "test"; } str) bool).description == "string or boolean";
231 assert (either (pathWith { absolute = true; }) bool).description == "absolute path or boolean";
232 assert
233 (either (separatedString ",") bool).description == "strings concatenated with \",\" or boolean";
234 assert (either (attrsOf str) bool).description == "(attribute set of string) or boolean";
235 assert (either (listOf str) bool).description == "(list of string) or boolean";
236 assert (either (nullOr str) bool).description == "null or string or boolean";
237 assert (either (lazyAttrsOf str) bool).description == "(lazy attribute set of string) or boolean";
238 assert (either (submodule { }) bool).description == "(submodule) or boolean"; # FIXME: extra parentheses around submodule
239 assert (either ints.positive bool).description == "positive integer, meaning >0, or boolean";
240 assert
241 (either numbers.positive bool).description
242 == "positive integer or floating point number, meaning >0, or boolean";
243
244 # Additional either tests covered above";
245 assert (enum [ ]).description == "impossible (empty enum)";
246 assert (enum [ "single" ]).description == "value \"single\" (singular enum)";
247 assert
248 (enum [
249 "a"
250 "b"
251 ]).description == "one of \"a\", \"b\"";
252 assert
253 (enum [
254 true
255 false
256 ]).description == "one of true, false";
257 assert
258 (enum [
259 1
260 2
261 3
262 ]).description == "one of 1, 2, 3";
263 assert (enum [ null ]).description == "value <null> (singular enum)";
264 assert (functionTo str).description == "function that evaluates to a(n) string";
265 assert (functionTo int).description == "function that evaluates to a(n) signed integer";
266 assert (functionTo bool).description == "function that evaluates to a(n) boolean";
267 assert
268 (functionTo (either int str)).description
269 == "function that evaluates to a(n) (signed integer or string)";
270 assert (functionTo (nullOr str)).description == "function that evaluates to a(n) (null or string)";
271 assert (functionTo (listOf str)).description == "function that evaluates to a(n) list of string";
272 assert
273 (functionTo (attrsOf int)).description
274 == "function that evaluates to a(n) attribute set of signed integer";
275 assert
276 (functionTo ints.positive).description
277 == "function that evaluates to a(n) (positive integer, meaning >0)";
278 assert (lazyAttrsOf str).description == "lazy attribute set of string";
279 assert (lazyAttrsOf int).description == "lazy attribute set of signed integer";
280 assert (lazyAttrsOf bool).description == "lazy attribute set of boolean";
281 assert
282 (lazyAttrsOf (either int str)).description == "lazy attribute set of (signed integer or string)";
283 assert (lazyAttrsOf (nullOr str)).description == "lazy attribute set of (null or string)";
284 assert (lazyAttrsOf (listOf str)).description == "lazy attribute set of list of string";
285 assert
286 (lazyAttrsOf (attrsOf int)).description == "lazy attribute set of attribute set of signed integer";
287 assert
288 (lazyAttrsOf ints.positive).description == "lazy attribute set of (positive integer, meaning >0)";
289 assert (listOf str).description == "list of string";
290 assert (listOf int).description == "list of signed integer";
291 assert (listOf bool).description == "list of boolean";
292 assert (listOf (either int str)).description == "list of (signed integer or string)";
293 assert (listOf (nullOr str)).description == "list of (null or string)";
294 assert (listOf (listOf str)).description == "list of list of string";
295 assert (listOf (attrsOf int)).description == "list of attribute set of signed integer";
296 assert (listOf ints.positive).description == "list of (positive integer, meaning >0)";
297 assert (loaOf str).description == "attribute set of string";
298 assert (loaOf int).description == "attribute set of signed integer";
299 assert (loaOf bool).description == "attribute set of boolean";
300 assert (loaOf (either int str)).description == "attribute set of (signed integer or string)";
301 assert (loaOf (nullOr str)).description == "attribute set of (null or string)";
302 assert (loaOf (listOf str)).description == "attribute set of list of string";
303 assert (loaOf (attrsOf int)).description == "attribute set of attribute set of signed integer";
304 assert (loaOf ints.positive).description == "attribute set of (positive integer, meaning >0)";
305 assert (nonEmptyListOf str).description == "non-empty (list of string)"; # TODO: reduce parentheses?
306 assert (nonEmptyListOf int).description == "non-empty (list of signed integer)"; # TODO: reduce parentheses?
307 assert (nonEmptyListOf bool).description == "non-empty (list of boolean)"; # TODO: reduce parentheses?
308 assert
309 (nonEmptyListOf (either int str)).description == "non-empty (list of (signed integer or string))"; # TODO: reduce parentheses?
310 assert (nonEmptyListOf (nullOr str)).description == "non-empty (list of (null or string))"; # TODO: reduce parentheses?
311 assert (nonEmptyListOf (listOf str)).description == "non-empty (list of list of string)"; # TODO: reduce parentheses?
312 assert
313 (nonEmptyListOf (attrsOf int)).description
314 == "non-empty (list of attribute set of signed integer)"; # TODO: reduce parentheses?
315 assert
316 (nonEmptyListOf ints.positive).description == "non-empty (list of (positive integer, meaning >0))"; # TODO: reduce parentheses?
317 assert (nullOr str).description == "null or string";
318 assert (nullOr int).description == "null or signed integer";
319 assert (nullOr bool).description == "null or boolean";
320 assert (nullOr (either int str)).description == "null or signed integer or string";
321 assert (nullOr (nullOr str)).description == "null or null or string";
322 assert (nullOr (listOf str)).description == "null or (list of string)";
323 assert (nullOr (attrsOf int)).description == "null or (attribute set of signed integer)";
324 assert (nullOr ints.positive).description == "null or (positive integer, meaning >0)";
325 assert (oneOf [ str ]).description == "string";
326 assert (oneOf [ int ]).description == "signed integer";
327 assert (oneOf [ bool ]).description == "boolean";
328 assert (oneOf [ (either int str) ]).description == "signed integer or string";
329 assert (oneOf [ (nullOr str) ]).description == "null or string";
330 assert (oneOf [ (listOf str) ]).description == "list of string";
331 assert (oneOf [ (attrsOf int) ]).description == "attribute set of signed integer";
332 assert (oneOf [ ints.positive ]).description == "positive integer, meaning >0";
333 assert
334 (oneOf [
335 str
336 int
337 ]).description == "string or signed integer";
338 assert
339 (oneOf [
340 str
341 int
342 bool
343 ]).description == "string or signed integer or boolean";
344 assert
345 (oneOf [
346 (listOf str)
347 int
348 bool
349 ]).description == "(list of string) or signed integer or boolean";
350 assert
351 (oneOf [
352 ints.positive
353 str
354 ]).description == "positive integer, meaning >0, or string";
355 assert (passwdEntry str).description == "string, not containing newlines or colons";
356 assert (passwdEntry int).description == "signed integer, not containing newlines or colons";
357 assert (passwdEntry bool).description == "boolean, not containing newlines or colons";
358 assert
359 (passwdEntry (either int str)).description
360 == "(signed integer or string), not containing newlines or colons";
361 assert
362 (passwdEntry (nullOr str)).description == "(null or string), not containing newlines or colons";
363 assert
364 (passwdEntry (listOf str)).description == "(list of string), not containing newlines or colons";
365 assert
366 (passwdEntry (attrsOf int)).description
367 == "(attribute set of signed integer), not containing newlines or colons";
368 assert
369 (passwdEntry ints.positive).description
370 == "(positive integer, meaning >0), not containing newlines or colons";
371 assert (pathWith { }).description == "path";
372 assert (pathWith { absolute = true; }).description == "absolute path";
373 assert (pathWith { inStore = true; }).description == "path in the Nix store";
374 assert
375 (pathWith {
376 absolute = true;
377 inStore = true;
378 }).description == "absolute path in the Nix store";
379 assert (pathWith { absolute = false; }).description == "relative path";
380 assert (pathWith { absolute = null; }).description == "path";
381 assert (pathWith { inStore = false; }).description == "path not in the Nix store";
382 assert (pathWith { inStore = null; }).description == "path";
383 assert (separatedString "").description == "Concatenated string";
384 assert (separatedString ",").description == "strings concatenated with \",\"";
385 assert (separatedString "\n").description == ''strings concatenated with "\n"'';
386 assert (separatedString ":").description == "strings concatenated with \":\"";
387 assert (strMatching "[a-z]+").description == "string matching the pattern [a-z]+";
388 assert
389 (strMatching "[0-9]{3}-[0-9]{2}-[0-9]{4}").description
390 == "string matching the pattern [0-9]{3}-[0-9]{2}-[0-9]{4}";
391 assert (strMatching ".*\\.txt").description == "string matching the pattern .*\\.txt";
392 assert
393 (submodule { freeformType = attrsOf int; }).description
394 == "open submodule of attribute set of signed integer";
395 assert
396 (submodule { freeformType = attrsOf bool; }).description
397 == "open submodule of attribute set of boolean";
398 assert
399 (submodule { freeformType = attrsOf (either int str); }).description
400 == "open submodule of attribute set of (signed integer or string)";
401 assert
402 (submodule { freeformType = attrsOf (nullOr str); }).description
403 == "open submodule of attribute set of (null or string)";
404 assert (submodule { freeformType = listOf str; }).description == "open submodule of list of string";
405 assert
406 (submodule { freeformType = attrsOf ints.positive; }).description
407 == "open submodule of attribute set of (positive integer, meaning >0)";
408 assert
409 (submodule { freeformType = lazyAttrsOf str; }).description
410 == "open submodule of lazy attribute set of string";
411 assert
412 (submodule { freeformType = lazyAttrsOf int; }).description
413 == "open submodule of lazy attribute set of signed integer";
414 assert
415 (submodule { freeformType = lazyAttrsOf (listOf str); }).description
416 == "open submodule of lazy attribute set of list of string";
417 assert (submodule { }).description == "submodule";
418 assert (submodule [ { options.foo = mkOption { type = str; }; } ]).description == "submodule";
419 assert (submodule [ ]).description == "submodule";
420 assert
421 (submodule [ { freeformType = attrsOf str; } ]).description
422 == "open submodule of attribute set of string";
423 assert
424 (submodule [ { freeformType = lazyAttrsOf str; } ]).description
425 == "open submodule of lazy attribute set of string";
426 assert
427 (submodule [ { freeformType = lazyAttrsOf int; } ]).description
428 == "open submodule of lazy attribute set of signed integer";
429 assert
430 (submodule [ { freeformType = lazyAttrsOf (either int str); } ]).description
431 == "open submodule of lazy attribute set of (signed integer or string)";
432 assert
433 (submoduleWith { modules = [ { freeformType = attrsOf str; } ]; }).description
434 == "open submodule of attribute set of string";
435 assert
436 (submoduleWith { modules = [ { freeformType = attrsOf int; } ]; }).description
437 == "open submodule of attribute set of signed integer";
438 assert
439 (submoduleWith { modules = [ { freeformType = attrsOf bool; } ]; }).description
440 == "open submodule of attribute set of boolean";
441 assert
442 (submoduleWith { modules = [ { freeformType = attrsOf (either int str); } ]; }).description
443 == "open submodule of attribute set of (signed integer or string)";
444 assert
445 (submoduleWith { modules = [ { freeformType = attrsOf (nullOr str); } ]; }).description
446 == "open submodule of attribute set of (null or string)";
447 assert
448 (submoduleWith { modules = [ { freeformType = listOf str; } ]; }).description
449 == "open submodule of list of string";
450 assert
451 (submoduleWith { modules = [ { freeformType = lazyAttrsOf str; } ]; }).description
452 == "open submodule of lazy attribute set of string";
453 assert
454 (submoduleWith { modules = [ { freeformType = lazyAttrsOf int; } ]; }).description
455 == "open submodule of lazy attribute set of signed integer";
456 assert
457 (submoduleWith { modules = [ { freeformType = lazyAttrsOf (either int str); } ]; }).description
458 == "open submodule of lazy attribute set of (signed integer or string)";
459 assert
460 (submoduleWith { modules = [ { freeformType = attrsOf ints.positive; } ]; }).description
461 == "open submodule of attribute set of (positive integer, meaning >0)";
462 assert (submoduleWith { modules = [ ]; }).description == "submodule";
463 assert
464 (submoduleWith {
465 modules = [ ];
466 description = "custom";
467 }).description == "custom";
468 assert
469 (submoduleWith {
470 modules = [ ];
471 description = "custom module";
472 }).description == "custom module";
473 assert (uniq str).description == "string";
474 assert (uniq (either int str)).description == "signed integer or string";
475 assert (uniq (listOf str)).description == "list of string";
476 assert (unique { message = "test"; } str).description == "string";
477 assert (unique { message = ""; } (either int str)).description == "signed integer or string";
478 assert (unique { message = "custom"; } (listOf str)).description == "list of string";
479 assert (unique { message = "test"; } (either int str)).description == "signed integer or string";
480 assert (unique { message = "test"; } (listOf str)).description == "list of string";
481 # done
482 "ok";
483 };
484}