1 module dud.resolve.confstests;
2 
3 import core.exception : AssertError;
4 import std.algorithm.iteration : map, joiner, filter;
5 import std.algorithm.searching : canFind;
6 import std.exception : enforce;
7 import std.format : format;
8 import std.stdio;
9 
10 import dud.resolve.conf;
11 import dud.resolve.confs;
12 import dud.resolve.positive;
13 import dud.semver.versionrange;
14 
15 private:
16 
17 const c1 = Conf("foo", IsPositive.yes);
18 const c2 = Conf("foo", IsPositive.no);
19 const c3 = Conf("bar", IsPositive.yes);
20 const c4 = Conf("bar", IsPositive.no);
21 const c5 = Conf("", IsPositive.yes);
22 const c6 = Conf("", IsPositive.no);
23 const c7 = Conf("conf1", IsPositive.yes);
24 
25 const(Confs) c12 = Confs([c1, c2]);
26 const(Confs) c13 = Confs([c1, c3]);
27 const(Confs) c14 = Confs([c1, c4]);
28 const(Confs) c15 = Confs([c1, c5]);
29 const(Confs) c16 = Confs([c1, c6]);
30 
31 const(Confs) c23 = Confs([c2, c3]);
32 const(Confs) c24 = Confs([c2, c4]);
33 const(Confs) c25 = Confs([c2, c5]);
34 const(Confs) c26 = Confs([c2, c6]);
35 
36 const(Confs) c34 = Confs([c3, c4]);
37 const(Confs) c35 = Confs([c3, c5]);
38 const(Confs) c36 = Confs([c3, c6]);
39 
40 const(Confs) c45 = Confs([c4, c5]);
41 const(Confs) c46 = Confs([c4, c6]);
42 
43 const(Confs) c56 = Confs([c5, c6]);
44 
45 Confs[] cs;
46 
47 static this() {
48 	cs = buildConfs();
49 }
50 
51 unittest {
52 	auto a = Confs([c5]);
53 	auto b = Confs([c1]);
54 
55 	assert(allowsAny(c5, c1), format("\n%s\n%s", c5, c6));
56 	testAllowAny(a, b, true);
57 }
58 
59 Confs[] buildConfs() {
60 	Confs[] ret;
61 	const cs = [c1, c2, c3, c4, c5, c6];
62 	foreach(it; cs) {
63 		foreach(jt; cs) {
64 			foreach(kt; cs) {
65 				auto tmp = Confs([it, jt, kt]);
66 				if(tmp == Confs.init) {
67 					continue;
68 				}
69 				Confs d = tmp.dup();
70 				assert(d == tmp, format("\nold: %s\nnew: %s", tmp, d));
71 				ret ~= tmp;
72 			}
73 		}
74 	}
75 	return ret;
76 }
77 
78 // invert
79 
80 unittest {
81 	void testInvert(const(Confs) a, const(Confs) exp, int line = __LINE__) {
82 		const inv = a.invert();
83 		enforce!AssertError(inv == exp, format("\n  a: %s\nexp: %s\nrst: %s", a,
84 				exp, inv), __FILE__, line);
85 	}
86 
87 	testInvert(c12, Confs([]));
88 	testInvert(c13, c24);
89 	testInvert(c14, c23);
90 	testInvert(c15, Confs([c6])); // c5 is special
91 	testInvert(c16, Confs([c5])); // c6 makes everything false
92 
93 	testInvert(c23, c14);
94 	testInvert(c24, c13);
95 	testInvert(c25, Confs([c6]));
96 	testInvert(c26, Confs([c5]));
97 
98 	testInvert(c34, Confs([]));
99 	testInvert(c35, Confs([c6]));
100 	testInvert(c36, Confs([c5]));
101 
102 	testInvert(c45, Confs([c6]));
103 	testInvert(c46, Confs([c5]));
104 
105 	testInvert(c56, Confs([c5]));
106 }
107 
108 unittest {
109 	const c = Confs([c1]).invert();
110 	const e = Confs([c2]);
111 	assert(c == e, format("\n%s\n%s", c, e));
112 }
113 
114 // allowAll
115 
116 unittest {
117 	void testAllowAll(const(Confs) a, const(Confs) b, const bool exp,
118 			int line = __LINE__)
119 	{
120 		struct Indivitual {
121 			@safe pure:
122 			const(Conf) a;
123 			const(Conf) b;
124 
125 			string toString() const {
126 				return format("\ta: %s\tb: %s\t%s", a, b, allowsAll(a, b));
127 			}
128 		}
129 
130 		const bool rslt = allowsAll(a, b);
131 		enforce!AssertError(rslt == exp,
132 			format("\na: %s\nb: %s\nexp: %s\nrsl: %s\nall:\n%(%s\n%)", a, b,
133 				exp,
134 				rslt,
135 				a.confs
136 					.map!(it => b.confs.map!(jt => Indivitual(it, jt)))
137 					.joiner),
138 			__FILE__, line);
139 	}
140 
141 	testAllowAll(Confs.init, Confs.init, true);
142 	testAllowAll(Confs([c1, c5]), Confs([c1]), true);
143 	testAllowAll(Confs([c5]), Confs([c1, c5]), true);
144 	testAllowAll(Confs([c5]), Confs([c1, c3]), true);
145 	testAllowAll(Confs([c1]), Confs([c1, c3, c5]), true);
146 	testAllowAll(Confs([c3]), Confs([c1, c3, c5]), true);
147 	testAllowAll(Confs([c3]), Confs([c3]), true);
148 	testAllowAll(Confs([c1]), Confs([c1]), true);
149 	testAllowAll(Confs([c2]), Confs([c2]), false);
150 	testAllowAll(Confs([c2]), Confs([c1]), false);
151 	testAllowAll(Confs([c2]), Confs([c3]), false);
152 	testAllowAll(Confs([c2]), Confs([c4]), false);
153 	testAllowAll(Confs([c2]), Confs([c5]), true);
154 	testAllowAll(Confs([c2]), Confs([c6]), false);
155 
156 	foreach(it; cs) {
157 		testAllowAll(Confs.init, it, false);
158 		foreach(jt; cs) {
159 			allowsAll(it, jt);
160 		}
161 	}
162 }
163 
164 unittest {
165 	void testAllowAll(const(Confs) a, const(Conf) b, const bool exp,
166 			int line = __LINE__)
167 	{
168 		struct Indivitual {
169 			@safe pure:
170 			const(Conf) a;
171 			const(Conf) b;
172 
173 			string toString() const {
174 				return format("\ta: %s\tb: %s\t%s", a, b, allowsAll(a, b));
175 			}
176 		}
177 
178 		const bool rslt = allowsAll(a, b);
179 		enforce!AssertError(rslt == exp,
180 			format("\na: %s\nb: %s\nexp: %s\nrsl: %s\nall:\n%(%s\n%)", a, b, exp,
181 				rslt, a.confs.map!(it => Indivitual(it, b))),
182 			__FILE__, line);
183 	}
184 
185 	testAllowAll(c12, c1, false);
186 	testAllowAll(c12, c2, false);
187 	testAllowAll(c12, c3, false);
188 	testAllowAll(c12, c4, false);
189 	testAllowAll(c12, c5, false);
190 	testAllowAll(c12, c6, false);
191 
192 	testAllowAll(c13, c1, true);
193 	testAllowAll(c13, c2, false);
194 	testAllowAll(c13, c3, true);
195 	testAllowAll(c13, c4, false);
196 	testAllowAll(c13, c5, false);
197 	testAllowAll(c13, c6, false);
198 
199 	testAllowAll(c24, c1, false);
200 	testAllowAll(c24, c2, false);
201 	testAllowAll(c24, c3, false);
202 	testAllowAll(c24, c4, false);
203 	testAllowAll(c24, c5, false);
204 	testAllowAll(c24, c6, false);
205 
206 	const(Confs) c22 = Confs([c2, c2]);
207 	testAllowAll(c22, c2, false);
208 }
209 
210 // allowsAny
211 struct IndivitualAny {
212 	@safe pure:
213 	const(Conf) a;
214 	const(Conf) b;
215 
216 	string toString() const {
217 		return format("\ta: %s\tb: %s\t%s", a, b, allowsAny(a, b));
218 	}
219 }
220 
221 void testAllowAny(const(Confs) a, const(Conf) b, const bool exp,
222 		int line = __LINE__)
223 {
224 	const rsl = allowsAny(a, b);
225 	enforce!AssertError(rsl == exp, format(
226 			"\na: %s\nb: %s\nint: %s\nexp: %s\neach:%(%s\n%)", a, b, rsl, exp,
227 			a.confs
228 				.map!(aIt => IndivitualAny(aIt, b))),
229 			__FILE__, line);
230 }
231 
232 unittest {
233 	testAllowAny(c13, c1, true);
234 	testAllowAny(c13, c3, true);
235 	testAllowAny(c13, c5, true);
236 	testAllowAny(c12, c5, false);
237 }
238 
239 void testAllowAny(const(Confs) a, const(Confs) b, const bool exp,
240 		int line = __LINE__)
241 {
242 	const rsl = allowsAny(a, b);
243 	enforce!AssertError(rsl == exp, format(
244 			"\na: %s\nb: %s\nint: %s\nexp: %s\neach:%(%s\n%)", a, b, rsl, exp,
245 			a.confs
246 				.map!(aIt => b.confs.map!(bIt => IndivitualAny(aIt, bIt)))
247 				.joiner),
248 			__FILE__, line);
249 }
250 
251 unittest {
252 	testAllowAny(c12, c12, true);
253 	testAllowAny(c12, c13, false);
254 	testAllowAny(c12, c14, false);
255 	testAllowAny(c12, c15, false);
256 	testAllowAny(c12, c16, false);
257 
258 	testAllowAny(c13, c14, true);
259 }
260 
261 unittest {
262 	foreach(it; cs) {
263 		foreach(c; it.confs.filter!(it => it.isPositive == IsPositive.yes)) {
264 			testAllowAny(it, c, true);
265 		}
266 	}
267 }
268 
269 // intersectionOf
270 
271 void testInter(const(Conf) a, const(Conf) b, const(Confs) exp,
272 		int line = __LINE__)
273 {
274 	const inter = intersectionOf(a, b);
275 	enforce!AssertError(inter == exp, format(
276 			"\na: %s\nb: %s\nint: %s\nexp: %s", a, b, inter, exp),
277 			__FILE__, line);
278 }
279 
280 unittest {
281 	testInter(c7, c6, Confs([c6]));
282 }
283 
284 void testInter(const(Confs) a, const(Confs) b, const(Confs) exp,
285 		int line = __LINE__)
286 {
287 	const inter = intersectionOf(a, b);
288 	enforce!AssertError(inter == exp, format(
289 			"\na: %s\nb: %s\nint: %s\nexp: %s", a, b, inter, exp),
290 			__FILE__, line);
291 }
292 
293 unittest {
294 	testInter(Confs([c1, c3]), Confs([c1]), Confs([c1]));
295 	testInter(Confs([c1]), Confs([c1]), Confs([c1]));
296 	testInter(Confs([c3]), Confs([c1]), Confs([]));
297 }
298 
299 unittest {
300 	testInter(c13, c13, c13);
301 	testInter(c13, c35, Confs([c1, c3]));
302 	testInter(c35, c35, Confs([c3, c5]));
303 	testInter(c56, c56, Confs([c6]));
304 
305 	Confs a = Confs([c1, c3]);
306 	Confs b = Confs([c1, c3, c5]);
307 
308 	testInter(a, b, a);
309 }
310 
311 unittest {
312 	const a = Confs([c1]);
313 	const b = Confs([c3]);
314 
315 	testInter(a, b, Confs([]));
316 }
317 
318 // differenceOf
319 
320 unittest {
321 	const c11 = Confs([c1]);
322 	const c33 = Confs([c3]);
323 	const c13 = differenceOf(c11, c33);
324 }
325 
326 unittest {
327 	const none = Confs([Conf("", IsPositive.no)]);
328 	foreach(it; cs) {
329 		foreach(jt; cs) {
330 			const r = differenceOf(it, jt);
331 			if(it == jt && it != none) {
332 				allowsAny(r, it);
333 				allowsAny(r, jt);
334 			}
335 		}
336 	}
337 }
338 
339 // additional
340 
341 unittest {
342 	auto a = Confs([Conf("", IsPositive.no)]);
343 	auto b = Confs([]);
344 
345 	assert(allowsAll(a, b));
346 	assert(allowsAny(a, b));
347 }