Passed
Push — master ( de0f46...445da7 )
by Alex
01:11 queued 12s
created

testOrWhereWillProxyToInternalQueryBuilder()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 9
Code Lines 5

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 1
eloc 5
nc 1
nop 1
dl 0
loc 9
rs 10
c 1
b 0
f 0
1
<?php
2
3
declare(strict_types=1);
4
5
namespace ArpTest\DoctrineQueryFilter;
6
7
use Arp\DoctrineQueryFilter\Enum\SortDirection;
8
use Arp\DoctrineQueryFilter\QueryBuilder;
9
use Arp\DoctrineQueryFilter\QueryBuilderInterface;
10
use Doctrine\Common\Collections\ArrayCollection;
11
use Doctrine\DBAL\Types\Types;
12
use Doctrine\ORM\Configuration;
13
use Doctrine\ORM\EntityManager;
14
use Doctrine\ORM\EntityManagerInterface;
15
use Doctrine\ORM\Query;
16
use Doctrine\ORM\Query\Expr;
17
use Doctrine\ORM\Query\Parameter;
18
use Doctrine\ORM\QueryBuilder as DoctrineQueryBuilder;
19
use PHPUnit\Framework\MockObject\MockObject;
20
use PHPUnit\Framework\TestCase;
21
22
/**
23
 * @author  Alex Patterson <[email protected]>
24
 * @package ArpTest\DoctrineQueryFilter
25
 */
26
final class QueryBuilderTest extends TestCase
27
{
28
    /**
29
     * @var DoctrineQueryBuilder&MockObject
30
     */
31
    private DoctrineQueryBuilder $doctrineQueryBuilder;
32
33
    /**
34
     * Prepare the test case dependencies
35
     */
36
    public function setUp(): void
37
    {
38
        $this->doctrineQueryBuilder = $this->createMock(DoctrineQueryBuilder::class);
39
    }
40
41
    /**
42
     * Assert the class implement QueryBuilderInterface
43
     */
44
    public function testInstanceOfQueryBuilderInterface(): void
45
    {
46
        $queryBuilder = new QueryBuilder($this->doctrineQueryBuilder);
47
48
        $this->assertInstanceOf(QueryBuilderInterface::class, $queryBuilder);
49
    }
50
51
    /**
52
     * Assert calls to createQueryBuilder will return a new instance of itself
53
     */
54
    public function testCreateQueryBuilderWillReturnAnewInstanceOfItself(): void
55
    {
56
        $queryBuilder = new QueryBuilder($this->doctrineQueryBuilder);
57
58
        /** @var EntityManager&MockObject $entityManager */
59
        $entityManager = $this->createMock(EntityManager::class);
60
61
        /** @var DoctrineQueryBuilder&MockObject $newDoctrineQueryBuilder */
62
        $newDoctrineQueryBuilder = $this->createMock(DoctrineQueryBuilder::class);
63
64
        $this->doctrineQueryBuilder->expects($this->once())
0 ignored issues
show
Bug introduced by
The method expects() does not exist on Doctrine\ORM\QueryBuilder. ( Ignorable by Annotation )

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

64
        $this->doctrineQueryBuilder->/** @scrutinizer ignore-call */ 
65
                                     expects($this->once())

This check looks for calls to methods that do not seem to exist on a given type. It looks for the method on the type itself as well as in inherited classes or implemented interfaces.

This is most likely a typographical error or the method has been renamed.

Loading history...
65
            ->method('getEntityManager')
66
            ->willReturn($entityManager);
67
68
        $entityManager->expects($this->once())
69
            ->method('createQueryBuilder')
70
            ->willReturn($newDoctrineQueryBuilder);
71
72
        $this->assertInstanceOf(QueryBuilder::class, $queryBuilder->createQueryBuilder());
73
    }
74
75
    /**
76
     * Assert that calls to getEntityManager will return the internal query builder's entity manager instance
77
     */
78
    public function testGetEntityManagerWillReturnTheConfiguredEntityManagerInstance(): void
79
    {
80
        $queryBuilder = new QueryBuilder($this->doctrineQueryBuilder);
81
82
        /** @var EntityManager&MockObject $entityManager */
83
        $entityManager = $this->createMock(EntityManager::class);
84
85
        $this->doctrineQueryBuilder->expects($this->once())
86
            ->method('getEntityManager')
87
            ->willReturn($entityManager);
88
89
        $this->assertSame($entityManager, $queryBuilder->getEntityManager());
90
    }
91
92
    /**
93
     * Assert that the root alias returned from calls to getRootAlias()
94
     *
95
     * @dataProvider getGetRootAliasWillReturnQueryBuilderAliasAtIndexZeroData
96
     *
97
     * @param array<mixed> $aliases
98
     */
99
    public function testGetRootAliasWillReturnQueryBuilderAliasAtIndexZero(array $aliases = []): void
100
    {
101
        $queryBuilder = new QueryBuilder($this->doctrineQueryBuilder);
102
103
        if (empty($aliases[0])) {
104
            $expected = '';
105
        } else {
106
            $expected = $aliases[0];
107
        }
108
109
        $this->doctrineQueryBuilder->expects($this->once())
110
            ->method('getRootAliases')
111
            ->willReturn($aliases);
112
113
        $this->assertSame($expected, $queryBuilder->getRootAlias());
114
    }
115
116
    /**
117
     * @return array<mixed>
118
     */
119
    public function getGetRootAliasWillReturnQueryBuilderAliasAtIndexZeroData(): array
120
    {
121
        return [
122
            [
123
                [],
124
            ],
125
            [
126
                [
127
                    'foo',
128
                ],
129
            ],
130
            [
131
                [
132
                    'baz',
133
                    'foo',
134
                    'bar',
135
                ],
136
            ],
137
        ];
138
    }
139
140
    /**
141
     * Assert that calls to getQuery() will proxy and return the wrapped query builders query instance
142
     */
143
    public function testGetWrappedQueryBuilderWillReturnTheDoctrineQueryBuilder(): void
144
    {
145
        $queryBuilder = new QueryBuilder($this->doctrineQueryBuilder);
146
147
        $this->assertSame($this->doctrineQueryBuilder, $queryBuilder->getWrappedQueryBuilder());
148
    }
149
150
    /**
151
     * Assert that calls to expr() will return the internal query builder's Expr instance
152
     */
153
    public function testGetQueryBuilderWillReturnTheConfiguredExprInstance(): void
154
    {
155
        $queryBuilder = new QueryBuilder($this->doctrineQueryBuilder);
156
157
        /** @var Expr&MockObject $expr */
158
        $expr = $this->createMock(Expr::class);
159
160
        $this->doctrineQueryBuilder->expects($this->once())
161
            ->method('expr')
162
            ->willReturn($expr);
163
164
        $queryBuilder->expr();
165
    }
166
167
    /**
168
     * Assert that calls to expr() will return the internal query builder's DQL parts
169
     */
170
    public function testGetEntityManagerWillReturnTheConfiguredExprInstance(): void
171
    {
172
        $queryBuilder = new QueryBuilder($this->doctrineQueryBuilder);
173
174
        $parts = [
175
            'foo' => 'bar',
176
        ];
177
178
        $this->doctrineQueryBuilder->expects($this->once())
179
            ->method('getDQLParts')
180
            ->willReturn($parts);
181
182
        $this->assertSame($parts, $queryBuilder->getQueryParts());
183
    }
184
185
    /**
186
     * Assert the Query instance is returned from getQuery()
187
     */
188
    public function testGetQuery(): void
189
    {
190
        $queryBuilder = new QueryBuilder($this->doctrineQueryBuilder);
191
192
        /** @var EntityManagerInterface&MockObject $entityManager */
193
        $entityManager = $this->createMock(EntityManagerInterface::class);
194
195
        /** @var Configuration&MockObject $configuration */
196
        $configuration = $this->createMock(Configuration::class);
197
198
        $entityManager->expects($this->exactly(2))
199
            ->method('getConfiguration')
200
            ->willReturn($configuration);
201
202
        $configuration->expects($this->once())
203
            ->method('getDefaultQueryHints')
204
            ->willReturn([]);
205
206
        $configuration->expects($this->once())
207
            ->method('isSecondLevelCacheEnabled')
208
            ->willReturn(false);
209
210
        $query = new Query($entityManager);
211
212
        $this->doctrineQueryBuilder->expects($this->once())
213
            ->method('getQuery')
214
            ->willReturn($query);
215
216
        $this->assertSame($query, $queryBuilder->getQuery());
217
    }
218
219
    /**
220
     * Assert that arguments passed to orWhere() will proxy to the internal query builder's orWhere() method
221
     *
222
     * @param array<mixed> $orWhere
223
     *
224
     * @dataProvider getWhereWillProxyToInternalQueryBuilderData
225
     */
226
    public function testOrWhereWillProxyToInternalQueryBuilder(array $orWhere): void
227
    {
228
        $queryBuilder = new QueryBuilder($this->doctrineQueryBuilder);
229
230
        $this->doctrineQueryBuilder->expects($this->once())
231
            ->method('orWhere')
232
            ->with($orWhere);
233
234
        $this->assertSame($queryBuilder, $queryBuilder->orWhere($orWhere));
235
    }
236
237
    /**
238
     * Assert that arguments passed to andWhere() will proxy to the internal query builder's andWhere() method
239
     *
240
     * @param array<mixed> $orWhere
241
     *
242
     * @dataProvider getWhereWillProxyToInternalQueryBuilderData
243
     */
244
    public function testAndWhereWillProxyToInternalQueryBuilder(array $orWhere): void
245
    {
246
        $queryBuilder = new QueryBuilder($this->doctrineQueryBuilder);
247
248
        $this->doctrineQueryBuilder->expects($this->once())
249
            ->method('andWhere')
250
            ->with($orWhere);
251
252
        $this->assertSame($queryBuilder, $queryBuilder->andWhere($orWhere));
253
    }
254
255
    /**
256
     * @return array[]
257
     */
258
    public function getWhereWillProxyToInternalQueryBuilderData(): array
259
    {
260
        $expr = new Expr();
261
262
        return [
263
            [
264
                [
265
                    '2 = 2',
266
                ],
267
            ],
268
            [
269
                [
270
                    'a.bar = :bar',
271
                    'a.test != :test AND b.foo = :foo',
272
                ],
273
            ],
274
            [
275
                [
276
                    $expr->eq('t.foo', ':foo'),
277
                    't.bar = 123',
278
                    $expr->eq('b.baz', ':baz'),
279
                ],
280
            ],
281
        ];
282
    }
283
284
    /**
285
     * Assert that calls to innerJoin() will proxy to the internal query builder
286
     */
287
    public function testInnerJoinWillProxyToInternalQueryBuilder(): void
288
    {
289
        $queryBuilder = new QueryBuilder($this->doctrineQueryBuilder);
290
291
        $name = 'foo';
292
        $alias = 'a';
293
        $type = Expr\Join::ON;
294
        $condition = '1 = 1';
295
        $indexBy = null;
296
297
        $this->doctrineQueryBuilder->expects($this->once())
298
            ->method('innerJoin')
299
            ->with($name, $alias, $type, $condition, $indexBy);
300
301
        $this->assertSame($queryBuilder, $queryBuilder->innerJoin($name, $alias, $type, $condition, $indexBy));
302
    }
303
304
    /**
305
     * Assert that calls to leftJoin() will proxy to the internal query builder
306
     */
307
    public function testLeftJoinWillProxyToInternalQueryBuilder(): void
308
    {
309
        $queryBuilder = new QueryBuilder($this->doctrineQueryBuilder);
310
311
        $name = 'bar';
312
        $alias = 'b';
313
        $type = Expr\Join::ON;
314
        $condition = 'a.test = b.hello';
315
        $indexBy = 'a.name';
316
317
        $this->doctrineQueryBuilder->expects($this->once())
318
            ->method('leftJoin')
319
            ->with($name, $alias, $type, $condition, $indexBy);
320
321
        $this->assertSame($queryBuilder, $queryBuilder->leftJoin($name, $alias, $type, $condition, $indexBy));
322
    }
323
324
    /**
325
     * Assert that calls to orderBy() will proxy to the internal query builder instance
326
     *
327
     * @param Expr\OrderBy|string $sort
328
     * @param string|null         $direction
329
     *
330
     * @dataProvider getOrderByWillProxyToInternalQueryBuilderData
331
     */
332
    public function testOrderByWillProxyToInternalQueryBuilder($sort, ?string $direction = null): void
333
    {
334
        $queryBuilder = new QueryBuilder($this->doctrineQueryBuilder);
335
336
        $this->assertSame($queryBuilder, $queryBuilder->orderBy($sort, $direction));
337
    }
338
339
    /**
340
     * Assert that calls to addOrderBy() will proxy to the internal query builder instance
341
     *
342
     * @param Expr\OrderBy|string $sort
343
     * @param string|null         $direction
344
     *
345
     * @dataProvider getOrderByWillProxyToInternalQueryBuilderData
346
     */
347
    public function testAddOrderByWillProxyToInternalQueryBuilder($sort, ?string $direction = null): void
348
    {
349
        $queryBuilder = new QueryBuilder($this->doctrineQueryBuilder);
350
351
        $this->assertSame($queryBuilder, $queryBuilder->addOrderBy($sort, $direction));
352
    }
353
354
    /**
355
     * @return array[]
356
     */
357
    public function getOrderByWillProxyToInternalQueryBuilderData(): array
358
    {
359
        $expr = new Expr();
360
361
        return [
362
            [
363
                'a.test',
364
                SortDirection::DESC,
365
            ],
366
            [
367
                'b.foo',
368
                null
369
            ],
370
            [
371
                $expr->asc('a.bar')
372
            ],
373
            [
374
                $expr->desc('a.baz'),
375
                null
376
            ]
377
        ];
378
    }
379
380
    /**
381
     * Assert that calls to getParameters() will proxy to the internal query builder
382
     */
383
    public function testGetParametersWillProxyToInternalQueryBuilder(): void
384
    {
385
        $queryBuilder = new QueryBuilder($this->doctrineQueryBuilder);
386
387
        /** @var ArrayCollection<int, Parameter>&MockObject $parameters */
388
        $parameters = $this->createMock(ArrayCollection::class);
389
390
        $this->doctrineQueryBuilder->expects($this->once())
391
            ->method('getParameters')
392
            ->willReturn($parameters);
393
394
        $this->assertSame($parameters, $queryBuilder->getParameters());
395
    }
396
397
    /**
398
     * Assert that calls to setParameters() will proxy to the internal query builder
399
     */
400
    public function testSetParametersWillProxyToInternalQueryBuilder(): void
401
    {
402
        $queryBuilder = new QueryBuilder($this->doctrineQueryBuilder);
403
404
        /** @var ArrayCollection<int, Parameter>&MockObject $parameters */
405
        $parameters = $this->createMock(ArrayCollection::class);
406
407
        $this->doctrineQueryBuilder->expects($this->once())
408
            ->method('setParameters')
409
            ->with($parameters);
410
411
        $this->assertSame($queryBuilder, $queryBuilder->setParameters($parameters));
412
    }
413
414
    /**
415
     * Assert that calls to setParameter() will proxy to the internal query builder
416
     */
417
    public function testSetParameterWillProxyToInternalQueryBuilder(): void
418
    {
419
        $queryBuilder = new QueryBuilder($this->doctrineQueryBuilder);
420
421
        $name = 'Foo';
422
        $value = 'This is a test value';
423
        $type = Types::STRING;
424
425
        $this->doctrineQueryBuilder->expects($this->once())
426
            ->method('setParameter')
427
            ->with($name, $value, $type);
428
429
        $this->assertSame($queryBuilder, $queryBuilder->setParameter($name, $value, $type));
430
    }
431
432
    /**
433
     * Assert that calls to mergeParameters() will proxy to the internal query builder
434
     */
435
    public function testMergeParametersWillProxyToInternalQueryBuilder(): void
436
    {
437
        $queryBuilder = new QueryBuilder($this->doctrineQueryBuilder);
438
439
        $bParams = $addArgs = [];
440
        $b = [
441
            'bar'  => 456,
442
            'test' => 'This is value from B',
443
        ];
444
        $count = count($b);
445
        for ($x = 1; $x < $count; $x++) {
446
            /** @var Parameter&MockObject $parameter */
447
            $parameter = $this->createMock(Parameter::class);
448
            $bParams[] = $parameter;
449
            $addArgs[] = [$parameter];
450
        }
451
452
        /** @var ArrayCollection<int, Parameter>&MockObject $params */
453
        $params = $this->createMock(ArrayCollection::class);
454
        $this->doctrineQueryBuilder->expects($this->once())
455
            ->method('getParameters')
456
            ->willReturn($params);
457
458
        /** @var QueryBuilderInterface&MockObject $newQueryBuilder */
459
        $newQueryBuilder = $this->createMock(QueryBuilderInterface::class);
460
461
        /** @var ArrayCollection<int, Parameter>&MockObject $newParams */
462
        $newParams = $this->createMock(ArrayCollection::class);
463
464
        $newQueryBuilder->expects($this->once())
465
            ->method('getParameters')
466
            ->willReturn($newParams);
467
468
        $newParams->expects($this->once())
0 ignored issues
show
Bug introduced by
The method expects() does not exist on Doctrine\Common\Collections\ArrayCollection. ( Ignorable by Annotation )

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

468
        $newParams->/** @scrutinizer ignore-call */ 
469
                    expects($this->once())

This check looks for calls to methods that do not seem to exist on a given type. It looks for the method on the type itself as well as in inherited classes or implemented interfaces.

This is most likely a typographical error or the method has been renamed.

Loading history...
469
            ->method('getIterator')
470
            ->willReturn(new \ArrayIterator($bParams));
471
472
        $params->expects($this->exactly(count($bParams)))
473
            ->method('add')
474
            ->withConsecutive(...$addArgs);
475
476
        $this->assertSame($queryBuilder, $queryBuilder->mergeParameters($newQueryBuilder));
477
    }
478
}
479