Completed
Push — master ( 3b753f...226934 )
by Dmitry
09:04
created

DomainValidatorTest   B

Complexity

Total Complexity 44

Size/Duplication

Total Lines 683
Duplicated Lines 0 %

Coupling/Cohesion

Components 2
Dependencies 4

Importance

Changes 7
Bugs 0 Features 0
Metric Value
wmc 44
c 7
b 0
f 0
lcom 2
cbo 4
dl 0
loc 683
rs 8.0672

31 Methods

Rating   Name   Duplication   Size   Complexity  
A setUp() 0 5 1
A validDomainProvider() 0 21 1
B validDomainInUrlProvider() 0 24 1
A validDomainIdnProvider() 0 21 1
B validDomainIdnInUrlProvider() 0 24 1
A validDomainAllWithoutIdnProvider() 0 7 1
A validDomainAllOnlyIdnProvider() 0 7 1
A validDomainAllProvider() 0 9 1
A testValidDomain() 0 4 1
A testInvalidDomainWithDisabledIdn() 0 8 1
A testValidDomainWithEnabledIdn() 0 10 2
A testDns() 0 20 2
B testDnsWithEnabledIdn() 0 27 3
B testUnderscore() 0 26 3
A testUnderscoreWithEnabledIdn() 0 10 2
A urlNotAllowedProvider() 0 7 1
A testUrlNotAllowed() 0 6 1
A urlNotAllowedProviderWithEnabledIdn() 0 8 1
A testUrlNotAllowedWithEnabledIdn() 0 10 2
A testLabelNumberMin() 0 13 1
A testLabelNumberMinWithEnabledIdn() 0 10 2
B invalidDomainProvider() 0 88 2
A testInvalidDomain() 0 5 1
A testInvalidDomainWithEnabledIdn() 0 10 2
A testCustomErrorMessage() 0 8 1
A testSimpleErrorMessage() 0 7 1
B testValidateAttributeAndI18n() 0 27 1
A testInitIdnIntlException() 0 10 3
A arrayAddColumn() 0 10 1
A invalidDomainWithEnabledIdnProvider() 0 69 1
A u() 0 4 1

How to fix   Complexity   

Complex Class

Complex classes like DomainValidatorTest often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes. You can also have a look at the cohesion graph to spot any un-connected, or weakly-connected components.

Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.

While breaking up the class, it is a good idea to analyze how other classes use DomainValidatorTest, and based on these observations, apply Extract Interface, too.

1
<?php
2
3
namespace kdn\yii2\validators;
4
5
use kdn\yii2\validators\mocks\ModelMock;
6
use stdClass;
7
use Yii;
8
9
/**
10
 * Class DomainValidatorTest.
11
 * @package kdn\yii2\validators
12
 * @covers kdn\yii2\validators\DomainValidator::init
13
 */
14
class DomainValidatorTest extends TestCase
15
{
16
    /**
17
     * @var DomainValidator
18
     */
19
    protected $validator;
20
21
    /**
22
     * @inheritdoc
23
     */
24
    protected function setUp()
25
    {
26
        parent::setUp();
27
        $this->validator = new DomainValidator(['labelNumberMin' => 1]);
28
    }
29
30
    public static function validDomainProvider()
31
    {
32
        return [
33
            'one domain name label' => ['localhost'],
34
            'two domain name labels' => ['example.com'],
35
            'domain name with trailing dot' => ['example.com.'],
36
            '127 levels, 253 characters and trailing dot' => [
37
                'a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.' .
38
                'a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.' .
39
                'a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.' .
40
                'a.a.a.a.',
41
            ],
42
            'domain name labels with 63 characters' => [
43
                'aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa.' .
44
                'aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa.' .
45
                'example.com',
46
            ],
47
            'domain name with various symbols' => ['1.a-B.c2'],
48
            'Punycode, mixed domain name' => ['xn--e1afmkfd.test.xn--80akhbyknj4f'],
49
        ];
50
    }
51
52
    public static function validDomainInUrlProvider()
53
    {
54
        return [
55
            'HTTP, one domain name label' => ['http://localhost'],
56
            'HTTP, two domain name labels' => ['http://example.com/index.html'],
57
            'FTP, domain name with trailing dot' => ['ftp://example.com./img/dir/'],
58
            // todo it causes empty array in "idn_to_ascii" $idnaInfo
59
            'HTTPS, 127 levels, 253 characters and trailing dot' => [
60
                'https://a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.' .
61
                'a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.' .
62
                'a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.' .
63
                'a.a.a.a./index.html',
64
            ],
65
            'missing scheme, domain name labels with 63 characters' => [
66
                '//aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa.' .
67
                'aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa.' .
68
                'example.com',
69
            ],
70
            'complex URL, domain name with various symbols' => [
71
                'http://username:[email protected]:9090/path?a=b&c=d#anchor',
72
            ],
73
            'Punycode, FTP, mixed domain name' => ['ftp://xn--e1afmkfd.test.xn--80akhbyknj4f/img/dir/'],
74
        ];
75
    }
76
77
    public static function validDomainIdnProvider()
78
    {
79
        return [
80
            'IDN, one domain name label' => ['пример'],
81
            'IDN, two domain name labels' => ['пример.испытание'],
82
            'IDN, domain name with trailing dot' => ['пример.испытание.'],
83
            'IDN, mixed domain name' => ['пример.test.испытание'],
84
            'IDN, 34 levels, 253 characters (ф. == xn--t1a.) and trailing dot' => [
85
                'ф.ф.ф.ф.ф.ф.ф.ф.ф.ф.ф.ф.ф.ф.ф.ф.ф.ф.ф.ф.ф.ф.ф.ф.ф.ф.ф.ф.ф.ф.ф.s.s.s.',
86
            ],
87
            'IDN, domain name labels with 63 characters' => [
88
                'ффффффффффффффффффффффффффффффффффффффффффффффффффффффффф.' .
89
                'ффффффффффффффффффффффффффффффффффффффффффффффффффффффффф.' .
90
                'испытание'
91
            ],
92
            'IDN, domain name with various symbols' => ['1.a-B.cф2'],
93
            'IDN, hot beverage' => ['☕.us'],
94
            'IDN, full-width characters' => ['日本語。JP'],
95
            'IDN, box-drawing character' => ['ex╬ample.com'],
96
        ];
97
    }
98
99
    public static function validDomainIdnInUrlProvider()
100
    {
101
        return [
102
            'IDN, HTTP, one domain name label' => ['http://пример'],
103
            'IDN, HTTP, two domain name labels' => ['http://пример.испытание/index.html'],
104
            'IDN, FTP, domain name with trailing dot' => ['ftp://пример.испытание./img/dir/'],
105
            'IDN, FTP, mixed domain name' => ['ftp://пример.test.испытание/img/dir/'],
106
            // todo it causes empty array in "idn_to_ascii" $idnaInfo
107
            'IDN, HTTPS, 34 levels, 253 characters (ф. == xn--t1a.) and trailing dot' => [
108
                'https://ф.ф.ф.ф.ф.ф.ф.ф.ф.ф.ф.ф.ф.ф.ф.ф.ф.ф.ф.ф.ф.ф.ф.ф.ф.ф.ф.ф.ф.ф.ф.s.s.s./index.html',
109
            ],
110
            'IDN, missing scheme, domain name labels with 63 characters' => [
111
                '//ффффффффффффффффффффффффффффффффффффффффффффффффффффффффф.' .
112
                'ффффффффффффффффффффффффффффффффффффффффффффффффффффффффф.' .
113
                'испытание'
114
            ],
115
            'IDN, complex URL, domain name with various symbols' => [
116
                'http://username:[email protected]ф2:9090/path?a=ф&c=d#-пример',
117
            ],
118
            'IDN, HTTP, hot beverage' => ['http://☕.us/index.html'],
119
            'IDN, HTTP, full-width characters' => ['http://日本語。JP/index.html'],
120
            'IDN, HTTP, box-drawing character' => ['http://ex╬ample.com/index.html'],
121
        ];
122
    }
123
124
    public static function validDomainAllWithoutIdnProvider()
125
    {
126
        return array_merge(
127
            static::validDomainProvider(),
128
            static::validDomainInUrlProvider()
129
        );
130
    }
131
132
    public static function validDomainAllOnlyIdnProvider()
133
    {
134
        return array_merge(
135
            static::validDomainIdnProvider(),
136
            static::validDomainIdnInUrlProvider()
137
        );
138
    }
139
140
    public static function validDomainAllProvider()
141
    {
142
        return array_merge(
143
            static::validDomainProvider(),
144
            static::validDomainInUrlProvider(),
145
            static::validDomainIdnProvider(),
146
            static::validDomainIdnInUrlProvider()
147
        );
148
    }
149
150
    /**
151
     * @param string $value
152
     * @covers       kdn\yii2\validators\DomainValidator::validateValue
153
     * @dataProvider validDomainAllWithoutIdnProvider
154
     * @small
155
     */
156
    public function testValidDomain($value)
157
    {
158
        $this->assertTrue($this->validator->validate($value));
159
    }
160
161
    /**
162
     * @param string $value
163
     * @covers       kdn\yii2\validators\DomainValidator::getDefaultErrorMessages
164
     * @covers       kdn\yii2\validators\DomainValidator::getErrorMessage
165
     * @covers       kdn\yii2\validators\DomainValidator::validateValue
166
     * @dataProvider validDomainAllOnlyIdnProvider
167
     * @small
168
     */
169
    public function testInvalidDomainWithDisabledIdn($value)
170
    {
171
        $this->assertFalse($this->validator->validate($value, $errorMessage));
172
        $this->assertEquals(
173
            'Each label of the input value can consist of only latin letters, numbers and hyphens.',
174
            $errorMessage
175
        );
176
    }
177
178
    /**
179
     * @param string $value
180
     * @covers       kdn\yii2\validators\DomainValidator::validateValue
181
     * @dataProvider validDomainAllProvider
182
     * @small
183
     */
184
    public function testValidDomainWithEnabledIdn($value)
185
    {
186
        if (!function_exists('idn_to_ascii')) {
187
            $this->markTestSkipped('intl extension required.');
188
            return;
189
        }
190
191
        $this->validator->enableIDN = true;
192
        $this->testValidDomain($value);
193
    }
194
195
    /**
196
     * @covers kdn\yii2\validators\DomainValidator::getDefaultErrorMessages
197
     * @covers kdn\yii2\validators\DomainValidator::getErrorMessage
198
     * @covers kdn\yii2\validators\DomainValidator::validateValue
199
     * @medium
200
     */
201
    public function testDns()
202
    {
203
        $validator = $this->validator;
204
        $nonExistingDomain = 'non-existing-subdomain.example.com';
205
        $this->assertTrue($validator->validate($nonExistingDomain));
206
        $validator->checkDNS = true;
207
        $this->assertFalse($validator->validate($nonExistingDomain, $errorMessage));
208
        $this->assertEquals('DNS record corresponding to the input value not found.', $errorMessage);
209
210
        $data = [
211
            'google.com',
212
            'http://username:[email protected]:9090/path?a=b&c=d#anchor',
213
        ];
214
        foreach ($data as $value) {
215
            $this->assertTrue(
216
                $validator->validate($value),
217
                "Failed to validate \"$value\" (checkDNS = true)."
218
            );
219
        }
220
    }
221
222
    /**
223
     * @covers kdn\yii2\validators\DomainValidator::getDefaultErrorMessages
224
     * @covers kdn\yii2\validators\DomainValidator::getErrorMessage
225
     * @covers kdn\yii2\validators\DomainValidator::validateValue
226
     * @medium
227
     */
228
    public function testDnsWithEnabledIdn()
229
    {
230
        if (!function_exists('idn_to_ascii')) {
231
            $this->markTestSkipped('intl extension required.');
232
            return;
233
        }
234
235
        $validator = $this->validator;
236
        $validator->checkDNS = true;
237
        // enabling of IDN should not affect error message
238
        $validator->enableIDN = true;
239
        $this->assertFalse($validator->validate('non-existing-subdomain.example.com', $errorMessage));
240
        $this->assertEquals('DNS record corresponding to the input value not found.', $errorMessage);
241
242
        $data = [
243
            'google.com',
244
            'http://username:[email protected]:9090/path?a=b&c=d#anchor',
245
            'яндекс.рф',
246
            'http://username:password@яндекс.рф:9090/path?a=ф&c=d#-пример',
247
        ];
248
        foreach ($data as $value) {
249
            $this->assertTrue(
250
                $validator->validate($value),
251
                "Failed to validate \"$value\" (checkDNS = true, enableIDN = true)."
252
            );
253
        }
254
    }
255
256
    /**
257
     * @covers kdn\yii2\validators\DomainValidator::getDefaultErrorMessages
258
     * @covers kdn\yii2\validators\DomainValidator::getErrorMessage
259
     * @covers kdn\yii2\validators\DomainValidator::validateValue
260
     * @small
261
     */
262
    public function testUnderscore()
263
    {
264
        $validator = $this->validator;
265
        $validator->allowUnderscore = true;
266
267
        $data = [
268
            'ex_ample.com',
269
            'http://username:password@ex_ample.com:9090/path?a=b&c=d#anchor',
270
        ];
271
        foreach ($data as $value) {
272
            $this->assertTrue(
273
                $validator->validate($value),
274
                "Failed to validate \"$value\" (allowUnderscore = true)."
275
            );
276
        }
277
278
        $this->assertFalse($validator->validate('a_@_a', $errorMessage));
279
        if ($validator->enableIDN) {
280
            $expectedErrorMessage =
281
                'Each label of the input value can consist of only letters, numbers, hyphens and underscores.';
282
        } else {
283
            $expectedErrorMessage =
284
                'Each label of the input value can consist of only latin letters, numbers, hyphens and underscores.';
285
        }
286
        $this->assertEquals($expectedErrorMessage, $errorMessage);
287
    }
288
289
    /**
290
     * @covers kdn\yii2\validators\DomainValidator::getDefaultErrorMessages
291
     * @covers kdn\yii2\validators\DomainValidator::getErrorMessage
292
     * @covers kdn\yii2\validators\DomainValidator::validateValue
293
     * @small
294
     */
295
    public function testUnderscoreWithEnabledIdn()
296
    {
297
        if (!function_exists('idn_to_ascii')) {
298
            $this->markTestSkipped('intl extension required.');
299
            return;
300
        }
301
302
        $this->validator->enableIDN = true;
303
        $this->testUnderscore();
304
    }
305
306
    public static function urlNotAllowedProvider()
307
    {
308
        return array_merge(
309
            static::arrayAddColumn(static::validDomainProvider(), true),
310
            static::arrayAddColumn(static::validDomainInUrlProvider(), false)
311
        );
312
    }
313
314
    /**
315
     * @param string $value
316
     * @param boolean $expectedResult
317
     * @covers       kdn\yii2\validators\DomainValidator::validateValue
318
     * @uses         kdn\yii2\validators\DomainValidator::getDefaultErrorMessages
319
     * @uses         kdn\yii2\validators\DomainValidator::getErrorMessage
320
     * @dataProvider urlNotAllowedProvider
321
     * @small
322
     */
323
    public function testUrlNotAllowed($value, $expectedResult)
324
    {
325
        $validator = $this->validator;
326
        $validator->allowURL = false;
327
        $this->assertEquals($expectedResult, $validator->validate($value));
328
    }
329
330
    public static function urlNotAllowedProviderWithEnabledIdn()
331
    {
332
        return array_merge(
333
            static::urlNotAllowedProvider(),
334
            static::arrayAddColumn(static::validDomainIdnProvider(), true),
335
            static::arrayAddColumn(static::validDomainIdnInUrlProvider(), false)
336
        );
337
    }
338
339
    /**
340
     * @param string $value
341
     * @param boolean $expectedResult
342
     * @covers       kdn\yii2\validators\DomainValidator::validateValue
343
     * @uses         kdn\yii2\validators\DomainValidator::getDefaultErrorMessages
344
     * @uses         kdn\yii2\validators\DomainValidator::getErrorMessage
345
     * @dataProvider urlNotAllowedProviderWithEnabledIdn
346
     * @small
347
     */
348
    public function testUrlNotAllowedWithEnabledIdn($value, $expectedResult)
349
    {
350
        if (!function_exists('idn_to_ascii')) {
351
            $this->markTestSkipped('intl extension required.');
352
            return;
353
        }
354
355
        $this->validator->enableIDN = true;
356
        $this->testUrlNotAllowed($value, $expectedResult);
357
    }
358
359
    /**
360
     * @covers kdn\yii2\validators\DomainValidator::getDefaultErrorMessages
361
     * @covers kdn\yii2\validators\DomainValidator::getErrorMessage
362
     * @covers kdn\yii2\validators\DomainValidator::validateValue
363
     * @small
364
     */
365
    public function testLabelNumberMin()
366
    {
367
        $validator = $this->validator;
368
        $validator->labelNumberMin = 2;
369
        $this->assertFalse($validator->validate('localhost', $errorMessage));
370
        $this->assertEquals('the input value should consist of at least 2 labels separated by dot.', $errorMessage);
371
        $this->assertTrue($validator->validate('example.com'));
372
        $this->assertTrue($validator->validate('test.example.com'));
373
        $validator->labelNumberMin = 3;
374
        $this->assertFalse($validator->validate('example.com', $errorMessage));
375
        $this->assertEquals('the input value should consist of at least 3 labels separated by dots.', $errorMessage);
376
        $this->assertTrue($validator->validate('test.example.com'));
377
    }
378
379
    /**
380
     * @covers kdn\yii2\validators\DomainValidator::getDefaultErrorMessages
381
     * @covers kdn\yii2\validators\DomainValidator::getErrorMessage
382
     * @covers kdn\yii2\validators\DomainValidator::validateValue
383
     * @small
384
     */
385
    public function testLabelNumberMinWithEnabledIdn()
386
    {
387
        if (!function_exists('idn_to_ascii')) {
388
            $this->markTestSkipped('intl extension required.');
389
            return;
390
        }
391
392
        $this->validator->enableIDN = true;
393
        $this->testLabelNumberMin();
394
    }
395
396
    public static function invalidDomainProvider($testName)
397
    {
398
        if ($testName == 'testInvalidDomain') {
399
            $messageInvalidCharacter =
400
                'Each label of the input value can consist of only latin letters, numbers and hyphens.';
401
            $messageLabelStartEnd = 'Each label of the input value should start and end with latin letter or number.' .
402
                ' The rightmost label of the input value should start with latin letter.';
403
            $messageLabelTooLong = 'Each label of the input value should contain at most 63 characters.';
404
            $messageTooLong = 'the input value should contain at most 253 characters.';
405
        } else {
406
            $messageInvalidCharacter =
407
                'Each label of the input value can consist of only letters, numbers and hyphens.';
408
            $messageLabelStartEnd = 'Each label of the input value should start and end with letter or number.' .
409
                ' The rightmost label of the input value should start with letter.';
410
            $messageLabelTooLong = 'Label of the input value is too long.';
411
            $messageTooLong = 'the input value is too long.';
412
        }
413
        $messageLabelTooShort = 'Each label of the input value should contain at least 1 character.';
414
        $messageNotString = 'the input value must be a string.';
415
        $messageTooShort = 'the input value should contain at least 1 character.';
416
        return [
417
            'null' => [null, $messageNotString],
418
            'boolean' => [true, $messageNotString],
419
            'integer' => [1, $messageNotString],
420
            'float' => [1.2, $messageNotString],
421
            'array' => [[], $messageNotString],
422
            'object' => [new stdClass, $messageNotString],
423
424
            'domain name too long' => [str_repeat('a.', 126) . 'aa', $messageTooLong],
425
426
            'domain name too short' => ['', $messageTooShort],
427
428
            'first domain name label starts with hyphen' => ['-example.com', $messageLabelStartEnd],
429
            'first domain name label ends with hyphen' => ['example-.com', $messageLabelStartEnd],
430
            'last domain name label starts with hyphen' => ['example.-com', $messageLabelStartEnd],
431
            'last domain name label ends with hyphen' => ['example.com-', $messageLabelStartEnd],
432
433
            'IDN, first domain name label starts with hyphen' => ['-пример.испытание', $messageInvalidCharacter],
434
            'IDN, first domain name label ends with hyphen' => ['пример-.испытание', $messageInvalidCharacter],
435
            'IDN, last domain name label starts with hyphen' => ['пример.-испытание', $messageInvalidCharacter],
436
            'IDN, last domain name label ends with hyphen' => ['пример.испытание-', $messageInvalidCharacter],
437
438
            'IDN, HTTP, first domain name label starts with hyphen' => [
439
                'http://-пример.испытание/index.html',
440
                $messageInvalidCharacter,
441
            ],
442
            'IDN, HTTP, first domain name label ends with hyphen' => [
443
                'http://пример-.испытание/index.html',
444
                $messageInvalidCharacter,
445
            ],
446
            'IDN, HTTP, last domain name label starts with hyphen' => [
447
                'http://пример.-испытание/index.html',
448
                $messageInvalidCharacter,
449
            ],
450
            'IDN, HTTP, last domain name label ends with hyphen' => [
451
                'http://пример.испытание-/index.html',
452
                $messageInvalidCharacter,
453
            ],
454
455
            'last domain name label starts with number' => ['example.4om', $messageLabelStartEnd],
456
457
            'domain name label too long' => [str_repeat('a', 64), $messageLabelTooLong],
458
459
            'dot' => ['.', $messageLabelTooShort],
460
            'domain name starts with dot' => ['.example.com', $messageLabelTooShort],
461
            'domain name ends with two dots' => ['example.com..', $messageLabelTooShort],
462
            'domain name contains two dots in a row' => ['example..com', $messageLabelTooShort],
463
464
            'domain name contains underscore' => ['ex_ample.com', $messageInvalidCharacter],
465
            'domain name contains space' => ['ex ample.com', $messageInvalidCharacter],
466
            'domain name contains disallowed character' => ['a⒈com', $messageInvalidCharacter],
467
468
            'IDN, domain name too long' => [
469
                'ффффффффффффффффффффффффффффффффффффффффффффффффффффффффф.' .
470
                'ффффффффффффффффффффффффффффффффффффффффффффффффффффффффф.' .
471
                'ффффффффффффффффффффффффффффффффффффффффффффффффффффффффф.' .
472
                'ффффффффффффффффффффффффффффффффффффффффффффффффффффффффф.',
473
                $messageInvalidCharacter,
474
            ],
475
            'IDN, domain name label too long' => [
476
                'фффффффффффффффффффффффффффффффффффффффффффффффффффффффффs',
477
                $messageInvalidCharacter,
478
            ],
479
480
            'invalid url with valid domain name' => ['http//example.com/index.html', $messageInvalidCharacter],
481
            'IDN, invalid url with valid domain name' => ['http//пример.com/index.html', $messageInvalidCharacter],
482
        ];
483
    }
484
485
    /**
486
     * @param string $value
487
     * @param string $expectedErrorMessage
488
     * @covers       kdn\yii2\validators\DomainValidator::getDefaultErrorMessages
489
     * @covers       kdn\yii2\validators\DomainValidator::getErrorMessage
490
     * @covers       kdn\yii2\validators\DomainValidator::validateValue
491
     * @dataProvider invalidDomainProvider
492
     * @small
493
     */
494
    public function testInvalidDomain($value, $expectedErrorMessage)
495
    {
496
        $this->assertFalse($this->validator->validate($value, $errorMessage));
497
        $this->assertEquals($expectedErrorMessage, $errorMessage);
498
    }
499
500
    public static function invalidDomainWithEnabledIdnProvider()
501
    {
502
        $message = 'the input value is invalid.';
503
        $messageLabelStartEnd = 'Each label of the input value should start and end with letter or number.' .
504
            ' The rightmost label of the input value should start with letter.';
505
        $messageLabelTooLong = 'Label of the input value is too long.';
506
        $messageTooLong = 'the input value is too long.';
507
        return array_merge(
508
            static::invalidDomainProvider('testInvalidDomainWithEnabledIdn'),
509
            [
510
                /* todo it causes fatal error
511
                'IDN, domain name too long, fatal' => [
512
                    'ф.ф.ф.ф.ф.ф.ф.ф.ф.ф.ф.ф.ф.ф.ф.ф.ф.ф.ф.ф.ф.ф.ф.ф.ф.ф.ф.ф.ф.ф.ф.s.s.s.s',
513
                    $messageTooLong,
514
                ],
515
                //*/
516
                /* todo it causes fatal error
517
                'IDN, domain name too long, fatal' => [
518
                    'ффффффффффффффффффффффффффффффффффффффффффффффффффффффффф.' .
519
                    'ффффффффффффффффффффффффффффффффффффффффффффффффффффффффф.' .
520
                    'ффффффффффффффффффффффффффффффффффффффффффффффффффффффффф.' .
521
                    'фффффффффффффффффффффффффффффффффффффффффффффффффффффффф.',
522
                    $messageTooLong,
523
                ],
524
                //*/
525
526
                'IDN, first domain name label starts with hyphen' => ['-пример.испытание', $messageLabelStartEnd],
527
                'IDN, first domain name label ends with hyphen' => ['пример-.испытание', $messageLabelStartEnd],
528
                'IDN, last domain name label starts with hyphen' => ['пример.-испытание', $messageLabelStartEnd],
529
                'IDN, last domain name label ends with hyphen' => ['пример.испытание-', $messageLabelStartEnd],
530
531
                'IDN, HTTP, first domain name label starts with hyphen' => [
532
                    'http://-пример.испытание/index.html',
533
                    $messageLabelStartEnd,
534
                ],
535
                'IDN, HTTP, first domain name label ends with hyphen' => [
536
                    'http://пример-.испытание/index.html',
537
                    $messageLabelStartEnd,
538
                ],
539
                'IDN, HTTP, last domain name label starts with hyphen' => [
540
                    'http://пример.-испытание/index.html',
541
                    $messageLabelStartEnd,
542
                ],
543
                'IDN, HTTP, last domain name label ends with hyphen' => [
544
                    'http://пример.испытание-/index.html',
545
                    $messageLabelStartEnd,
546
                ],
547
548
                // todo it causes empty array in "idn_to_ascii" $idnaInfo
549
                'IDN, domain name too long' => [
550
                    'ффффффффффффффффффффффффффффффффффффффффффффффффффффффффф.' .
551
                    'ффффффффффффффффффффффффффффффффффффффффффффффффффффффффф.' .
552
                    'ффффффффффффффффффффффффффффффффффффффффффффффффффффффффф.' .
553
                    'ффффффффффффффффффффффффффффффффффффффффффффффффффффффффф.',
554
                    $messageTooLong,
555
                ],
556
                'IDN, domain name label too long' => [
557
                    'фффффффффффффффффффффффффффффффффффффффффффффффффффффффффs',
558
                    $messageLabelTooLong,
559
                ],
560
561
                'IDN, IDNA_ERROR_HYPHEN_3_4' => ['aa--a', $message],
562
                'IDN, IDNA_ERROR_LEADING_COMBINING_MARK' => [static::u('\u0308c'), $message],
563
                'IDN, IDNA_ERROR_PUNYCODE' => ['xn--0', $message],
564
                'IDN, IDNA_ERROR_INVALID_ACE_LABEL' => ['xn--a', $message],
565
                'IDN, IDNA_ERROR_BIDI' => [static::u('0A.\u05D0'), $message],
566
            ]
567
        );
568
    }
569
570
    /**
571
     * @param string $value
572
     * @param string $expectedErrorMessage
573
     * @covers       kdn\yii2\validators\DomainValidator::getDefaultErrorMessages
574
     * @covers       kdn\yii2\validators\DomainValidator::getErrorMessage
575
     * @covers       kdn\yii2\validators\DomainValidator::validateValue
576
     * @dataProvider invalidDomainWithEnabledIdnProvider
577
     * @small
578
     */
579
    public function testInvalidDomainWithEnabledIdn($value, $expectedErrorMessage)
580
    {
581
        if (!function_exists('idn_to_ascii')) {
582
            $this->markTestSkipped('intl extension required.');
583
            return;
584
        }
585
586
        $this->validator->enableIDN = true;
587
        $this->testInvalidDomain($value, $expectedErrorMessage);
588
    }
589
590
    /**
591
     * @covers kdn\yii2\validators\DomainValidator::getErrorMessage
592
     * @covers kdn\yii2\validators\DomainValidator::validateValue
593
     * @small
594
     */
595
    public function testCustomErrorMessage()
596
    {
597
        $validator = $this->validator;
598
        $messageNotString = 'test';
599
        $validator->messageNotString = $messageNotString;
600
        $this->assertFalse($validator->validate(null, $errorMessage));
601
        $this->assertEquals($messageNotString, $errorMessage);
602
    }
603
604
    /**
605
     * @covers kdn\yii2\validators\DomainValidator::getDefaultErrorMessages
606
     * @covers kdn\yii2\validators\DomainValidator::getErrorMessage
607
     * @covers kdn\yii2\validators\DomainValidator::validateValue
608
     * @small
609
     */
610
    public function testSimpleErrorMessage()
611
    {
612
        $validator = $this->validator;
613
        $validator->simpleErrorMessage = true;
614
        $this->assertFalse($validator->validate('-', $errorMessage));
615
        $this->assertEquals('the input value is invalid.', $errorMessage);
616
    }
617
618
    /**
619
     * @covers kdn\yii2\validators\DomainValidator::getDefaultErrorMessages
620
     * @covers kdn\yii2\validators\DomainValidator::getErrorMessage
621
     * @covers kdn\yii2\validators\DomainValidator::validateValue
622
     * @small
623
     */
624
    public function testValidateAttributeAndI18n()
625
    {
626
        Yii::$app->language = 'ru-RU';
627
        $model = new ModelMock(['domain' => 'example']);
628
        $validator = $this->validator;
629
630
        $validator->validateAttribute($model, 'domain');
631
        $this->assertFalse($model->hasErrors('domain'));
632
633
        $validator->labelNumberMin = 2;
634
        $validator->validateAttribute($model, 'domain');
635
        $this->assertTrue($model->hasErrors('domain'));
636
        $this->assertEquals(
637
            'Значение «Доменное имя» должно состоять минимум из 2 меток, разделённых точкой.',
638
            $model->getFirstError('domain')
639
        );
640
641
        $model->clearErrors('domain');
642
643
        $validator->labelNumberMin = 21;
644
        $validator->validateAttribute($model, 'domain');
645
        $this->assertTrue($model->hasErrors('domain'));
646
        $this->assertEquals(
647
            'Значение «Доменное имя» должно состоять минимум из 21 метки, разделённых точками.',
648
            $model->getFirstError('domain')
649
        );
650
    }
651
652
    /**
653
     * Important: this test should be executed last, because it can remove function "idn_to_ascii".
654
     * @covers kdn\yii2\validators\DomainValidator::init
655
     * @expectedException \yii\base\InvalidConfigException
656
     * @expectedExceptionMessage In order to use IDN validation intl extension must be installed and enabled.
657
     * @small
658
     */
659
    public function testInitIdnIntlException()
660
    {
661
        if (!function_exists('runkit_function_remove') || !ini_get('runkit.internal_override')) {
662
            $this->markTestSkipped('runkit extension required. runkit.internal_override should be set to "On".');
663
            return;
664
        }
665
666
        runkit_function_remove('idn_to_ascii');
667
        new DomainValidator(['enableIDN' => true]);
668
    }
669
670
    /**
671
     * Add column to array.
672
     * @param array $array
673
     * @param mixed $value
674
     * @return array
675
     */
676
    protected static function arrayAddColumn($array, $value)
677
    {
678
        return array_map(
679
            function ($data) use ($value) {
680
                $data[] = $value;
681
                return $data;
682
            },
683
            $array
684
        );
685
    }
686
687
    /**
688
     * \u escape sequence for PHP.
689
     * @param string $text
690
     * @return string
691
     */
692
    protected static function u($text)
693
    {
694
        return json_decode("\"$text\"");
695
    }
696
}
697