SpecificationVisitorTests::testVisitAnd()   B
last analyzed

Complexity

Conditions 1
Paths 1

Size

Total Lines 38
Code Lines 26

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
c 1
b 0
f 0
dl 0
loc 38
rs 8.8571
cc 1
eloc 26
nc 1
nop 0
1
<?php
2
3
/**
4
 * This file is part of the Cubiche package.
5
 *
6
 * Copyright (c) Cubiche
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 Cubiche\Infrastructure\Repository\Doctrine\Tests\Units\ODM\MongoDB\Query;
13
14
use Cubiche\Core\Selector\Composite;
15
use Cubiche\Core\Selector\Field;
16
use Cubiche\Core\Selector\Property;
17
use Cubiche\Core\Specification\AndSpecification;
18
use Cubiche\Core\Specification\Criteria;
19
use Cubiche\Core\Specification\NotSpecification;
20
use Cubiche\Core\Specification\SpecificationInterface;
21
use Cubiche\Domain\Repository\Tests\Fixtures\User;
22
use Cubiche\Domain\Repository\Tests\Fixtures\UserId;
23
use Cubiche\Infrastructure\Repository\Doctrine\ODM\MongoDB\Query\QueryBuilder;
24
use Cubiche\Infrastructure\Repository\Doctrine\ODM\MongoDB\Query\SpecificationVisitor;
25
use Cubiche\Infrastructure\Repository\Doctrine\Tests\Units\ODM\MongoDB\TestCase;
26
use Cubiche\Core\Visitor\VisiteeInterface;
27
use Cubiche\Core\Selector\SelectorInterface;
28
use Cubiche\Core\Specification\Selector;
29
30
/**
31
 * Specification Visitor Tests Class.
32
 *
33
 * @author Karel Osorio Ramírez <[email protected]>
34
 */
35
class SpecificationVisitorTests extends TestCase
36
{
37
    /**
38
     * Test visitAnd.
39
     */
40
    public function testVisitAnd()
41
    {
42
        $this->visitTest(
43
            Criteria::property('foo')->eq(10)->andX(Criteria::property('bar')->eq(20)),
44
            function () {
45
                return  $this->createQueryBuilder()
46
                    ->field('foo')->equals(10)
47
                    ->field('bar')->equals(20);
48
            }
49
        );
50
51
        $this->visitTest(
52
            Criteria::property('foo')->gt(10)->andX(Criteria::property('foo')->lt(20)),
53
            function () {
54
                return $this->createQueryBuilder()
55
                    ->field('foo')->gt(10)
56
                    ->field('foo')->lt(20);
57
            }
58
        );
59
60
        $this->visitTest(
61
            new AndSpecification(
62
                Criteria::property('foo')->lt(20)->orX(Criteria::property('bar')->lt(20)),
63
                Criteria::property('foo')->gt(10)->orX(Criteria::property('foo')->lt(25))
64
            ),
65
            function () {
66
                $qb = $this->createQueryBuilder();
67
68
                return $qb
69
                    ->addAnd($qb->expr()
70
                        ->addOr($qb->expr()->field('foo')->lt(20))
71
                        ->addOr($qb->expr()->field('bar')->lt(20)))
72
                    ->addAnd($qb->expr()
73
                        ->addOr($qb->expr()->field('foo')->gt(10))
74
                        ->addOr($qb->expr()->field('foo')->lt(25)));
75
            }
76
        );
77
    }
78
79
    /**
80
     * Test visitOr.
81
     */
82 View Code Duplication
    public function testVisitOr()
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
83
    {
84
        $this->visitTest(
85
            Criteria::property('foo')->eq(10)->orX(Criteria::property('bar')->eq(20)),
86
            function () {
87
                $qb = $this->createQueryBuilder();
88
89
                return $qb
90
                    ->addOr($qb->expr()->field('foo')->equals(10))
91
                    ->addOr($qb->expr()->field('bar')->equals(20));
92
            }
93
        );
94
    }
95
96
    /**
97
     * Test visitOr.
98
     */
99
    public function testVisitNot()
100
    {
101
        $this->visitTest(new NotSpecification(Criteria::property('foo')->eq(10)), function () {
102
            $qb = $this->createQueryBuilder();
103
104
            return $qb->not($qb->expr()->field('foo')->equals(10));
105
        });
106
    }
107
108
    /**
109
     * Test visitValue.
110
     */
111
    public function testVisitValue()
112
    {
113
        $this->notSupportedOperationTest(Criteria::false()->selector());
114
    }
115
116
    /**
117
     * Test visitValue.
118
     */
119
    public function testVisitKey()
120
    {
121
        $this->visitFieldTest(Criteria::key('foo')->selector());
122
    }
123
124
    /**
125
     * Test visitProperty.
126
     */
127
    public function testVisitPorperty()
128
    {
129
        $this->visitFieldTest(Criteria::property('foo')->selector());
130
    }
131
132
    /**
133
     * Test visitMethod.
134
     */
135
    public function testVisitMethod()
136
    {
137
        $this->notSupportedOperationTest(Criteria::method('foo')->selector());
138
    }
139
140
    /**
141
     * Test visitCallback.
142
     */
143
    public function testVisitCallback()
144
    {
145
        $this->notSupportedOperationTest(Criteria::callback(function () {
146
147
        })->selector());
148
    }
149
150
    /**
151
     * Test visitThis.
152
     */
153
    public function testVisitThis()
154
    {
155
        $this->notSupportedOperationTest(Criteria::this()->selector());
156
    }
157
158
    /**
159
     * Test visitComposite.
160
     */
161
    public function testVisitComposite()
162
    {
163
        $this->visitFieldTest(Criteria::property('foo')->property('bar')->selector(), 'foo.bar');
164
        $this->visitFieldTest(Criteria::property('foo')->property('bar')->key('length')->selector(), 'foo.bar.length');
165
    }
166
167
    /**
168
     * Test visitCount.
169
     */
170
    public function testVisitCount()
171
    {
172
        $this->notSupportedOperationTest(Criteria::count()->selector());
173
    }
174
175
    /**
176
     * Test visitGreaterThan.
177
     */
178
    public function tesVisittGreaterThan()
179
    {
180
        $this->visitTest(Criteria::property('foo')->gt(10), function () {
181
            return $this->createQueryBuilder()->field('foo')->gt(10);
182
        });
183
    }
184
185
    /**
186
     * Test visitGreaterThanEqual.
187
     */
188
    public function testVisitGreaterThanEqual()
189
    {
190
        $this->visitTest(Criteria::property('foo')->gte(10), function () {
191
            return $this->createQueryBuilder()->field('foo')->gte(10);
192
        });
193
    }
194
195
    /**
196
     * Test visitLessThan.
197
     */
198
    public function testVisitLessThan()
199
    {
200
        $this->visitTest(Criteria::property('foo')->lt(10), function () {
201
            return $this->createQueryBuilder()->field('foo')->lt(10);
202
        });
203
    }
204
205
    /**
206
     * Test visitLessThanEqual.
207
     */
208
    public function testVisitLessThanEqual()
209
    {
210
        $this->visitTest(Criteria::property('foo')->lte(10), function () {
211
            return $this->createQueryBuilder()->field('foo')->lte(10);
212
        });
213
    }
214
215
    /**
216
     * Test visitEqual.
217
     */
218
    public function testVisitEqual()
219
    {
220
        $this->visitTest(Criteria::property('foo')->eq(10), function () {
221
            return $this->createQueryBuilder()->field('foo')->equals(10);
222
        });
223
224
        $this->visitTest(Criteria::property('foo')->count()->eq(10), function () {
225
            return $this->createQueryBuilder()->field('foo')->size(10);
226
        });
227
228
        $user = new User(UserId::next(), 'user', 20, $this->faker->email);
229
230
        $this->visitTest(Criteria::eq($user), function () use ($user) {
231
            return $this->createQueryBuilder()->field('id')->equals($user->id()->toNative());
232
        });
233
234
        $this->visitTest(Criteria::property('id')->eq($user->id()), function () use ($user) {
235
            return $this->createQueryBuilder()->field('id')->equals($user->id()->toNative());
236
        });
237
238
        $this->logicExceptionTest(
239
            Criteria::callback(function () {
240
241
            })->eq(10)
242
        );
243
244
        $this->logicExceptionTest(Criteria::property('foo')->eq(Criteria::property('bar')));
245
    }
246
247
    /**
248
     * Test visitNotEqual.
249
     */
250
    public function testVisitNotEqual()
251
    {
252
        $this->visitTest(Criteria::property('foo')->neq(10), function () {
253
            return $this->createQueryBuilder()->field('foo')->notEqual(10);
254
        });
255
    }
256
257
    /**
258
     * Test visitSame.
259
     */
260
    public function testVisitSame()
261
    {
262
        $this->visitTest(Criteria::property('foo')->same(10), function () {
263
            return $this->createQueryBuilder()->field('foo')->equals(10);
264
        });
265
    }
266
267
    /**
268
     * Test visitNotSame.
269
     */
270
    public function testVisitNotSame()
271
    {
272
        $this->visitTest(Criteria::property('foo')->notsame(10), function () {
273
            return $this->createQueryBuilder()->field('foo')->notEqual(10);
274
        });
275
    }
276
277
    /**
278
     * Test visitAll.
279
     */
280 View Code Duplication
    public function testVisitAll()
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
281
    {
282
        $this->visitTest(Criteria::property('foo')->all(Criteria::property('bar')->gt(10)), function () {
283
            $qb = $this->createQueryBuilder();
284
285
            return $qb->field('foo')->all(
286
                $qb->expr()->elemMatch(
287
                    $qb->expr()->field('bar')->gt(10)
288
                )->getQuery()
289
            );
290
        });
291
    }
292
293
    /**
294
     * Test visitAtLeast.
295
     */
296
    public function testAtLeast()
297
    {
298
        $this->visitTest(Criteria::property('foo')->any(Criteria::property('bar')->gt(10)), function () {
299
            $qb = $this->createQueryBuilder();
300
301
            return $qb->field('foo')
302
                ->elemMatch(
303
                    $qb->expr()->field('bar')->gt(10)
304
                );
305
        });
306
307
        $this->notSupportedOperationTest(Criteria::property('foo')->atLeast(2, Criteria::property('bar')->gt(10)));
308
    }
309
310
    /**
311
     * @param SpecificationInterface|SelectorInterface $criteria
312
     * @param \Closure                                 $expectedCreate
313
     */
314
    protected function visitTest($criteria, \Closure $expectedCreate)
315
    {
316
        $this
317
            ->given($qb = $this->createQueryBuilder())
318
            ->given($visitor = $this->createVisitor($qb))
319
            ->given($criteria)
320
            ->given($expected = $expectedCreate())
321
            ->when($criteria->accept($visitor))
322
                ->array($qb->getQueryArray())
323
                    ->isEqualTo($expected->getQueryArray())
324
            ;
325
    }
326
327
    /**
328
     * @param Field|Composite $field
329
     * @param string          $expected
330
     */
331
    protected function visitFieldTest($field, $expected = null)
332
    {
333
        $expected = $expected === null && $field instanceof Field ? $field->name() : $expected;
334
        $this->visitTest($field, function () use ($expected) {
335
            return $this->createQueryBuilder()->field($expected)->equals(true);
336
        });
337
    }
338
339
    /**
340
     * @param SpecificationInterface|SelectorInterface $criteria
341
     */
342
    protected function notSupportedOperationTest($criteria)
343
    {
344
        $this->logicExceptionTest($criteria);
345
    }
346
347
    /**
348
     * @param VisiteeInterface $criteria
349
     */
350
    private function logicExceptionTest($criteria)
351
    {
352
        $this
353
            ->given($qb = $this->createQueryBuilder())
354
            ->given($visitor = $this->createVisitor($qb))
355
            ->exception(function () use ($visitor, $criteria) {
356
                $criteria->accept($visitor);
357
            })
358
                ->isInstanceOf(\LogicException::class)
359
            ;
360
    }
361
362
    /**
363
     * @param QueryBuilder $queryBuilder
364
     *
365
     * @return \Cubiche\Infrastructure\Repository\Doctrine\ODM\MongoDB\Query\SpecificationVisitor
366
     */
367
    protected function createVisitor(QueryBuilder $queryBuilder)
368
    {
369
        return new SpecificationVisitor($queryBuilder);
370
    }
371
372
    /**
373
     * @return \Cubiche\Infrastructure\Repository\Doctrine\ODM\MongoDB\Query\QueryBuilder
374
     */
375
    protected function createQueryBuilder()
376
    {
377
        return new QueryBuilder($this->dm(), User::class);
378
    }
379
}
380