1<?php
2/* Icinga Web 2 | (c) 2015 Icinga Development Team | GPLv2+ */
3
4namespace Tests\Icinga\Module\Setup;
5
6use Icinga\Test\BaseTestCase;
7use Icinga\Module\Setup\Requirement;
8use Icinga\Module\Setup\RequirementSet;
9
10class TrueRequirement extends Requirement
11{
12    protected function evaluate()
13    {
14        return true;
15    }
16}
17
18class FalseRequirement extends Requirement
19{
20    protected function evaluate()
21    {
22        return false;
23    }
24}
25
26class RequirementSetTest extends BaseTestCase
27{
28    public function testFlatMandatoryRequirementsOfTypeAnd()
29    {
30        $emptySet = new RequirementSet();
31        $this->assertFalse($emptySet->fulfilled(), 'A empty mandatory set of type and is fulfilled');
32
33        $singleTrueSet = new RequirementSet();
34        $singleTrueSet->add(new TrueRequirement());
35        $this->assertTrue(
36            $singleTrueSet->fulfilled(),
37            'A mandatory set of type and with a single TrueRequirement is not fulfilled'
38        );
39
40        $singleFalseSet = new RequirementSet();
41        $singleFalseSet->add(new FalseRequirement());
42        $this->assertFalse(
43            $singleFalseSet->fulfilled(),
44            'A mandatory set of type and with a single FalseRequirement is fulfilled'
45        );
46
47        $mixedSet = new RequirementSet();
48        $mixedSet->add(new TrueRequirement());
49        $mixedSet->add(new FalseRequirement());
50        $this->assertFalse(
51            $mixedSet->fulfilled(),
52            'A mandatory set of type and with one True- and one FalseRequirement is fulfilled'
53        );
54    }
55
56    public function testFlatOptionalRequirementsOfTypeAnd()
57    {
58        $emptySet = new RequirementSet(true);
59        $this->assertTrue($emptySet->fulfilled(), 'A empty optional set of type and is not fulfilled');
60
61        $singleTrueSet = new RequirementSet(true);
62        $singleTrueSet->add(new TrueRequirement());
63        $this->assertTrue(
64            $singleTrueSet->fulfilled(),
65            'A optional set of type and with a single TrueRequirement is not fulfilled'
66        );
67
68        $singleFalseSet = new RequirementSet(true);
69        $singleFalseSet->add(new FalseRequirement());
70        $this->assertTrue(
71            $singleFalseSet->fulfilled(),
72            'A optional set of type and with a single FalseRequirement is not fulfilled'
73        );
74
75        $mixedSet = new RequirementSet(true);
76        $mixedSet->add(new TrueRequirement());
77        $mixedSet->add(new FalseRequirement());
78        $this->assertTrue(
79            $mixedSet->fulfilled(),
80            'A optional set of type and with one True- and one FalseRequirement is not fulfilled'
81        );
82    }
83
84    public function testFlatMixedRequirementsOfTypeAnd()
85    {
86        $mandatoryOptionalTrueSet = new RequirementSet();
87        $mandatoryOptionalTrueSet->add(new TrueRequirement(array('optional' => true)));
88        $mandatoryOptionalTrueSet->add(new FalseRequirement());
89        $this->assertFalse(
90            $mandatoryOptionalTrueSet->fulfilled(),
91            'A mandatory set of type and with one optional True- and one mandatory FalseRequirement is fulfilled'
92        );
93
94        $mandatoryOptionalFalseSet = new RequirementSet();
95        $mandatoryOptionalFalseSet->add(new TrueRequirement());
96        $mandatoryOptionalFalseSet->add(new FalseRequirement(array('optional' => true)));
97        $this->assertTrue(
98            $mandatoryOptionalFalseSet->fulfilled(),
99            'A mandatory set of type and with one mandatory True- and one optional FalseRequirement is not fulfilled'
100        );
101
102        $optionalOptionalTrueSet = new RequirementSet(true);
103        $optionalOptionalTrueSet->add(new TrueRequirement(array('optional' => true)));
104        $optionalOptionalTrueSet->add(new FalseRequirement());
105        $this->assertTrue(
106            $optionalOptionalTrueSet->fulfilled(),
107            'A optional set of type and with one optional True- and one mandatory FalseRequirement is not fulfilled'
108        );
109
110        $optionalOptionalFalseSet = new RequirementSet(true);
111        $optionalOptionalFalseSet->add(new TrueRequirement());
112        $optionalOptionalFalseSet->add(new FalseRequirement(array('optional' => true)));
113        $this->assertTrue(
114            $optionalOptionalFalseSet->fulfilled(),
115            'A optional set of type and with one mandatory True- and one optional FalseRequirement is not fulfilled'
116        );
117    }
118
119    public function testFlatMandatoryRequirementsOfTypeOr()
120    {
121        $emptySet = new RequirementSet(false, RequirementSet::MODE_OR);
122        $this->assertFalse($emptySet->fulfilled(), 'A empty mandatory set of type or is fulfilled');
123
124        $singleTrueSet = new RequirementSet(false, RequirementSet::MODE_OR);
125        $singleTrueSet->add(new TrueRequirement());
126        $this->assertTrue(
127            $singleTrueSet->fulfilled(),
128            'A mandatory set of type or with a single TrueRequirement is not fulfilled'
129        );
130
131        $singleFalseSet = new RequirementSet(false, RequirementSet::MODE_OR);
132        $singleFalseSet->add(new FalseRequirement());
133        $this->assertFalse(
134            $singleFalseSet->fulfilled(),
135            'A mandatory set of type or with a single FalseRequirement is fulfilled'
136        );
137
138        $mixedSet = new RequirementSet(false, RequirementSet::MODE_OR);
139        $mixedSet->add(new TrueRequirement());
140        $mixedSet->add(new FalseRequirement());
141        $this->assertTrue(
142            $mixedSet->fulfilled(),
143            'A mandatory set of type or with one True- and one FalseRequirement is not fulfilled'
144        );
145    }
146
147    public function testFlatOptionalRequirementsOfTypeOr()
148    {
149        $emptySet = new RequirementSet(true, RequirementSet::MODE_OR);
150        $this->assertTrue($emptySet->fulfilled(), 'A empty optional set of type or is not fulfilled');
151
152        $singleTrueSet = new RequirementSet(true, RequirementSet::MODE_OR);
153        $singleTrueSet->add(new TrueRequirement());
154        $this->assertTrue(
155            $singleTrueSet->fulfilled(),
156            'A optional set of type or with a single TrueRequirement is not fulfilled'
157        );
158
159        $singleFalseSet = new RequirementSet(true, RequirementSet::MODE_OR);
160        $singleFalseSet->add(new FalseRequirement());
161        $this->assertTrue(
162            $singleFalseSet->fulfilled(),
163            'A optional set of type or with a single FalseRequirement is not fulfilled'
164        );
165
166        $mixedSet = new RequirementSet(true, RequirementSet::MODE_OR);
167        $mixedSet->add(new TrueRequirement());
168        $mixedSet->add(new FalseRequirement());
169        $this->assertTrue(
170            $mixedSet->fulfilled(),
171            'A optional set of type or with one True- and one FalseRequirement is not fulfilled'
172        );
173    }
174
175    public function testFlatMixedRequirementsOfTypeOr()
176    {
177        $mandatoryOptionalTrueSet = new RequirementSet(false, RequirementSet::MODE_OR);
178        $mandatoryOptionalTrueSet->add(new TrueRequirement(array('optional' => true)));
179        $mandatoryOptionalTrueSet->add(new FalseRequirement());
180        $this->assertTrue(
181            $mandatoryOptionalTrueSet->fulfilled(),
182            'A mandatory set of type or with one optional True- and one mandatory FalseRequirement is not fulfilled'
183        );
184
185        $mandatoryOptionalFalseSet = new RequirementSet(false, RequirementSet::MODE_OR);
186        $mandatoryOptionalFalseSet->add(new TrueRequirement());
187        $mandatoryOptionalFalseSet->add(new FalseRequirement(array('optional' => true)));
188        $this->assertTrue(
189            $mandatoryOptionalFalseSet->fulfilled(),
190            'A mandatory set of type or with one mandatory True- and one optional FalseRequirement is not fulfilled'
191        );
192
193        $optionalOptionalTrueSet = new RequirementSet(true, RequirementSet::MODE_OR);
194        $optionalOptionalTrueSet->add(new TrueRequirement(array('optional' => true)));
195        $optionalOptionalTrueSet->add(new FalseRequirement());
196        $this->assertTrue(
197            $optionalOptionalTrueSet->fulfilled(),
198            'A optional set of type or with one optional True- and one mandatory FalseRequirement is not fulfilled'
199        );
200
201        $optionalOptionalFalseSet = new RequirementSet(true, RequirementSet::MODE_OR);
202        $optionalOptionalFalseSet->add(new TrueRequirement());
203        $optionalOptionalFalseSet->add(new FalseRequirement(array('optional' => true)));
204        $this->assertTrue(
205            $optionalOptionalFalseSet->fulfilled(),
206            'A optional set of type or with one mandatory True- and one optional FalseRequirement is not fulfilled'
207        );
208    }
209
210    public function testNestedMandatoryRequirementsOfTypeAnd()
211    {
212        $trueSet = new RequirementSet();
213        $trueSet->add(new TrueRequirement());
214        $falseSet = new RequirementSet();
215        $falseSet->add(new FalseRequirement());
216
217        $nestedTrueSet = new RequirementSet();
218        $nestedTrueSet->merge($trueSet);
219        $this->assertTrue(
220            $nestedTrueSet->fulfilled(),
221            'A nested mandatory set of type and with one mandatory TrueRequirement is not fulfilled'
222        );
223
224        $nestedFalseSet = new RequirementSet();
225        $nestedFalseSet->merge($falseSet);
226        $this->assertFalse(
227            $nestedFalseSet->fulfilled(),
228            'A nested mandatory set of type and with one mandatory FalseRequirement is fulfilled'
229        );
230
231        $nestedMixedSet = new RequirementSet();
232        $nestedMixedSet->merge($trueSet);
233        $nestedMixedSet->merge($falseSet);
234        $this->assertFalse(
235            $nestedMixedSet->fulfilled(),
236            'Two nested mandatory sets of type and with one mandatory True- and'
237            . ' one mandatory FalseRequirement respectively are fulfilled'
238        );
239    }
240
241    public function testNestedOptionalRequirementsOfTypeAnd()
242    {
243        $trueSet = new RequirementSet(true);
244        $trueSet->add(new TrueRequirement());
245        $falseSet = new RequirementSet(true);
246        $falseSet->add(new FalseRequirement());
247
248        $nestedTrueSet = new RequirementSet(true);
249        $nestedTrueSet->merge($trueSet);
250        $this->assertTrue(
251            $nestedTrueSet->fulfilled(),
252            'A nested optional set of type and with one mandatory TrueRequirement is not fulfilled'
253        );
254
255        $nestedFalseSet = new RequirementSet(true);
256        $nestedFalseSet->merge($falseSet);
257        $this->assertTrue(
258            $nestedFalseSet->fulfilled(),
259            'A nested optional set of type and with one mandatory FalseRequirement is not fulfilled'
260        );
261
262        $nestedMixedSet = new RequirementSet(true);
263        $nestedMixedSet->merge($trueSet);
264        $nestedMixedSet->merge($falseSet);
265        $this->assertTrue(
266            $nestedMixedSet->fulfilled(),
267            'Two nested optional sets of type and with one mandatory True- and'
268            . ' one mandatory FalseRequirement respectively are not fulfilled'
269        );
270    }
271
272    public function testNestedMixedRequirementsOfTypeAnd()
273    {
274        $mandatoryMandatoryTrueSet = new RequirementSet();
275        $mandatoryMandatoryTrueSet->add(new TrueRequirement());
276        $mandatoryOptionalTrueSet = new RequirementSet();
277        $mandatoryOptionalTrueSet->add(new TrueRequirement(array('optional' => true)));
278        $mandatoryMandatoryFalseSet = new RequirementSet();
279        $mandatoryMandatoryFalseSet->add(new FalseRequirement());
280        $mandatoryOptionalFalseSet = new RequirementSet();
281        $mandatoryOptionalFalseSet->add(new FalseRequirement(array('optional' => true)));
282        $optionalMandatoryTrueSet = new RequirementSet(true);
283        $optionalMandatoryTrueSet->add(new TrueRequirement());
284        $optionalOptionalTrueSet = new RequirementSet(true);
285        $optionalOptionalTrueSet->add(new TrueRequirement(array('optional' => true)));
286        $optionalMandatoryFalseSet = new RequirementSet(true);
287        $optionalMandatoryFalseSet->add(new FalseRequirement());
288        $optionalOptionalFalseSet = new RequirementSet(true);
289        $optionalOptionalFalseSet->add(new FalseRequirement(array('optional' => true)));
290
291        $mandatoryMandatoryOptionalTrueSet = new RequirementSet();
292        $mandatoryMandatoryOptionalTrueSet->merge($mandatoryOptionalTrueSet);
293        $mandatoryMandatoryOptionalTrueSet->merge($mandatoryMandatoryFalseSet);
294        $this->assertFalse(
295            $mandatoryMandatoryOptionalTrueSet->fulfilled(),
296            'A mandatory set of type and with two nested mandatory sets of type and where one has a optional'
297            . ' TrueRequirement and the other one has a mandatory FalseRequirement is fulfilled'
298        );
299
300        $mandatoryMandatoryOptionalFalseSet = new RequirementSet();
301        $mandatoryMandatoryOptionalFalseSet->merge($mandatoryOptionalFalseSet);
302        $mandatoryMandatoryOptionalFalseSet->merge($mandatoryMandatoryTrueSet);
303        $this->assertTrue(
304            $mandatoryMandatoryOptionalFalseSet->fulfilled(),
305            'A mandatory set of type and with two nested mandatory sets of type and where one has a mandatory'
306            . ' TrueRequirement and the other one has a optional FalseRequirement is not fulfilled'
307        );
308
309        $optionalOptionalOptionalTrueSet = new RequirementSet(true);
310        $optionalOptionalOptionalTrueSet->merge($optionalOptionalTrueSet);
311        $optionalOptionalOptionalTrueSet->merge($optionalMandatoryFalseSet);
312        $this->assertTrue(
313            $optionalOptionalOptionalTrueSet->fulfilled(),
314            'A optional set of type and with two nested optional sets of type and where one has a optional'
315            . ' TrueRequirement and the other one has a mandatory FalseRequirement is not fulfilled'
316        );
317
318        $optionalOptionalOptionalFalseSet = new RequirementSet(true);
319        $optionalOptionalOptionalFalseSet->merge($optionalOptionalFalseSet);
320        $optionalOptionalOptionalFalseSet->merge($optionalMandatoryTrueSet);
321        $this->assertTrue(
322            $optionalOptionalOptionalFalseSet->fulfilled(),
323            'A optional set of type and with two nested optional sets of type and where one has a mandatory'
324            . ' TrueRequirement and the other one has a optional FalseRequirement is not fulfilled'
325        );
326    }
327
328    public function testNestedMandatoryRequirementsOfTypeOr()
329    {
330        $trueSet = new RequirementSet(false, RequirementSet::MODE_OR);
331        $trueSet->add(new TrueRequirement());
332        $falseSet = new RequirementSet(false, RequirementSet::MODE_OR);
333        $falseSet->add(new FalseRequirement());
334
335        $nestedTrueSet = new RequirementSet(false, RequirementSet::MODE_OR);
336        $nestedTrueSet->merge($trueSet);
337        $this->assertTrue(
338            $nestedTrueSet->fulfilled(),
339            'A nested mandatory set of type or with one mandatory TrueRequirement is not fulfilled'
340        );
341
342        $nestedFalseSet = new RequirementSet(false, RequirementSet::MODE_OR);
343        $nestedFalseSet->merge($falseSet);
344        $this->assertFalse(
345            $nestedFalseSet->fulfilled(),
346            'A nested mandatory set of type or with one mandatory FalseRequirement is fulfilled'
347        );
348
349        $nestedMixedSet = new RequirementSet(false, RequirementSet::MODE_OR);
350        $nestedMixedSet->merge($trueSet);
351        $nestedMixedSet->merge($falseSet);
352        $this->assertTrue(
353            $nestedMixedSet->fulfilled(),
354            'Two nested mandatory sets of type or with one mandatory True- and'
355            . ' one mandatory FalseRequirement respectively are not fulfilled'
356        );
357    }
358
359    public function testNestedOptionalRequirementsOfTypeOr()
360    {
361        $trueSet = new RequirementSet(true, RequirementSet::MODE_OR);
362        $trueSet->add(new TrueRequirement());
363        $falseSet = new RequirementSet(true, RequirementSet::MODE_OR);
364        $falseSet->add(new FalseRequirement());
365
366        $nestedTrueSet = new RequirementSet(true, RequirementSet::MODE_OR);
367        $nestedTrueSet->merge($trueSet);
368        $this->assertTrue(
369            $nestedTrueSet->fulfilled(),
370            'A nested optional set of type or with one mandatory TrueRequirement is not fulfilled'
371        );
372
373        $nestedFalseSet = new RequirementSet(true, RequirementSet::MODE_OR);
374        $nestedFalseSet->merge($falseSet);
375        $this->assertTrue(
376            $nestedFalseSet->fulfilled(),
377            'A nested optional set of type or with one mandatory FalseRequirement is not fulfilled'
378        );
379
380        $nestedMixedSet = new RequirementSet(true, RequirementSet::MODE_OR);
381        $nestedMixedSet->merge($trueSet);
382        $nestedMixedSet->merge($falseSet);
383        $this->assertTrue(
384            $nestedMixedSet->fulfilled(),
385            'Two nested optional sets of type or with one mandatory True- and'
386            . ' one mandatory FalseRequirement respectively are not fulfilled'
387        );
388    }
389
390    public function testNestedMixedRequirementsOfTypeOr()
391    {
392        $mandatoryMandatoryTrueSet = new RequirementSet(false, RequirementSet::MODE_OR);
393        $mandatoryMandatoryTrueSet->add(new TrueRequirement());
394        $mandatoryOptionalTrueSet = new RequirementSet(false, RequirementSet::MODE_OR);
395        $mandatoryOptionalTrueSet->add(new TrueRequirement(array('optional' => true)));
396        $mandatoryMandatoryFalseSet = new RequirementSet(false, RequirementSet::MODE_OR);
397        $mandatoryMandatoryFalseSet->add(new FalseRequirement());
398        $mandatoryOptionalFalseSet = new RequirementSet(false, RequirementSet::MODE_OR);
399        $mandatoryOptionalFalseSet->add(new FalseRequirement(array('optional' => true)));
400        $optionalMandatoryTrueSet = new RequirementSet(true, RequirementSet::MODE_OR);
401        $optionalMandatoryTrueSet->add(new TrueRequirement());
402        $optionalOptionalTrueSet = new RequirementSet(true, RequirementSet::MODE_OR);
403        $optionalOptionalTrueSet->add(new TrueRequirement(array('optional' => true)));
404        $optionalMandatoryFalseSet = new RequirementSet(true, RequirementSet::MODE_OR);
405        $optionalMandatoryFalseSet->add(new FalseRequirement());
406        $optionalOptionalFalseSet = new RequirementSet(true, RequirementSet::MODE_OR);
407        $optionalOptionalFalseSet->add(new FalseRequirement(array('optional' => true)));
408
409        $mandatoryMandatoryOptionalTrueSet = new RequirementSet(false, RequirementSet::MODE_OR);
410        $mandatoryMandatoryOptionalTrueSet->merge($mandatoryOptionalTrueSet);
411        $mandatoryMandatoryOptionalTrueSet->merge($mandatoryMandatoryFalseSet);
412        $this->assertTrue($mandatoryMandatoryOptionalTrueSet->fulfilled());
413
414        $mandatoryMandatoryOptionalFalseSet = new RequirementSet(false, RequirementSet::MODE_OR);
415        $mandatoryMandatoryOptionalFalseSet->merge($mandatoryOptionalFalseSet);
416        $mandatoryMandatoryOptionalFalseSet->merge($mandatoryMandatoryTrueSet);
417        $this->assertTrue($mandatoryMandatoryOptionalFalseSet->fulfilled());
418
419        $optionalOptionalOptionalTrueSet = new RequirementSet(true, RequirementSet::MODE_OR);
420        $optionalOptionalOptionalTrueSet->merge($optionalOptionalTrueSet);
421        $optionalOptionalOptionalTrueSet->merge($optionalMandatoryFalseSet);
422        $this->assertTrue($optionalOptionalOptionalTrueSet->fulfilled());
423
424        $optionalOptionalOptionalFalseSet = new RequirementSet(true, RequirementSet::MODE_OR);
425        $optionalOptionalOptionalFalseSet->merge($optionalOptionalFalseSet);
426        $optionalOptionalOptionalFalseSet->merge($optionalMandatoryTrueSet);
427        $this->assertTrue($optionalOptionalOptionalFalseSet->fulfilled());
428    }
429
430    public function testNestedMandatoryRequirementsOfDifferentTypes()
431    {
432        $true = new TrueRequirement();
433        $false = new FalseRequirement();
434
435        $level1And = new RequirementSet();
436        $level2FirstOr = new RequirementSet(false, RequirementSet::MODE_OR);
437        $level2SecondOr = new RequirementSet(false, RequirementSet::MODE_OR);
438        $level1And->merge($level2FirstOr)->merge($level2SecondOr);
439        $level3FirstAnd = new RequirementSet();
440        $level3SecondAnd = new RequirementSet();
441        $level2FirstOr->merge($level3FirstAnd)->merge($level3SecondAnd);
442        $level2SecondOr->merge($level3FirstAnd)->merge($level3SecondAnd);
443        $level3FirstAnd->add($true)->add($true);
444        $level3SecondAnd->add($false)->add($true);
445        $this->assertTrue($level1And->fulfilled());
446
447        $level1Or = new RequirementSet(false, RequirementSet::MODE_OR);
448        $level2FirstAnd = new RequirementSet();
449        $level2SecondAnd = new RequirementSet();
450        $level1Or->merge($level2FirstAnd)->merge($level2SecondAnd);
451        $level3FirstOr = new RequirementSet(false, RequirementSet::MODE_OR);
452        $level3SecondOr = new RequirementSet(false, RequirementSet::MODE_OR);
453        $level2FirstAnd->merge($level3FirstOr)->merge($level3SecondOr);
454        $level2SecondAnd->merge($level3FirstOr)->merge($level3SecondOr);
455        $level3FirstOr->add($false);
456        $level3SecondOr->add($true);
457        $this->assertFalse($level1Or->fulfilled());
458    }
459
460    public function testNestedOptionalRequirementsOfDifferentTypes()
461    {
462        $true = new TrueRequirement();
463        $false = new FalseRequirement();
464
465        $level1And = new RequirementSet();
466        $level2FirstAnd = new RequirementSet(true);
467        $level2SecondAnd = new RequirementSet(true);
468        $level1And->merge($level2FirstAnd)->merge($level2SecondAnd);
469        $level3FirstOr = new RequirementSet(true, RequirementSet::MODE_OR);
470        $level3SecondOr = new RequirementSet(true, RequirementSet::MODE_OR);
471        $level2FirstAnd->merge($level3FirstOr)->merge($level3SecondOr);
472        $level2SecondAnd->merge($level3FirstOr)->merge($level3SecondOr);
473        $level3FirstOr->add($false);
474        $level3SecondOr->add($false);
475        $this->assertFalse($level1And->fulfilled());
476        $this->assertTrue($level2FirstAnd->fulfilled());
477        $this->assertTrue($level2SecondAnd->fulfilled());
478
479        $level1Or = new RequirementSet(false, RequirementSet::MODE_OR);
480        $level2FirstOr = new RequirementSet(true, RequirementSet::MODE_OR);
481        $level2SecondOr = new RequirementSet(true, RequirementSet::MODE_OR);
482        $level1Or->merge($level2FirstOr)->merge($level2SecondOr);
483        $level3FirstAnd = new RequirementSet(true);
484        $level3SecondAnd = new RequirementSet(true);
485        $level2FirstOr->merge($level3FirstAnd)->merge($level3SecondAnd);
486        $level2SecondOr->merge($level3FirstAnd)->merge($level3SecondAnd);
487        $level3FirstAnd->add($true)->add($true);
488        $level3SecondAnd->add($false)->add($true);
489        $this->assertTrue($level1Or->fulfilled());
490    }
491
492    public function testNestedMixedRequirementsOfDifferentTypes()
493    {
494        $this->markTestIncomplete();
495    }
496}
497