Completed
Push — master ( 57eaae...d53a99 )
by Simone
03:18 queued 01:22
created

ResourceTest::testProvideRule()   B

Complexity

Conditions 1
Paths 1

Size

Total Lines 33
Code Lines 18

Duplication

Lines 33
Ratio 100 %

Importance

Changes 0
Metric Value
dl 33
loc 33
c 0
b 0
f 0
rs 8.8571
cc 1
eloc 18
nc 1
nop 0
1
<?php
2
3
/**
4
 * This file is part of sensorario/resources repository
5
 *
6
 * (c) Simone Gentili <[email protected]>
7
 *
8
 * For the full copyright and license information, please view the LICENSE
9
 * file that was distributed with this source code.
10
 */
11
12
namespace Sensorario\Resources\Test\Resources;
13
14
use DateInterval;
15
use DateTime;
16
use PHPUnit\Framework\TestCase;
17
use Resources\Bar;
18
use Resources\BirthDay;
19
use Resources\UndefinedObject;
20
use Resources\ComposedResource;
21
use Resources\Foo;
22
use Resources\MandatoryDependency;
23
use Resources\ResourceWithoutRules;
24
use Resources\SomeApiRequest;
25
use Resources\UserCreationEvent;
26
use Sensorario\Resources\Configurator;
27
use Sensorario\Resources\Container;
28
use Sensorario\Resources\Resource;
29
use Sensorario\Resources\Validators\ResourcesValidator;
30
31
final class ResourceTest extends TestCase
32
{
33
    /**
34
     * @expectedException              \Sensorario\Resources\Exceptions\UndefinedMethodException
35
     * @expectedExceptionMessageRegExp #Method `.*::.*()` is not yet implemented#
36
     */
37
    public function testExceptionIsThrownWhenNotYetImplementedMethodIsCalled()
38
    {
39
        $configurator = new Configurator(
40
            'empty_resource',
41
            new Container([
42
                'resources' => [
43
                    'empty_resource' => [
44
                        'constraints' => [],
45
                    ],
46
                ],
47
            ])
48
        );
49
50
        $resource = Resource::box([], $configurator);
51
52
        $resource->notYetImplementedMethod();
53
    }
54
55
    /**
56
     * @expectedException              Sensorario\Resources\Exceptions\NotAllowedKeyException
57
     * @expectedExceptionMessageRegExp #Key `.*::.*` is not allowed#
58
     */
59
    public function testNotAllowedFieldThroghRuntimeException()
60
    {
61
        $configurator = new Configurator(
62
            'empty_resource',
63
            new Container([
64
                'resources' => [
65
                    'empty_resource' => [
66
                        'constraints' => [
67
                            'allowedValues' => [
68
                                'name',
69
                                'surname',
70
                            ],
71
                        ],
72
                    ],
73
                ],
74
            ])
75
        );
76
77
        $resource = Resource::box([
78
            'name' => 'Simone',
79
            'surname' => 'Gentili',
80
            'not allowed' => 'foo',
81
        ], $configurator);
82
    }
83
84
    /**
85
     * @expectedException              Sensorario\Resources\Exceptions\PropertyException
86
     * @expectedExceptionMessageRegExp #Property `.*::.*` is mandatory but not set#
87
     */
88
    public function testMissingMandatoryFieldThroghRuntimeException()
89
    {
90
        $configurator = new Configurator(
91
            'empty_resource',
92
            new Container([
93
                'resources' => [
94
                    'empty_resource' => [
95
                        'constraints' => [
96
                            'mandatory' => [
97
                                'name',
98
                            ],
99
                        ],
100
                    ],
101
                ],
102
            ])
103
        );
104
105
        $resource = Resource::box([
106
            'surname' => 'Gentili',
107
        ], $configurator);
108
    }
109
110
    public function testMandatoryFieldsAreAuthomaticallyAllowed()
111
    {
112
        $configurator = new Configurator(
113
            'empty_resource',
114
            new Container([
115
                'resources' => [
116
                    'empty_resource' => [
117
                        'constraints' => [
118
                            'mandatory' => [
119
                                'name',
120
                                'surname',
121
                            ],
122
                        ],
123
                    ],
124
                ],
125
            ])
126
        );
127
128
        $resource = Resource::box([
129
            'name'    => 'Simone',
130
            'surname' => 'Gentili',
131
        ], $configurator);
132
133
        $this->assertEquals(
134
            'Simone',
135
            $resource->name()
136
        );
137
    }
138
139
    /**
140
     * @expectedException        Sensorario\Resources\Exceptions\PropertyNameEmptyException
141
     * @expectedExceptionMessage Oops! Property name requested is empty string!!
142
     */
143
    public function testExceptionMessageInCaseOfEmptyPropertyName()
144
    {
145
        $configurator = new Configurator(
146
            'empty_resource',
147
            new Container([
148
                'resources' => [
149
                    'empty_resource' => [
150
                        'constraints' => [
151
                            'mandatory' => [
152
                                'name',
153
                                'surname',
154
                            ],
155
                        ],
156
                    ],
157
                ],
158
            ])
159
        );
160
161
        $resource = Resource::box([
162
            'name'    => 'Simone',
163
            'surname' => 'Gentili',
164
        ], $configurator);
165
166
        $this->assertEquals(
167
            'Simone',
168
            $resource->get('')
169
        );
170
    }
171
172
    /**
173
     * @expectedException              Sensorario\Resources\Exceptions\FactoryMethodException
174
     * @expectedExceptionMessageRegExp #Invalid factory method#
175
     */
176
    public function testFactoryMethods()
177
    {
178
        Resource::invalidFactoryName();
179
    }
180
181
    public function testCanHaveDefaultValues()
182
    {
183
        $configurator = new Configurator(
184
            'empty_resource',
185
            new Container([
186
                'resources' => [
187
                    'empty_resource' => [
188
                        'constraints' => [
189
                            'mandatory' => [
190
                                'name',
191
                            ],
192
                            'defaults' => [
193
                                'name' => 'Firefox',
194
                            ],
195
                        ],
196
                    ],
197
                ],
198
            ])
199
        );
200
201
        $resource = Resource::box([], $configurator);
202
203
        $this->assertEquals(
204
            'Firefox',
205
            $resource->name()
206
        );
207
    }
208
209
    public function testPropertyExists()
210
    {
211
        $foo = Bar::box();
212
213
        $this->assertFalse(
214
            $foo->hasProperty('nonExistentProperty')
215
        );
216
    }
217
218
    /** @dataProvider propertiesProvider */
219
    public function testHasProperties($result, $properties)
220
    {
221
        $foo = UserCreationEvent::box([
222
            'type' => 'human',
223
            'username' => 'Sensorario',
224
        ]);
225
226
        $this->assertSame(
227
            $result,
228
            $foo->hasProperties($properties)
229
        );
230
    }
231
232
    public function propertiesProvider()
233
    {
234
        return [
235
            [false, ['buppa']],
236
            [true, ['type', 'username']],
237
        ];
238
    }
239
240
    public function testAllowAccessToProperties()
241
    {
242
        $foo = Bar::box([
243
            'name' => 'Firefox'
244
        ]);
245
246
        $this->assertEquals(
247
            'Firefox',
248
            $foo->get('name')
249
        );
250
    }
251
252
    public function testAllowAccessToPropertiesThroughDefaultValue()
253
    {
254
        $foo = Bar::box();
255
256
        $this->assertEquals(
257
            'Firefox',
258
            $foo->get('name')
259
        );
260
    }
261
262
    /**
263
     * @expectedException Sensorario\Resources\Exceptions\NoValuesException
264
     */
265
    public function testThroughExceptionWhenNoValuesProvided()
266
    {
267
        $foo = Bar::box();
268
        $foo->get('foo');
269
    }
270
271
    /**
272
     * @expectedException              Sensorario\Resources\Exceptions\AttributeTypeException
273
     * @expectedExceptionMessageRegExp #Attribute `.*` must be of type `array`#
274
     */
275
    public function testPropertyCouldBeAScalar()
276
    {
277
        SomeApiRequest::box([
278
            'fields' => 'not a scalar',
279
        ]);
280
    }
281
282
    /**
283
     * @expectedException              Sensorario\Resources\Exceptions\NotObjectTypeFoundException
284
     * @expectedExceptionMessageRegExp #Attribute `.*` must be an object of type DateTime#
285
     */
286
    public function testPropertyCouldBeTheRightnObject()
287
    {
288
        BirthDay::box([
289
            'date' => new DateInterval('P1D'),
290
        ]);
291
    }
292
293
    public function testPropertiesAccessor()
294
    {
295
        $aSpecificRule = [ 'custom-validator' => 'email' ];
296
297
        $configurator = new Configurator(
298
            'email-resource',
299
            new Container([
300
                'resources' => [
301
                    'email-resource' => [
302
                        'constraints' => [
303
                            'mandatory' => [
304
                                'name',
305
                            ],
306
                        ]
307
                    ],
308
                ],
309
            ])
310
        );
311
312
        $properties = [
313
            'name' => 'Simone',
314
        ];
315
316
        $resource = Resource::box($properties, $configurator);
317
318
        $this->assertEquals(
319
            $properties,
320
            $resource->properties()
321
        );
322
    }
323
324
    /**
325
     * @expectedException              Sensorario\Resources\Exceptions\PropertyNotSetException
326
     * @expectedExceptionMessageRegExp #Property `.*::.*` is mandatory but not set#
327
     */
328
    public function testWhenCondition()
329
    {
330
        MandatoryDependency::box([
331
            'foo' => 'bar',
332
            'mandatory_mello' => 'bar',
333
        ]);
334
    }
335
336
    public function testResourcesComposition()
337
    {
338
        $composition = ComposedResource::box([
339
            'credentials' => Foo::box([
340
                'name' => 'Sam'
341
            ]),
342
        ]);
343
344
        $this->assertEquals([
345
            'credentials' => [
346
                'name' => 'Sam',
347
            ]
348
        ],
349
        $composition->properties()
350
    );
351
    }
352
353
    /**
354
     * @expectedException              Sensorario\Resources\Exceptions\PropertyException
355
     * @expectedExceptionMessageRegExp #When property `.*` has value `.*` also `.*` is mandatory#
356
     */
357
    public function testMandatoryValuesWhenPropertyAssumeAValue()
358
    {
359
        UserCreationEvent::box([
360
            'type' => 'guest',
361
        ]);
362
    }
363
364
    /**
365
     * @expectedException              Sensorario\Resources\Exceptions\PropertyWithoutRuleException
366
     * @expectedExceptionMessageRegExp #When property `.*` is an object class, must be defined in Resources::rules()#
367
     */
368
    public function testAnExceptionIsThrownIfAPropertyIsAnObjectButClassInNotDefinedInRuleMethod()
369
    {
370
        ResourceWithoutRules::box([
371
            'datetime' => new DateTime(),
372
        ]);
373
    }
374
375
    public function testDefaultValuesTwo()
376
    {
377
        $resource = new Resource(
378
            [],
379
            new ResourcesValidator()
380
        );
381
382
        $this->assertEquals(
383
            [],
384
            $resource->allowed()
385
        );
386
387
        $resource->applyConfiguration(
388
            new Configurator(
389
                'bar',
390
                new Container([
391
                    'resources' => [
392
                        'bar' => [
393
                            'constraints' => [
394
                                'allowed' => [ 'allowed_property_name' ],
395
                            ]
396
                        ],
397
                    ],
398
                ])
399
            )
400
        );
401
402
        $this->assertEquals(
403
            [ 'allowed_property_name' ],
404
            $resource->allowed('bar')
405
        );
406
    }
407
408
    public function testDefaultValues()
409
    {
410
        $configurator = new Configurator(
411
            'foo',
412
            new Container([
413
                'resources' => [
414
                    'foo' => [
415
                        'constraints' => [
416
                            'mandatory' => [
417
                                'ciambella',
418
                            ],
419
                            'defaults' => [
420
                                'ciambella' => '42',
421
                            ],
422
                        ]
423
                    ],
424
                ],
425
            ])
426
        );
427
428
        $resource = Resource::box(
429
            [],
430
            $configurator
431
        );
432
433
        $this->assertEquals(
434
            '42',
435
            $resource->get('ciambella')
436
        );
437
    }
438
439
    public function testResourceShouldBeCreatedViaContainer()
440
    {
441
        $container = new Container([
442
            'resources' => [
443
                'foo' => [
444
                    'constraints' => [
445
                        'allowed' => [ 'allowed_property_name' ],
446
                    ]
447
                ],
448
                'unused_resource' => [
449
                    'constraints' => [
450
                        'allowed' => [ 'bar' ],
451
                    ]
452
                ],
453
            ],
454
        ]);
455
456
        $this->assertEquals(
457
            [ 'allowed_property_name' ],
458
            $container->allowed('foo')
459
        );
460
    }
461
462
    /**
463
     * @expectedException              Sensorario\Resources\Exceptions\PropertyNotSetException
464
     * @expectedExceptionMessageRegExp #Property `.*::.*` is mandatory but not set#
465
     */
466
    public function testDependentMandatoryProperties()
467
    {
468
        $configurator = new Configurator(
469
            'foo',
470
            new Container([
471
                'resources' => [
472
                    'foo' => [
473
                        'constraints' => [
474
                            'allowed' => [
475
                                'bar',
476
                            ],
477
                            'mandatory' => [
478
                                'mandatory_property_name',
479
                                'foo' => [
480
                                    'when' => [
481
                                        'property' => 'bar',
482
                                        'condition' => 'is_present',
483
                                    ]
484
                                ],
485
                            ],
486
                        ]
487
                    ],
488
                ],
489
            ])
490
        );
491
492
        $properties = [
493
            'mandatory_property_name' => '42',
494
            'bar' => 'beer',
495
        ];
496
497
        Resource::box(
498
            $properties,
499
            $configurator
500
        );
501
    }
502
503
    public function testMandatoryConstraintsAreAutomaticallyAllowed()
504
    {
505
        $container = new Container([
506
            'resources' => [
507
                'foo' => [
508
                    'constraints' => [
509
                        'mandatory' => [ 'mandatory_property' ],
510
                    ]
511
                ],
512
            ],
513
        ]);
514
515
        $this->assertEquals(
516
            [ 'mandatory_property' ],
517
            $container->allowed('foo')
518
        );
519
    }
520
521
    /**
522
     * @expectedException              Sensorario\Resources\Exceptions\UnexpectedValueException
523
     * @expectedExceptionMessageRegExp #Value `.*` is not allowed for key `.*`. Allowed values are:#
524
     */
525
    public function testAllowedValues()
526
    {
527
        $configurator = new Configurator(
528
            'foo',
529
            new Container([
530
                'resources' => [
531
                    'foo' => [
532
                        'constraints' => [
533
                            'allowed' => [ 'user_type' ],
534
                            'allowedValues' => [
535
                                'user_type' => [
536
                                    4, 
537
                                    7,
538
                                ],
539
                            ],
540
                        ],
541
                    ],
542
                ],
543
            ])
544
        );
545
546
        $properties = [ 'user_type' => 3 ];
547
548
        Resource::box(
549
            $properties,
550
            $configurator
551
        );
552
    }
553
554
    public function testRewriteRulesWithCondition()
555
    {
556
        $configurator = new Configurator(
557
            'foo',
558
            new Container([
559
                'resources' => [
560
                    'foo' => [
561
                        'rewrite' => [
562
                            'width' => [
563
                                'set' => [
564
                                    'equals_to' => 'height',
565
                                ],
566
                                'when' => [
567
                                    'greater_than' => 'height',
568
                                ],
569
                            ],
570
                        ],
571
                        'constraints' => [
572
                            'allowed' => [
573
                                'width',
574
                                'height',
575
                            ],
576
                        ],
577
                    ], 
578
                ],
579
            ])
580
        );
581
        $properties = [
582
            'width'  => 3000,
583
            'height' => 400,
584
        ];
585
586
        $box = Resource::box(
587
            $properties,
588
            $configurator
589
        );
590
591
        $overwritternProperties = [
592
            'width'  => 400,
593
            'height' => 400,
594
        ];
595
596
        $overWrittenBox = Resource::box(
597
            $overwritternProperties,
598
            $configurator
599
        );
600
601
        $this->assertEquals(
602
            $overWrittenBox,
603
            $box
604
        );
605
    }
606
607
    /**
608
     * @expectedException              Sensorario\Resources\Exceptions\OutOfRangeException
609
     * @expectedExceptionMessageRegExp #Value `.*` is out of range: `.*`.#
610
     */
611
    public function testAcceptRangeOfValues()
612
    {
613
        $configurator = new Configurator(
614
            'foo',
615
            new Container([
616
                'resources' => [
617
                    'foo' => [
618
                        'constraints' => [
619
                            'allowedRanges' => [
620
                                'age' => [
621
                                    'more_than' => 3,
622
                                    'less_than' => 42,
623
                                ],
624
                            ],
625
                            'allowed' => [
626
                                'age'
627
                            ],
628
                        ],
629
                    ],
630
                ],
631
            ])
632
        );
633
634
        Resource::box(
635
            [ 'age' => 2 ],
636
            $configurator
637
        );
638
    }
639
640
    public function testAllResourcesInheritGlobalAllowingConfiguration()
641
    {
642
        $configurator = new Configurator(
643
            'foo',
644
            new Container([
645
                'globals' => [
646
                    'allowed' => [
647
                        'width',
648
                        'height',
649
                    ],
650
                ],
651
                'resources' => [
652
                    'foo' => [
653
                        'constraints' => [
654
                            'allowed' => [
655
                                'foo_size',
656
                            ],
657
                        ],
658
                    ], 
659
                    'bar' => [
660
                        'constraints' => [
661
                            'allowed' => [
662
                                'bar_size',
663
                            ],
664
                        ],
665
                    ], 
666
                ],
667
            ])
668
        );
669
670
        $resource = Resource::box(
671
            [],
672
            $configurator
673
        );
674
675
        $this->assertEquals(
676
            ['foo_size', 'width', 'height'],
677
            $resource->allowed()
678
        );
679
    }
680
681
    /**
682
     * @expectedException Sensorario\Resources\Exceptions\PropertyException
683
     */
684
    public function testHasMandatoryPropertiesWhenAnotherOneHasAParticularValue()
685
    {
686
        $configurator = new Configurator(
687
            'foo',
688
            new Container([
689
                'resources' => [
690
                    'foo' => [
691
                        'constraints' => [
692
                            'allowed' => [
693
                                'bar',
694
                            ],
695
                            'mandatory' => [
696
                                'mandatory_property_name',
697
                                'foo' => [
698
                                    'when' => [
699
                                        'property' => 'bar',
700
                                        'has_value' => '42',
701
                                    ]
702
                                ],
703
                            ],
704
                        ]
705
                    ],
706
                ],
707
            ])
708
        );
709
710
        $properties = [
711
            'bar' => '42',
712
        ];
713
714
        Resource::box(
715
            $properties,
716
            $configurator
717
        );
718
    }
719
720
    /**
721
     * @expectedException Sensorario\Resources\Exceptions\EmailException
722
     */
723
    public function testEmailValidationFails()
724
    {
725
        $configurator = new Configurator(
726
            'email-resource',
727
            new Container([
728
                'resources' => [
729
                    'email-resource' => [
730
                        'constraints' => [
731
                            'mandatory' => [
732
                                'first-email',
733
                            ],
734
                            'rules' => [
735
                                'first-email' => [ 'custom-validator' => 'email' ],
736
                            ],
737
                        ]
738
                    ],
739
                ],
740
            ])
741
        );
742
743
        $properties = [
744
            'first-email' => 'invalid email',
745
        ];
746
747
        Resource::box($properties, $configurator);
748
    }
749
750
    /**
751
     * @expectedException              Sensorario\Resources\Exceptions\WrongPropertyValueException
752
     * @expectedExceptionMessageRegExp #Property .* must be an integer!#
753
     */
754
    public function testIntegersCanBeDefinedWithNumberRule()
755
    {
756
        $configurator = new Configurator(
757
            'type-with-number',
758
            new Container([
759
                'resources' => [
760
                    'type-with-number' => [
761
                        'constraints' => [
762
                            'mandatory' => [ 'a-magic-number' ],
763
                            'rules' => [ 'a-magic-number' => [ 'scalar' => 'integer' ] ],
764
                        ]
765
                    ],
766
                ],
767
            ])
768
        );
769
770
        $properties = [
771
            'a-magic-number' => '42',
772
        ];
773
774
        $resource = Resource::box($properties, $configurator);
775
    }
776
777
    public function testEmailValidation()
778
    {
779
        $configurator = new Configurator(
780
            'email-resource',
781
            new Container([
782
                'resources' => [
783
                    'email-resource' => [
784
                        'constraints' => [
785
                            'mandatory' => [
786
                                'first-email',
787
                            ],
788
                            'rules' => [
789
                                'first-email' => [ 'custom-validator' => 'email' ],
790
                            ],
791
                        ]
792
                    ],
793
                ],
794
            ])
795
        );
796
797
        $properties = [
798
            'first-email' => '[email protected]',
799
        ];
800
801
        $resource = Resource::box($properties, $configurator);
802
803
        $this->assertEquals(
804
            '[email protected]',
805
            $resource->get('first-email')
806
        );
807
    }
808
809
    /** @dataProvider rules */
810
    public function testRulesKnowsIfRuleIsDefinedOrNot($expectation, $ruleName)
811
    {
812
        $configurator = new Configurator(
813
            'email-resource',
814
            new Container([
815
                'resources' => [
816
                    'email-resource' => [
817
                        'constraints' => [
818
                            'mandatory' => [
819
                                'first-email',
820
                            ],
821
                            'rules' => [
822
                                'first-email' => [ 'custom-validator' => 'email' ],
823
                            ],
824
                        ]
825
                    ],
826
                ],
827
            ])
828
        );
829
830
        $properties = [
831
            'first-email' => '[email protected]',
832
        ];
833
834
        $resource = Resource::box($properties, $configurator);
835
836
        $this->assertEquals(
837
            $expectation,
838
            $resource->isRuleDefinedFor($ruleName)
839
        );
840
    }
841
842
    public function rules()
843
    {
844
        return [
845
            [true, 'first-email'],
846
            [false, 'non-existent-field-name'],
847
        ];
848
    }
849
850
    public function testProvideRule()
851
    {
852
        $aSpecificRule = [ 'custom-validator' => 'email' ];
853
854
        $configurator = new Configurator(
855
            'email-resource',
856
            new Container([
857
                'resources' => [
858
                    'email-resource' => [
859
                        'constraints' => [
860
                            'mandatory' => [
861
                                'first-email',
862
                            ],
863
                            'rules' => [
864
                                'first-email' => $aSpecificRule,
865
                            ],
866
                        ]
867
                    ],
868
                ],
869
            ])
870
        );
871
872
        $properties = [
873
            'first-email' => '[email protected]',
874
        ];
875
876
        $resource = Resource::box($properties, $configurator);
877
878
        $this->assertEquals(
879
            $aSpecificRule,
880
            $resource->getRule('first-email')->asArray()
881
        );
882
    }
883
884
    /**
885
     * @expectedException Sensorario\Resources\Exceptions\PropertyWithoutRuleException
886
     * @expectedExceptionMessage Property date is an object but is not defined in rules
887
     */
888
    public function testUndefinedObject()
889
    {
890
        UndefinedObject::box([
891
            'date' => new \stdClass(),
892
        ]);
893
    }
894
895
    /**
896
     * @expectedException \Sensorario\Resources\Exceptions\InvalidCustomValidatorException
897
     * @expectedExceptionMessage Oops! `custom-validator` custom validator is not available. Only email is.
898
     */
899
    public function testDenyCustomValidatorDifferentFromEmail()
900
    {
901
        $configurator = new Configurator(
902
            'foo',
903
            new Container([
904
                'resources' => [
905
                    'foo' => [
906
                        'constraints' => [
907
                            'allowed' => [
908
                                'property_name',
909
                            ],
910
                            'rules' => [
911
                                'property_name' => [
912
                                    'custom-validator' => 'foo',
913
                                ]
914
                            ]
915
                        ],
916
                    ],
917
                ]
918
            ])
919
        );
920
921
        Resource::box([
922
            'property_name' => '42',
923
        ], $configurator);
924
    }
925
926
}
927