Passed
Push — master ( dff13b...dab0e7 )
by Jesse
03:04
created

Instantiator_creates_empty_instances   A

Complexity

Total Complexity 9

Size/Duplication

Total Lines 112
Duplicated Lines 0 %

Importance

Changes 0
Metric Value
wmc 9
dl 0
loc 112
c 0
b 0
f 0
rs 10

8 Methods

Rating   Name   Duplication   Size   Complexity  
A allClasses() 0 3 1
A creating_a_new_instance_on_each_call() 0 9 1
A creating_instances_without_calling_the_constructor() 0 5 1
A throwing_an_invalid_argument_exception_when_the_class_does_not_exist() 0 9 1
A classes() 0 13 1
A either_throwing_an_exception_in_the_constructor_or_correctly_instantiating() 0 14 2
A finding_out_which_class_is_instantiated() 0 3 1
A illegalClasses() 0 17 1
1
<?php
2
declare(strict_types=1);
3
4
namespace Stratadox\Instantiator\Test;
5
6
use function array_merge;
7
use Exception;
8
use InvalidArgumentException;
9
use PHPUnit\Framework\TestCase;
10
use ReflectionClass;
11
use stdClass;
12
use Stratadox\Instantiator\CannotFindTheClass;
13
use Stratadox\Instantiator\CannotInstantiateThis;
14
use Stratadox\Instantiator\ClassIsAbstract;
15
use Stratadox\Instantiator\Instantiator;
16
use Stratadox\Instantiator\Test\Fixtures\AbstractClass;
17
use Stratadox\Instantiator\Test\Fixtures\AnInterface;
18
use Stratadox\Instantiator\Test\Fixtures\ExceptionThrowingConstructor;
19
use Stratadox\Instantiator\Test\Fixtures\FinalInternal;
20
use Stratadox\Instantiator\Test\Fixtures\PrivateClone;
21
use Stratadox\Instantiator\Test\Fixtures\PrivateConstructor;
22
use Stratadox\Instantiator\Test\Fixtures\PrivateConstructorAndClone;
23
use Stratadox\Instantiator\ThatIsAnInterface;
24
25
/**
26
 * @covers \Stratadox\Instantiator\Instantiator
27
 * @covers \Stratadox\Instantiator\CannotFindTheClass
28
 * @covers \Stratadox\Instantiator\ClassIsAbstract
29
 * @covers \Stratadox\Instantiator\ThatIsAnInterface
30
 */
31
class Instantiator_creates_empty_instances extends TestCase
32
{
33
    /**
34
     * @test
35
     * @dataProvider classes
36
     */
37
    function creating_instances_without_calling_the_constructor(string $class)
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
38
    {
39
        $instance = Instantiator::forThe($class)->instance();
40
41
        $this->assertInstanceOf($class, $instance);
42
    }
43
44
    /**
45
     * @test
46
     * @dataProvider classes
47
     */
48
    function creating_a_new_instance_on_each_call(string $class)
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
49
    {
50
        $instantiator = Instantiator::forThe($class);
51
52
        $instance1 = $instantiator->instance();
53
        $instance2 = $instantiator->instance();
54
55
        $this->assertEquals($instance1, $instance2);
56
        $this->assertNotSame($instance1, $instance2);
57
    }
58
59
    /**
60
     * @test
61
     * @dataProvider classes
62
     */
63
    function finding_out_which_class_is_instantiated(string $class)
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
64
    {
65
        $this->assertEquals($class, Instantiator::forThe($class)->class());
66
    }
67
68
    /**
69
     * @test
70
     * @dataProvider illegalClasses
71
     */
72
    function throwing_an_invalid_argument_exception_when_the_class_does_not_exist(
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
73
        string $class,
74
        string $expectedClass,
75
        string $expectedMessage
76
    ) {
77
        $this->expectException($expectedClass);
78
        $this->expectExceptionMessage($expectedMessage);
79
80
        Instantiator::forThe($class);
81
    }
82
83
    /**
84
     * @test
85
     * @dataProvider allClasses
86
     */
87
    function either_throwing_an_exception_in_the_constructor_or_correctly_instantiating(
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
88
        string $class,
89
        string $expectedClass = 'N/A',
90
        string $expectedMessage = 'N/A'
91
    ) {
92
        try {
93
            $instantiator = Instantiator::forThe($class);
94
        } catch (CannotInstantiateThis $exception) {
95
            $this->assertInstanceOf($expectedClass, $exception);
96
            $this->assertEquals($expectedMessage, $exception->getMessage());
97
            return;
98
        }
99
        $instance = $instantiator->instance();
100
        $this->assertInstanceOf($class, $instance);
101
    }
102
103
    public function classes(): array
104
    {
105
        return [
106
            'class with exception in the constructor'  => [ExceptionThrowingConstructor::class],
107
            'class with private clone'                 => [PrivateClone::class],
108
            'class with private constructor'           => [PrivateConstructor::class],
109
            'class with private constructor and clone' => [PrivateConstructorAndClone::class],
110
            'this test class'                          => [__CLASS__],
111
            'the basic Exception class'                => [Exception::class],
112
            'an InvalidArgumentException'              => [InvalidArgumentException::class],
113
            'the built-in stdClass'                    => [stdClass::class],
114
            'a ReflectionClass'                        => [ReflectionClass::class],
115
            'a final internal class'                   => [FinalInternal::class],
116
        ];
117
    }
118
119
    public function illegalClasses(): array
120
    {
121
        return [
122
            'non existing class' => [
123
                'non existing class',
124
                CannotFindTheClass::class,
125
                'Could not create instantiator: Class non existing class does not exist.'
126
            ],
127
            'abstract class' => [
128
                AbstractClass::class,
129
                ClassIsAbstract::class,
130
                'Could not create instantiator: Class '.AbstractClass::class.' is abstract.'
131
            ],
132
            'interface' => [
133
                AnInterface::class,
134
                ThatIsAnInterface::class,
135
                'Could not create instantiator: '.AnInterface::class.' is an interface.'
136
            ],
137
        ];
138
    }
139
140
    public function allClasses(): array
141
    {
142
        return array_merge($this->classes(), $this->illegalClasses());
143
    }
144
}
145