email_validator 1.6.0 → 2.2.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -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