email_validator 1.6.0 → 2.2.1

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,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