1{
2 pkgs ? import ../.. { },
3 currLibPath ? ../.,
4 prevLibPath ? "${
5 pkgs.fetchFromGitHub {
6 owner = "nixos";
7 repo = "nixpkgs";
8 # Parent commit of [#391544](https://github.com/NixOS/nixpkgs/pull/391544)
9 # Which was before the type.merge.v2 introduction
10 rev = "bcf94dd3f07189b7475d823c8d67d08b58289905";
11 hash = "sha256-MuMiIY3MX5pFSOCvutmmRhV6RD0R3CG0Hmazkg8cMFI=";
12 }
13 }/lib",
14}:
15let
16 lib = import currLibPath;
17
18 lib_with_merge_v2 = lib;
19 lib_with_merge_v1 = import prevLibPath;
20
21 getMatrix =
22 {
23 getType ? null,
24 # If getType is set this is only used as test prefix
25 # And the type from getType is used
26 outerTypeName,
27 innerTypeName,
28 value,
29 testAttrs,
30 }:
31 let
32 evalModules.call_v1 = lib_with_merge_v1.evalModules;
33 evalModules.call_v2 = lib_with_merge_v2.evalModules;
34 outerTypes.outer_v1 = lib_with_merge_v1.types;
35 outerTypes.outer_v2 = lib_with_merge_v2.types;
36 innerTypes.inner_v1 = lib_with_merge_v1.types;
37 innerTypes.inner_v2 = lib_with_merge_v2.types;
38 in
39 lib.mapAttrs (
40 _: evalModules:
41 lib.mapAttrs (
42 _: outerTypes:
43 lib.mapAttrs (_: innerTypes: {
44 "test_${outerTypeName}_${innerTypeName}" = testAttrs // {
45 expr =
46 (evalModules {
47 modules = [
48 (m: {
49 options.foo = m.lib.mkOption {
50 type =
51 if getType != null then
52 getType outerTypes innerTypes
53 else
54 outerTypes.${outerTypeName} innerTypes.${innerTypeName};
55 default = value;
56 };
57 })
58 ];
59 }).config.foo;
60 };
61 }) innerTypes
62 ) outerTypes
63 ) evalModules;
64in
65{
66 # AttrsOf string
67 attrsOf_str_ok = getMatrix {
68 outerTypeName = "attrsOf";
69 innerTypeName = "str";
70 value = {
71 bar = "test";
72 };
73 testAttrs = {
74 expected = {
75 bar = "test";
76 };
77 };
78 };
79 attrsOf_str_err_inner = getMatrix {
80 outerTypeName = "attrsOf";
81 innerTypeName = "str";
82 value = {
83 bar = 1; # not a string
84 };
85 testAttrs = {
86 expectedError = {
87 type = "ThrownError";
88 msg = "A definition for option `foo.bar' is not of type `string'.*";
89 };
90 };
91 };
92 attrsOf_str_err_outer = getMatrix {
93 outerTypeName = "attrsOf";
94 innerTypeName = "str";
95 value = [ "foo" ]; # not an attrset
96 testAttrs = {
97 expectedError = {
98 type = "ThrownError";
99 msg = "A definition for option `foo' is not of type `attribute set of string'.*";
100 };
101 };
102 };
103
104 # listOf string
105 listOf_str_ok = getMatrix {
106 outerTypeName = "listOf";
107 innerTypeName = "str";
108 value = [
109 "foo"
110 "bar"
111 ];
112 testAttrs = {
113 expected = [
114 "foo"
115 "bar"
116 ];
117 };
118 };
119 listOf_str_err_inner = getMatrix {
120 outerTypeName = "listOf";
121 innerTypeName = "str";
122 value = [
123 "foo"
124 1
125 ]; # not a string
126 testAttrs = {
127 expectedError = {
128 type = "ThrownError";
129 msg = ''A definition for option `foo."\[definition 1-entry 2\]"' is not of type `string'.'';
130 };
131 };
132 };
133 listOf_str_err_outer = getMatrix {
134 outerTypeName = "listOf";
135 innerTypeName = "str";
136 value = {
137 foo = 42;
138 }; # not a list
139 testAttrs = {
140 expectedError = {
141 type = "ThrownError";
142 msg = "A definition for option `foo' is not of type `list of string'.*";
143 };
144 };
145 };
146
147 attrsOf_submodule_ok = getMatrix {
148 getType =
149 a: b:
150 a.attrsOf (
151 b.submodule (m: {
152 options.nested = m.lib.mkOption {
153 type = m.lib.types.str;
154 };
155 })
156 );
157 outerTypeName = "attrsOf";
158 innerTypeName = "submodule";
159 value = {
160 foo = {
161 nested = "test1";
162 };
163 bar = {
164 nested = "test2";
165 };
166 };
167 testAttrs = {
168 expected = {
169 foo = {
170 nested = "test1";
171 };
172 bar = {
173 nested = "test2";
174 };
175 };
176 };
177 };
178 attrsOf_submodule_err_inner = getMatrix {
179 outerTypeName = "attrsOf";
180 innerTypeName = "submodule";
181 getType =
182 a: b:
183 a.attrsOf (
184 b.submodule (m: {
185 options.nested = m.lib.mkOption {
186 type = m.lib.types.str;
187 };
188 })
189 );
190 value = {
191 foo = [ 1 ]; # not a submodule
192 bar = {
193 nested = "test2";
194 };
195 };
196 testAttrs = {
197 expectedError = {
198 type = "ThrownError";
199 msg = "A definition for option `foo.foo' is not of type `submodule'.*";
200 };
201 };
202 };
203 attrsOf_submodule_err_outer = getMatrix {
204 outerTypeName = "attrsOf";
205 innerTypeName = "submodule";
206 getType =
207 a: b:
208 a.attrsOf (
209 b.submodule (m: {
210 options.nested = m.lib.mkOption {
211 type = m.lib.types.str;
212 };
213 })
214 );
215 value = [ 123 ]; # not an attrsOf
216 testAttrs = {
217 expectedError = {
218 type = "ThrownError";
219 msg = ''A definition for option `foo' is not of type `attribute set of \(submodule\).*'';
220 };
221 };
222 };
223
224 # either
225 either_str_attrsOf_ok = getMatrix {
226 outerTypeName = "either";
227 innerTypeName = "str_or_attrsOf_str";
228
229 getType = a: b: a.either b.str (b.attrsOf a.str);
230 value = "string value";
231 testAttrs = {
232 expected = "string value";
233 };
234 };
235 either_str_attrsOf_err_1 = getMatrix {
236 outerTypeName = "either";
237 innerTypeName = "str_or_attrsOf_str";
238
239 getType = a: b: a.either b.str (b.attrsOf a.str);
240 value = 1;
241 testAttrs = {
242 expectedError = {
243 type = "ThrownError";
244 msg = "A definition for option `foo' is not of type `string or attribute set of string'.*";
245 };
246 };
247 };
248 either_str_attrsOf_err_2 = getMatrix {
249 outerTypeName = "either";
250 innerTypeName = "str_or_attrsOf_str";
251
252 getType = a: b: a.either b.str (b.attrsOf a.str);
253 value = {
254 bar = 1; # not a string
255 };
256 testAttrs = {
257 expectedError = {
258 type = "ThrownError";
259 msg = "A definition for option `foo.bar' is not of type `string'.*";
260 };
261 };
262 };
263
264 # Coereced to
265 coerce_attrsOf_str_to_listOf_str_run = getMatrix {
266 outerTypeName = "coercedTo";
267 innerTypeName = "attrsOf_str->listOf_str";
268 getType = a: b: a.coercedTo (b.attrsOf b.str) builtins.attrValues (b.listOf b.str);
269 value = {
270 bar = "test1"; # coerced to listOf string
271 foo = "test2"; # coerced to listOf string
272 };
273 testAttrs = {
274 expected = [
275 "test1"
276 "test2"
277 ];
278 };
279 };
280 coerce_attrsOf_str_to_listOf_str_final = getMatrix {
281 outerTypeName = "coercedTo";
282 innerTypeName = "attrsOf_str->listOf_str";
283 getType = a: b: a.coercedTo (b.attrsOf b.str) (abort "This shouldnt run") (b.listOf b.str);
284 value = [
285 "test1"
286 "test2"
287 ]; # already a listOf string
288 testAttrs = {
289 expected = [
290 "test1"
291 "test2"
292 ]; # Order should be kept
293 };
294 };
295 coerce_attrsOf_str_to_listOf_err_coercer_input = getMatrix {
296 outerTypeName = "coercedTo";
297 innerTypeName = "attrsOf_str->listOf_str";
298 getType = a: b: a.coercedTo (b.attrsOf b.str) builtins.attrValues (b.listOf b.str);
299 value = [
300 { }
301 { }
302 ]; # not coercible to listOf string, with the given coercer
303 testAttrs = {
304 expectedError = {
305 type = "ThrownError";
306 msg = ''A definition for option `foo."\[definition 1-entry 1\]"' is not of type `string'.*'';
307 };
308 };
309 };
310 coerce_attrsOf_str_to_listOf_err_coercer_ouput = getMatrix {
311 outerTypeName = "coercedTo";
312 innerTypeName = "attrsOf_str->listOf_str";
313 getType = a: b: a.coercedTo (b.attrsOf b.str) builtins.attrValues (b.listOf b.str);
314 value = {
315 foo = {
316 bar = 1;
317 }; # coercer produces wrong type -> [ { bar = 1; } ]
318 };
319 testAttrs = {
320 expectedError = {
321 type = "ThrownError";
322 msg = ''A definition for option `foo."\[definition 1-entry 1\]"' is not of type `string'.*'';
323 };
324 };
325 };
326 coerce_str_to_int_coercer_ouput = getMatrix {
327 outerTypeName = "coercedTo";
328 innerTypeName = "int->str";
329 getType = a: b: a.coercedTo b.int toString a.str;
330 value = [ ];
331 testAttrs = {
332 expectedError = {
333 type = "ThrownError";
334 msg = ''A definition for option `foo' is not of type `string or signed integer convertible to it.*'';
335 };
336 };
337 };
338
339 # Submodule
340 submodule_with_ok = getMatrix {
341 outerTypeName = "submoduleWith";
342 innerTypeName = "mixed_types";
343 getType =
344 a: b:
345 a.submodule (m: {
346 options.attrs = m.lib.mkOption {
347 type = b.attrsOf b.str;
348 };
349 options.list = m.lib.mkOption {
350 type = b.listOf b.str;
351 };
352 options.either = m.lib.mkOption {
353 type = b.either a.str a.int;
354 };
355 });
356 value = {
357 attrs = {
358 foo = "bar";
359 };
360 list = [
361 "foo"
362 "bar"
363 ];
364 either = 123; # int
365 };
366 testAttrs = {
367 expected = {
368 attrs = {
369 foo = "bar";
370 };
371 list = [
372 "foo"
373 "bar"
374 ];
375 either = 123;
376 };
377 };
378 };
379}