email_validator 1.6.0 → 2.2.1

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