email_validator 1.6.0 → 2.2.3

Sign up to get free protection for your applications and to get access to all the features.
@@ -1,201 +1,1051 @@
1
- # encoding: UTF-8
2
1
  require 'spec_helper'
3
2
 
4
- class TestUser < TestModel
3
+ class DefaultUser < TestModel
5
4
  validates :email, :email => true
6
5
  end
7
6
 
8
7
  class StrictUser < TestModel
9
- validates :email, :email => {:strict_mode => true}
8
+ validates :email, :email => { :mode => :strict }
10
9
  end
11
10
 
12
- class TestUserAllowsNil < TestModel
13
- validates :email, :email => {:allow_nil => true}
11
+ class RfcUser < TestModel
12
+ validates :email, :email => { :mode => :rfc }
14
13
  end
15
14
 
16
- class TestUserAllowsNilFalse < TestModel
17
- validates :email, :email => {:allow_nil => false}
15
+ class AllowNilDefaultUser < TestModel
16
+ validates :email, :email => { :allow_nil => true }
18
17
  end
19
18
 
20
- class TestUserWithMessage < TestModel
21
- validates :email_address, :email => {:message => 'is not looking very good!'}
19
+ class AllowNilStrictUser < TestModel
20
+ validates :email, :email => { :allow_nil => true, :mode => :strict }
22
21
  end
23
22
 
24
- describe EmailValidator do
23
+ class AllowNilRfcUser < TestModel
24
+ validates :email, :email => { :allow_nil => true, :mode => :rfc }
25
+ end
26
+
27
+ class DisallowNilDefaultUser < TestModel
28
+ validates :email, :email => { :allow_nil => false }
29
+ end
30
+
31
+ class DisallowNilStrictUser < TestModel
32
+ validates :email, :email => { :allow_nil => false, :mode => :strict }
33
+ end
34
+
35
+ class DisallowNilRfcUser < TestModel
36
+ validates :email, :email => { :allow_nil => false, :mode => :rfc }
37
+ end
38
+
39
+ class DomainStrictUser < TestModel
40
+ validates :email, :email => { :domain => 'example.com', :mode => :strict }
41
+ end
42
+
43
+ class DomainRfcUser < TestModel
44
+ validates :email, :email => { :domain => 'example.com', :mode => :rfc }
45
+ end
46
+
47
+ class NonFqdnStrictUser < TestModel
48
+ validates :email, :email => { :require_fqdn => false, :mode => :strict }
49
+ end
50
+
51
+ class NonFqdnRfcUser < TestModel
52
+ validates :email, :email => { :require_fqdn => false, :mode => :rfc }
53
+ end
25
54
 
26
- describe "validation" do
27
- context "given the valid emails" do
55
+ class DefaultUserWithMessage < TestModel
56
+ validates :email_address, :email => { :message => 'is not looking very good!' }
57
+ end
58
+
59
+ RSpec.describe EmailValidator do
60
+ describe 'validation' do
61
+ valid_special_chars = {
62
+ :ampersand => '&',
63
+ :asterisk => '*',
64
+ :backtick => '`',
65
+ :braceleft => '{',
66
+ :braceright => '}',
67
+ :caret => '^',
68
+ :dollar => '$',
69
+ :equals => '=',
70
+ :exclaim => '!',
71
+ :hash => '#',
72
+ :hyphen => '-',
73
+ :percent => '%',
74
+ :plus => '+',
75
+ :pipe => '|',
76
+ :question => '?',
77
+ :quotedouble => '"',
78
+ :quotesingle => "'",
79
+ :slash => '/',
80
+ :tilde => '~',
81
+ :underscore => '_'
82
+ }
83
+
84
+ invalid_special_chars = {
85
+ :backslash => '\\',
86
+ :braketleft => '[',
87
+ :braketright => ']',
88
+ :colon => ':',
89
+ :comma => ',',
90
+ :greater => '>',
91
+ :lesser => '<',
92
+ :parenleft => '(',
93
+ :parenright => ')',
94
+ :semicolon => ';'
95
+ }
96
+
97
+ valid_includable = valid_special_chars.merge({ :dot => '.' })
98
+ valid_beginable = valid_special_chars
99
+ valid_endable = valid_special_chars
100
+ invalid_includable = { :at => '@' }
101
+ whitespace = { :newline => "\n", :tab => "\t", :carriage_return => "\r", :space => ' ' }
102
+ strictly_invalid_includable = invalid_special_chars
103
+ strictly_invalid_beginable = strictly_invalid_includable.merge({ :dot => '.' })
104
+ strictly_invalid_endable = strictly_invalid_beginable
105
+ domain_invalid_beginable = invalid_special_chars.merge(valid_special_chars)
106
+ domain_invalid_endable = domain_invalid_beginable
107
+ domain_invalid_includable = domain_invalid_beginable.reject { |k, _v| k == :hyphen }
108
+
109
+ # rubocop:disable Layout/BlockEndNewline, Layout/MultilineBlockLayout, Layout/MultilineMethodCallBraceLayout, Style/BlockDelimiters, Style/MultilineBlockChain
110
+ context 'when given the valid email' do
111
+ valid_includable.map { |k, v| [
112
+ "include-#{v}-#{k}@valid-characters-in-local.dev"
113
+ ]}.concat(valid_beginable.map { |k, v| [
114
+ "#{v}start-with-#{k}@valid-characters-in-local.dev"
115
+ ]}).concat(valid_endable.map { |k, v| [
116
+ "end-with-#{k}-#{v}@valid-characters-in-local.dev"
117
+ ]}).concat([
118
+ 'a+b@plus-in-local.com',
119
+ 'a_b@underscore-in-local.com',
120
+ 'user@example.com',
121
+ 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ@letters-in-local.dev',
122
+ '01234567890@numbers-in-local.dev',
123
+ 'a@single-character-in-local.dev',
124
+ 'one-character-third-level@a.example.com',
125
+ 'single-character-in-sld@x.dev',
126
+ 'local@dash-in-sld.com',
127
+ 'numbers-in-sld@s123.com',
128
+ 'one-letter-sld@x.dev',
129
+ 'uncommon-tld@sld.museum',
130
+ 'uncommon-tld@sld.travel',
131
+ 'uncommon-tld@sld.mobi',
132
+ 'country-code-tld@sld.uk',
133
+ 'country-code-tld@sld.rw',
134
+ 'local@sld.newTLD',
135
+ 'local@sub.domains.com',
136
+ 'aaa@bbb.co.jp',
137
+ 'nigel.worthington@big.co.uk',
138
+ 'f@c.com',
139
+ 'f@s.c',
140
+ 'someuser@somehost.somedomain',
141
+ 'mixed-1234-in-{+^}-local@sld.dev',
142
+ 'partially."quoted"@sld.com',
143
+ 'areallylongnameaasdfasdfasdfasdf@asdfasdfasdfasdfasdf.ab.cd.ef.gh.co.ca',
144
+ 'john.doe@2020.example.com',
145
+ 'john.doe@2a.com',
146
+ 'john.doe@a2.com',
147
+ 'john.doe@2020.a-z.com',
148
+ 'john.doe@2020.a2z.com',
149
+ 'john.doe@2020.12345a6789.com',
150
+ 'jonh.doe@163.com'
151
+ ]).flatten.each do |email|
152
+ context 'when using defaults' do
153
+ it "'#{email}' should be valid" do
154
+ expect(DefaultUser.new(:email => email)).to be_valid
155
+ end
156
+
157
+ it "'#{email}' should be valid using EmailValidator.valid?" do
158
+ expect(described_class).to be_valid(email)
159
+ end
160
+
161
+ it "'#{email}' should not be invalid using EmailValidator.invalid?" do
162
+ expect(described_class).not_to be_invalid(email)
163
+ end
164
+
165
+ it "'#{email}' should match the regexp" do
166
+ expect(!!(email.strip =~ described_class.regexp)).to be(true)
167
+ end
168
+ end
169
+
170
+ context 'when in `:strict` mode' do
171
+ it "'#{email}' should be valid" do
172
+ expect(StrictUser.new(:email => email)).to be_valid
173
+ end
174
+
175
+ it "'#{email}' should be valid using EmailValidator.valid?" do
176
+ expect(described_class).to be_valid(email, :mode => :strict)
177
+ end
178
+
179
+ it "'#{email}' should not be invalid using EmailValidator.valid?" do
180
+ expect(described_class).not_to be_invalid(email, :mode => :strict)
181
+ end
182
+
183
+ it "'#{email}' should match the regexp" do
184
+ expect(!!(email.strip =~ described_class.regexp(:mode => :strict))).to be(true)
185
+ end
186
+ end
187
+
188
+ context 'when in `:rfc` mode' do
189
+ it "'#{email}' should be valid" do
190
+ expect(RfcUser.new(:email => email)).to be_valid
191
+ end
192
+
193
+ it "'#{email}' should be valid using EmailValidator.valid?" do
194
+ expect(described_class).to be_valid(email, :mode => :rfc)
195
+ end
196
+
197
+ it "'#{email}' should not be invalid using EmailValidator.invalid?" do
198
+ expect(described_class).not_to be_invalid(email, :mode => :rfc)
199
+ end
200
+
201
+ it "'#{email}' should match the regexp" do
202
+ expect(!!(email.strip =~ described_class.regexp(:mode => :rfc))).to be(true)
203
+ end
204
+ end
205
+ end
206
+ end
207
+
208
+ context 'when given the valid host-only email' do
28
209
  [
29
- "a+b@plus-in-local.com",
30
- "a_b@underscore-in-local.com",
31
- "user@example.com",
32
- " user@example.com ",
33
- "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ@letters-in-local.org",
34
- "01234567890@numbers-in-local.net",
35
- "a@single-character-in-local.org",
36
- "one-character-third-level@a.example.com",
37
- "single-character-in-sld@x.org",
38
- "local@dash-in-sld.com",
39
- "letters-in-sld@123.com",
40
- "one-letter-sld@x.org",
41
- "uncommon-tld@sld.museum",
42
- "uncommon-tld@sld.travel",
43
- "uncommon-tld@sld.mobi",
44
- "country-code-tld@sld.uk",
45
- "country-code-tld@sld.rw",
46
- "local@sld.newTLD",
47
- "local@sub.domains.com",
48
- "aaa@bbb.co.jp",
49
- "nigel.worthington@big.co.uk",
50
- "f@c.com",
51
- "areallylongnameaasdfasdfasdfasdf@asdfasdfasdfasdfasdf.ab.cd.ef.gh.co.ca",
52
- "ящик@яндекс.рф"
210
+ 'f@s',
211
+ 'user@localhost',
212
+ 'someuser@somehost'
53
213
  ].each do |email|
214
+ context 'when using defaults' do
215
+ it "'#{email}' should be valid" do
216
+ expect(DefaultUser.new(:email => email)).to be_valid
217
+ end
218
+
219
+ it "'#{email}' should be valid using EmailValidator.valid?" do
220
+ expect(described_class).to be_valid(email)
221
+ end
54
222
 
55
- it "#{email.inspect} should be valid" do
56
- expect(TestUser.new(:email => email)).to be_valid
223
+ it "'#{email}' should not be invalid using EmailValidator.invalid?" do
224
+ expect(described_class).not_to be_invalid(email)
225
+ end
226
+
227
+ it "'#{email}' should match the regexp" do
228
+ expect(!!(email.strip =~ described_class.regexp)).to be(true)
229
+ end
57
230
  end
58
231
 
59
- it "#{email.inspect} should be valid in strict_mode" do
60
- expect(StrictUser.new(:email => email)).to be_valid
232
+ context 'when in `:strict` mode' do
233
+ it "'#{email}' should not be valid" do
234
+ expect(StrictUser.new(:email => email)).not_to be_valid
235
+ end
236
+
237
+ it "'#{email}' should not be valid using EmailValidator.valid?" do
238
+ expect(described_class).not_to be_valid(email, :mode => :strict)
239
+ end
240
+
241
+ it "'#{email}' should be invalid using EmailValidator.invalid?" do
242
+ expect(described_class).to be_invalid(email, :mode => :strict)
243
+ end
244
+
245
+ it "'#{email}' should not match the regexp" do
246
+ expect(!!(email.strip =~ described_class.regexp(:mode => :strict))).to be(false)
247
+ end
61
248
  end
62
249
 
63
- it "#{email.inspect} should match the regexp" do
64
- expect(email =~ EmailValidator.regexp).to be_truthy
250
+ context 'when in `:rfc` mode' do
251
+ it "'#{email}' should be valid" do
252
+ expect(RfcUser.new(:email => email)).to be_valid
253
+ end
254
+
255
+ it "'#{email}' should be valid using EmailValidator.valid?" do
256
+ expect(described_class).to be_valid(email, :mode => :rfc)
257
+ end
258
+
259
+ it "'#{email}' should not be invalid using EmailValidator.invalid?" do
260
+ expect(described_class).not_to be_invalid(email, :mode => :rfc)
261
+ end
262
+
263
+ it "'#{email}' should match the regexp" do
264
+ expect(!!(email.strip =~ described_class.regexp(:mode => :rfc))).to be(true)
265
+ end
65
266
  end
267
+ end
268
+ end
269
+
270
+ context 'when given the numeric domain' do
271
+ [
272
+ 'only-numbers-in-domain-label@sub.123.custom'
273
+ ].each do |email|
274
+ context 'when using defaults' do
275
+ it "'#{email}' should be valid" do
276
+ expect(DefaultUser.new(:email => email)).to be_valid
277
+ end
66
278
 
67
- it "#{email.inspect} should match the strict regexp" do
68
- expect(email =~ EmailValidator.regexp(:strict_mode => true)).to be_truthy
279
+ it "'#{email}' should be valid using EmailValidator.valid?" do
280
+ expect(described_class).to be_valid(email)
281
+ end
282
+
283
+ it "'#{email}' should not be invalid using EmailValidator.invalid?" do
284
+ expect(described_class).not_to be_invalid(email)
285
+ end
286
+
287
+ it "'#{email}' should match the regexp" do
288
+ expect(!!(email.strip =~ described_class.regexp)).to be(true)
289
+ end
69
290
  end
70
291
 
71
- it "#{email.inspect} should pass the class tester" do
72
- expect(EmailValidator.valid?(email)).to be_truthy
292
+ context 'when in `:strict` mode' do
293
+ it "'#{email}' should be valid" do
294
+ expect(StrictUser.new(:email => email)).to be_valid
295
+ end
296
+
297
+ it "'#{email}' should be valid using EmailValidator.valid?" do
298
+ expect(described_class).to be_valid(email, :mode => :strict)
299
+ end
300
+
301
+ it "'#{email}' should be not invalid using EmailValidator.invalid?" do
302
+ expect(described_class).not_to be_invalid(email, :mode => :strict)
303
+ end
304
+
305
+ it "'#{email}' should match the regexp" do
306
+ expect(!!(email.strip =~ described_class.regexp(:mode => :strict))).to be(true)
307
+ end
73
308
  end
74
309
 
310
+ context 'when in `:rfc` mode' do
311
+ it "'#{email}' should be valid" do
312
+ expect(RfcUser.new(:email => email)).to be_valid
313
+ end
314
+
315
+ it "'#{email}' should be valid using EmailValidator.valid?" do
316
+ expect(described_class).to be_valid(email, :mode => :rfc)
317
+ end
318
+
319
+ it "'#{email}' should not be invalid using EmailValidator.invalid?" do
320
+ expect(described_class).not_to be_invalid(email, :mode => :rfc)
321
+ end
322
+
323
+ it "'#{email}' should match the regexp" do
324
+ expect(!!(email.strip =~ described_class.regexp(:mode => :rfc))).to be(true)
325
+ end
326
+ end
75
327
  end
328
+ end
329
+
330
+ context 'when given the valid mailbox-only email' do
331
+ valid_includable.map { |k, v| [
332
+ "user-#{v}-#{k}-name"
333
+ ]}.concat(valid_beginable.map { |k, v| [
334
+ "#{v}-start-with-#{k}-user"
335
+ ]}).concat(valid_endable.map { |k, v| [
336
+ "end-with-#{k}-#{v}"
337
+ ]}).concat([
338
+ 'user'
339
+ ]).flatten.each do |email|
340
+ context 'when using defaults' do
341
+ it "'#{email}' should not be valid" do
342
+ expect(DefaultUser.new(:email => email)).not_to be_valid
343
+ end
344
+
345
+ it "'#{email}' should not be valid using EmailValidator.valid?" do
346
+ expect(described_class).not_to be_valid(email)
347
+ end
348
+
349
+ it "'#{email}' should be invalid using EmailValidator.invalid?" do
350
+ expect(described_class).to be_invalid(email)
351
+ end
352
+
353
+ it "'#{email}' should not match the regexp" do
354
+ expect(!!(email.strip =~ described_class.regexp)).to be(false)
355
+ end
356
+ end
357
+
358
+ context 'when in `:strict` mode' do
359
+ it "'#{email}' should not be valid" do
360
+ expect(StrictUser.new(:email => email)).not_to be_valid
361
+ end
362
+
363
+ it "'#{email}' should not be valid using EmailValidator.valid?" do
364
+ expect(described_class).not_to be_valid(email, :mode => :strict)
365
+ end
366
+
367
+ it "'#{email}' should be invalid using EmailValidator.invalid?" do
368
+ expect(described_class).to be_invalid(email, :mode => :strict)
369
+ end
370
+
371
+ it "'#{email}' should not match the regexp" do
372
+ expect(!!(email.strip =~ described_class.regexp(:mode => :strict))).to be(false)
373
+ end
374
+ end
375
+
376
+ context 'when in `:rfc` mode' do
377
+ it "'#{email}' should be valid" do
378
+ expect(RfcUser.new(:email => email)).to be_valid
379
+ end
380
+
381
+ it "'#{email}' should be valid using EmailValidator.valid?" do
382
+ expect(described_class).to be_valid(email, :mode => :rfc)
383
+ end
76
384
 
385
+ it "'#{email}' should not be invalid using EmailValidator.invalid?" do
386
+ expect(described_class).not_to be_invalid(email, :mode => :rfc)
387
+ end
388
+
389
+ it "'#{email}' should match the regexp" do
390
+ expect(!!(email.strip =~ described_class.regexp(:mode => :rfc))).to be(true)
391
+ end
392
+ end
393
+ end
77
394
  end
78
395
 
79
- context "given the invalid emails" do
396
+ context 'when given the valid IP address email' do
80
397
  [
81
- "",
82
- "f@s",
83
- "f@s.c",
84
- "@bar.com",
85
- "test@example.com@example.com",
86
- "test@",
87
- "@missing-local.org",
88
- "a b@space-in-local.com",
89
- "! \#$%\`|@invalid-characters-in-local.org",
90
- "<>@[]\`|@even-more-invalid-characters-in-local.org",
91
- "missing-sld@.com",
92
- "invalid-characters-in-sld@! \"\#$%(),/;<>_[]\`|.org",
93
- "missing-dot-before-tld@com",
94
- "missing-tld@sld.",
95
- " ",
96
- "missing-at-sign.net",
97
- "unbracketed-IP@127.0.0.1",
98
- "invalid-ip@127.0.0.1.26",
99
- "another-invalid-ip@127.0.0.256",
100
- "IP-and-port@127.0.0.1:25",
101
- "the-local-part-is-invalid-if-it-is-longer-than-sixty-four-characters@sld.net",
102
- "user@example.com\n<script>alert('hello')</script>"
398
+ 'bracketed-IP@[127.0.0.1]',
399
+ 'bracketed-and-labeled-IPv6@[IPv6:abcd:ef01:1234:5678:9abc:def0:1234:5678]'
103
400
  ].each do |email|
401
+ context 'when using defaults' do
402
+ it "'#{email}' should be valid" do
403
+ expect(DefaultUser.new(:email => email)).to be_valid
404
+ end
405
+
406
+ it "'#{email}' should be valid using EmailValidator.valid?" do
407
+ expect(described_class).to be_valid(email)
408
+ end
104
409
 
105
- it "#{email.inspect} should not be valid" do
106
- expect(TestUser.new(:email => email)).not_to be_valid
410
+ it "'#{email}' should not be invalid using EmailValidator.invalid?" do
411
+ expect(described_class).not_to be_invalid(email)
412
+ end
413
+
414
+ it "'#{email}' should match the regexp" do
415
+ expect(!!(email.strip =~ described_class.regexp)).to be(true)
416
+ end
107
417
  end
108
418
 
109
- it "#{email.inspect} should not be valid in strict_mode" do
110
- expect(StrictUser.new(:email => email)).not_to be_valid
419
+ context 'when in `:strict` mode' do
420
+ it "'#{email}' should not be valid" do
421
+ expect(StrictUser.new(:email => email)).not_to be_valid
422
+ end
423
+
424
+ it "'#{email}' should not be valid using EmailValidator.valid?" do
425
+ expect(described_class).not_to be_valid(email, :mode => :strict)
426
+ end
427
+
428
+ it "'#{email}' should be invalid using EmailValidator.invalid?" do
429
+ expect(described_class).to be_invalid(email, :mode => :strict)
430
+ end
431
+
432
+ it "'#{email}' should not match the regexp" do
433
+ expect(!!(email.strip =~ described_class.regexp(:mode => :strict))).to be(false)
434
+ end
111
435
  end
112
436
 
113
- it "#{email.inspect} should not match the regexp" do
114
- expect(email =~ EmailValidator.regexp).to be_falsy
437
+ context 'when in `:rfc` mode' do
438
+ it "'#{email}' should be valid" do
439
+ expect(RfcUser.new(:email => email)).to be_valid
440
+ end
441
+
442
+ it "'#{email}' should be valid using EmailValidator.valid?" do
443
+ expect(described_class).to be_valid(email, :mode => :rfc)
444
+ end
445
+
446
+ it "'#{email}' should not be invalid using EmailValidator.invalid?" do
447
+ expect(described_class).not_to be_invalid(email, :mode => :rfc)
448
+ end
449
+
450
+ it "'#{email}' should match the regexp" do
451
+ expect(!!(email.strip =~ described_class.regexp(:mode => :rfc))).to be(true)
452
+ end
115
453
  end
454
+ end
455
+ end
456
+
457
+ context 'when given the invalid email' do
458
+ invalid_includable.map { |k, v| [
459
+ "include-#{v}-#{k}@invalid-characters-in-local.dev"
460
+ ]}.concat(domain_invalid_beginable.map { |k, v| [
461
+ "start-with-#{k}@#{v}invalid-characters-in-domain.dev"
462
+ ]}).concat(domain_invalid_endable.map { |k, v| [
463
+ "end-with-#{k}@invalid-characters-in-domain#{v}.dev"
464
+ ]}).concat(domain_invalid_includable.map { |k, v| [
465
+ "include-#{k}@invalid-characters-#{v}-in-domain.dev"
466
+ ]}).concat([
467
+ 'test@example.com@example.com',
468
+ 'missing-sld@.com',
469
+ 'missing-tld@sld.',
470
+ 'unbracketed-IPv6@abcd:ef01:1234:5678:9abc:def0:1234:5678',
471
+ 'unbracketed-and-labled-IPv6@IPv6:abcd:ef01:1234:5678:9abc:def0:1234:5678',
472
+ 'bracketed-and-unlabeled-IPv6@[abcd:ef01:1234:5678:9abc:def0:1234:5678]',
473
+ 'unbracketed-IPv4@127.0.0.1',
474
+ 'invalid-IPv4@127.0.0.1.26',
475
+ 'another-invalid-IPv4@127.0.0.256',
476
+ 'IPv4-and-port@127.0.0.1:25',
477
+ 'host-beginning-with-dot@.example.com',
478
+ 'domain-beginning-with-dash@-example.com',
479
+ 'domain-ending-with-dash@example-.com',
480
+ 'domain-contains-double-dash@foo--example.com',
481
+ 'the-local-part-is-invalid-if-it-is-longer-than-sixty-four-characters@sld.dev',
482
+ "domain-too-long@t#{".#{'o' * 63}" * 5}.long",
483
+ "user@example.com<script>alert('hello')</script>"
484
+ ]).flatten.each do |email|
485
+ context 'when using defaults' do
486
+ it "'#{email}' should be valid" do
487
+ expect(DefaultUser.new(:email => email)).to be_valid
488
+ end
116
489
 
117
- it "#{email.inspect} should not match the strict regexp" do
118
- expect(email =~ EmailValidator.regexp(:strict_mode => true)).to be_falsy
490
+ it "'#{email}' should be valid using EmailValidator.valid?" do
491
+ expect(described_class).to be_valid(email)
492
+ end
493
+
494
+ it "'#{email}' should not be invalid using EmailValidator.invalid?" do
495
+ expect(described_class).not_to be_invalid(email)
496
+ end
497
+
498
+ it "'#{email}' should match the regexp" do
499
+ expect(!!(email.strip =~ described_class.regexp)).to be(true)
500
+ end
501
+ end
502
+
503
+ context 'when in `:strict` mode' do
504
+ it "'#{email}' should not be valid" do
505
+ expect(StrictUser.new(:email => email)).not_to be_valid
506
+ end
507
+
508
+ it "'#{email}' should not be valid using EmailValidator.valid?" do
509
+ expect(described_class).not_to be_valid(email, :mode => :strict)
510
+ end
511
+
512
+ it "'#{email}' should be invalid using EmailValidator.invalid?" do
513
+ expect(described_class).to be_invalid(email, :mode => :strict)
514
+ end
515
+
516
+ it "'#{email}' should not match the regexp" do
517
+ expect(!!(email.strip =~ described_class.regexp(:mode => :strict))).to be(false)
518
+ end
519
+ end
520
+
521
+ context 'when in `:rfc` mode' do
522
+ it "'#{email}' should not be valid" do
523
+ expect(RfcUser.new(:email => email)).not_to be_valid
524
+ end
525
+
526
+ it "'#{email}' should not be valid using EmailValidator.valid?" do
527
+ expect(described_class).not_to be_valid(email, :mode => :rfc)
528
+ end
529
+
530
+ it "'#{email}' should be invalid using EmailValidator.invalid?" do
531
+ expect(described_class).to be_invalid(email, :mode => :rfc)
532
+ end
533
+
534
+ it "'#{email}' should not match the regexp" do
535
+ expect(!!(email.strip =~ described_class.regexp(:mode => :rfc))).to be(false)
536
+ end
537
+ end
538
+ end
539
+ end
540
+
541
+ context 'when given the invalid email with whitespace in parts' do
542
+ whitespace.map { |k, v| [
543
+ "include-#{v}-#{k}@invalid-characters-in-local.dev"
544
+ ]}.concat([
545
+ 'foo @bar.com',
546
+ "foo\t@bar.com",
547
+ "foo\n@bar.com",
548
+ "foo\r@bar.com",
549
+ 'test@ example.com',
550
+ 'user@example .com',
551
+ "user@example\t.com",
552
+ "user@example\n.com",
553
+ "user@example\r.com",
554
+ 'user@exam ple.com',
555
+ "user@exam\tple.com",
556
+ "user@exam\nple.com",
557
+ "user@exam\rple.com",
558
+ 'us er@example.com',
559
+ "us\ter@example.com",
560
+ "us\ner@example.com",
561
+ "us\rer@example.com",
562
+ "user@example.com\n<script>alert('hello')</script>",
563
+ "user@example.com\t<script>alert('hello')</script>",
564
+ "user@example.com\r<script>alert('hello')</script>",
565
+ "user@example.com <script>alert('hello')</script>",
566
+ ' leading-whitespace@example.com',
567
+ 'trailing-whitespace@example.com ',
568
+ ' leading-and-trailing-whitespace@example.com ',
569
+ ' user-with-leading-whitespace-space@example.com',
570
+ "\tuser-with-leading-whitespace-tab@example.com",
571
+ "
572
+ user-with-leading-whitespace-newline@example.com",
573
+ 'domain-with-trailing-whitespace-space@example.com ',
574
+ "domain-with-trailing-whitespace-tab@example.com\t",
575
+ "domain-with-trailing-whitespace-newline@example.com
576
+ "
577
+ ]).flatten.each do |email|
578
+ context 'when using defaults' do
579
+ it "'#{email}' should not be valid" do
580
+ expect(DefaultUser.new(:email => email)).not_to be_valid
581
+ end
582
+
583
+ it "'#{email}' should not be valid using EmailValidator.valid?" do
584
+ expect(described_class).not_to be_valid(email)
585
+ end
586
+
587
+ it "'#{email}' should be invalid using EmailValidator.invalid?" do
588
+ expect(described_class).to be_invalid(email)
589
+ end
590
+
591
+ it "'#{email}' should not match the regexp" do
592
+ expect(!!(email =~ described_class.regexp)).to be(false)
593
+ end
119
594
  end
120
595
 
121
- it "#{email.inspect} should fail the class tester" do
122
- expect(EmailValidator.valid?(email)).to be_falsy
596
+ context 'when in `:strict` mode' do
597
+ it "'#{email}' should not be valid" do
598
+ expect(StrictUser.new(:email => email)).not_to be_valid
599
+ end
600
+
601
+ it "'#{email}' should not be valid using EmailValidator.valid?" do
602
+ expect(described_class).not_to be_valid(email, :mode => :strict)
603
+ end
604
+
605
+ it "'#{email}' should be invalid using EmailValidator.invalid?" do
606
+ expect(described_class).to be_invalid(email, :mode => :strict)
607
+ end
608
+
609
+ it "'#{email}' should not match the regexp" do
610
+ expect(!!(email =~ described_class.regexp(:mode => :strict))).to be(false)
611
+ end
123
612
  end
124
613
 
614
+ context 'when in `:rfc` mode' do
615
+ it "'#{email}' should not be valid" do
616
+ expect(RfcUser.new(:email => email)).not_to be_valid
617
+ end
618
+
619
+ it "'#{email}' should not be valid using EmailValidator.valid?" do
620
+ expect(described_class).not_to be_valid(email, :mode => :rfc)
621
+ end
622
+
623
+ it "'#{email}' should be invalid using EmailValidator.invalid?" do
624
+ expect(described_class).to be_invalid(email, :mode => :rfc)
625
+ end
626
+
627
+ it "'#{email}' should not match the regexp" do
628
+ expect(!!(email =~ described_class.regexp(:mode => :rfc))).to be(false)
629
+ end
630
+ end
125
631
  end
126
632
  end
127
633
 
128
- context "given the emails that should be invalid in strict_mode but valid in normal mode" do
634
+ context 'when given the invalid email with missing parts' do
129
635
  [
130
- "hans,peter@example.com",
131
- "hans(peter@example.com",
132
- "hans)peter@example.com",
133
- "partially.\"quoted\"@sld.com",
134
- "&'*+-./=?^_{}~@other-valid-characters-in-local.net",
135
- "mixed-1234-in-{+^}-local@sld.net"
636
+ '',
637
+ '@bar.com',
638
+ 'test@',
639
+ '@missing-local.dev',
640
+ ' '
136
641
  ].each do |email|
642
+ context 'when using defaults' do
643
+ it "'#{email}' should not be valid" do
644
+ expect(DefaultUser.new(:email => email)).not_to be_valid
645
+ end
646
+
647
+ it "'#{email}' should not be valid using EmailValidator.valid?" do
648
+ expect(described_class).not_to be_valid(email)
649
+ end
650
+
651
+ it "'#{email}' should be invalid using EmailValidator.invalid?" do
652
+ expect(described_class).to be_invalid(email)
653
+ end
137
654
 
138
- it "#{email.inspect} should be valid" do
139
- expect(TestUser.new(:email => email)).to be_valid
655
+ it "'#{email}' should not match the regexp" do
656
+ expect(!!(email.strip =~ described_class.regexp)).to be(false)
657
+ end
140
658
  end
141
659
 
142
- it "#{email.inspect} should not be valid in strict_mode" do
143
- expect(StrictUser.new(:email => email)).not_to be_valid
660
+ context 'when in `:strict` mode' do
661
+ it "'#{email}' should not be valid" do
662
+ expect(StrictUser.new(:email => email)).not_to be_valid
663
+ end
664
+
665
+ it "'#{email}' should not be valid using EmailValidator.valid?" do
666
+ expect(described_class).not_to be_valid(email, :mode => :strict)
667
+ end
668
+
669
+ it "'#{email}' should be invalid using EmailValidator.invalid?" do
670
+ expect(described_class).to be_invalid(email, :mode => :strict)
671
+ end
672
+
673
+ it "'#{email}' should not match the regexp" do
674
+ expect(!!(email.strip =~ described_class.regexp(:mode => :strict))).to be(false)
675
+ end
144
676
  end
145
677
 
146
- it "#{email.inspect} should match the regexp" do
147
- expect(email =~ EmailValidator.regexp).to be_truthy
678
+ context 'when in `:rfc` mode' do
679
+ it "'#{email}' should not be valid" do
680
+ expect(RfcUser.new(:email => email)).not_to be_valid
681
+ end
682
+
683
+ it "'#{email}' should not be valid using EmailValidator.valid?" do
684
+ expect(described_class).not_to be_valid(email, :mode => :rfc)
685
+ end
686
+
687
+ it "'#{email}' should be invalid using EmailValidator.invalid?" do
688
+ expect(described_class).to be_invalid(email, :mode => :rfc)
689
+ end
690
+
691
+ it "'#{email}' should not match the regexp" do
692
+ expect(!!(email.strip =~ described_class.regexp(:mode => :rfc))).to be(false)
693
+ end
148
694
  end
695
+ end
696
+ end
149
697
 
150
- it "#{email.inspect} should not match the strict regexp" do
151
- expect(email =~ EmailValidator.regexp(:strict_mode => true)).to be_falsy
698
+ context 'when given the strictly invalid email' do
699
+ strictly_invalid_includable.map { |k, v| [
700
+ "include-#{v}-#{k}@invalid-characters-in-local.dev"
701
+ ]}.concat(strictly_invalid_beginable.map { |k, v| [
702
+ "#{v}start-with-#{k}@invalid-characters-in-local.dev"
703
+ ]}).concat(strictly_invalid_endable.map { |k, v| [
704
+ "end-with-#{k}#{v}@invalid-characters-in-local.dev"
705
+ ]}).concat([
706
+ 'user..-with-double-dots@example.com',
707
+ '.user-beginning-with-dot@example.com',
708
+ 'user-ending-with-dot.@example.com',
709
+ 'fully-numeric-tld@example.123'
710
+ ]).flatten.each do |email|
711
+ context 'when using defaults' do
712
+ it "#{email.strip} in a model should be valid" do
713
+ expect(DefaultUser.new(:email => email)).to be_valid
714
+ end
715
+
716
+ it "#{email.strip} should be valid using EmailValidator.valid?" do
717
+ expect(described_class).to be_valid(email)
718
+ end
719
+
720
+ it "#{email.strip} should not be invalid using EmailValidator.invalid?" do
721
+ expect(described_class).not_to be_invalid(email)
722
+ end
723
+
724
+ it "#{email.strip} should match the regexp" do
725
+ expect(!!(email =~ described_class.regexp)).to be(true)
726
+ end
152
727
  end
153
728
 
729
+ context 'when in `:strict` mode' do
730
+ it "#{email.strip} in a model should be valid" do
731
+ expect(StrictUser.new(:email => email)).not_to be_valid
732
+ end
733
+
734
+ it "#{email.strip} should not be valid using EmailValidator.valid?" do
735
+ expect(described_class).not_to be_valid(email, :mode => :strict)
736
+ end
737
+
738
+ it "#{email.strip} should be invalid using EmailValidator.invalid?" do
739
+ expect(described_class).to be_invalid(email, :mode => :strict)
740
+ end
741
+
742
+ it "#{email.strip} should not match the regexp" do
743
+ expect(!!(email =~ described_class.regexp(:mode => :strict))).to be(false)
744
+ end
745
+ end
746
+
747
+ context 'when in `:rfc` mode' do
748
+ it "#{email.strip} in a model should not be valid" do
749
+ expect(RfcUser.new(:email => email)).not_to be_valid
750
+ end
751
+
752
+ it "#{email.strip} should not be valid using EmailValidator.valid?" do
753
+ expect(described_class).not_to be_valid(email, :mode => :rfc)
754
+ end
755
+
756
+ it "#{email.strip} should be invalid using EmailValidator.invalid?" do
757
+ expect(described_class).to be_invalid(email, :mode => :rfc)
758
+ end
759
+
760
+ it "#{email.strip} should not match the regexp" do
761
+ expect(!!(email =~ described_class.regexp(:mode => :rfc))).to be(false)
762
+ end
763
+ end
764
+ end
765
+ end
766
+
767
+ context 'when `require_fqdn` is explicitly disabled' do
768
+ let(:opts) { { :require_fqdn => false } }
769
+
770
+ context 'when given a valid hostname-only email' do
771
+ let(:email) { 'someuser@somehost' }
772
+
773
+ context 'when using defaults' do
774
+ it 'is valid using EmailValidator.valid?' do
775
+ expect(described_class).to be_valid(email, opts)
776
+ end
777
+
778
+ it 'is not invalid using EmailValidator.invalid?' do
779
+ expect(described_class).not_to be_invalid(email, opts)
780
+ end
781
+
782
+ it 'matches the regexp' do
783
+ expect(!!(email =~ described_class.regexp(opts))).to be(true)
784
+ end
785
+ end
786
+
787
+ # Strict mode enables `require_fqdn` anyway
788
+ context 'when in `:strict` mode' do
789
+ let(:opts) { { :require_fqdn => false, :mode => :strict } }
790
+
791
+ it 'is not valid' do
792
+ expect(NonFqdnStrictUser.new(:email => email)).not_to be_valid
793
+ end
794
+
795
+ it 'is not valid using EmailValidator.valid?' do
796
+ expect(described_class).not_to be_valid(email, opts)
797
+ end
798
+
799
+ it 'is invalid using EmailValidator.invalid?' do
800
+ expect(described_class).to be_invalid(email, opts)
801
+ end
802
+
803
+ it 'matches the regexp' do
804
+ expect(!!(email =~ described_class.regexp(opts))).to be(false)
805
+ end
806
+ end
807
+
808
+ context 'when in `:rfc` mode' do
809
+ let(:opts) { { :require_fqdn => false, :mode => :rfc } }
810
+
811
+ it 'is valid' do
812
+ expect(NonFqdnRfcUser.new(:email => email)).to be_valid
813
+ end
814
+
815
+ it 'is valid using EmailValidator.valid?' do
816
+ expect(described_class).to be_valid(email, opts)
817
+ end
818
+
819
+ it 'is not invalid using EmailValidator.invalid?' do
820
+ expect(described_class).not_to be_invalid(email, opts)
821
+ end
822
+
823
+ it 'matches the regexp' do
824
+ expect(!!(email =~ described_class.regexp(opts))).to be(true)
825
+ end
826
+ end
827
+ end
828
+
829
+ context 'when given a valid email using an FQDN' do
830
+ let(:email) { 'someuser@somehost.somedomain' }
831
+
832
+ it 'is valid' do
833
+ expect(NonFqdnStrictUser.new(:email => email)).to be_valid
834
+ end
835
+
836
+ # rubocop:disable RSpec/PredicateMatcher
837
+ it 'is valid using EmailValidator.valid?' do
838
+ expect(described_class.valid?(email, opts)).to be(true)
839
+ end
840
+
841
+ it 'is not invalid using EmailValidator.invalid?' do
842
+ expect(described_class.invalid?(email, opts)).to be(false)
843
+ end
844
+ # rubocop:enable RSpec/PredicateMatcher
845
+
846
+ it 'matches the regexp' do
847
+ expect(!!(email =~ described_class.regexp(opts))).to be(true)
848
+ end
849
+
850
+ context 'when in `:rfc` mode' do
851
+ let(:opts) { { :require_fqdn => false, :mode => :rfc } }
852
+
853
+ # rubocop:disable RSpec/PredicateMatcher
854
+ it 'is valid using EmailValidator.valid?' do
855
+ expect(described_class.valid?(email, opts)).to be(true)
856
+ end
857
+
858
+ it 'is not invalid using EmailValidator.invalid?' do
859
+ expect(described_class.invalid?(email, opts)).to be(false)
860
+ end
861
+ # rubocop:enable RSpec/PredicateMatcher
862
+
863
+ it 'is valid' do
864
+ expect(NonFqdnRfcUser.new(:email => email)).to be_valid
865
+ end
866
+
867
+ it 'matches the regexp' do
868
+ expect(!!(email =~ described_class.regexp(opts))).to be(true)
869
+ end
870
+ end
871
+
872
+ context 'when requiring a non-matching domain' do
873
+ let(:domain) { 'example.com' }
874
+ let(:opts) { { :domain => domain } }
875
+
876
+ it 'is not valid' do
877
+ expect(DomainStrictUser.new(:email => email)).not_to be_valid
878
+ end
879
+
880
+ it 'is not valid using EmailValidator.valid?' do
881
+ expect(described_class).not_to be_valid(email, opts)
882
+ end
883
+
884
+ it 'is invalid using EmailValidator.invalid?' do
885
+ expect(described_class).to be_invalid(email, opts)
886
+ end
887
+
888
+ it 'does not matches the regexp' do
889
+ expect(!!(email =~ described_class.regexp(opts))).to be(false)
890
+ end
891
+
892
+ context 'when in `:rfc` mode' do
893
+ let(:opts) { { :domain => domain, :require_fqdn => false, :mode => :rfc } }
894
+
895
+ it 'is not valid using EmailValidator.valid?' do
896
+ expect(described_class).not_to be_valid(email, opts)
897
+ end
898
+
899
+ it 'is invalid using EmailValidator.invalid?' do
900
+ expect(described_class).to be_invalid(email, opts)
901
+ end
902
+
903
+ it 'is not valid' do
904
+ expect(DomainRfcUser.new(:email => email)).not_to be_valid
905
+ end
906
+
907
+ it 'does not match the regexp' do
908
+ expect(!!(email =~ described_class.regexp(opts))).to be(false)
909
+ end
910
+ end
911
+ end
154
912
  end
155
913
  end
156
914
  end
915
+ # rubocop:enable Layout/BlockEndNewline, Layout/MultilineBlockLayout, Layout/MultilineMethodCallBraceLayout, Style/BlockDelimiters, Style/MultilineBlockChain
916
+
917
+ describe 'error messages' do
918
+ context 'when the message is not defined' do
919
+ let(:model) { DefaultUser.new :email => 'invalidemail@' }
157
920
 
158
- describe "error messages" do
159
- context "when the message is not defined" do
160
- subject { TestUser.new :email => 'invalidemail@' }
161
- before { subject.valid? }
921
+ before { model.valid? }
162
922
 
163
- it "should add the default message" do
164
- expect(subject.errors[:email]).to include "is invalid"
923
+ it 'adds the default message' do
924
+ expect(model.errors[:email]).to include 'is invalid'
165
925
  end
166
926
  end
167
927
 
168
- context "when the message is defined" do
169
- subject { TestUserWithMessage.new :email_address => 'invalidemail@' }
170
- before { subject.valid? }
928
+ context 'when the message is defined' do
929
+ let(:model) { DefaultUserWithMessage.new :email_address => 'invalidemail@' }
171
930
 
172
- it "should add the customized message" do
173
- expect(subject.errors[:email_address]).to include "is not looking very good!"
931
+ before { model.valid? }
932
+
933
+ it 'adds the customized message' do
934
+ expect(model.errors[:email_address]).to include 'is not looking very good!'
174
935
  end
175
936
  end
176
937
  end
177
938
 
178
- describe "nil email" do
179
- it "should not be valid when :allow_nil option is missing" do
180
- expect(TestUser.new(:email => nil)).not_to be_valid
939
+ describe 'nil email' do
940
+ it 'is not valid when :allow_nil option is missing' do
941
+ expect(DefaultUser.new(:email => nil)).not_to be_valid
942
+ end
943
+
944
+ it 'is valid when :allow_nil options is set to true' do
945
+ expect(AllowNilDefaultUser.new(:email => nil)).to be_valid
181
946
  end
182
947
 
183
- it "should be valid when :allow_nil options is set to true" do
184
- expect(TestUserAllowsNil.new(:email => nil)).to be_valid
948
+ it 'is not valid when :allow_nil option is set to false' do
949
+ expect(DisallowNilDefaultUser.new(:email => nil)).not_to be_valid
185
950
  end
951
+ end
952
+
953
+ describe 'limited to a domain' do
954
+ context 'when in `:strict` mode' do
955
+ it 'is not valid with mismatched domain' do
956
+ expect(DomainStrictUser.new(:email => 'user@not-matching.io')).not_to be_valid
957
+ end
958
+
959
+ it 'is valid with matching domain' do
960
+ expect(DomainStrictUser.new(:email => 'user@example.com')).to be_valid
961
+ end
962
+
963
+ it 'does not interpret the dot as any character' do
964
+ expect(DomainStrictUser.new(:email => 'user@example-com')).not_to be_valid
965
+ end
966
+ end
967
+
968
+ context 'when in `:rfc` mode' do
969
+ it 'does not interpret the dot as any character' do
970
+ expect(DomainRfcUser.new(:email => 'user@example-com')).not_to be_valid
971
+ end
186
972
 
187
- it "should not be valid when :allow_nil option is set to false" do
188
- expect(TestUserAllowsNilFalse.new(:email => nil)).not_to be_valid
973
+ it 'is valid with matching domain' do
974
+ expect(DomainRfcUser.new(:email => 'user@example.com')).to be_valid
975
+ end
976
+
977
+ it 'is not valid with mismatched domain' do
978
+ expect(DomainRfcUser.new(:email => 'user@not-matching.io')).not_to be_valid
979
+ end
189
980
  end
190
981
  end
191
982
 
192
- describe "default_options" do
193
- context "when 'email_validator/strict' has been required" do
983
+ describe 'default_options' do
984
+ let(:valid_email) { 'valid-email@localhost.localdomain' }
985
+ let(:invalid_email) { 'invalid email@localhost.localdomain' }
986
+
987
+ it 'validates valid using `:loose` mode' do
988
+ expect(DefaultUser.new(:email => valid_email)).to be_valid
989
+ end
990
+
991
+ it 'invalidates invalid using `:loose` mode' do
992
+ expect(DefaultUser.new(:email => invalid_email)).to be_invalid
993
+ end
994
+
995
+ context 'when `email_validator/strict` has been required' do
194
996
  before { require 'email_validator/strict' }
195
997
 
196
- it "should validate using strict mode" do
197
- expect(TestUser.new(:email => "&'*+-./=?^_{}~@other-valid-characters-in-local.net")).not_to be_valid
998
+ it 'validates valid using `:strict` mode' do
999
+ expect(DefaultUser.new(:email => valid_email)).to be_valid
1000
+ end
1001
+
1002
+ it 'invalidates invalid using `:strict` mode' do
1003
+ expect(DefaultUser.new(:email => invalid_email)).to be_invalid
1004
+ end
1005
+ end
1006
+
1007
+ context 'when `email_validator/rfc` has been required' do
1008
+ before { require 'email_validator/rfc' }
1009
+
1010
+ it 'validates valid using `:rfc` mode' do
1011
+ expect(DefaultUser.new(:email => valid_email)).to be_valid
198
1012
  end
1013
+
1014
+ it 'invalidates invalid using `:rfc` mode' do
1015
+ expect(DefaultUser.new(:email => invalid_email)).to be_invalid
1016
+ end
1017
+ end
1018
+ end
1019
+
1020
+ context 'with regexp' do
1021
+ it 'returns a regexp when asked' do
1022
+ expect(described_class.regexp).to be_a(Regexp)
1023
+ end
1024
+
1025
+ it 'returns a strict regexp when asked' do
1026
+ expect(described_class.regexp(:mode => :strict)).to be_a(Regexp)
1027
+ end
1028
+
1029
+ it 'returns a RFC regexp when asked' do
1030
+ expect(described_class.regexp(:mode => :rfc)).to be_a(Regexp)
1031
+ end
1032
+
1033
+ it 'has different regexp for strict and loose' do
1034
+ expect(described_class.regexp(:mode => :strict)).not_to eq(described_class.regexp(:mode => :loose))
1035
+ end
1036
+
1037
+ it 'has different regexp for RFC and loose' do
1038
+ expect(described_class.regexp(:mode => :rfc)).not_to eq(described_class.regexp(:mode => :loose))
1039
+ end
1040
+
1041
+ it 'has different regexp for RFC and strict' do
1042
+ expect(described_class.regexp(:mode => :rfc)).not_to eq(described_class.regexp(:mode => :strict))
1043
+ end
1044
+ end
1045
+
1046
+ context 'with invalid `:mode`' do
1047
+ it 'raises an error' do
1048
+ expect { described_class.regexp(:mode => :invalid) }.to raise_error(EmailValidator::Error)
199
1049
  end
200
1050
  end
201
1051
  end