Passed
Pull Request — master (#5)
by Alex
03:18
created

testExecuteWillPrepareAndExecuteQuery()   B

Complexity

Conditions 7
Paths 32

Size

Total Lines 40
Code Lines 24

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
eloc 24
dl 0
loc 40
rs 8.6026
c 0
b 0
f 0
cc 7
nc 32
nop 1
1
<?php
2
3
declare(strict_types=1);
4
5
namespace ArpTest\DoctrineEntityRepository\Query;
6
7
use Arp\DoctrineEntityRepository\Constant\QueryServiceOption;
8
use Arp\DoctrineEntityRepository\Query\Exception\QueryServiceException;
9
use Arp\DoctrineEntityRepository\Query\QueryService;
10
use Arp\DoctrineEntityRepository\Query\QueryServiceInterface;
11
use Arp\Entity\EntityInterface;
12
use Doctrine\ORM\AbstractQuery;
13
use Doctrine\ORM\EntityManagerInterface;
14
use Doctrine\ORM\Query;
15
use Doctrine\ORM\QueryBuilder;
16
use PHPUnit\Framework\MockObject\MockObject;
17
use PHPUnit\Framework\TestCase;
18
use Psr\Log\LoggerInterface;
19
20
/**
21
 * @author  Alex Patterson <[email protected]>
22
 * @package ArpTest\DoctrineEntityRepository\Query
23
 */
24
final class QueryServiceTest extends TestCase
25
{
26
    /**
27
     * @var string
28
     */
29
    private $entityName;
30
31
    /**
32
     * @var EntityManagerInterface|MockObject
33
     */
34
    private $entityManager;
35
36
    /**
37
     * @var LoggerInterface|MockObject
38
     */
39
    private $logger;
40
41
    /**
42
     * Setup the test case dependencies.
43
     */
44
    public function setUp(): void
45
    {
46
        $this->entityName = EntityInterface::class;
47
48
        $this->entityManager = $this->getMockForAbstractClass(EntityManagerInterface::class);
49
50
        $this->logger = $this->getMockForAbstractClass(LoggerInterface::class);
51
    }
52
53
    /**
54
     * Assert that the QueryService implements QueryServiceInterface
55
     *
56
     * @covers \Arp\DoctrineEntityRepository\Query\QueryService::__construct
57
     */
58
    public function testImplementsQueryServiceInterface(): void
59
    {
60
        $queryService = new QueryService($this->entityName, $this->entityManager, $this->logger);
61
62
        $this->assertInstanceOf(QueryServiceInterface::class, $queryService);
63
    }
64
65
    /**
66
     * Assert that a query builder is returned without an alias.
67
     *
68
     * @covers \Arp\DoctrineEntityRepository\Query\QueryService::createQueryBuilder
69
     */
70
    public function testCreateQueryBuilderWillReturnQueryBuilderWithoutAlias(): void
71
    {
72
        $queryService = new QueryService($this->entityName, $this->entityManager, $this->logger);
73
74
        /** @var QueryBuilder|MockObject $queryBuilder */
75
        $queryBuilder = $this->createMock(QueryBuilder::class);
76
77
        $this->entityManager->expects($this->once())
78
            ->method('createQueryBuilder')
79
            ->willReturn($queryBuilder);
80
81
        $queryBuilder->expects($this->never())->method('select');
82
        $queryBuilder->expects($this->never())->method('from');
83
84
        $this->assertInstanceOf(QueryBuilder::class, $queryService->createQueryBuilder());
85
    }
86
87
    /**
88
     * Assert that a query builder is returned with the provided $alias
89
     *
90
     * @covers \Arp\DoctrineEntityRepository\Query\QueryService::createQueryBuilder
91
     */
92
    public function testCreateQueryBuilderWillReturnQueryBuilderWithAlias(): void
93
    {
94
        $queryService = new QueryService($this->entityName, $this->entityManager, $this->logger);
95
96
        $alias = 'foo';
97
98
        /** @var QueryBuilder|MockObject $queryBuilder */
99
        $queryBuilder = $this->createMock(QueryBuilder::class);
100
101
        $this->entityManager->expects($this->once())
102
            ->method('createQueryBuilder')
103
            ->willReturn($queryBuilder);
104
105
        $queryBuilder->expects($this->once())
106
            ->method('select')
107
            ->with($alias)
108
            ->willReturn($queryBuilder);
109
110
        $queryBuilder->expects($this->once())
111
            ->method('from')
112
            ->with($this->entityName, $alias);
113
114
        $this->assertInstanceOf(QueryBuilder::class, $queryService->createQueryBuilder($alias));
115
    }
116
117
    /**
118
     * Assert that if we provide a invalid query object to execute() a QueryServiceException will be thrown.
119
     *
120
     * @covers \Arp\DoctrineEntityRepository\Query\QueryService::execute
121
     *
122
     * @throws QueryServiceException
123
     */
124
    public function testExecuteWillThrowQueryServiceExceptionIfProvidedInvalidQuery(): void
125
    {
126
        $queryService = new QueryService($this->entityName, $this->entityManager, $this->logger);
127
128
        $invalidQuery = new \stdClass();
129
130
        $this->expectException(QueryServiceException::class);
131
        $this->expectExceptionMessage(
132
            sprintf(
133
                'Query provided must be of type \'%s\'; \'%s\' provided in \'%s::%s\'.',
134
                AbstractQuery::class,
135
                (is_object($invalidQuery) ? get_class($invalidQuery) : gettype($invalidQuery)),
136
                QueryService::class,
137
                'execute'
138
            )
139
        );
140
141
        $queryService->execute($invalidQuery);
0 ignored issues
show
Bug introduced by
$invalidQuery of type stdClass is incompatible with the type Doctrine\ORM\AbstractQue...ctrine\ORM\QueryBuilder expected by parameter $queryOrBuilder of Arp\DoctrineEntityReposi...QueryService::execute(). ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

141
        $queryService->execute(/** @scrutinizer ignore-type */ $invalidQuery);
Loading history...
142
    }
143
144
    /**
145
     * Assert that a query object provided to execute will be prepared with the provided options and then executed.
146
     *
147
     * @param array $options  The optional query options to assert get set on the query when being prepared.
148
     *
149
     * @covers \Arp\DoctrineEntityRepository\Query\QueryService::execute
150
     * @covers \Arp\DoctrineEntityRepository\Query\QueryService::prepareQuery
151
     *
152
     * @dataProvider getExecuteWillPrepareAndExecuteQueryData
153
     * @throws QueryServiceException
154
     */
155
    public function testExecuteWillPrepareAndExecuteQuery(array $options = []): void
156
    {
157
        $queryService = new QueryService($this->entityName, $this->entityManager, $this->logger);
158
159
        /** @var AbstractQuery|MockObject $query */
160
        $query = $this->createMock(AbstractQuery::class);
161
162
        if (array_key_exists('params', $options)) {
163
            $query->expects($this->once())
164
                ->method('setParameters')
165
                ->with($options['params']);
166
        }
167
168
        if (array_key_exists(QueryServiceOption::HYDRATION_MODE, $options)) {
169
            $query->expects($this->once())
170
                ->method('setHydrationMode')
171
                ->with($options[QueryServiceOption::HYDRATION_MODE]);
172
        }
173
174
        if (array_key_exists('hydration_cache_profile', $options)) {
175
            $query->expects($this->once())
176
                ->method('setHydrationCacheProfile')
177
                ->with($options['hydration_cache_profile']);
178
        }
179
180
        if (array_key_exists('result_set_mapping', $options)) {
181
            $query->expects($this->once())
182
                ->method('setResultSetMapping')
183
                ->with($options['result_set_mapping']);
184
        }
185
186
        if (!empty($options[QueryServiceOption::DQL]) && $query instanceof Query) {
187
            $query->expects($this->once())
188
                ->method('setDQL')
189
                ->with($options[QueryServiceOption::DQL]);
190
        }
191
192
        $query->expects($this->once())->method('execute')->willReturn([]);
193
194
        $queryService->execute($query, $options);
195
    }
196
197
    /**
198
     * @return array|\array[][]
199
     */
200
    public function getExecuteWillPrepareAndExecuteQueryData(): array
201
    {
202
        return [
203
            // Empty options
204
            [
205
                [],
206
            ],
207
208
            // Set parameters
209
            [
210
                [
211
                    'params' => [
212
                        'foo' => 'bar',
213
                        'baz' => 123,
214
                    ]
215
                ],
216
            ],
217
218
            // Hydration Mode
219
            [
220
                [
221
                    QueryServiceOption::HYDRATION_MODE => Query::HYDRATE_ARRAY,
222
                ]
223
            ],
224
        ];
225
    }
226
}
227