Completed
Pull Request — master (#4)
by Timóteo
05:46
created

RepositoryFactoryTest   A

Complexity

Total Complexity 11

Size/Duplication

Total Lines 153
Duplicated Lines 0 %

Importance

Changes 0
Metric Value
eloc 56
dl 0
loc 153
rs 10
c 0
b 0
f 0
wmc 11
1
<?php
2
3
declare(strict_types=1);
4
5
namespace TZachi\PhalconRepository\Tests\Unit;
6
7
use Phalcon\Annotations\AdapterInterface as AnnotationsAdapterInterface;
8
use Phalcon\Annotations\Annotation;
9
use Phalcon\Annotations\Collection;
10
use Phalcon\Annotations\Reflection;
11
use PHPUnit\Framework\MockObject\MockObject;
12
use PHPUnit\Framework\TestCase;
13
use RuntimeException;
14
use TZachi\PhalconRepository\Repository;
15
use TZachi\PhalconRepository\RepositoryFactory;
16
use TZachi\PhalconRepository\Tests\Mock\Repository\Company as CompanyRepository;
17
use function get_class;
18
19
final class RepositoryFactoryTest extends TestCase
20
{
21
    /**
22
     * @var Annotation|MockObject
23
     */
24
    private $annotation;
25
26
    /**
27
     * @var Collection|MockObject
28
     */
29
    private $collection;
30
31
32
    /**
33
     * @var Reflection|MockObject
34
     */
35
    private $reflection;
36
37
    /**
38
     * @var AnnotationsAdapterInterface|MockObject
39
     */
40
    private $annotations;
41
42
    /**
43
     * @var RepositoryFactory
44
     */
45
    private $factory;
46
47
    /**
48
     * @before
49
     */
50
    public function createDependencies(): void
51
    {
52
        $this->annotation  = $this->createMock(Annotation::class);
53
        $this->collection  = $this->createMock(Collection::class);
54
        $this->reflection  = $this->createMock(Reflection::class);
55
        $this->annotations = $this->createMock(AnnotationsAdapterInterface::class);
56
        $this->factory     = new RepositoryFactory($this->annotations);
57
    }
58
59
    /**
60
     * @test
61
     */
62
    public function getShouldUseSameRepositoryInstanceOnMultipleCalls(): void
63
    {
64
        $repository = $this->createMock(Repository::class);
65
66
        /**
67
         * @var RepositoryFactory|MockObject $factory
68
         */
69
        $factory = $this->createPartialMock(RepositoryFactory::class, ['create']);
70
        $factory->expects(self::once())
71
            ->method('create')
72
            ->with('Model')
73
            ->willReturn($repository);
74
75
        // Multiple calls to `get` to make sure that `create` will only be called once
76
        self::assertSame($repository, $factory->get('Model'));
77
        self::assertSame($repository, $factory->get('Model'));
78
        self::assertSame($repository, $factory->get('Model'));
79
    }
80
81
    /**
82
     * @test
83
     */
84
    public function createShouldUseRepositoryInAnnotations(): void
85
    {
86
        $this->setUpMocks(true, true, CompanyRepository::class);
87
88
        self::assertInstanceOf(CompanyRepository::class, $this->factory->create('Model'));
89
    }
90
91
    /**
92
     * @test
93
     */
94
    public function createShouldUseDefaultRepositoryWhenThereAreNoAnnotations(): void
95
    {
96
        $this->setUpMocks(false, false, null);
97
98
        // Make sure that the result repository is not an instance of a Repository subclass, but the actual class
99
        self::assertSame(Repository::class, get_class($this->factory->create('Model')));
100
    }
101
102
    /**
103
     * @test
104
     */
105
    public function createShouldUseDefaultRepositoryWhenRepositoryAnnotationWasNotSpecified(): void
106
    {
107
        $this->setUpMocks(true, false, null);
108
109
        // Make sure that the result repository is not an instance of a Repository subclass, but the actual class
110
        self::assertSame(Repository::class, get_class($this->factory->create('Model')));
111
    }
112
113
    /**
114
     * @test
115
     */
116
    public function createShouldThrowExceptionWithNoAnnotationParameter(): void
117
    {
118
        $this->setUpMocks(true, true, null);
119
120
        $this->expectException(RuntimeException::class);
121
        $this->expectExceptionMessage("Repository class '' doesn't exists");
122
123
        $this->factory->create('Model');
124
    }
125
126
    /**
127
     * @test
128
     */
129
    public function createShouldThrowExceptionWithInvalidAnnotation(): void
130
    {
131
        $this->setUpMocks(true, true, 'Inexistent\Class\Name');
132
133
        $this->expectException(RuntimeException::class);
134
        $this->expectExceptionMessage("Repository class 'Inexistent\Class\Name' doesn't exists");
135
136
        $this->factory->create('Model');
137
    }
138
139
    private function setUpMocks(bool $hasAnnotations, bool $hasRepositoryAnnotation, ?string $annotationArgument): void
140
    {
141
        $this->annotations->expects(self::once())
142
            ->method('get')
143
            ->with(self::identicalTo('Model'))
144
            ->willReturn($this->reflection);
145
146
        $this->reflection->expects(self::once())
147
            ->method('getClassAnnotations')
148
            ->willReturn($hasAnnotations ? $this->collection : false);
149
150
        if (!$hasAnnotations) {
151
            return;
152
        }
153
154
        $this->collection->expects(self::once())
155
            ->method('has')
156
            ->with(self::identicalTo(RepositoryFactory::REPOSITORY_ANNOTATION_NAME))
157
            ->willReturn($hasRepositoryAnnotation);
158
159
        if (!$hasRepositoryAnnotation) {
160
            return;
161
        }
162
163
        $this->annotation->expects(self::once())
164
            ->method('getArgument')
165
            ->with(self::identicalTo(0))
166
            ->willReturn($annotationArgument);
167
168
        $this->collection->expects(self::once())
169
            ->method('get')
170
            ->with(self::identicalTo(RepositoryFactory::REPOSITORY_ANNOTATION_NAME))
171
            ->willReturn($this->annotation);
172
    }
173
}
174