Completed
Push — master ( 892c82...825b72 )
by Valentin
19s queued 15s
created

DatetimeTest   A

Complexity

Total Complexity 21

Size/Duplication

Total Lines 339
Duplicated Lines 0 %

Importance

Changes 10
Bugs 3 Features 0
Metric Value
eloc 168
c 10
b 3
f 0
dl 0
loc 339
rs 10
wmc 21

16 Methods

Rating   Name   Duplication   Size   Complexity  
A testValid() 0 5 1
A testFormat() 0 5 1
A formatProvider() 0 18 1
A testFuture() 0 7 2
A testPast() 0 7 2
A testAfter() 0 16 2
A inPast() 0 4 1
A inFuture() 0 4 1
A now() 0 4 1
A beforeProvider() 0 30 1
A testTimezone() 0 10 2
A validProvider() 0 21 1
A testBefore() 0 16 2
A pastProvider() 0 28 1
A afterProvider() 0 29 1
A futureProvider() 0 33 1
1
<?php
2
3
/**
4
 * Spiral Framework.
5
 *
6
 * @license   MIT
7
 * @author    Anton Titov (Wolfy-J)
8
 */
9
10
declare(strict_types=1);
11
12
namespace Spiral\Tests\Validation\Checkers;
13
14
use PHPUnit\Framework\TestCase;
15
use Spiral\Validation\Checker\DatetimeChecker;
16
use Spiral\Validation\ValidatorInterface;
17
18
class DatetimeTest extends TestCase
19
{
20
    /**
21
     * @dataProvider futureProvider
22
     *
23
     * @param bool  $expected
24
     * @param mixed $value
25
     * @param bool  $orNow
26
     * @param bool  $useMicroseconds
27
     */
28
    public function testFuture(bool $expected, $value, bool $orNow, bool $useMicroseconds): void
29
    {
30
        $value = $value instanceof \Closure ? $value() : $value;
31
32
        $checker = new DatetimeChecker();
33
34
        $this->assertSame($expected, $checker->future($value, $orNow, $useMicroseconds));
35
    }
36
37
    /**
38
     * @return array
39
     */
40
    public function futureProvider(): array
41
    {
42
        return [
43
            //the date is 100% in the future
44
            [true, $this->inFuture(1000), false, false],
45
            [true, $this->inFuture(1000), true, false],
46
            [true, $this->inFuture(1000), false, true],
47
            [true, $this->inFuture(1000), true, true],
48
49
            [true, 'tomorrow + 2hours', false, false],
50
            [true, 'now + 1000 seconds', false, false],
51
52
            // the "now" date can differ in ms
53
            [false, 'now', false, false],
54
            [false, 'now', false, true], //the threshold date comes a little bit later (in ms)
55
            [true, 'now', true, false],
56
            [false, 'now', true, true], //the threshold date comes a little bit later (in ms)
57
58
            //the date is invalid, don't check after this
59
            [false, [], false, false],
60
            [false, [], true, false],
61
            [false, [], false, true],
62
            [false, [], true, true],
63
64
            [false, $this->inPast(1000), false, false],
65
            [false, '', false, false],
66
            [false, 0, false, false],
67
            [false, 1.1, false, false],
68
            [false, false, false, false],
69
            [false, true, false, false],
70
            [false, null, false, false],
71
            [false, [], false, false],
72
            [false, new \stdClass(), false, false],
73
        ];
74
    }
75
76
    /**
77
     * @dataProvider pastProvider
78
     * @param bool  $expected
79
     * @param mixed $value
80
     * @param bool  $orNow
81
     * @param bool  $useMicroseconds
82
     */
83
    public function testPast(bool $expected, $value, bool $orNow, bool $useMicroseconds): void
84
    {
85
        $value = $value instanceof \Closure ? $value() : $value;
86
87
        $checker = new DatetimeChecker();
88
89
        $this->assertSame($expected, $checker->past($value, $orNow, $useMicroseconds));
90
    }
91
92
    /**
93
     * @return array
94
     */
95
    public function pastProvider(): array
96
    {
97
        return [
98
            //the date is 100% in the past
99
            [true, $this->inPast(1000), false, false],
100
            [true, $this->inPast(1000), true, false],
101
            [true, $this->inPast(1000), false, true],
102
            [true, $this->inPast(1000), true, true],
103
104
            [true, 'yesterday -2hours', false, false],
105
            [true, 'now - 1000 seconds', false, false],
106
107
            //the "now" date can differ in ms
108
            [false, 'now', false, false],
109
            [true, 'now', false, true], //the threshold date comes a little bit later (in ms)
110
            [true, 'now', true, false],
111
            [true, 'now', true, true], //the threshold date comes a little bit later (in ms)
112
113
            [false, $this->inFuture(1000), false, false],
114
            [true, '', false, false],
115
            [true, 0, false, false],
116
            [true, 1.1, false, false],
117
            [false, [], false, false],
118
            [false, false, false, false],
119
            [false, true, false, false],
120
            [false, null, false, false],
121
            [false, [], false, false],
122
            [false, new \stdClass(), false, false],
123
        ];
124
    }
125
126
    /**
127
     * @dataProvider formatProvider
128
     * @param bool   $expected
129
     * @param mixed  $value
130
     * @param string $format
131
     */
132
    public function testFormat(bool $expected, $value, string $format): void
133
    {
134
        $checker = new DatetimeChecker();
135
136
        $this->assertSame($expected, $checker->format($value, $format));
137
    }
138
139
    /**
140
     * @return array
141
     */
142
    public function formatProvider(): array
143
    {
144
        return [
145
            [true, '2019-12-27T14:27:44+00:00', 'c'], //this one is converted using other format chars
146
            [true, '2019-12-27T14:27:44+00:00', 'Y-m-d\TH:i:sT'], //like the 'c' one
147
            [true, 'Wed, 02 Oct 19 08:00:00 EST', \DateTime::RFC822],
148
            [true, 'Wed, 02 Oct 19 08:00:00 +0200', \DateTime::RFC822],
149
            [true, '2019-12-12', 'Y-m-d'],
150
            [true, '2019-12-12', 'Y-d-m'],
151
            [true, '2019-13-12', 'Y-m-d'],
152
            [true, '2019-12-13', 'Y-d-m'],
153
            [true, '2019-12-Nov', 'Y-d-M'],
154
            [true, '2019-12-Nov', 'Y-m-\N\o\v'],
155
            [false, '2019-12-Nov', 'Y-M-d'],
156
            [false, '2019-12-Nov', '123'],
157
            [false, '2019+12-Nov', 'Y-m-d'],
158
            [false, '-2019-12-Nov', 'Y-m-d'],
159
            [false, '2019-12-Abc', 'Y-d-M'],
160
        ];
161
    }
162
163
    /**
164
     * @dataProvider validProvider
165
     * @param bool  $expected
166
     * @param mixed $value
167
     */
168
    public function testValid(bool $expected, $value): void
169
    {
170
        $checker = new DatetimeChecker();
171
172
        $this->assertSame($expected, $checker->valid($value));
173
    }
174
175
    /**
176
     * @return array
177
     */
178
    public function validProvider(): array
179
    {
180
        return [
181
            [true, time() - 1000,],
182
            [true, time(),],
183
            [true, date('u'),],
184
            [true, time() + 1000,],
185
            [true, '',],
186
            [true, 'tomorrow +2hours',],
187
            [true, 'yesterday -2hours',],
188
            [true, 'now',],
189
            [true, 'now + 1000 seconds',],
190
            [true, 'now - 1000 seconds',],
191
            [true, 0,],
192
            [true, 1.1,],
193
            [false, [],],
194
            [false, false,],
195
            [false, true,],
196
            [false, null,],
197
            [false, [],],
198
            [false, new \stdClass(),],
199
        ];
200
    }
201
202
    public function testTimezone(): void
203
    {
204
        $checker = new DatetimeChecker();
205
206
        foreach (\DateTimeZone::listIdentifiers() as $identifier) {
207
            $this->assertTrue($checker->timezone($identifier));
208
            $this->assertFalse($checker->timezone(str_rot13($identifier)));
209
        }
210
211
        $this->assertFalse($checker->timezone('Any zone'));
212
    }
213
214
    /**
215
     * @dataProvider beforeProvider
216
     * @param bool  $expected
217
     * @param mixed $value
218
     * @param mixed $threshold
219
     * @param bool  $orEquals
220
     * @param bool  $useMicroseconds
221
     */
222
    public function testBefore(bool $expected, $value, $threshold, bool $orEquals, bool $useMicroseconds): void
223
    {
224
        $value = $value instanceof \Closure ? $value() : $value;
225
226
        $checker = new DatetimeChecker();
227
228
        $mock = $this->getMockBuilder(ValidatorInterface::class)->disableOriginalConstructor()->getMock();
229
        $mock->method('getValue')->with('threshold')->willReturn($threshold);
230
231
        /** @var ValidatorInterface $mock */
232
        $this->assertSame($expected, $checker->check(
233
            $mock,
234
            'before',
235
            'field',
236
            $value,
237
            ['threshold', $orEquals, $useMicroseconds]
238
        ));
239
    }
240
241
    /**
242
     * @return array
243
     */
244
    public function beforeProvider(): array
245
    {
246
        return [
247
            //the date is 100% in the past
248
            [true, $this->inPast(1000), 'now', false, false],
249
            [true, $this->inPast(1000), 'now', true, false],
250
            [true, $this->inPast(1000), 'now', false, true],
251
            [true, $this->inPast(1000), 'now', true, true],
252
253
            [true, 'yesterday -2hours', 'now', false, false],
254
            [true, 'now - 1000 seconds', 'now', false, false],
255
            [true, 'now + 1000 seconds', 'tomorrow', false, false],
256
257
            //the "now" date can differ in ms
258
            [false, 'now', 'now', false, false],
259
            [true, 'now', 'now + 1000 second', false, false],
260
            [true, 'now', 'now', false, true], //the threshold date comes a little bit later (in ms)
261
            [true, 'now', 'now', true, false],
262
            [true, 'now', 'now', true, true], //the threshold date comes a little bit later (in ms)
263
264
            [false, $this->inFuture(1000), 'now', false, false],
265
            [true, '', 'now', false, false],
266
            [true, 0, 'now', false, false],
267
            [true, 1.1, 'now', false, false],
268
            [false, [], 'now', false, false],
269
            [false, false, 'now', false, false],
270
            [false, true, 'now', false, false],
271
            [false, null, 'now', false, false],
272
            [false, [], 'now', false, false],
273
            [false, new \stdClass(), 'now', false, false],
274
        ];
275
    }
276
277
    /**
278
     * @dataProvider afterProvider
279
     * @param bool  $expected
280
     * @param mixed $value
281
     * @param mixed $threshold
282
     * @param bool  $orEquals
283
     * @param bool  $useMicroseconds
284
     */
285
    public function testAfter(bool $expected, $value, $threshold, bool $orEquals, bool $useMicroseconds): void
286
    {
287
        $value = $value instanceof \Closure ? $value() : $value;
288
289
        $checker = new DatetimeChecker();
290
291
        $mock = $this->getMockBuilder(ValidatorInterface::class)->disableOriginalConstructor()->getMock();
292
        $mock->method('getValue')->with('threshold')->willReturn($threshold);
293
294
        /** @var ValidatorInterface $mock */
295
        $this->assertSame($expected, $checker->check(
296
            $mock,
297
            'after',
298
            'field',
299
            $value,
300
            ['threshold', $orEquals, $useMicroseconds]
301
        ));
302
    }
303
304
    /**
305
     * @return array
306
     */
307
    public function afterProvider(): array
308
    {
309
        return [
310
            [true, $this->inFuture(1000), 'now', false, false],
311
            [true, $this->inFuture(1000), 'now', true, false],
312
            [true, $this->inFuture(1000), 'now', false, true],
313
            [true, $this->inFuture(1000), 'now', true, true],
314
315
            [true, 'tomorrow +2hours', 'now', false, false],
316
            [true, 'now + 1000 seconds', 'now', false, false],
317
            [true, 'now - 1000 seconds', 'yesterday', false, false],
318
319
            //the "now" date can differ in ms
320
            [false, 'now', 'now', false, false],
321
            [true, 'now', 'now - 1000 second', false, false],
322
            [false, 'now', 'now', false, true], //the threshold date comes a little bit later (in ms)
323
            [true, 'now', 'now', true, false],
324
            [false, 'now', 'now', true, true], //the threshold date comes a little bit later (in ms)
325
326
            [false, $this->inPast(1000), 'now', false, false],
327
            [false, '', 'now', false, false],
328
            [false, 0, 'now', false, false],
329
            [false, 1.1, 'now', false, false],
330
            [false, [], 'now', false, false],
331
            [false, false, 'now', false, false],
332
            [false, true, 'now', false, false],
333
            [false, null, 'now', false, false],
334
            [false, [], 'now', false, false],
335
            [false, new \stdClass(), 'now', false, false],
336
        ];
337
    }
338
339
    private function now(): \Closure
340
    {
341
        return static function () {
342
            return \time();
343
        };
344
    }
345
346
    private function inFuture(int $seconds): \Closure
347
    {
348
        return static function () use ($seconds) {
349
            return \time() + $seconds;
350
        };
351
    }
352
353
    private function inPast(int $seconds): \Closure
354
    {
355
        return static function () use ($seconds) {
356
            return \time() - $seconds;
357
        };
358
    }
359
}
360