chromium,chromedriver: 129.0.6668.91 -> 129.0.6668.100
[NixPkgs.git] / pkgs / pkgs-lib / tests / formats.nix
blob86a35c6bf26dc34759b7e73a4f8802a6109932f2
1 { pkgs }:
2 let
3   inherit (pkgs) lib formats;
5   # merging allows us to add metadata to the input
6   # this makes error messages more readable during development
7   mergeInput = name: format: input:
8     format.type.merge [] [
9       {
10         # explicitly throw here to trigger the code path that prints the error message for users
11         value = lib.throwIfNot (format.type.check input) (builtins.trace input "definition does not pass the type's check function") input;
12         # inject the name
13         file = "format-test-${name}";
14       }
15     ];
17   # run a diff between expected and real output
18   runDiff = name: drv: expected: pkgs.runCommand name {
19     passAsFile = ["expected"];
20     inherit expected drv;
21   } ''
22     if diff -u "$expectedPath" "$drv"; then
23       touch "$out"
24     else
25       echo
26       echo "Got different values than expected; diff above."
27       exit 1
28     fi
29   '';
31   # use this to check for proper serialization
32   # in practice you do not have to supply the name parameter as this one will be added by runBuildTests
33   shouldPass = { format, input, expected }: name: {
34     name = "pass-${name}";
35     path = runDiff "test-format-${name}" (format.generate "test-format-${name}" (mergeInput name format input)) expected;
36   };
38   # use this function to assert that a type check must fail
39   # in practice you do not have to supply the name parameter as this one will be added by runBuildTests
40   # note that as per 352e7d330a26 and 352e7d330a26 the type checking of attrsets and lists are not strict
41   # this means that the code below needs to properly merge the module type definition and also evaluate the (lazy) return value
42   shouldFail = { format, input }: name:
43     let
44       # trigger a deep type check using the module system
45       typeCheck = lib.modules.mergeDefinitions
46         [ "tests" name ]
47         format.type
48         [
49           {
50             file = "format-test-${name}";
51             value = input;
52           }
53         ];
54       # actually use the return value to trigger the evaluation
55       eval = builtins.tryEval (typeCheck.mergedValue == input);
56       # the check failing is what we want, so don't do anything here
57       typeFails = pkgs.runCommand "test-format-${name}" {} "touch $out";
58       # bail with some verbose information in case the type check passes
59       typeSucceeds = pkgs.runCommand "test-format-${name}" {
60           passAsFile = [ "inputText" ];
61           testName = name;
62           # this will fail if the input contains functions as values
63           # however that should get caught by the type check already
64           inputText = builtins.toJSON input;
65         }
66         ''
67           echo "Type check $testName passed when it shouldn't."
68           echo "The following data was used as input:"
69           echo
70           cat "$inputTextPath"
71           exit 1
72         '';
73     in {
74       name = "fail-${name}";
75       path = if eval.success then typeSucceeds else typeFails;
76     };
78   # this function creates a linkFarm for all the tests below such that the results are easily visible in the filesystem after a build
79   # the parameters are an attrset of name: test pairs where the name is automatically passed to the test
80   # the test therefore is an invocation of ShouldPass or shouldFail with the attrset parameters but *not* the name (which this adds for convenience)
81   runBuildTests = (lib.flip lib.pipe) [
82     (lib.mapAttrsToList (name: value: value name))
83     (pkgs.linkFarm "nixpkgs-pkgs-lib-format-tests")
84   ];
86 in runBuildTests {
88   jsonAtoms = shouldPass {
89     format = formats.json {};
90     input = {
91       null = null;
92       false = false;
93       true = true;
94       int = 10;
95       float = 3.141;
96       str = "foo";
97       attrs.foo = null;
98       list = [ null null ];
99       path = ./formats.nix;
100     };
101     expected = ''
102       {
103         "attrs": {
104           "foo": null
105         },
106         "false": false,
107         "float": 3.141,
108         "int": 10,
109         "list": [
110           null,
111           null
112         ],
113         "null": null,
114         "path": "${./formats.nix}",
115         "str": "foo",
116         "true": true
117       }
118     '';
119   };
121   yamlAtoms = shouldPass {
122     format = formats.yaml {};
123     input = {
124       null = null;
125       false = false;
126       true = true;
127       float = 3.141;
128       str = "foo";
129       attrs.foo = null;
130       list = [ null null ];
131       path = ./formats.nix;
132     };
133     expected = ''
134       attrs:
135         foo: null
136       'false': false
137       float: 3.141
138       list:
139       - null
140       - null
141       'null': null
142       path: ${./formats.nix}
143       str: foo
144       'true': true
145     '';
146   };
148   iniAtoms = shouldPass {
149     format = formats.ini {};
150     input = {
151       foo = {
152         bool = true;
153         int = 10;
154         float = 3.141;
155         str = "string";
156       };
157     };
158     expected = ''
159       [foo]
160       bool=true
161       float=3.141000
162       int=10
163       str=string
164     '';
165   };
167   iniInvalidAtom = shouldFail {
168     format = formats.ini {};
169     input = {
170       foo = {
171         function = _: 1;
172       };
173     };
174   };
176   iniDuplicateKeysWithoutList = shouldFail {
177     format = formats.ini {};
178     input = {
179       foo = {
180         bar = [ null true "test" 1.2 10 ];
181         baz = false;
182         qux = "qux";
183       };
184     };
185   };
187   iniDuplicateKeys = shouldPass {
188     format = formats.ini { listsAsDuplicateKeys = true; };
189     input = {
190       foo = {
191         bar = [ null true "test" 1.2 10 ];
192         baz = false;
193         qux = "qux";
194       };
195     };
196     expected = ''
197       [foo]
198       bar=null
199       bar=true
200       bar=test
201       bar=1.200000
202       bar=10
203       baz=false
204       qux=qux
205     '';
206   };
208   iniListToValue = shouldPass {
209     format = formats.ini { listToValue = lib.concatMapStringsSep ", " (lib.generators.mkValueStringDefault {}); };
210     input = {
211       foo = {
212         bar = [ null true "test" 1.2 10 ];
213         baz = false;
214         qux = "qux";
215       };
216     };
217     expected = ''
218       [foo]
219       bar=null, true, test, 1.200000, 10
220       baz=false
221       qux=qux
222     '';
223   };
225   iniWithGlobalNoSections = shouldPass {
226     format = formats.iniWithGlobalSection {};
227     input = {};
228     expected = "";
229   };
231   iniWithGlobalOnlySections = shouldPass {
232     format = formats.iniWithGlobalSection {};
233     input = {
234       sections = {
235         foo = {
236           bar = "baz";
237         };
238       };
239     };
240     expected = ''
241       [foo]
242       bar=baz
243     '';
244   };
246   iniWithGlobalOnlyGlobal = shouldPass {
247     format = formats.iniWithGlobalSection {};
248     input = {
249       globalSection = {
250         bar = "baz";
251       };
252     };
253     expected = ''
254       bar=baz
256     '';
257   };
259   iniWithGlobalWrongSections = shouldFail {
260     format = formats.iniWithGlobalSection {};
261     input = {
262       foo = {};
263     };
264   };
266   iniWithGlobalEverything = shouldPass {
267     format = formats.iniWithGlobalSection {};
268     input = {
269       globalSection = {
270         bar = true;
271       };
272       sections = {
273         foo = {
274           bool = true;
275           int = 10;
276           float = 3.141;
277           str = "string";
278         };
279       };
280     };
281     expected = ''
282       bar=true
284       [foo]
285       bool=true
286       float=3.141000
287       int=10
288       str=string
289     '';
290   };
292   iniWithGlobalListToValue = shouldPass {
293     format = formats.iniWithGlobalSection { listToValue = lib.concatMapStringsSep ", " (lib.generators.mkValueStringDefault {}); };
294     input = {
295       globalSection = {
296         bar = [ null true "test" 1.2 10 ];
297         baz = false;
298         qux = "qux";
299       };
300       sections = {
301         foo = {
302           bar = [ null true "test" 1.2 10 ];
303           baz = false;
304           qux = "qux";
305         };
306       };
307     };
308     expected = ''
309       bar=null, true, test, 1.200000, 10
310       baz=false
311       qux=qux
313       [foo]
314       bar=null, true, test, 1.200000, 10
315       baz=false
316       qux=qux
317     '';
318   };
320   keyValueAtoms = shouldPass {
321     format = formats.keyValue {};
322     input = {
323       bool = true;
324       int = 10;
325       float = 3.141;
326       str = "string";
327     };
328     expected = ''
329       bool=true
330       float=3.141000
331       int=10
332       str=string
333     '';
334   };
336   keyValueDuplicateKeys = shouldPass {
337     format = formats.keyValue { listsAsDuplicateKeys = true; };
338     input = {
339       bar = [ null true "test" 1.2 10 ];
340       baz = false;
341       qux = "qux";
342     };
343     expected = ''
344       bar=null
345       bar=true
346       bar=test
347       bar=1.200000
348       bar=10
349       baz=false
350       qux=qux
351     '';
352   };
354   keyValueListToValue = shouldPass {
355     format = formats.keyValue { listToValue = lib.concatMapStringsSep ", " (lib.generators.mkValueStringDefault {}); };
356     input = {
357       bar = [ null true "test" 1.2 10 ];
358       baz = false;
359       qux = "qux";
360     };
361     expected = ''
362       bar=null, true, test, 1.200000, 10
363       baz=false
364       qux=qux
365     '';
366   };
368   tomlAtoms = shouldPass {
369     format = formats.toml {};
370     input = {
371       false = false;
372       true = true;
373       int = 10;
374       float = 3.141;
375       str = "foo";
376       attrs.foo = "foo";
377       list = [ 1 2 ];
378       level1.level2.level3.level4 = "deep";
379     };
380     expected = ''
381       false = false
382       float = 3.141
383       int = 10
384       list = [1, 2]
385       str = "foo"
386       true = true
387       [attrs]
388       foo = "foo"
390       [level1.level2.level3]
391       level4 = "deep"
392     '';
393   };
395   # This test is responsible for
396   #   1. testing type coercions
397   #   2. providing a more readable example test
398   # Whereas java-properties/default.nix tests the low level escaping, etc.
399   javaProperties = shouldPass {
400     format = formats.javaProperties {};
401     input = {
402       floaty = 3.1415;
403       tautologies = true;
404       contradictions = false;
405       foo = "bar";
406       # # Disallowed at eval time, because it's ambiguous:
407       # # add to store or convert to string?
408       # root = /root;
409       "1" = 2;
410       package = pkgs.hello;
411       "ütf 8" = "dûh";
412       # NB: Some editors (vscode) show this _whole_ line in right-to-left order
413       "الجبر" = "أكثر من مجرد أرقام";
414     };
415     expected = ''
416       # Generated with Nix
418       1 = 2
419       contradictions = false
420       floaty = 3.141500
421       foo = bar
422       package = ${pkgs.hello}
423       tautologies = true
424       \u00fctf\ 8 = d\u00fbh
425       \u0627\u0644\u062c\u0628\u0631 = \u0623\u0643\u062b\u0631 \u0645\u0646 \u0645\u062c\u0631\u062f \u0623\u0631\u0642\u0627\u0645
426     '';
427   };
429   phpAtoms = shouldPass rec {
430     format = formats.php { finalVariable = "config"; };
431     input = {
432       null = null;
433       false = false;
434       true = true;
435       int = 10;
436       float = 3.141;
437       str = "foo";
438       str_special = "foo\ntesthello'''";
439       attrs.foo = null;
440       list = [ null null ];
441       mixed = format.lib.mkMixedArray [ 10 3.141 ] {
442         str = "foo";
443         attrs.foo = null;
444       };
445       raw = format.lib.mkRaw "random_function()";
446     };
447     expected = ''
448       <?php
449       declare(strict_types=1);
450       $config = ['attrs' => ['foo' => null], 'false' => false, 'float' => 3.141000, 'int' => 10, 'list' => [null, null], 'mixed' => [10, 3.141000, 'attrs' => ['foo' => null], 'str' => 'foo'], 'null' => null, 'raw' => random_function(), 'str' => 'foo', 'str_special' => 'foo
451       testhello\'\'\'${"'"}, 'true' => true];
452     '';
453   };
455   phpReturn = shouldPass {
456     format = formats.php { };
457     input = {
458       int = 10;
459       float = 3.141;
460       str = "foo";
461       str_special = "foo\ntesthello'''";
462       attrs.foo = null;
463     };
464     expected = ''
465       <?php
466       declare(strict_types=1);
467       return ['attrs' => ['foo' => null], 'float' => 3.141000, 'int' => 10, 'str' => 'foo', 'str_special' => 'foo
468       testhello\'\'\'${"'"}];
469     '';
470   };