Passed
Push — master ( 5b4064...cd467c )
by Valentin
17:10 queued 13:04
created

DatetimeTest::testNow()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 5
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 1
Metric Value
cc 1
eloc 2
c 1
b 0
f 1
nc 1
nop 5
dl 0
loc 5
rs 10
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 nowProvider
22
     * @param bool $expected
23
     * @param      $now
24
     * @param      $value
25
     * @param bool $orNow
26
     * @param bool $useMicroseconds
27
     */
28
    public function testNow(bool $expected, $now, $value, bool $orNow, bool $useMicroseconds): void
29
    {
30
        $checker = new DatetimeChecker($now);
31
32
        $this->assertSame($expected, $checker->future($value, $orNow, $useMicroseconds));
33
    }
34
35
    public function nowProvider(): iterable
36
    {
37
        $now = new \DateTime();
38
        $callableNow = static function () use ($now) {
39
            return $now;
40
        };
41
42
        yield from [
43
            [false, $callableNow, $now, false, true],
44
            [true, $callableNow, $now, true, true]
45
        ];
46
47
        $callableFutureTime = static function () {
48
            return time() + 1000;
49
        };
50
        yield from [
51
            [false, $callableFutureTime, $now, false, true],
52
            [false, $callableFutureTime, $now, true, true],
53
        ];
54
55
        $callablePastTime = static function () {
56
            return time() - 1000;
57
        };
58
        yield from [
59
            [true, $callablePastTime, $now, false, true],
60
            [true, $callablePastTime, $now, true, true],
61
        ];
62
63
        return [
64
            [false, 'tomorrow + 2hours', $now, false, true],
65
            [false, 'tomorrow + 2hours', $now, true, true],
66
            [true, 'yesterday - 2hours', $now, false, true],
67
            [true, 'yesterday - 2hours', $now, true, true],
68
            [false, $now, $now, false, true],
69
            [true, $now, $now, true, true],
70
        ];
71
    }
72
73
    /**
74
     * @dataProvider futureProvider
75
     *
76
     * @param bool  $expected
77
     * @param mixed $value
78
     * @param bool  $orNow
79
     * @param bool  $useMicroseconds
80
     */
81
    public function testFuture(bool $expected, $value, bool $orNow, bool $useMicroseconds): void
82
    {
83
        $value = $value instanceof \Closure ? $value() : $value;
84
85
        $checker = new DatetimeChecker();
86
87
        $this->assertSame($expected, $checker->future($value, $orNow, $useMicroseconds));
88
    }
89
90
    /**
91
     * @return array
92
     */
93
    public function futureProvider(): array
94
    {
95
        return [
96
            //the date is 100% in the future
97
            [true, $this->inFuture(1000), false, false],
98
            [true, $this->inFuture(1000), true, false],
99
            [true, $this->inFuture(1000), false, true],
100
            [true, $this->inFuture(1000), true, true],
101
102
            [true, 'tomorrow + 2hours', false, false],
103
            [true, 'now + 1000 seconds', false, false],
104
105
            // the "now" date can differ in ms
106
            [false, 'now', false, false],
107
            [false, 'now', false, true], //the threshold date comes a little bit later (in ms)
108
            [true, 'now', true, false],
109
            [false, 'now', true, true], //the threshold date comes a little bit later (in ms)
110
111
            //the date is invalid, don't check after this
112
            [false, [], false, false],
113
            [false, [], true, false],
114
            [false, [], false, true],
115
            [false, [], true, true],
116
117
            [false, $this->inPast(1000), false, false],
118
            [false, '', false, false],
119
            [false, 0, false, false],
120
            [false, 1.1, false, false],
121
            [false, false, false, false],
122
            [false, true, false, false],
123
            [false, null, false, false],
124
            [false, [], false, false],
125
            [false, new \stdClass(), false, false],
126
        ];
127
    }
128
129
    /**
130
     * @dataProvider pastProvider
131
     * @param bool  $expected
132
     * @param mixed $value
133
     * @param bool  $orNow
134
     * @param bool  $useMicroseconds
135
     */
136
    public function testPast(bool $expected, $value, bool $orNow, bool $useMicroseconds): void
137
    {
138
        $value = $value instanceof \Closure ? $value() : $value;
139
140
        $checker = new DatetimeChecker();
141
142
        $this->assertSame($expected, $checker->past($value, $orNow, $useMicroseconds));
143
    }
144
145
    /**
146
     * @return array
147
     */
148
    public function pastProvider(): array
149
    {
150
        return [
151
            //the date is 100% in the past
152
            [true, $this->inPast(1000), false, false],
153
            [true, $this->inPast(1000), true, false],
154
            [true, $this->inPast(1000), false, true],
155
            [true, $this->inPast(1000), true, true],
156
157
            [true, 'yesterday -2hours', false, false],
158
            [true, 'now - 1000 seconds', false, false],
159
160
            //the "now" date can differ in ms
161
            [false, 'now', false, false],
162
            [true, 'now', false, true], //the threshold date comes a little bit later (in ms)
163
            [true, 'now', true, false],
164
            [true, 'now', true, true], //the threshold date comes a little bit later (in ms)
165
166
            [false, $this->inFuture(1000), false, false],
167
            [true, '', false, false],
168
            [true, 0, false, false],
169
            [true, 1.1, false, false],
170
            [false, [], false, false],
171
            [false, false, false, false],
172
            [false, true, false, false],
173
            [false, null, false, false],
174
            [false, [], false, false],
175
            [false, new \stdClass(), false, false],
176
        ];
177
    }
178
179
    /**
180
     * @dataProvider formatProvider
181
     * @param bool   $expected
182
     * @param mixed  $value
183
     * @param string $format
184
     */
185
    public function testFormat(bool $expected, $value, string $format): void
186
    {
187
        $checker = new DatetimeChecker();
188
189
        $this->assertSame($expected, $checker->format($value, $format));
190
    }
191
192
    /**
193
     * @return array
194
     */
195
    public function formatProvider(): array
196
    {
197
        return [
198
            [true, '2019-12-27T14:27:44+00:00', 'c'], //this one is converted using other format chars
199
            [true, '2019-12-27T14:27:44+00:00', 'Y-m-d\TH:i:sT'], //like the 'c' one
200
            [true, 'Wed, 02 Oct 19 08:00:00 EST', \DateTime::RFC822],
201
            [true, 'Wed, 02 Oct 19 08:00:00 +0200', \DateTime::RFC822],
202
            [true, '2019-12-12', 'Y-m-d'],
203
            [true, '2019-12-12', 'Y-d-m'],
204
            [true, '2019-13-12', 'Y-m-d'],
205
            [true, '2019-12-13', 'Y-d-m'],
206
            [true, '2019-12-Nov', 'Y-d-M'],
207
            [true, '2019-12-Nov', 'Y-m-\N\o\v'],
208
            [false, '2019-12-Nov', 'Y-M-d'],
209
            [false, '2019-12-Nov', '123'],
210
            [false, '2019+12-Nov', 'Y-m-d'],
211
            [false, '-2019-12-Nov', 'Y-m-d'],
212
            [false, '2019-12-Abc', 'Y-d-M'],
213
        ];
214
    }
215
216
    /**
217
     * @dataProvider validProvider
218
     * @param bool  $expected
219
     * @param mixed $value
220
     */
221
    public function testValid(bool $expected, $value): void
222
    {
223
        $checker = new DatetimeChecker();
224
225
        $this->assertSame($expected, $checker->valid($value));
226
    }
227
228
    /**
229
     * @return array
230
     */
231
    public function validProvider(): array
232
    {
233
        return [
234
            [true, time() - 1000,],
235
            [true, time(),],
236
            [true, date('u'),],
237
            [true, time() + 1000,],
238
            [true, '',],
239
            [true, 'tomorrow +2hours',],
240
            [true, 'yesterday -2hours',],
241
            [true, 'now',],
242
            [true, 'now + 1000 seconds',],
243
            [true, 'now - 1000 seconds',],
244
            [true, 0,],
245
            [true, 1.1,],
246
            [false, [],],
247
            [false, false,],
248
            [false, true,],
249
            [false, null,],
250
            [false, [],],
251
            [false, new \stdClass(),],
252
        ];
253
    }
254
255
    public function testTimezone(): void
256
    {
257
        $checker = new DatetimeChecker();
258
259
        foreach (\DateTimeZone::listIdentifiers() as $identifier) {
260
            $this->assertTrue($checker->timezone($identifier));
261
            $this->assertFalse($checker->timezone(str_rot13($identifier)));
262
        }
263
264
        $this->assertFalse($checker->timezone('Any zone'));
265
    }
266
267
    /**
268
     * @dataProvider beforeProvider
269
     * @param bool  $expected
270
     * @param mixed $value
271
     * @param mixed $threshold
272
     * @param bool  $orEquals
273
     * @param bool  $useMicroseconds
274
     */
275
    public function testBefore(bool $expected, $value, $threshold, bool $orEquals, bool $useMicroseconds): void
276
    {
277
        $value = $value instanceof \Closure ? $value() : $value;
278
279
        $checker = new DatetimeChecker();
280
281
        $mock = $this->getMockBuilder(ValidatorInterface::class)->disableOriginalConstructor()->getMock();
282
        $mock->method('getValue')->with('threshold')->willReturn($threshold);
283
284
        /** @var ValidatorInterface $mock */
285
        $this->assertSame(
286
            $expected,
287
            $checker->check(
288
                $mock,
289
                'before',
290
                'field',
291
                $value,
292
                ['threshold', $orEquals, $useMicroseconds]
293
            )
294
        );
295
    }
296
297
    /**
298
     * @return array
299
     */
300
    public function beforeProvider(): array
301
    {
302
        return [
303
            //the date is 100% in the past
304
            [true, $this->inPast(1000), 'now', false, false],
305
            [true, $this->inPast(1000), 'now', true, false],
306
            [true, $this->inPast(1000), 'now', false, true],
307
            [true, $this->inPast(1000), 'now', true, true],
308
309
            [true, 'yesterday -2hours', 'now', false, false],
310
            [true, 'now - 1000 seconds', 'now', false, false],
311
            [true, 'now + 1000 seconds', 'tomorrow', false, false],
312
313
            //the "now" date can differ in ms
314
            [false, 'now', 'now', false, false],
315
            [true, 'now', 'now + 1000 second', false, false],
316
            [true, 'now', 'now', false, true], //the threshold date comes a little bit later (in ms)
317
            [true, 'now', 'now', true, false],
318
            [true, 'now', 'now', true, true], //the threshold date comes a little bit later (in ms)
319
320
            [false, $this->inFuture(1000), 'now', false, false],
321
            [true, '', 'now', false, false],
322
            [true, 0, 'now', false, false],
323
            [true, 1.1, 'now', false, false],
324
            [false, [], 'now', false, false],
325
            [false, false, 'now', false, false],
326
            [false, true, 'now', false, false],
327
            [false, null, 'now', false, false],
328
            [false, [], 'now', false, false],
329
            [false, new \stdClass(), 'now', false, false],
330
        ];
331
    }
332
333
    /**
334
     * @dataProvider afterProvider
335
     * @param bool  $expected
336
     * @param mixed $value
337
     * @param mixed $threshold
338
     * @param bool  $orEquals
339
     * @param bool  $useMicroseconds
340
     */
341
    public function testAfter(bool $expected, $value, $threshold, bool $orEquals, bool $useMicroseconds): void
342
    {
343
        $value = $value instanceof \Closure ? $value() : $value;
344
345
        $checker = new DatetimeChecker();
346
347
        $mock = $this->getMockBuilder(ValidatorInterface::class)->disableOriginalConstructor()->getMock();
348
        $mock->method('getValue')->with('threshold')->willReturn($threshold);
349
350
        /** @var ValidatorInterface $mock */
351
        $this->assertSame(
352
            $expected,
353
            $checker->check(
354
                $mock,
355
                'after',
356
                'field',
357
                $value,
358
                ['threshold', $orEquals, $useMicroseconds]
359
            )
360
        );
361
    }
362
363
    /**
364
     * @return array
365
     */
366
    public function afterProvider(): array
367
    {
368
        return [
369
            [true, $this->inFuture(1000), 'now', false, false],
370
            [true, $this->inFuture(1000), 'now', true, false],
371
            [true, $this->inFuture(1000), 'now', false, true],
372
            [true, $this->inFuture(1000), 'now', true, true],
373
374
            [true, 'tomorrow +2hours', 'now', false, false],
375
            [true, 'now + 1000 seconds', 'now', false, false],
376
            [true, 'now - 1000 seconds', 'yesterday', false, false],
377
378
            //the "now" date can differ in ms
379
            [false, 'now', 'now', false, false],
380
            [true, 'now', 'now - 1000 second', false, false],
381
            [false, 'now', 'now', false, true], //the threshold date comes a little bit later (in ms)
382
            [true, 'now', 'now', true, false],
383
            [false, 'now', 'now', true, true], //the threshold date comes a little bit later (in ms)
384
385
            [false, $this->inPast(1000), 'now', false, false],
386
            [false, '', 'now', false, false],
387
            [false, 0, 'now', false, false],
388
            [false, 1.1, 'now', false, false],
389
            [false, [], 'now', false, false],
390
            [false, false, 'now', false, false],
391
            [false, true, 'now', false, false],
392
            [false, null, 'now', false, false],
393
            [false, [], 'now', false, false],
394
            [false, new \stdClass(), 'now', false, false],
395
        ];
396
    }
397
398
    private function now(): \Closure
399
    {
400
        return static function () {
401
            return \time();
402
        };
403
    }
404
405
    private function inFuture(int $seconds): \Closure
406
    {
407
        return static function () use ($seconds) {
408
            return \time() + $seconds;
409
        };
410
    }
411
412
    private function inPast(int $seconds): \Closure
413
    {
414
        return static function () use ($seconds) {
415
            return \time() - $seconds;
416
        };
417
    }
418
}
419