email_validator 2.0.0 → 2.2.2

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.
@@ -0,0 +1,4 @@
1
+ # require this file to enable `:rfc` mode by default
2
+
3
+ require 'email_validator'
4
+ EmailValidator.default_options[:mode] = :rfc
@@ -1,9 +1,4 @@
1
- # frozen_string_literal: true
2
-
3
- ActiveSupport::Deprecation.warn(
4
- 'Strict mode has been deprecated in email_validator 2.0. You are receiving '\
5
- 'this warning because your project is requiring "email_validator/strict", '\
6
- 'most likely in your Gemfile.'
7
- )
1
+ # require this file to enable `:strict` mode by default
8
2
 
9
3
  require 'email_validator'
4
+ EmailValidator.default_options[:mode] = :strict
@@ -1,144 +1,1015 @@
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
- class TestUserAllowsNil < TestModel
9
- validates :email, :email => {:allow_nil => true}
7
+ class StrictUser < TestModel
8
+ validates :email, :email => { :mode => :strict }
10
9
  end
11
10
 
12
- class TestUserAllowsNilFalse < TestModel
13
- validates :email, :email => {:allow_nil => false}
11
+ class RfcUser < TestModel
12
+ validates :email, :email => { :mode => :rfc }
14
13
  end
15
14
 
16
- class TestUserWithMessage < TestModel
17
- validates :email_address, :email => {:message => 'is not looking very good!'}
15
+ class AllowNilDefaultUser < TestModel
16
+ validates :email, :email => { :allow_nil => true }
18
17
  end
19
18
 
20
- describe EmailValidator do
19
+ class AllowNilStrictUser < TestModel
20
+ validates :email, :email => { :allow_nil => true, :mode => :strict }
21
+ end
22
+
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
206
+
207
+ context 'when given the valid host-only email' do
208
+ [
209
+ 'f@s',
210
+ 'user@localhost',
211
+ 'someuser@somehost'
212
+ ].each do |email|
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
229
+ end
230
+
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
247
+ end
248
+
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
265
+ end
266
+ end
267
+ end
268
+
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
289
+ end
290
+
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
307
+ end
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
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
379
+
380
+ it "'#{email}' should be valid using EmailValidator.valid?" do
381
+ expect(described_class).to be_valid(email, :mode => :rfc)
382
+ end
21
383
 
22
- describe "validation" do
23
- context "given the valid emails" do
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
393
+ end
394
+
395
+ context 'when given the valid IP address email' do
24
396
  [
25
- "a+b@plus-in-local.com",
26
- "a_b@underscore-in-local.com",
27
- "user@example.com",
28
- " user@example.com ",
29
- "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ@letters-in-local.org",
30
- "01234567890@numbers-in-local.net",
31
- "a@single-character-in-local.org",
32
- "one-character-third-level@a.example.com",
33
- "single-character-in-sld@x.org",
34
- "local@dash-in-sld.com",
35
- "letters-in-sld@123.com",
36
- "one-letter-sld@x.org",
37
- "uncommon-tld@sld.museum",
38
- "uncommon-tld@sld.travel",
39
- "uncommon-tld@sld.mobi",
40
- "country-code-tld@sld.uk",
41
- "country-code-tld@sld.rw",
42
- "local@sld.newTLD",
43
- "local@sub.domains.com",
44
- "aaa@bbb.co.jp",
45
- "nigel.worthington@big.co.uk",
46
- "f@c.com",
47
- "areallylongnameaasdfasdfasdfasdf@asdfasdfasdfasdfasdf.ab.cd.ef.gh.co.ca",
48
- "ящик@яндекс.рф",
49
- "test@test.testtesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttes",
50
- "hans,peter@example.com",
51
- "hans(peter@example.com",
52
- "hans)peter@example.com",
53
- "partially.\"quoted\"@sld.com",
54
- "&'*+-./=?^_{}~@other-valid-characters-in-local.net",
55
- "mixed-1234-in-{+^}-local@sld.net",
56
- "user@domain.рф",
57
- "寿司@example.com"
397
+ 'bracketed-IP@[127.0.0.1]',
398
+ 'bracketed-and-labeled-IPv6@[IPv6:abcd:ef01:1234:5678:9abc:def0:1234:5678]'
58
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
59
408
 
60
- it "#{email.inspect} should be valid" do
61
- expect(TestUser.new(:email => email)).to be_valid
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
62
416
  end
63
417
 
64
- it "#{email.inspect} should not be invalid" do
65
- expect(TestUser.new(:email => email)).not_to be_invalid
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
66
434
  end
67
435
 
68
- it "#{email.inspect} should match the regexp" do
69
- expect(email =~ EmailValidator.regexp).to be_truthy
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
440
+
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
70
452
  end
453
+ end
454
+ end
71
455
 
72
- it "#{email.inspect} should pass the class tester" do
73
- expect(EmailValidator.valid?(email)).to be_truthy
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
499
+ end
500
+
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
74
517
  end
75
518
 
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
535
+ end
76
536
  end
537
+ end
538
+
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
77
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
592
+ end
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
629
+ end
78
630
  end
79
631
 
80
- context "given the invalid emails" do
632
+ context 'when given the invalid email with missing parts' do
81
633
  [
82
- "",
83
- "@bar.com",
84
- " @bar.com",
85
- "test@",
86
- "test@ ",
87
- " ",
88
- "missing-at-sign.net",
634
+ '',
635
+ '@bar.com',
636
+ 'test@',
637
+ '@missing-local.dev',
638
+ ' '
89
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
662
+
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
674
+ end
675
+
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
692
+ end
693
+ end
694
+ end
695
+
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
724
+ end
725
+
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
742
+ end
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
90
803
 
91
- it "#{email.inspect} should not be valid" do
92
- expect(TestUser.new(:email => email)).not_to be_valid
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
93
830
  end
94
831
 
95
- it "#{email.inspect} should be invalid" do
96
- expect(TestUser.new(:email => email)).to be_invalid
832
+ # rubocop:disable RSpec/PredicateMatcher
833
+ it 'is valid using EmailValidator.valid?' do
834
+ expect(described_class.valid?(email, opts)).to be(true)
97
835
  end
98
836
 
99
- it "#{email.inspect} should not match the regexp" do
100
- expect(email =~ EmailValidator.regexp).to be_falsy
837
+ it 'is not invalid using EmailValidator.invalid?' do
838
+ expect(described_class.invalid?(email, opts)).to be(false)
101
839
  end
840
+ # rubocop:enable RSpec/PredicateMatcher
102
841
 
103
- it "#{email.inspect} should fail the class tester" do
104
- expect(EmailValidator.valid?(email)).to be_falsy
842
+ it 'matches the regexp' do
843
+ expect(!!(email =~ described_class.regexp(opts))).to be(true)
105
844
  end
106
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
107
908
  end
108
909
  end
109
910
  end
911
+ # rubocop:enable Layout/BlockEndNewline, Layout/MultilineBlockLayout, Layout/MultilineMethodCallBraceLayout, Style/BlockDelimiters, Style/MultilineBlockChain
912
+
913
+ describe 'error messages' do
914
+ context 'when the message is not defined' do
915
+ let(:model) { DefaultUser.new :email => 'invalidemail@' }
110
916
 
111
- describe "error messages" do
112
- context "when the message is not defined" do
113
- subject { TestUser.new :email => 'invalidemail@' }
114
- before { subject.valid? }
917
+ before { model.valid? }
115
918
 
116
- it "should add the default message" do
117
- expect(subject.errors[:email]).to include "is invalid"
919
+ it 'adds the default message' do
920
+ expect(model.errors[:email]).to include 'is invalid'
118
921
  end
119
922
  end
120
923
 
121
- context "when the message is defined" do
122
- subject { TestUserWithMessage.new :email_address => 'invalidemail@' }
123
- before { subject.valid? }
924
+ context 'when the message is defined' do
925
+ let(:model) { DefaultUserWithMessage.new :email_address => 'invalidemail@' }
124
926
 
125
- it "should add the customized message" do
126
- expect(subject.errors[:email_address]).to include "is not looking very good!"
927
+ before { model.valid? }
928
+
929
+ it 'adds the customized message' do
930
+ expect(model.errors[:email_address]).to include 'is not looking very good!'
127
931
  end
128
932
  end
129
933
  end
130
934
 
131
- describe "nil email" do
132
- it "should not be valid when :allow_nil option is missing" do
133
- 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
134
938
  end
135
939
 
136
- it "should be valid when :allow_nil options is set to true" do
137
- 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
138
942
  end
139
943
 
140
- it "should not be valid when :allow_nil option is set to false" do
141
- 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
946
+ end
947
+ end
948
+
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
992
+ before { require 'email_validator/strict' }
993
+
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
1012
+ end
142
1013
  end
143
1014
  end
144
1015
  end