Passed
Pull Request — master (#25)
by Alexander
14:50
created

DateTest::testIntlValidate()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 12
Code Lines 8

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
eloc 8
c 0
b 0
f 0
dl 0
loc 12
rs 10
cc 1
nc 1
nop 1
1
<?php
2
namespace Yiisoft\Validator\Tests\Rule;
3
4
use IntlDateFormatter;
5
use PHPUnit\Framework\TestCase;
6
use Yiisoft\Validator\Rule\Date;
7
use Yiisoft\Validator\Tests\data\FakedValidationModel;
8
use Yiisoft\Validator\Tests\IntlTestHelper;
9
10
/**
11
 * @group validators
12
 */
13
class DateTest extends TestCase
14
{
15
    /**
16
     * @var array Default timeZone and locale settings for the validator
17
     */
18
    public $params = [
19
        'format' => 'd/m/Y',
20
        'timeZone' => 'UTC',
21
        'locale' => 'ru-RU',
22
    ];
23
24
    protected function setUp()
25
    {
26
        parent::setUp();
27
28
        IntlTestHelper::setIntlStatus($this);
29
    }
30
31
    protected function tearDown()
32
    {
33
        parent::tearDown();
34
        IntlTestHelper::resetIntlStatus();
35
    }
36
37
    public function testEnsureMessageIsSet()
38
    {
39
        $val = new Date($this->params['format'], $this->params['locale'], $this->params['timeZone']);
40
41
        $reflection = new \ReflectionObject($val);
42
        $prop = $reflection->getProperty('message');
43
        $prop->setAccessible(true);
44
45
        $message = ($prop->getValue($val));
46
47
        $this->assertTrue($message !== null && strlen($message) > 1);
48
    }
49
50
    /**
51
     * @dataProvider provideTimezones
52
     * @param string $timezone
53
     */
54
    public function testIntlValidate($timezone)
55
    {
56
        date_default_timezone_set($timezone);
57
        $this->testValidate($timezone);
58
59
        $val = new Date('short', 'en-GB', $this->params['timeZone']);
60
        $this->assertTrue($val->validate('31/5/2017')->isValid());
61
        $this->assertFalse($val->validate('5/31/2017')->isValid());
62
63
        $val = new Date('short', 'de-DE', $this->params['timeZone']);
64
        $this->assertTrue($val->validate('31.5.2017')->isValid());
65
        $this->assertFalse($val->validate('5.31.2017')->isValid());
66
    }
67
68
    /**
69
     * @dataProvider provideTimezones
70
     * @param string $timezone
71
     */
72
    public function testValidate($timezone)
73
    {
74
        date_default_timezone_set($timezone);
75
76
        // test PHP format
77
        $val = new Date('php:Y-m-d', $this->params['locale'], $timezone);
78
        $this->assertFalse($val->validate('3232-32-32')->isValid());
79
        $this->assertTrue($val->validate('2013-09-13')->isValid());
80
        $this->assertFalse($val->validate('31.7.2013')->isValid());
81
        $this->assertFalse($val->validate('31-7-2013')->isValid());
82
        $this->assertFalse($val->validate('20121212')->isValid());
83
        $this->assertFalse($val->validate('asdasdfasfd')->isValid());
84
        $this->assertFalse($val->validate('2012-12-12foo')->isValid());
85
        $this->assertFalse($val->validate('')->isValid());
86
        $this->assertFalse($val->validate(time())->isValid());
87
        $val->format = 'php:U';
88
        $this->assertTrue($val->validate(time())->isValid());
89
        $val->format = 'php:d.m.Y';
90
        $this->assertTrue($val->validate('31.7.2013')->isValid());
91
        $val->format = 'php:Y-m-!d H:i:s';
92
        $this->assertTrue($val->validate('2009-02-15 15:16:17')->isValid());
93
94
        // test ICU format
95
        $val = new Date('yyyy-MM-dd', $this->params['locale'], $timezone);
96
        $this->assertFalse($val->validate('3232-32-32')->isValid());
97
        $this->assertTrue($val->validate('2013-09-13')->isValid());
98
        $this->assertFalse($val->validate('31.7.2013')->isValid());
99
        $this->assertFalse($val->validate('31-7-2013')->isValid());
100
        $this->assertFalse($val->validate('20121212')->isValid());
101
        $this->assertFalse($val->validate('asdasdfasfd')->isValid());
102
        $this->assertFalse($val->validate('2012-12-12foo')->isValid());
103
        $this->assertFalse($val->validate('')->isValid());
104
        $this->assertFalse($val->validate(time())->isValid());
105
        $val->format = 'dd.MM.yyyy';
106
        $this->assertTrue($val->validate('31.7.2013')->isValid());
107
        $val->format = 'yyyy-MM-dd HH:mm:ss';
108
        $this->assertTrue($val->validate('2009-02-15 15:16:17')->isValid());
109
    }
110
111
    /**
112
     * @dataProvider provideTimezones
113
     * @param string $timezone
114
     */
115
    public function testIntlValidateAttributePHPFormat($timezone)
116
    {
117
        $this->testValidateAttributePHPFormat($timezone);
118
    }
119
120
    /**
121
     * @dataProvider provideTimezones
122
     * @param string $timezone
123
     */
124
    public function testValidateAttributePHPFormat($timezone)
125
    {
126
        date_default_timezone_set($timezone);
127
128
        // error-array-add
129
        $val = new Date('php:Y-m-d', $this->params['locale'], $timezone);
130
        $model = new FakedValidationModel();
131
        $model->attr_date = '2013-09-13';
132
        $result = $val->validateAttribute($model, 'attr_date');
133
        $this->assertTrue($result->isValid());
134
        $model = new FakedValidationModel();
135
        $model->attr_date = '1375293913';
136
        $result = $val->validateAttribute($model, 'attr_date');
137
        $this->assertFalse($result->isValid());
138
        //// timestamp attribute
139
        $val = (new Date('php:Y-m-d', $this->params['locale'], $timezone))->timestampAttribute('attr_timestamp');
140
        $model = new FakedValidationModel();
141
        $model->attr_date = '2013-09-13';
142
        $model->attr_timestamp = true;
143
        $result = $val->validateAttribute($model, 'attr_date');
144
        $this->assertTrue($result->isValid());
145
        $this->assertEquals(
146
            1379030400, // 2013-09-13 00:00:00
147
            $model->attr_timestamp
148
        );
149
        // array value
150
        $val = (new Date('php:Y-m-d', $this->params['locale'], $timezone))->timestampAttribute('attr_timestamp');
151
        $model = FakedValidationModel::createWithAttributes(['attr_date' => ['2013-09-13']]);
152
        $result = $val->validateAttribute($model, 'attr_date');
153
        $this->assertFalse($result->isValid());
154
    }
155
156
    /**
157
     * @dataProvider provideTimezones
158
     * @param string $timezone
159
     */
160
    public function testIntlValidateAttributeICUFormat($timezone)
161
    {
162
        $this->testValidateAttributeICUFormat($timezone);
163
    }
164
165
    /**
166
     * @dataProvider provideTimezones
167
     * @param string $timezone
168
     */
169
    public function testValidateAttributeICUFormat($timezone)
170
    {
171
        date_default_timezone_set($timezone);
172
173
        // error-array-add
174
        $val = new Date('yyyy-MM-dd', $this->params['locale'], $timezone);
175
        $model = new FakedValidationModel();
176
        $model->attr_date = '2013-09-13';
177
        $result = $val->validateAttribute($model, 'attr_date');
178
        $this->assertTrue($result->isValid());
179
        $model = new FakedValidationModel();
180
        $model->attr_date = '1375293913';
181
        $result = $val->validateAttribute($model, 'attr_date');
182
        $this->assertFalse($result->isValid());
183
        //// timestamp attribute
184
        $val = (new Date('yyyy-MM-dd', $this->params['locale'], $timezone))->timestampAttribute('attr_timestamp');
185
        $model = new FakedValidationModel();
186
        $model->attr_date = '2013-09-13';
187
        $model->attr_timestamp = true;
188
        $result = $val->validateAttribute($model, 'attr_date');
189
        $this->assertTrue($result->isValid());
190
        $this->assertSame(
191
            1379030400, // 2013-09-13 00:00:00
192
            $model->attr_timestamp
193
        );
194
        // array value
195
        $val = new Date('yyyy-MM-dd', $this->params['locale'], $timezone);
196
        $model = FakedValidationModel::createWithAttributes(['attr_date' => ['2013-09-13']]);
197
        $result = $val->validateAttribute($model, 'attr_date');
198
        $this->assertFalse($result->isValid());
199
        // invalid format
200
        $val = new Date('yyyy-MM-dd', $this->params['locale'], $timezone);
201
        $model = FakedValidationModel::createWithAttributes(['attr_date' => '2012-12-12foo']);
202
        $result = $val->validateAttribute($model, 'attr_date');
203
        $this->assertFalse($result->isValid());
204
    }
205
206
    public function testIntlMultibyteString()
207
    {
208
        $val = new Date('dd MMM yyyy', 'de_DE', $this->params['timeZone']);
209
        $model = FakedValidationModel::createWithAttributes(['attr_date' => '12 Mai 2014']);
210
        $result = $val->validateAttribute($model, 'attr_date');
211
        $this->assertTrue($result->isValid());
212
213
        $val = new Date('dd MMM yyyy', 'ru_RU', $this->params['timeZone']);
214
        $model = FakedValidationModel::createWithAttributes(['attr_date' => '12 мая 2014']);
215
        $result = $val->validateAttribute($model, 'attr_date');
216
        $this->assertTrue($result->isValid());
217
    }
218
219
    public function provideTimezones()
220
    {
221
        return [
222
            ['UTC'],
223
            ['Europe/Berlin'],
224
            ['America/Jamaica'],
225
        ];
226
    }
227
228
    public function timestampFormatProvider()
229
    {
230
        $return = [];
231
        foreach ($this->provideTimezones() as $appTz) {
232
            foreach ($this->provideTimezones() as $tz) {
233
                $return[] = ['yyyy-MM-dd', '2013-09-13', '2013-09-13', $tz[0], $appTz[0]];
234
                // regardless of timezone, a simple date input should always result in 00:00:00 time
235
                $return[] = ['yyyy-MM-dd HH:mm:ss', '2013-09-13', '2013-09-13 00:00:00', $tz[0], $appTz[0]];
236
                $return[] = ['php:Y-m-d', '2013-09-13', '2013-09-13', $tz[0], $appTz[0]];
237
                $return[] = ['php:Y-m-d H:i:s', '2013-09-13', '2013-09-13 00:00:00', $tz[0], $appTz[0]];
238
                $return[] = ['php:U', '2013-09-13', '1379030400', $tz[0], $appTz[0]];
239
                $return[] = [null, '2013-09-13', 1379030400, $tz[0], $appTz[0]];
240
            }
241
        }
242
243
        return $return;
244
    }
245
246
    /**
247
     * @dataProvider timestampFormatProvider
248
     * @param string|null $format
249
     * @param string $date
250
     * @param string|int $expectedDate
251
     * @param string $timezone
252
     * @param string $appTimezone
253
     */
254
    public function testIntlTimestampAttributeFormat($format, $date, $expectedDate, $timezone, $appTimezone)
255
    {
256
        $this->testTimestampAttributeFormat($format, $date, $expectedDate, $timezone, $appTimezone);
257
    }
258
259
    /**
260
     * @dataProvider timestampFormatProvider
261
     * @param string|null $format
262
     * @param string $date
263
     * @param string|int $expectedDate
264
     * @param string $timezone
265
     * @param string $appTimezone
266
     */
267
    public function testTimestampAttributeFormat($format, $date, $expectedDate, $timezone, $appTimezone)
268
    {
269
        date_default_timezone_set($timezone);
270
271
        $val = (new Date('yyyy-MM-dd', $this->params['locale'], $appTimezone))->timestampAttribute('attr_timestamp')->timestampAttributeFormat($format);
272
        $model = new FakedValidationModel();
273
        $model->attr_date = $date;
274
        $model->attr_timestamp = true;
275
        $result = $val->validateAttribute($model, 'attr_date');
276
        $this->assertTrue($result->isValid());
277
        $this->assertSame($expectedDate, $model->attr_timestamp);
278
    }
279
280
    /**
281
     * @dataProvider provideTimezones
282
     * @param string $timezone
283
     */
284
    public function testIntlValidationWithTime($timezone)
285
    {
286
        // prepare data for specific ICU version, see https://github.com/yiisoft/yii2/issues/15140
287
        switch (true) {
288
            case (version_compare(INTL_ICU_VERSION, '57.1', '>=')):
289
            case (INTL_ICU_VERSION === '55.1'):
290
                $enGB_dateTime_valid = '31/05/2017, 12:30';
291
                $enGB_dateTime_invalid = '05/31/2017, 12:30';
292
                $deDE_dateTime_valid = '31.05.2017, 12:30';
293
                $deDE_dateTime_invalid = '05.31.2017, 12:30';
294
                break;
295
            default:
296
                $enGB_dateTime_valid = '31/5/2017 12:30';
297
                $enGB_dateTime_invalid = '5/31/2017 12:30';
298
                $deDE_dateTime_valid = '31.5.2017 12:30';
299
                $deDE_dateTime_invalid = '5.31.2017 12:30';
300
        }
301
302
        $this->testValidationWithTime($timezone);
303
304
        $locale = 'en-GB';
305
        $dateTimeFormat = 'short';
306
307
        $val = (new Date($dateTimeFormat, $locale, $timezone))->type(Date::TYPE_DATETIME);
308
        $this->assertTrue($val->validate($enGB_dateTime_valid)->isValid());
309
        $this->assertFalse($val->validate($enGB_dateTime_invalid)->isValid());
310
        $val = (new Date('short', 'en-GB', $timezone))->type(Date::TYPE_DATETIME);
311
        $this->assertTrue($val->validate($enGB_dateTime_valid)->isValid());
312
        $this->assertFalse($val->validate($enGB_dateTime_invalid)->isValid());
313
314
        $locale = 'de-DE';
315
        $val = (new Date($dateTimeFormat, $locale, $timezone))->type(Date::TYPE_DATETIME);
316
        $this->assertTrue($val->validate($deDE_dateTime_valid)->isValid());
317
        $this->assertFalse($val->validate($deDE_dateTime_invalid)->isValid());
318
319
        $this->assertTrue($val->validate($deDE_dateTime_valid)->isValid());
320
        $this->assertFalse($val->validate($deDE_dateTime_invalid)->isValid());
321
    }
322
323
    /**
324
     * @dataProvider provideTimezones
325
     * @param string $timezone
326
     */
327
    public function testValidationWithTime($timezone)
328
    {
329
        date_default_timezone_set($timezone);
330
331
        $val = (new Date('yyyy-MM-dd HH:mm:ss', $this->params['locale'], 'UTC'))
332
            ->timestampAttribute('attr_timestamp');
333
        $model = new FakedValidationModel();
334
        $model->attr_date = '2013-09-13 14:23:15';
335
        $model->attr_timestamp = true;
336
        $result = $val->validateAttribute($model, 'attr_date');
337
        $this->assertTrue($result->isValid());
338
        $this->assertSame(1379082195, $model->attr_timestamp);
339
340
        $val =(new Date('yyyy-MM-dd HH:mm:ss', $this->params['locale'], 'Europe/Berlin'))->timestampAttribute('attr_timestamp');
341
        $model = new FakedValidationModel();
342
        $model->attr_date = '2013-09-13 16:23:15';
343
        $model->attr_timestamp = true;
344
        $result = $val->validateAttribute($model, 'attr_date');
345
        $this->assertTrue($result->isValid());
346
        $this->assertSame(1379082195, $model->attr_timestamp);
347
348
        $val = (new Date('yyyy-MM-dd HH:mm:ss', $this->params['locale'], 'UTC'))->timestampAttribute('attr_timestamp')->timestampAttributeFormat('yyyy-MM-dd HH:mm:ss');
349
        $model = new FakedValidationModel();
350
        $model->attr_date = '2013-09-13 14:23:15';
351
        $model->attr_timestamp = true;
352
        $result = $val->validateAttribute($model, 'attr_date');
353
        $this->assertTrue($result->isValid());
354
        $this->assertSame('2013-09-13 14:23:15', $model->attr_timestamp);
355
356
        $val = (new Date('yyyy-MM-dd HH:mm:ss', $this->params['locale'], 'Europe/Berlin'))->timestampAttribute('attr_timestamp')->timestampAttributeFormat('yyyy-MM-dd HH:mm:ss');
357
        $model = new FakedValidationModel();
358
        $model->attr_date = '2013-09-13 16:23:15';
359
        $model->attr_timestamp = true;
360
        $result = $val->validateAttribute($model, 'attr_date');
361
        $this->assertTrue($result->isValid());
362
        $this->assertSame('2013-09-13 14:23:15', $model->attr_timestamp);
363
364
        $val = (new Date('yyyy-MM-dd HH:mm:ss', $this->params['locale'], 'UTC'))->timestampAttribute('attr_timestamp')->timestampAttributeFormat('php:Y-m-d H:i:s');
365
        $model = new FakedValidationModel();
366
        $model->attr_date = '2013-09-13 14:23:15';
367
        $model->attr_timestamp = true;
368
        $result = $val->validateAttribute($model, 'attr_date');
369
        $this->assertTrue($result->isValid());
370
        $this->assertSame('2013-09-13 14:23:15', $model->attr_timestamp);
371
372
        $val = (new Date('yyyy-MM-dd HH:mm:ss', $this->params['locale'], 'Europe/Berlin'))->timestampAttribute('attr_timestamp')->timestampAttributeFormat('php:Y-m-d H:i:s');
373
        $model = new FakedValidationModel();
374
        $model->attr_date = '2013-09-13 16:23:15';
375
        $model->attr_timestamp = true;
376
        $result = $val->validateAttribute($model, 'attr_date');
377
        $this->assertTrue($result->isValid());
378
        $this->assertSame('2013-09-13 14:23:15', $model->attr_timestamp);
379
    }
380
381
    /**
382
     * @dataProvider provideTimezones
383
     * @param string $timezone
384
     */
385
    public function testIntlValidationWithTimeAndOutputTimeZone($timezone)
386
    {
387
        $this->testValidationWithTime($timezone);
388
    }
389
390
    /**
391
     * @dataProvider provideTimezones
392
     * @param string $timezone
393
     */
394
    public function testValidationWithTimeAndOutputTimeZone($timezone)
395
    {
396
        date_default_timezone_set($timezone);
397
398
        $val = (new Date('yyyy-MM-dd HH:mm:ss', $this->params['locale'], 'UTC'))
399
            ->timestampAttribute('attr_timestamp')->timestampAttributeFormat('yyyy-MM-dd HH:mm:ss')
400
            ->timestampAttributeTimeZone('Europe/Berlin');
401
        $model = new FakedValidationModel();
402
        $model->attr_date = '2013-09-13 14:23:15';
403
        $model->attr_timestamp = true;
404
        $result = $val->validateAttribute($model, 'attr_date');
405
        $this->assertTrue($result->isValid());
406
        $this->assertSame('2013-09-13 16:23:15', $model->attr_timestamp);
407
        $val = (new Date('php:Y-m-d H:i:s', $this->params['locale'], 'UTC'))
408
            ->timestampAttribute('attr_timestamp')->timestampAttributeFormat('yyyy-MM-dd HH:mm:ss')
409
            ->timestampAttributeTimeZone('Europe/Berlin');
410
        $model = new FakedValidationModel();
411
        $model->attr_date = '2013-09-13 14:23:15';
412
        $model->attr_timestamp = true;
413
        $result = $val->validateAttribute($model, 'attr_date');
414
        $this->assertTrue($result->isValid());
415
        $this->assertSame('2013-09-13 16:23:15', $model->attr_timestamp);
416
417
        $val = (new Date('yyyy-MM-dd HH:mm:ss', $this->params['locale'], 'Europe/Berlin'))
418
            ->timestampAttribute('attr_timestamp')->timestampAttributeFormat('yyyy-MM-dd HH:mm:ss')
419
            ->timestampAttributeTimeZone('Europe/Berlin');
420
        $model = new FakedValidationModel();
421
        $model->attr_date = '2013-09-13 16:23:15';
422
        $model->attr_timestamp = true;
423
        $result = $val->validateAttribute($model, 'attr_date');
424
        $this->assertTrue($result->isValid());
425
        $this->assertSame('2013-09-13 16:23:15', $model->attr_timestamp);
426
        $val = (new Date('php:Y-m-d H:i:s', $this->params['locale'], 'Europe/Berlin'))
427
            ->timestampAttribute('attr_timestamp')->timestampAttributeFormat('yyyy-MM-dd HH:mm:ss')
428
            ->timestampAttributeTimeZone('Europe/Berlin');
429
        $model = new FakedValidationModel();
430
        $model->attr_date = '2013-09-13 16:23:15';
431
        $model->attr_timestamp = true;
432
        $result = $val->validateAttribute($model, 'attr_date');
433
        $this->assertTrue($result->isValid());
434
        $this->assertSame('2013-09-13 16:23:15', $model->attr_timestamp);
435
436
        $val = (new Date('yyyy-MM-dd HH:mm:ss', $this->params['locale'], 'Europe/Berlin'))
437
            ->timestampAttribute('attr_timestamp')->timestampAttributeFormat('yyyy-MM-dd HH:mm:ss')
438
            ->timestampAttributeTimeZone('America/New_York');
439
        $model = new FakedValidationModel();
440
        $model->attr_date = '2013-09-13 16:23:15';
441
        $model->attr_timestamp = true;
442
        $result = $val->validateAttribute($model, 'attr_date');
443
        $this->assertTrue($result->isValid());
444
        $this->assertSame('2013-09-13 10:23:15', $model->attr_timestamp);
445
        $val = (new Date('php:Y-m-d H:i:s', $this->params['locale'], 'Europe/Berlin'))
446
            ->timestampAttribute('attr_timestamp')->timestampAttributeFormat('yyyy-MM-dd HH:mm:ss')
447
            ->timestampAttributeTimeZone('America/New_York');
448
        $model = new FakedValidationModel();
449
        $model->attr_date = '2013-09-13 16:23:15';
450
        $model->attr_timestamp = true;
451
        $result = $val->validateAttribute($model, 'attr_date');
452
        $this->assertTrue($result->isValid());
453
        $this->assertSame('2013-09-13 10:23:15', $model->attr_timestamp);
454
    }
455
456
    public function testIntlValidateRange()
457
    {
458
        $this->testvalidateRange();
459
    }
460
461
    public function testvalidateRange()
462
    {
463
        if (PHP_INT_SIZE == 8) { // this passes only on 64bit systems
464
            // intl parser allows 14 for yyyy pattern, see the following for more details:
465
            // https://github.com/yiisoft/yii2/blob/a003a8fb487dfa60c0f88ecfacf18a7407ced18b/framework/validators/DateValidator.php#L51-L57
466
            $date = '14-09-13';
467
            $val = new Date('yyyy-MM-dd', $this->params['locale'], $this->params['timeZone']);
468
            $this->assertTrue($val->validate($date)->isValid(), "$date is valid");
469
470
            $min = '1900-01-01';
471
            $beforeMin = '1899-12-31';
472
        } else {
473
            $min = '1920-01-01';
474
            $beforeMin = '1919-12-31';
475
        }
476
477
        $val = (new Date('yyyy-MM-dd', $this->params['locale'], $this->params['timeZone']))->min($min);
478
        $date = '1958-01-12';
479
        $this->assertTrue($val->validate($date)->isValid(), "$date is valid");
480
481
        $val = (new Date('yyyy-MM-dd', $this->params['locale'], $this->params['timeZone']))->max('2000-01-01');
482
        $date = '2014-09-13';
483
        $this->assertFalse($val->validate($date)->isValid(), "$date is too big");
484
        $date = '1958-01-12';
485
        $this->assertTrue($val->validate($date)->isValid(), "$date is valid");
486
487
        $val = (new Date('yyyy-MM-dd', $this->params['locale'], $this->params['timeZone']))->min($min)
488
            ->max('2000-01-01');
489
        $this->assertTrue($val->validate('1999-12-31')->isValid(), 'max -1 day is valid');
490
        $this->assertTrue($val->validate('2000-01-01')->isValid(), 'max is inside range');
491
        $this->assertTrue($val->validate($min)->isValid(), 'min is inside range');
492
        $this->assertFalse($val->validate($beforeMin)->isValid(), 'min -1 day is invalid');
493
        $this->assertFalse($val->validate('2000-01-02')->isValid(), 'max +1 day is invalid');
494
    }
495
496
    private function validateModelAttribute($validator, $date, $expected, $message = '')
497
    {
498
        $model = new FakedValidationModel();
499
        $model->attr_date = $date;
500
        $result = $validator->validateAttribute($model, 'attr_date');
501
        if (!$expected) {
502
            $this->assertFalse($result->isValid(), $message);
503
        } else {
504
            $this->assertTrue($result->isValid(), $message);
505
        }
506
    }
507
508
    public function testIntlValidateAttributeRange()
509
    {
510
        $this->testValidateAttributeRange();
511
    }
512
513
    public function testValidateAttributeRange()
514
    {
515
        if (PHP_INT_SIZE == 8) { // this passes only on 64bit systems
516
            // intl parser allows 14 for yyyy pattern, see the following for more details:
517
            // https://github.com/yiisoft/yii2/blob/a003a8fb487dfa60c0f88ecfacf18a7407ced18b/framework/validators/DateValidator.php#L51-L57
518
            $val = new Date('yyyy-MM-dd', $this->params['locale'], $this->params['timeZone']);
519
            $date = '14-09-13';
520
            $this->validateModelAttribute($val, $date, true, "$date is valid");
521
522
            $min = '1900-01-01';
523
            $beforeMin = '1899-12-31';
524
        } else {
525
            $min = '1920-01-01';
526
            $beforeMin = '1919-12-31';
527
        }
528
529
        $val = (new Date('yyyy-MM-dd', $this->params['locale'], $this->params['timeZone']))->min($min);
530
        $date = '1958-01-12';
531
        $this->validateModelAttribute($val, $date, true, "$date is valid");
532
533
        $val = (new Date('yyyy-MM-dd', $this->params['locale'], $this->params['timeZone']))
534
            ->max('2000-01-01');
535
        $date = '2014-09-13';
536
        $this->validateModelAttribute($val, $date, false, "$date is too big");
537
        $date = '1958-01-12';
538
        $this->validateModelAttribute($val, $date, true, "$date is valid");
539
540
        $val = (new Date('yyyy-MM-dd', $this->params['locale'], $this->params['timeZone']))
541
            ->min($min)->max('2000-01-01');
542
        $this->validateModelAttribute($val, '1999-12-31', true, 'max -1 day is valid');
543
        $this->validateModelAttribute($val, '2000-01-01', true, 'max is inside range');
544
        $this->validateModelAttribute($val, $min, true, 'min is inside range');
545
        $this->validateModelAttribute($val, $beforeMin, false, 'min -1 day is invalid');
546
        $this->validateModelAttribute($val, '2000-01-02', false, 'max +1 day is invalid');
547
    }
548
549
    public function testIntlvalidateRangeOld()
550
    {
551
        if ($this->checkOldIcuBug()) {
552
            $this->markTestSkipped('ICU is too old.');
553
        }
554
        $date = '14-09-13';
555
        $val = (new Date('yyyy-MM-dd', $this->params['locale'], $this->params['timeZone']))
556
            ->min('1920-01-01');
557
        $this->assertFalse($val->validate($date)->isValid(), "$date is too small");
558
    }
559
560
    public function testIntlValidateAttributeRangeOld()
561
    {
562
        if ($this->checkOldIcuBug()) {
563
            $this->markTestSkipped('ICU is too old.');
564
        }
565
        $date = '14-09-13';
566
        $val = (new Date('yyyy-MM-dd', $this->params['locale'], $this->params['timeZone']))
567
            ->min('1920-01-01');
568
        $this->validateModelAttribute($val, $date, false, "$date is too small");
569
    }
570
571
    /**
572
     * Returns true if the version of ICU is old and has a bug that makes it
573
     * impossible to parse two digit years properly.
574
     * @see http://bugs.icu-project.org/trac/ticket/9836
575
     * @return bool
576
     */
577
    private function checkOldIcuBug()
578
    {
579
        $date = '14';
580
        $formatter = new IntlDateFormatter('en-US', IntlDateFormatter::NONE, IntlDateFormatter::NONE, null, null, 'yyyy');
581
        $parsePos = 0;
582
        $parsedDate = @$formatter->parse($date, $parsePos);
583
584
        if (is_int($parsedDate) && $parsedDate > 0) {
585
            return true;
586
        }
587
588
        return false;
589
    }
590
591
    /**
592
     * @depends testValidateAttributePHPFormat
593
     */
594
    public function testTimestampAttributeSkipValidation()
595
    {
596
        // timestamp as integer
597
        $val = (new Date('php:Y/m/d', $this->params['locale'], $this->params['timeZone']))
598
            ->timestampAttribute('attr_date');
599
        $model = new FakedValidationModel();
600
        $model->attr_date = 1379030400;
601
        $result = $val->validateAttribute($model, 'attr_date');
602
        $this->assertTrue($result->isValid());
603
604
        $val = (new Date('php:Y/m/d', $this->params['locale'], $this->params['timeZone']))
605
            ->timestampAttribute('attr_date');
606
        $model = new FakedValidationModel();
607
        $model->attr_date = 'invalid';
608
        $result = $val->validateAttribute($model, 'attr_date');
609
        $this->assertFalse($result->isValid());
610
611
        // timestamp as formatted date
612
        $val = (new Date('php:Y/m/d', $this->params['locale'], $this->params['timeZone']))
613
            ->timestampAttribute('attr_date')->timestampAttributeFormat('php:Y-m-d');
614
        $model = new FakedValidationModel();
615
        $model->attr_date = '2013-09-13';
616
        $result = $val->validateAttribute($model, 'attr_date');
617
        $this->assertTrue($result->isValid());
618
619
        $val = (new Date('php:Y/m/d', $this->params['locale'], $this->params['timeZone']))
620
            ->timestampAttribute('attr_date')->timestampAttributeFormat('php:Y-m-d');
621
        $model = new FakedValidationModel();
622
        $model->attr_date = '2013-09-2013';
623
        $result = $val->validateAttribute($model, 'attr_date');
624
        $this->assertFalse($result->isValid());
625
    }
626
627
    /**
628
     * @depends testValidateAttributePHPFormat
629
     */
630
    public function testTimestampAttributeOnEmpty()
631
    {
632
        $validator = (new Date('php:Y/m/d', $this->params['locale'], $this->params['timeZone']))
633
            ->timestampAttribute('attr_date')->skipOnEmpty(false);
634
        $model = new FakedValidationModel();
635
        $model->attr_date = '';
636
        $result = $validator->validateAttribute($model, 'attr_date');
637
        $this->assertTrue($result->isValid());
638
        $this->assertNull($model->attr_date);
639
640
        $validator = (new Date('php:Y/m/d', $this->params['locale'], $this->params['timeZone']))
641
            ->timestampAttribute('attr_timestamp')->skipOnEmpty(false);
642
        $model = new FakedValidationModel();
643
        $model->attr_date = '';
644
        $model->attr_timestamp = 1379030400;
645
        $result = $validator->validateAttribute($model, 'attr_date');
646
        $this->assertTrue($result->isValid());
647
        $this->assertNull($model->attr_timestamp);
648
    }
649
650
    /**
651
     * Tests that DateValidator with format `php:U` does not truncate timestamp to date.
652
     * @see https://github.com/yiisoft/yii2/issues/15628
653
     */
654
    public function testIssue15628()
655
    {
656
        $validator = (new Date('php:U', $this->params['locale'], $this->params['timeZone']))
657
            ->type(Date::TYPE_DATETIME)->timestampAttribute('attr_date');
658
        $model = new FakedValidationModel();
659
        $value = 1518023610;
660
        $model->attr_date = $value;
661
662
        $validator->validateAttribute($model, 'attr_date');
663
664
        $this->assertEquals($value, $model->attr_date);
665
    }
666
}
667