Passed
Pull Request — master (#408)
by
unknown
02:42
created

EmailTest::beforeTestOptions()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 4
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 2
eloc 2
nc 2
nop 0
dl 0
loc 4
rs 10
c 0
b 0
f 0
1
<?php
2
3
declare(strict_types=1);
4
5
namespace Yiisoft\Validator\Tests\Rule;
6
7
use RuntimeException;
8
use Yiisoft\Validator\Rule\Email;
9
use Yiisoft\Validator\Rule\EmailHandler;
10
use Yiisoft\Validator\Tests\Rule\Base\DifferentRuleInHandlerTestTrait;
11
use Yiisoft\Validator\Tests\Rule\Base\RuleTestCase;
12
use Yiisoft\Validator\Tests\Rule\Base\RuleWithOptionsTestTrait;
0 ignored issues
show
Coding Style introduced by
Header blocks must not contain blank lines
Loading history...
13
14
use Yiisoft\Validator\Tests\Rule\Base\SkipOnErrorTestTrait;
15
use Yiisoft\Validator\Tests\Rule\Base\WhenTestTrait;
0 ignored issues
show
Coding Style introduced by
Header blocks must be separated by a single blank line
Loading history...
16
17
18
use function extension_loaded;
19
20
final class EmailTest extends RuleTestCase
21
{
22
    use DifferentRuleInHandlerTestTrait;
23
    use RuleWithOptionsTestTrait;
24
    use SkipOnErrorTestTrait;
25
    use WhenTestTrait;
26
27
    public function testGetName(): void
28
    {
29
        $rule = new Email();
30
        $this->assertSame('email', $rule->getName());
31
    }
32
33
    public function dataOptions(): array
34
    {
35
        if (!extension_loaded('intl')) {
36
            return [];
37
        }
38
39
        return [
40
            [
41
                new Email(),
42
                [
43
                    'pattern' => '/^[a-zA-Z0-9!#$%&\'*+\\/=?^_`{|}~-]+(?:\.[a-zA-Z0-9!#$%&\'*+\\/=?^_`{|}~-]+)*@(?:[a-zA-Z0-9](?:[a-zA-Z0-9-]*[a-zA-Z0-9])?\.)+[a-zA-Z0-9](?:[a-zA-Z0-9-]*[a-zA-Z0-9])?$/',
44
                    'fullPattern' => '/^[^@]*<[a-zA-Z0-9!#$%&\'*+\\/=?^_`{|}~-]+(?:\.[a-zA-Z0-9!#$%&\'*+\\/=?^_`{|}~-]+)*@(?:[a-zA-Z0-9](?:[a-zA-Z0-9-]*[a-zA-Z0-9])?\.)+[a-zA-Z0-9](?:[a-zA-Z0-9-]*[a-zA-Z0-9])?>$/',
45
                    'idnEmailPattern' => '/^([a-zA-Z0-9._%+-]+)@((\[\d{1,3}\.\d{1,3}\.\d{1,3}\.)|(([\w-]+\.)+))([a-zA-Z]{2,4}|\d{1,3})(\]?)$/',
46
                    'allowName' => false,
47
                    'checkDNS' => false,
48
                    'enableIDN' => false,
49
                    'incorrectInputMessage' => [
50
                        'template' => 'The value must have a string type.',
51
                        'parameters' => [],
52
                    ],
53
                    'message' => [
54
                        'template' => 'This value is not a valid email address.',
55
                        'parameters' => [],
56
                    ],
57
                    'skipOnEmpty' => false,
58
                    'skipOnError' => false,
59
                ],
60
            ],
61
            [
62
                new Email(allowName: true),
63
                [
64
                    'pattern' => '/^[a-zA-Z0-9!#$%&\'*+\\/=?^_`{|}~-]+(?:\.[a-zA-Z0-9!#$%&\'*+\\/=?^_`{|}~-]+)*@(?:[a-zA-Z0-9](?:[a-zA-Z0-9-]*[a-zA-Z0-9])?\.)+[a-zA-Z0-9](?:[a-zA-Z0-9-]*[a-zA-Z0-9])?$/',
65
                    'fullPattern' => '/^[^@]*<[a-zA-Z0-9!#$%&\'*+\\/=?^_`{|}~-]+(?:\.[a-zA-Z0-9!#$%&\'*+\\/=?^_`{|}~-]+)*@(?:[a-zA-Z0-9](?:[a-zA-Z0-9-]*[a-zA-Z0-9])?\.)+[a-zA-Z0-9](?:[a-zA-Z0-9-]*[a-zA-Z0-9])?>$/',
66
                    'idnEmailPattern' => '/^([a-zA-Z0-9._%+-]+)@((\[\d{1,3}\.\d{1,3}\.\d{1,3}\.)|(([\w-]+\.)+))([a-zA-Z]{2,4}|\d{1,3})(\]?)$/',
67
                    'allowName' => true,
68
                    'checkDNS' => false,
69
                    'enableIDN' => false,
70
                    'incorrectInputMessage' => [
71
                        'template' => 'The value must have a string type.',
72
                        'parameters' => [],
73
                    ],
74
                    'message' => [
75
                        'template' => 'This value is not a valid email address.',
76
                        'parameters' => [],
77
                    ],
78
                    'skipOnEmpty' => false,
79
                    'skipOnError' => false,
80
                ],
81
            ],
82
            [
83
                new Email(allowName: true, checkDNS: true),
84
                [
85
                    'pattern' => '/^[a-zA-Z0-9!#$%&\'*+\\/=?^_`{|}~-]+(?:\.[a-zA-Z0-9!#$%&\'*+\\/=?^_`{|}~-]+)*@(?:[a-zA-Z0-9](?:[a-zA-Z0-9-]*[a-zA-Z0-9])?\.)+[a-zA-Z0-9](?:[a-zA-Z0-9-]*[a-zA-Z0-9])?$/',
86
                    'fullPattern' => '/^[^@]*<[a-zA-Z0-9!#$%&\'*+\\/=?^_`{|}~-]+(?:\.[a-zA-Z0-9!#$%&\'*+\\/=?^_`{|}~-]+)*@(?:[a-zA-Z0-9](?:[a-zA-Z0-9-]*[a-zA-Z0-9])?\.)+[a-zA-Z0-9](?:[a-zA-Z0-9-]*[a-zA-Z0-9])?>$/',
87
                    'idnEmailPattern' => '/^([a-zA-Z0-9._%+-]+)@((\[\d{1,3}\.\d{1,3}\.\d{1,3}\.)|(([\w-]+\.)+))([a-zA-Z]{2,4}|\d{1,3})(\]?)$/',
88
                    'allowName' => true,
89
                    'checkDNS' => true,
90
                    'enableIDN' => false,
91
                    'incorrectInputMessage' => [
92
                        'template' => 'The value must have a string type.',
93
                        'parameters' => [],
94
                    ],
95
                    'message' => [
96
                        'template' => 'This value is not a valid email address.',
97
                        'parameters' => [],
98
                    ],
99
                    'skipOnEmpty' => false,
100
                    'skipOnError' => false,
101
                ],
102
            ],
103
            [
104
                new Email(allowName: true, enableIDN: true),
105
                [
106
                    'pattern' => '/^[a-zA-Z0-9!#$%&\'*+\\/=?^_`{|}~-]+(?:\.[a-zA-Z0-9!#$%&\'*+\\/=?^_`{|}~-]+)*@(?:[a-zA-Z0-9](?:[a-zA-Z0-9-]*[a-zA-Z0-9])?\.)+[a-zA-Z0-9](?:[a-zA-Z0-9-]*[a-zA-Z0-9])?$/',
107
                    'fullPattern' => '/^[^@]*<[a-zA-Z0-9!#$%&\'*+\\/=?^_`{|}~-]+(?:\.[a-zA-Z0-9!#$%&\'*+\\/=?^_`{|}~-]+)*@(?:[a-zA-Z0-9](?:[a-zA-Z0-9-]*[a-zA-Z0-9])?\.)+[a-zA-Z0-9](?:[a-zA-Z0-9-]*[a-zA-Z0-9])?>$/',
108
                    'idnEmailPattern' => '/^([a-zA-Z0-9._%+-]+)@((\[\d{1,3}\.\d{1,3}\.\d{1,3}\.)|(([\w-]+\.)+))([a-zA-Z]{2,4}|\d{1,3})(\]?)$/',
109
                    'allowName' => true,
110
                    'checkDNS' => false,
111
                    'enableIDN' => true,
112
                    'incorrectInputMessage' => [
113
                        'template' => 'The value must have a string type.',
114
                        'parameters' => [],
115
                    ],
116
                    'message' => [
117
                        'template' => 'This value is not a valid email address.',
118
                        'parameters' => [],
119
                    ],
120
                    'skipOnEmpty' => false,
121
                    'skipOnError' => false,
122
                ],
123
            ],
124
        ];
125
    }
126
127
    public function dataValidationPassed(): array
128
    {
129
        if (!extension_loaded('intl')) {
130
            return [];
131
        }
132
133
        $rule = new Email();
134
        $ruleAllowedName = new Email(allowName: true);
135
        $ruleEnabledIDN = new Email(enableIDN: true);
136
        $ruleEnabledIDNandAllowedName = new Email(allowName: true, enableIDN: true);
137
138
        return [
139
            ['[email protected]', [$rule]],
140
            ['[email protected]', [$rule]],
141
            ['[email protected]', [$rule]],
142
            ['[email protected]', [$rule]],
143
            ['user+mailbox/[email protected]', [$rule]],
144
            ['!#$%&\'*+-/=?^_`.{|}[email protected]', [$rule]],
145
            ['[email protected]', [$rule]], // checkDNS is disabled
146
            ['[email protected]', [$rule]],
147
            [str_repeat('a', 64) . '@gmail.com', [$rule]],
148
            ['name@' . str_repeat('a', 245) . '.com', [$rule]],
149
            ['[email protected]', [$rule]],
150
151
            ['[email protected]', [$ruleAllowedName]],
152
            ['[email protected]', [$ruleAllowedName]],
153
            ['[email protected]', [$ruleAllowedName]],
154
            ['Carsten Brandt <[email protected]>', [$ruleAllowedName]],
155
            ['"Carsten Brandt" <[email protected]>', [$ruleAllowedName]],
156
            ['<[email protected]>', [$ruleAllowedName]],
157
            ['[email protected]', [$ruleAllowedName]],
158
            ['John Smith <[email protected]>', [$ruleAllowedName]],
159
            [
160
                '"This name is longer than 64 characters. Blah blah blah blah blah" <[email protected]>',
161
                [$ruleAllowedName],
162
            ],
163
164
            ['[email protected]', [$ruleEnabledIDN]],
165
            ['[email protected]', [$ruleEnabledIDN]],
166
            ['example@äüößìà.de', [$ruleEnabledIDN]],
167
            ['[email protected]', [$ruleEnabledIDN]],
168
            ['info@örtliches.de', [$ruleEnabledIDN]],
169
            ['sam@рмкреатиф.ru', [$ruleEnabledIDN]],
170
            ['[email protected]', [$ruleEnabledIDN]],
171
            ['[email protected]', [$ruleEnabledIDN]],
172
            ['üñîçøðé@üñîçøðé.com', [$ruleEnabledIDN]],
173
174
            ['info@örtliches.de', [$ruleEnabledIDNandAllowedName]],
175
            ['Information <info@örtliches.de>', [$ruleEnabledIDNandAllowedName]],
176
            ['sam@рмкреатиф.ru', [$ruleEnabledIDNandAllowedName]],
177
            ['[email protected]', [$ruleEnabledIDNandAllowedName]],
178
            ['[email protected]', [$ruleEnabledIDNandAllowedName]],
179
            ['Carsten Brandt <[email protected]>', [$ruleEnabledIDNandAllowedName]],
180
            ['"Carsten Brandt" <[email protected]>', [$ruleEnabledIDNandAllowedName]],
181
            ['üñîçøðé 日本国 <üñîçøðé@üñîçøðé.com>', [$ruleEnabledIDNandAllowedName]],
182
            ['<[email protected]>', [$ruleEnabledIDNandAllowedName]],
183
            ['[email protected]', [$ruleEnabledIDNandAllowedName]],
184
            ['John Smith <[email protected]>', [$ruleEnabledIDNandAllowedName]],
185
            [
186
                '"Такое имя достаточно длинное, но оно все равно может пройти валидацию" <[email protected]>',
187
                [$ruleEnabledIDNandAllowedName],
188
            ],
189
190
            ['[email protected]', [new Email(checkDNS: true)]],
191
192
            ['[email protected]', [new Email(allowName: true, checkDNS: true)]],
193
            ['Ivan Petrov <[email protected]>', [new Email(allowName: true, checkDNS: true)]],
194
            ['name@ñandu.cl', [new Email(checkDNS: true, enableIDN: true)]],
195
        ];
196
    }
197
198
    public function dataValidationFailed(): array
199
    {
200
        if (!extension_loaded('intl')) {
201
            return [];
202
        }
203
204
        $rule = new Email();
205
        $ruleAllowedName = new Email(allowName: true);
206
        $ruleEnabledIDN = new Email(enableIDN: true);
207
        $ruleEnabledIDNandAllowedName = new Email(allowName: true, enableIDN: true);
208
        $errors = ['' => ['This value is not a valid email address.']];
209
        $incorrectInputErrors = ['' => ['The value must have a string type.']];
210
211
        return [
212
            'incorrect input, integer' => [1, [$rule], $incorrectInputErrors],
213
            'incorrect input, array containing string element' => [
214
                ['[email protected]'],
215
                [$ruleAllowedName],
216
                $incorrectInputErrors,
217
            ],
218
            'custom incorrect input message' => [
219
                1,
220
                [new Email(incorrectInputMessage: 'Custom incorrect input message.')],
221
                ['' => ['Custom incorrect input message.']],
222
            ],
223
            'custom incorrect input message with parameters' => [
224
                1,
225
                [new Email(incorrectInputMessage: 'Attribute - {attribute}, type - {type}.')],
226
                ['' => ['Attribute - , type - int.']],
227
            ],
228
            'custom incorrect input message with parameters, attribute set' => [
229
                ['data' => 1],
230
                ['data' => [new Email(incorrectInputMessage: 'Attribute - {attribute}, type - {type}.')]],
231
                ['data' => ['Attribute - data, type - int.']],
232
            ],
233
234
            ['rmcreative.ru', [$rule], $errors],
235
            ['Carsten Brandt <[email protected]>', [$rule], $errors],
236
            ['"Carsten Brandt" <[email protected]>', [$rule], $errors],
237
            ['<[email protected]>', [$rule], $errors],
238
            ['info@örtliches.de', [$rule], $errors],
239
            ['sam@рмкреатиф.ru', [$rule], $errors],
240
            ['[email protected]', [$rule], $errors],
241
            [str_repeat('a', 65) . '@gmail.com', [$rule], $errors],
242
            ['name@' . str_repeat('a', 246) . '.com', [$rule], $errors],
243
244
            // Malicious email addresses that can be used to exploit SwiftMailer vulnerability CVE-2016-10074 while IDN
245
            // is disabled.
246
            // https://legalhackers.com/advisories/SwiftMailer-Exploit-Remote-Code-Exec-CVE-2016-10074-Vuln.html
247
248
            // This is the demo email used in the proof of concept of the exploit
249
            ['"attacker\" -oQ/tmp/ -X/var/www/cache/phpcode.php "@email.com', [$rule], $errors],
250
251
            // Trying more addresses
252
            ['"Attacker -Param2 -Param3"@test.com', [$rule], $errors],
253
            ['\'Attacker -Param2 -Param3\'@test.com', [$rule], $errors],
254
            ['"Attacker \" -Param2 -Param3"@test.com', [$rule], $errors],
255
            ["'Attacker \\' -Param2 -Param3'@test.com", [$rule], $errors],
256
            ['"attacker\" -oQ/tmp/ -X/var/www/cache/phpcode.php "@email.com', [$rule], $errors],
257
258
            // And even more variants
259
            ['"attacker\"\ -oQ/tmp/\ -X/var/www/cache/phpcode.php"@email.com', [$rule], $errors],
260
            ["\"attacker\\\"\0-oQ/tmp/\0-X/var/www/cache/phpcode.php\"@email.com", [$rule], $errors],
261
            ['"[email protected]\"-Xbeep"@email.com', [$rule], $errors],
262
            ["'attacker\\' -oQ/tmp/ -X/var/www/cache/phpcode.php'@email.com", [$rule], $errors],
263
            ["'attacker\\\\' -oQ/tmp/ -X/var/www/cache/phpcode.php'@email.com", [$rule], $errors],
264
            ["'attacker\\\\'\\ -oQ/tmp/ -X/var/www/cache/phpcode.php'@email.com", [$rule], $errors],
265
            ["'attacker\\';touch /tmp/hackme'@email.com", [$rule], $errors],
266
            ["'attacker\\\\';touch /tmp/hackme'@email.com", [$rule], $errors],
267
            ["'attacker\\';touch/tmp/hackme'@email.com", [$rule], $errors],
268
            ["'attacker\\\\';touch/tmp/hackme'@email.com", [$rule], $errors],
269
            ['"attacker\" -oQ/tmp/ -X/var/www/cache/phpcode.php "@email.com', [$rule], $errors],
270
271
            ['rmcreative.ru', [$ruleAllowedName], $errors],
272
            ['info@örtliches.de', [$ruleAllowedName], $errors],
273
            ['üñîçøðé@üñîçøðé.com', [$ruleAllowedName], $errors],
274
            ['sam@рмкреатиф.ru', [$ruleAllowedName], $errors],
275
            ['Informtation [email protected]', [$ruleAllowedName], $errors],
276
            ['John Smith <example.com>', [$ruleAllowedName], $errors],
277
            [
278
                'Short Name <localPartMoreThan64Characters-blah-blah-blah-blah-blah-blah-blah-blah@example.com>',
279
                [$ruleAllowedName],
280
                $errors,
281
            ],
282
            [
283
                'Short Name <domainNameIsMoreThan254Characters@example-blah-blah-blah-blah-blah-blah-blah-blah-blah-' .
284
                'blah-blah-blah-blah-blah-blah-blah-blah-blah-blah-blah-blah-blah-blah-blah-blah-blah-blah-blah-blah-' .
285
                'blah-blah-blah-blah-blah-blah-blah-blah-blah-blah-blah-blah-blah-blah-blah-blah-blah-blah-blah-blah' .
286
                '.com>',
287
                [$ruleAllowedName],
288
                $errors,
289
            ],
290
291
            ['rmcreative.ru', [$ruleEnabledIDN], $errors],
292
            ['Carsten Brandt <[email protected]>', [$ruleEnabledIDN], $errors],
293
            ['"Carsten Brandt" <[email protected]>', [$ruleEnabledIDN], $errors],
294
            ['<[email protected]>', [$ruleEnabledIDN], $errors],
295
296
            [
297
                'Короткое имя <тест@это-доменное-имя.после-преобразования-в-idn.будет-содержать-больше-254-символов.' .
298
                'бла-бла-бла-бла-бла-бла-бла-бла.бла-бла-бла-бла-бла-бла.бла-бла-бла-бла-бла-бла.бла-бла-бла-бла-бла-' .
299
                'бла.com>',
300
                [$ruleEnabledIDNandAllowedName],
301
                $errors,
302
            ],
303
            ['Information info@örtliches.de', [$ruleEnabledIDNandAllowedName], $errors],
304
            ['rmcreative.ru', [$ruleEnabledIDNandAllowedName], $errors],
305
            ['John Smith <example.com>', [$ruleEnabledIDNandAllowedName], $errors],
306
            [
307
                'Короткое имя <после-преобразования-в-idn-тут-будет-больше-чем-64-символа@пример.com>',
308
                [$ruleEnabledIDNandAllowedName],
309
                $errors,
310
            ],
311
312
            ['name@ñandu.cl', [new Email(checkDNS: true)], $errors],
313
            ['gmail.con', [new Email(checkDNS: true)], $errors],
314
            [
315
                '[email protected]',
316
                [new Email(checkDNS: true)],
317
                $errors,
318
            ],
319
320
            'custom message' => [
321
                '[email protected]',
322
                [new Email(checkDNS: true, message: 'Custom message.')],
323
                ['' => ['Custom message.']],
324
            ],
325
            'custom message with parameters' => [
326
                '[email protected]',
327
                [new Email(checkDNS: true, message: 'Attribute - {attribute}, value - {value}.')],
328
                ['' => ['Attribute - , value - [email protected].']],
329
            ],
330
            'custom message with parameters, attribute set' => [
331
                ['data' => '[email protected]'],
332
                ['data' => new Email(checkDNS: true, message: 'Attribute - {attribute}, value - {value}.')],
333
                ['data' => ['Attribute - data, value - [email protected].']],
334
            ],
335
        ];
336
    }
337
338
    public function testEnableIdnWithMissingIntlExtension(): void
339
    {
340
        if (extension_loaded('intl')) {
341
            $this->markTestSkipped('The intl extension must be unavailable for this test.');
342
        }
343
344
        $this->expectException(RuntimeException::class);
345
        new Email(enableIDN: true);
346
    }
347
348
    public function testSkipOnError(): void
349
    {
350
        $this->testSkipOnErrorInternal(new Email(), new Email(skipOnError: true));
351
    }
352
353
    public function testWhen(): void
354
    {
355
        $when = static fn (mixed $value): bool => $value !== null;
356
        $this->testWhenInternal(new Email(), new Email(when: $when));
357
    }
358
359
    protected function beforeTestOptions(): void
360
    {
361
        if (!extension_loaded('intl')) {
362
            $this->markTestSkipped('The intl extension must be available for this test.');
363
        }
364
    }
365
366
    protected function beforeTestValidationPassed(): void
367
    {
368
        if (!extension_loaded('intl')) {
369
            $this->markTestSkipped('The intl extension must be available for this test.');
370
        }
371
    }
372
373
    protected function beforeTestValidationFailed(): void
374
    {
375
        if (!extension_loaded('intl')) {
376
            $this->markTestSkipped('The intl extension must be available for this test.');
377
        }
378
    }
379
380
    protected function getDifferentRuleInHandlerItems(): array
381
    {
382
        return [Email::class, EmailHandler::class];
383
    }
384
}
385