Passed
Pull Request — master (#4)
by Alex
03:40
created

testFilterWillThrowInvalidArgumentExceptionIfTheRequiredToCriteriaIsMissing()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 15
Code Lines 7

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
eloc 7
c 1
b 0
f 0
dl 0
loc 15
rs 10
cc 1
nc 1
nop 0
1
<?php
2
3
declare(strict_types=1);
4
5
namespace ArpTest\DoctrineQueryFilter\Filter;
6
7
use Arp\DoctrineQueryFilter\Constant\WhereType;
8
use Arp\DoctrineQueryFilter\Filter\Exception\FilterException;
9
use Arp\DoctrineQueryFilter\Filter\Exception\InvalidArgumentException;
10
use Arp\DoctrineQueryFilter\Filter\FilterInterface;
11
use Arp\DoctrineQueryFilter\Filter\IsBetween;
12
use Doctrine\ORM\Query\Expr;
13
use PHPUnit\Framework\MockObject\MockObject;
14
15
/**
16
 * @covers  \Arp\DoctrineQueryFilter\Filter\IsBetween
17
 * @covers  \Arp\DoctrineQueryFilter\Filter\AbstractFilter
18
 *
19
 * @author  Alex Patterson <[email protected]>
20
 * @package ArpTest\DoctrineQueryFilter\Filter
21
 */
22
final class IsBetweenTest extends AbstractFilterTest
23
{
24
    /**
25
     * Assert that the class implements FilterInterface
26
     */
27
    public function testImplementsFilterInterface(): void
28
    {
29
        $filter = new IsBetween($this->queryFilterManager, $this->typecaster);
30
31
        $this->assertInstanceOf(FilterInterface::class, $filter);
32
    }
33
34
    /**
35
     * Assert that a InvalidArgumentException is thrown when attempting to call filter() without
36
     * the required 'from' key
37
     *
38
     * @throws FilterException
39
     * @throws InvalidArgumentException
40
     */
41
    public function testFilterWillThrowInvalidArgumentExceptionIfTheRequiredFromCriteriaIsMissing(): void
42
    {
43
        $filter = new IsBetween($this->queryFilterManager, $this->typecaster);
44
45
        $criteria = [
46
            // Missing 'from' key
47
        ];
48
49
        $this->expectException(InvalidArgumentException::class);
50
        $this->expectExceptionMessage(
51
            sprintf('The required \'from\' criteria option is missing for filter \'%s\'', IsBetween::class)
52
        );
53
54
        $filter->filter($this->queryBuilder, $this->metadata, $criteria);
55
    }
56
57
    /**
58
     * Assert that a InvalidArgumentException is thrown when attempting to call filter() without
59
     * the required 'to' key
60
     *
61
     * @throws FilterException
62
     * @throws InvalidArgumentException
63
     */
64
    public function testFilterWillThrowInvalidArgumentExceptionIfTheRequiredToCriteriaIsMissing(): void
65
    {
66
        $filter = new IsBetween($this->queryFilterManager, $this->typecaster);
67
68
        $criteria = [
69
            'from' => '2021-03-01 00:00:00',
70
            // Missing required 'to' key
71
        ];
72
73
        $this->expectException(InvalidArgumentException::class);
74
        $this->expectExceptionMessage(
75
            sprintf('The required \'to\' criteria option is missing for filter \'%s\'', IsBetween::class)
76
        );
77
78
        $filter->filter($this->queryBuilder, $this->metadata, $criteria);
79
    }
80
81
    /**
82
     * @param array       $criteria
83
     * @param string|null $whereType
84
     * @param string|null $alias
85
     * @param string|null $formatType
86
     *
87
     * @throws FilterException
88
     * @throws InvalidArgumentException
89
     *
90
     * @dataProvider getFilterIsBetweenData
91
     */
92
    public function testFilterIsBetween(
93
        array $criteria,
94
        ?string $whereType = null,
95
        ?string $alias = null,
96
        ?string $formatType = null
97
    ): void {
98
        /** @var IsBetween|MockObject $filter */
99
        $filter = $this->getMockBuilder(IsBetween::class)
100
            ->setConstructorArgs([$this->queryFilterManager, $this->typecaster])
101
            ->onlyMethods(['createParamName'])
102
            ->getMock();
103
104
        $rootAlias = 'entity';
105
        $from = $criteria['from'] ?? '';
106
        $to = $criteria['to'] ?? '';
107
        $fieldName = $criteria['field'] = $criteria['field'] ?? 'test';
108
109
        if (null !== $alias) {
110
            $criteria['alias'] = $alias;
111
        }
112
113
        if (null !== $whereType) {
114
            $criteria['where'] = $whereType;
115
        }
116
117
        if (null !== $formatType) {
118
            $criteria['format'] = $formatType;
119
        }
120
121
        $this->metadata->expects($this->once())
122
            ->method('hasField')
123
            ->with($fieldName)
124
            ->willReturn(true);
125
126
        if (empty($alias)) {
127
            $alias = $rootAlias;
128
129
            $this->queryBuilder->expects($this->once())
130
                ->method('getRootAlias')
131
                ->willReturn($rootAlias);
132
        }
133
134
        /** @var Expr|MockObject $expr */
135
        $expr = $this->createMock(Expr::class);
136
137
        $this->queryBuilder->expects($this->once())
138
            ->method('expr')
139
            ->willReturn($expr);
140
141
        $fromParam = $alias . 'abc123';
142
        $toParam = $alias . 'zyx999';
143
144
        $filter->expects($this->exactly(2))
145
            ->method('createParamName')
146
            ->withConsecutive(
147
                [$alias],
148
                [$alias]
149
            )->willReturnOnConsecutiveCalls(
150
                $fromParam,
151
                $toParam
152
            );
153
154
        $isBetween = $alias . '.' . $fieldName . ' BETWEEN ' . $fromParam . ' AND ' . $toParam;
155
        $expr->expects($this->once())
156
            ->method('between')
157
            ->with(
158
                $alias . '.' . $fieldName,
159
                ':' . $fromParam,
160
                ':' . $toParam
161
            )->willReturn(
162
                $isBetween
163
            );
164
165
        if (null === $whereType || WhereType::AND === $whereType) {
166
            $this->queryBuilder->expects($this->once())
167
                ->method('andWhere')
168
                ->with($isBetween);
169
        } else {
170
            $this->queryBuilder->expects($this->once())
171
                ->method('orWhere')
172
                ->with($isBetween);
173
        }
174
175
        $this->typecaster->expects($this->exactly(2))
176
            ->method('typecast')
177
            ->withConsecutive(
178
                [$this->metadata, $fieldName, $from, $formatType, []],
179
                [$this->metadata, $fieldName, $to, $formatType, []],
180
            )->willReturnOnConsecutiveCalls(
181
                $from,
182
                $to
183
            );
184
185
        $this->queryBuilder->expects($this->exactly(2))
186
            ->method('setParameter')
187
            ->withConsecutive(
188
                [$fromParam, $from],
189
                [$toParam, $to]
190
            );
191
192
        $filter->filter($this->queryBuilder, $this->metadata, $criteria);
193
    }
194
195
    /**
196
     * @return array
197
     */
198
    public function getFilterIsBetweenData(): array
199
    {
200
        return [
201
            [
202
                [
203
                    'to' => '2021-01-01 00:00:00',
204
                    'from' => '2021-02-01 00:00:00',
205
                ]
206
            ],
207
        ];
208
    }
209
}
210