email_veracity 0.4.0

Sign up to get free protection for your applications and to get access to all the features.
data/.gitignore ADDED
@@ -0,0 +1,5 @@
1
+ *.tmproj
2
+ .DS_Store
3
+ /coverage
4
+ /pkg
5
+ /rdoc
data/LICENSE ADDED
@@ -0,0 +1,19 @@
1
+ Copyright (c) 2008 Carsten Nielsen
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining a copy
4
+ of this software and associated documentation files (the "Software"), to deal
5
+ in the Software without restriction, including without limitation the rights
6
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
7
+ copies of the Software, and to permit persons to whom the Software is
8
+ furnished to do so, subject to the following conditions:
9
+
10
+ The above copyright notice and this permission notice shall be included in
11
+ all copies or substantial portions of the Software.
12
+
13
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
18
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
19
+ THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,75 @@
1
+ Email Veracity
2
+ ==============
3
+
4
+ A straight-forward Ruby library for checking the real-world validity of email
5
+ addresses.
6
+
7
+
8
+ ### It Can
9
+
10
+ * Validate email addresses for proper form against a pattern.
11
+ * Accept and reject addresses based whitelists and blacklists of domains.
12
+ * Check an address' domain for MX and/or A records.
13
+ * Be configured for a variety of use-cases, to be as discerning or as
14
+ indiscriminate as you would like.
15
+
16
+
17
+ ### It Can Not
18
+
19
+ * Validate all possible permutations of addresses to the RFC 2822
20
+ specification.
21
+
22
+
23
+ A Note About The ActiveRecord Plugin
24
+ ------------------------------------
25
+
26
+ **It's dead!** Why? Determining the validity of an email address based on a lookup of its domain is a good idea, but basing it off of one single test done inline with a request is not. A name server might be down, shit happens, and you might be snubbing a totally legitimate person from using your product — not good.
27
+
28
+ I feel a better solution is to check the pattern of the email address and perhaps check it against the blacklist on creation. The other tests should be done in the background over the period of many days and be added to a log. A report can then be performed and you can statistically determine the addresses that are most likely false and take appropriate action from that point.
29
+
30
+
31
+ Using The Gem
32
+ -------------
33
+
34
+ In your project, you must require `email_veracity` after that you can try it
35
+ out, consider the following examples:
36
+
37
+
38
+ require 'email_veracity'
39
+
40
+ address = EmailVeracity::Address.new('heycarsten@gmail.com')
41
+
42
+ address.valid?
43
+ # => true
44
+
45
+ address.domain.to_s
46
+ # => 'gmail.com'
47
+
48
+ address.domain.address_servers.map { |s| s.to_s }
49
+ # => ["64.233.171.83", "64.233.161.83", "209.85.171.83"]
50
+
51
+ address = EmailVeracity::Address.new('fakey@crazy-z3d9df-domain.com')
52
+
53
+ address.valid?
54
+ # => false
55
+
56
+ address.errors
57
+ # => [:no_address_servers]
58
+
59
+
60
+ As you can see, playing with the core library is pretty fun. The basic building
61
+ blocks are:
62
+
63
+ #### Address
64
+
65
+ Responsible for parsing full email addresses and checking for pattern-based
66
+ validity.
67
+
68
+ #### Domain
69
+
70
+ Contains methods to query the domain for information.
71
+
72
+ #### Resolver
73
+
74
+ Abstracts Resolv::DNS into a super-simple single public method, this is where
75
+ the timeout error is raised.
data/Rakefile ADDED
@@ -0,0 +1,53 @@
1
+ require 'rubygems'
2
+ require 'rake'
3
+
4
+ begin
5
+ require 'jeweler'
6
+ Jeweler::Tasks.new do |gem|
7
+ gem.name = 'email_veracity'
8
+ gem.summary = 'A simple library for checking the real-world validity of email addresses.'
9
+ gem.description = 'Email Veracity abstracts an email address into a series of objects which makes it easy to see if an address is invalid, and if so, why.'
10
+ gem.email = 'heycarsten@gmail.com'
11
+ gem.homepage = 'http://github.com/heycarsten/email-veracity'
12
+ gem.authors = 'Carsten Nielsen'
13
+ gem.add_development_dependency 'mocha', '>= 0.9.8'
14
+ gem.add_development_dependency 'shoulda', '>= 2.10.2'
15
+ end
16
+ Jeweler::GemcutterTasks.new
17
+ rescue LoadError
18
+ puts "Jeweler (or a dependency) not available. Install it with: gem install jeweler"
19
+ end
20
+
21
+ require 'rake/testtask'
22
+ Rake::TestTask.new(:test) do |test|
23
+ test.libs << 'lib' << 'test'
24
+ test.pattern = 'test/**/test_*.rb'
25
+ test.verbose = true
26
+ end
27
+
28
+ begin
29
+ require 'rcov/rcovtask'
30
+ Rcov::RcovTask.new do |test|
31
+ test.libs << 'test'
32
+ test.pattern = 'test/**/test_*.rb'
33
+ test.verbose = true
34
+ end
35
+ rescue LoadError
36
+ task :rcov do
37
+ abort "RCov is not available. In order to run rcov, you must: sudo gem install spicycode-rcov"
38
+ end
39
+ end
40
+
41
+ task :test => :check_dependencies
42
+
43
+ task :default => :test
44
+
45
+ require 'rake/rdoctask'
46
+ Rake::RDocTask.new do |rdoc|
47
+ version = File.exist?('VERSION') ? File.read('VERSION') : ""
48
+
49
+ rdoc.rdoc_dir = 'rdoc'
50
+ rdoc.title = "email-veracity #{version}"
51
+ rdoc.rdoc_files.include('README*')
52
+ rdoc.rdoc_files.include('lib/**/*.rb')
53
+ end
data/VERSION ADDED
@@ -0,0 +1 @@
1
+ 0.4.0
@@ -0,0 +1,75 @@
1
+ # Generated by jeweler
2
+ # DO NOT EDIT THIS FILE DIRECTLY
3
+ # Instead, edit Jeweler::Tasks in Rakefile, and run the gemspec command
4
+ # -*- encoding: utf-8 -*-
5
+
6
+ Gem::Specification.new do |s|
7
+ s.name = %q{email_veracity}
8
+ s.version = "0.4.0"
9
+
10
+ s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
11
+ s.authors = ["Carsten Nielsen"]
12
+ s.date = %q{2009-12-12}
13
+ s.description = %q{Email Veracity abstracts an email address into a series of objects which makes it easy to see if an address is invalid, and if so, why.}
14
+ s.email = %q{heycarsten@gmail.com}
15
+ s.extra_rdoc_files = [
16
+ "LICENSE",
17
+ "README.md"
18
+ ]
19
+ s.files = [
20
+ ".gitignore",
21
+ "LICENSE",
22
+ "README.md",
23
+ "Rakefile",
24
+ "VERSION",
25
+ "email_veracity.gemspec",
26
+ "lib/email_veracity.rb",
27
+ "lib/email_veracity/address.rb",
28
+ "lib/email_veracity/config.rb",
29
+ "lib/email_veracity/domain.rb",
30
+ "lib/email_veracity/resolver.rb",
31
+ "lib/email_veracity/server.rb",
32
+ "lib/email_veracity/utils.rb",
33
+ "lib/email_veracity/validatability.rb",
34
+ "test/helper.rb",
35
+ "test/test_address.rb",
36
+ "test/test_config.rb",
37
+ "test/test_domain.rb",
38
+ "test/test_resolver.rb",
39
+ "test/test_server.rb",
40
+ "test/test_utils.rb",
41
+ "test/test_validatability.rb"
42
+ ]
43
+ s.homepage = %q{http://github.com/heycarsten/email-veracity}
44
+ s.rdoc_options = ["--charset=UTF-8"]
45
+ s.require_paths = ["lib"]
46
+ s.rubygems_version = %q{1.3.5}
47
+ s.summary = %q{A simple library for checking the real-world validity of email addresses.}
48
+ s.test_files = [
49
+ "test/helper.rb",
50
+ "test/test_address.rb",
51
+ "test/test_config.rb",
52
+ "test/test_domain.rb",
53
+ "test/test_resolver.rb",
54
+ "test/test_server.rb",
55
+ "test/test_utils.rb",
56
+ "test/test_validatability.rb"
57
+ ]
58
+
59
+ if s.respond_to? :specification_version then
60
+ current_version = Gem::Specification::CURRENT_SPECIFICATION_VERSION
61
+ s.specification_version = 3
62
+
63
+ if Gem::Version.new(Gem::RubyGemsVersion) >= Gem::Version.new('1.2.0') then
64
+ s.add_development_dependency(%q<mocha>, [">= 0.9.8"])
65
+ s.add_development_dependency(%q<shoulda>, [">= 2.10.2"])
66
+ else
67
+ s.add_dependency(%q<mocha>, [">= 0.9.8"])
68
+ s.add_dependency(%q<shoulda>, [">= 2.10.2"])
69
+ end
70
+ else
71
+ s.add_dependency(%q<mocha>, [">= 0.9.8"])
72
+ s.add_dependency(%q<shoulda>, [">= 2.10.2"])
73
+ end
74
+ end
75
+
@@ -0,0 +1,37 @@
1
+ module EmailVeracity
2
+ class Address
3
+
4
+ include Validatability
5
+
6
+ attr_reader :domain
7
+
8
+ def initialize(email = '')
9
+ self.email_address = email
10
+ end
11
+
12
+ def to_s
13
+ email_address
14
+ end
15
+
16
+ def email_address
17
+ @email_address.to_s.strip
18
+ end
19
+
20
+ def email_address=(new_email_address)
21
+ @email_address = new_email_address.to_s
22
+ @domain = Domain.new(@email_address.split('@')[1] || '')
23
+ end
24
+
25
+ protected
26
+
27
+ def validate!
28
+ add_error(:malformed) if !pattern_valid?
29
+ add_errors(domain.errors)
30
+ end
31
+
32
+ def pattern_valid?
33
+ @email_address =~ Config[:valid_pattern]
34
+ end
35
+
36
+ end
37
+ end
@@ -0,0 +1,71 @@
1
+ module EmailVeracity
2
+ module Config
3
+
4
+ DEFAULT_OPTIONS = {
5
+ :whitelist => %w[ aol.com gmail.com hotmail.com mac.com msn.com
6
+ rogers.com sympatico.ca yahoo.com telus.com sprint.com sprint.ca ],
7
+ :blacklist => %w[ dodgeit.com mintemail.com mintemail.uni.cc
8
+ 1mintemail.mooo.com spammotel.com trashmail.net ],
9
+ :valid_pattern => %r{\A
10
+ (
11
+ (
12
+ [a-z0-1]{1}
13
+ |
14
+ [\w]+[\w\+_\-\.]+
15
+ [\+_\-\.]{0}
16
+ )
17
+ @
18
+ (
19
+ (?:
20
+ [-a-z0-9]+\.
21
+ )+
22
+ [a-z]{2,}
23
+ )
24
+ ){1}
25
+ \Z}xi,
26
+ :must_include => [], # :a, :mx
27
+ :timeout => 2,
28
+ :enforce_blacklist => false,
29
+ :enforce_whitelist => true }
30
+ @options = DEFAULT_OPTIONS.clone
31
+
32
+ def [](key)
33
+ @options[key.to_sym]
34
+ end
35
+
36
+ def []=(key, value)
37
+ @options[key.to_sym] = value
38
+ end
39
+
40
+ def options
41
+ @options
42
+ end
43
+
44
+ def options=(options)
45
+ unless options.is_a?(Hash)
46
+ raise ArgumentError, "options must be a Hash not #{options.class}"
47
+ end
48
+ @options = options
49
+ end
50
+
51
+ def update(options)
52
+ unless options.is_a?(Hash)
53
+ raise ArgumentError, "options must be a Hash not #{options.class}"
54
+ end
55
+ @options.update(options)
56
+ end
57
+
58
+ def enforced_record?(record)
59
+ return unless @options[:must_include].is_a?(Array)
60
+ @options[:must_include].any? { |i| i.to_s == record.to_s }
61
+ end
62
+
63
+ def revert!
64
+ @options = DEFAULT_OPTIONS.clone
65
+ end
66
+
67
+ module_function :[], :[]=, :options, :options=, :update, :enforced_record?,
68
+ :revert!
69
+
70
+ end
71
+ end
@@ -0,0 +1,69 @@
1
+ module EmailVeracity
2
+ class Domain
3
+
4
+ include Validatability
5
+
6
+ def self.whitelisted?(name)
7
+ Config[:whitelist].include?(name.downcase.strip)
8
+ end
9
+
10
+ def self.blacklisted?(name)
11
+ Config[:blacklist].include?(name.downcase.strip)
12
+ end
13
+
14
+ def initialize(name = '')
15
+ @name = name
16
+ end
17
+
18
+ def to_s
19
+ name
20
+ end
21
+
22
+ def name
23
+ @name.to_s.downcase.strip
24
+ end
25
+
26
+ def whitelisted?
27
+ Domain.whitelisted?(name)
28
+ end
29
+
30
+ def blacklisted?
31
+ Domain.blacklisted?(name)
32
+ end
33
+
34
+ def address_servers
35
+ @address_servers ||= servers_in(:a)
36
+ end
37
+
38
+ def exchange_servers
39
+ @exchange_servers ||= servers_in(:mx)
40
+ end
41
+
42
+ def servers
43
+ address_servers + exchange_servers
44
+ end
45
+
46
+ protected
47
+
48
+ def validate!
49
+ return if whitelisted?
50
+ add_error(:blacklisted) if blacklisted? &&
51
+ Config[:enforce_blacklist]
52
+ add_error(:no_records) if servers.empty? &&
53
+ !Config.enforced_record?(:a) &&
54
+ !Config.enforced_record?(:mx)
55
+ add_error(:no_address_servers) if address_servers.empty? &&
56
+ Config.enforced_record?(:a)
57
+ add_error(:no_exchange_servers) if exchange_servers.empty? &&
58
+ Config.enforced_record?(:mx)
59
+ end
60
+
61
+ def servers_in(record)
62
+ return [] if Utils.blank?(name)
63
+ Resolver.get_servers_for(name, record)
64
+ rescue DomainResourcesTimeoutError
65
+ add_error :timed_out
66
+ end
67
+
68
+ end
69
+ end
@@ -0,0 +1,45 @@
1
+ module EmailVeracity
2
+ module Resolver
3
+
4
+ RECORD_NAMES_TO_RESOLVE_MAP = {
5
+ :a => {
6
+ :method => 'address',
7
+ :type => AddressServer,
8
+ :constant => Resolv::DNS::Resource::IN::A },
9
+ :mx => {
10
+ :method => 'exchange',
11
+ :type => ExchangeServer,
12
+ :constant => Resolv::DNS::Resource::IN::MX } }
13
+
14
+ def get_servers_for(domain_name, record = :a)
15
+ Timeout::timeout(Config[:timeout]) do
16
+ get_resources_for(domain_name, record).map do |server_name|
17
+ type = RECORD_NAMES_TO_RESOLVE_MAP[record.to_sym][:type]
18
+ type.new(server_name)
19
+ end
20
+ end
21
+ rescue Timeout::Error
22
+ raise DomainResourcesTimeoutError,
23
+ "Timed out while try to resolve #{domain_name}"
24
+ end
25
+
26
+ protected
27
+
28
+ def get_resources_for(domain_name, record = :a)
29
+ Resolv::DNS.open do |server|
30
+ record_map = RECORD_NAMES_TO_RESOLVE_MAP[record]
31
+ resources = server.getresources(domain_name, record_map[:constant])
32
+ resources_to_servers(resources, record_map[:method])
33
+ end
34
+ end
35
+
36
+ def resources_to_servers(resources, resolve_method)
37
+ resources.inject([]) do |array, resource|
38
+ array << resource.method(resolve_method).call.to_s.strip
39
+ end.reject { |i| Utils.blank?(i) }
40
+ end
41
+
42
+ module_function :get_servers_for, :get_resources_for, :resources_to_servers
43
+
44
+ end
45
+ end
@@ -0,0 +1,18 @@
1
+ module EmailVeracity
2
+
3
+ class Server
4
+
5
+ attr_reader :name
6
+ alias_method :to_s, :name
7
+
8
+ def initialize(name = '')
9
+ @name = name
10
+ end
11
+
12
+ end
13
+
14
+
15
+ class AddressServer < Server; end
16
+ class ExchangeServer < Server; end
17
+
18
+ end
@@ -0,0 +1,11 @@
1
+ module EmailVeracity
2
+ module Utils
3
+
4
+ def blank?(obj)
5
+ obj.respond_to?(:empty?) ? obj.empty? : !obj
6
+ end
7
+
8
+ module_function :blank?
9
+
10
+ end
11
+ end
@@ -0,0 +1,31 @@
1
+ module EmailVeracity
2
+ module Validatability
3
+
4
+ def valid?
5
+ self.errors.empty?
6
+ end
7
+
8
+ def errors
9
+ self.clear_errors!
10
+ self.validate!
11
+ @errors
12
+ end
13
+
14
+ protected
15
+
16
+ def validate!
17
+ # Adds errors to the object.
18
+ end
19
+
20
+ def clear_errors!
21
+ @errors = []
22
+ end
23
+
24
+ def add_error(*new_errors)
25
+ @errors ||= []
26
+ @errors.concat(new_errors.flatten)
27
+ end
28
+ alias_method :add_errors, :add_error
29
+
30
+ end
31
+ end
@@ -0,0 +1,19 @@
1
+ require 'resolv'
2
+ require 'timeout'
3
+
4
+ require 'email_veracity/utils'
5
+ require 'email_veracity/validatability'
6
+ require 'email_veracity/config'
7
+ require 'email_veracity/server'
8
+ require 'email_veracity/resolver'
9
+ require 'email_veracity/domain'
10
+ require 'email_veracity/address'
11
+
12
+
13
+ module EmailVeracity
14
+
15
+ class Error < StandardError; end
16
+ class MalformedEmailAddressError < Error; end
17
+ class DomainResourcesTimeoutError < Error; end
18
+
19
+ end
data/test/helper.rb ADDED
@@ -0,0 +1,51 @@
1
+ require 'rubygems'
2
+ require 'test/unit'
3
+ require 'shoulda'
4
+ require 'mocha'
5
+ require 'redgreen'
6
+
7
+ $LOAD_PATH.unshift(File.join(File.dirname(__FILE__), '..', 'lib'))
8
+ $LOAD_PATH.unshift(File.dirname(__FILE__))
9
+
10
+ require 'email_veracity'
11
+
12
+
13
+ class ClassWithValidationMock
14
+
15
+ include EmailVeracity::Validatability
16
+
17
+ attr_accessor :give_error
18
+ attr_accessor :give_errors
19
+ attr_accessor :give_array_of_errors
20
+
21
+ def validate!
22
+ add_error(:one) if give_error
23
+ add_errors(:two, :three) if give_errors
24
+ add_errors([:four, :five]) if give_array_of_errors
25
+ add_errors []
26
+ end
27
+
28
+ end
29
+
30
+
31
+ class Test::Unit::TestCase
32
+
33
+ def assert_empty(array, message = nil)
34
+ unless array.is_a?(Array)
35
+ raise ArgumentError, 'First argument must be an Array'
36
+ end
37
+ message = [message, "Expected #{array.inspect} to be empty."].
38
+ flatten.join("\n")
39
+ assert_block(message) { array.empty? }
40
+ end
41
+
42
+ def assert_not_empty(array, message = nil)
43
+ unless array.is_a?(Array)
44
+ raise ArgumentError, 'First argument must be an Array'
45
+ end
46
+ message = [message, "Expected #{array.inspect} to contain items."].
47
+ flatten.join("\n")
48
+ assert_block(message) { !array.empty? }
49
+ end
50
+
51
+ end
@@ -0,0 +1,54 @@
1
+ require 'helper'
2
+
3
+
4
+ class TestAddress < Test::Unit::TestCase
5
+
6
+ def test_initialize
7
+ assert_instance_of EmailVeracity::Address,
8
+ EmailVeracity::Address.new('heycarsten@gmail.com'),
9
+ 'Should create a new Address object.'
10
+ assert_instance_of Array,
11
+ EmailVeracity::Address.new('heycarsten@gmail.com').errors,
12
+ '#errors should be an array.'
13
+ end
14
+
15
+ end
16
+
17
+
18
+ class DefaultConfigurationAddressValidationsTest < Test::Unit::TestCase
19
+
20
+ def test_a_nil_address_argument
21
+ address = new_address(nil)
22
+ assert !address.valid?, 'Should be invalid.'
23
+ end
24
+
25
+ def test_a_well_formed_address_with_a_whitelisted_domain
26
+ address = new_address('heycarsten@gmail.com')
27
+ assert address.valid?, "Should be valid. @errors: #{address.errors.inspect}"
28
+ end
29
+
30
+ def test_a_well_formed_address_with_a_blacklisted_domain
31
+ address = new_address('heycarsten@dodgeit.com')
32
+ address.stubs(:domain).returns(stub(:errors => [:blacklisted]))
33
+ assert !address.valid?, "Should not be valid. @errors: #{address.errors.inspect}"
34
+ end
35
+
36
+ def test_a_well_formed_address_that_does_not_exist
37
+ address = new_address('heycarsten@i-surely-do-not-exist.nil')
38
+ address.stubs(:domain).returns(stub(:errors => [:no_records]))
39
+ assert !address.valid?, 'Should not be valid.'
40
+ end
41
+
42
+ def test_a_well_formed_address_that_exists
43
+ address = new_address('itsme@heycarsten.com')
44
+ address.stubs(:domain).returns(stub(:errors => []))
45
+ assert address.valid?, "Should be valid. @errors: #{address.errors.inspect}"
46
+ end
47
+
48
+ private
49
+
50
+ def new_address(address = '')
51
+ EmailVeracity::Address.new(address)
52
+ end
53
+
54
+ end
@@ -0,0 +1,101 @@
1
+ require 'helper'
2
+
3
+ class TestConfig < Test::Unit::TestCase
4
+
5
+ VALID_EMAIL_ADDRESS_EXAMPLES = %w[
6
+ goto@rubyfringe.ca
7
+ went.to@futureruby.com
8
+ heyd00d+stuff@gmail.com
9
+ carsten_nielsen@gmail.com
10
+ carsten-nielsen@gmail.com
11
+ goodoldemail@address.ca
12
+ old-skool@mail.mysite.on.ca
13
+ heycarsten@del.icio.us
14
+ nex3@haml.town
15
+ 1234@aplace.com
16
+ carsten2@happyland.net
17
+ sweetCandy4@me-and-you.ca
18
+ simple@example.com
19
+ neat@b.eat
20
+ i@shouldwork.com
21
+ 1@shouldworktoo.com ]
22
+ INVALID_EMAIL_ADDRESS_EXAMPLES = %w[
23
+ @failure.net
24
+ craptastic@
25
+ !!!!!@gmail.com
26
+ oh-noez@f4iL/\/\@il.net
27
+ someone@somewhere
28
+ this!fails@comtown.com
29
+ $oWrong@fail.net
30
+ charles\ babbage@gmail.com
31
+ ,@crap.com
32
+ dis%20blos@dot.com
33
+ &^%$#$%@yojimbo.nil
34
+ "greetings\ friend"@comtastic.dk
35
+ this,fails@ice-t.com
36
+ ungültige@adresse.de
37
+ failure@10.0.0.1
38
+ douche@@bag.net
39
+ .@fail.net
40
+ -@fail.org
41
+ _@fail.org
42
+ +_-@fail.die
43
+ +___--@crashburn.net ]
44
+
45
+ context 'Default email pattern' do
46
+ should 'match valid addresses' do
47
+ VALID_EMAIL_ADDRESS_EXAMPLES.each do |example|
48
+ assert_match EmailVeracity::Config[:valid_pattern], example
49
+ end
50
+ end
51
+
52
+ should 'not match invalid addresses' do
53
+ INVALID_EMAIL_ADDRESS_EXAMPLES.each do |example|
54
+ assert_no_match EmailVeracity::Config[:valid_pattern], example
55
+ end
56
+ end
57
+ end
58
+
59
+ def test_default_whitelist_domains
60
+ assert_instance_of Array, EmailVeracity::Config[:whitelist]
61
+ assert_not_empty EmailVeracity::Config[:whitelist],
62
+ 'Should have more than one item.'
63
+ end
64
+
65
+ def test_default_blacklist_domains
66
+ assert_instance_of Array, EmailVeracity::Config[:blacklist]
67
+ assert_not_empty EmailVeracity::Config[:blacklist],
68
+ 'Should have more than one item.'
69
+ end
70
+
71
+ def test_must_include_default_setting
72
+ assert_instance_of Array, EmailVeracity::Config[:must_include]
73
+ end
74
+
75
+ def test_enforced_record_with_symbols
76
+ assert !EmailVeracity::Config.enforced_record?(:a),
77
+ 'Should not check for A records by default'
78
+ assert !EmailVeracity::Config.enforced_record?(:mx),
79
+ 'Should not check for MX records be default'
80
+ end
81
+
82
+ def test_enforce_lookup_with_strings
83
+ assert !EmailVeracity::Config.enforced_record?('a'),
84
+ 'Should not check for A records by default'
85
+ assert !EmailVeracity::Config.enforced_record?('mx'),
86
+ 'Should not check for MX records be default'
87
+ end
88
+
89
+ def test_changing_and_reverting_configuration
90
+ EmailVeracity::Config.update(:lookup => false, :timeout => 3)
91
+ assert_equal false, EmailVeracity::Config[:lookup],
92
+ 'Should change configuration.'
93
+ assert_equal 3, EmailVeracity::Config[:timeout]
94
+ 'Should change configuration.'
95
+ EmailVeracity::Config.revert!
96
+ assert_equal EmailVeracity::Config::DEFAULT_OPTIONS,
97
+ EmailVeracity::Config.options,
98
+ 'Should revert configuration'
99
+ end
100
+
101
+ end
@@ -0,0 +1,94 @@
1
+ require 'helper'
2
+
3
+ class TestDomain < Test::Unit::TestCase
4
+
5
+ def test_blacklisted_domain
6
+ assert EmailVeracity::Domain.blacklisted?('dodgeit.com'),
7
+ 'Should match a blacklisted domain.'
8
+ assert EmailVeracity::Domain.blacklisted?('DoDgEiT.cOm'),
9
+ 'Should match a blacklisted domain regardless of case.'
10
+ assert EmailVeracity::Domain.blacklisted?(" dodgeit.com \r\n "),
11
+ 'Should match a blacklisted domain regardless of whitespace.'
12
+ assert !EmailVeracity::Domain.blacklisted?('iamnotblacklisted.com'),
13
+ 'Should not match a non-blacklisted domain.'
14
+ end
15
+
16
+ def test_whitelisted_domain
17
+ assert EmailVeracity::Domain.whitelisted?('gmail.com'),
18
+ 'Should match a whitelisted domain.'
19
+ assert EmailVeracity::Domain.whitelisted?('GmAiL.cOm'),
20
+ 'Should match a whitelisted domain regardless of case.'
21
+ assert EmailVeracity::Domain.whitelisted?(" gmail.com \r\n "),
22
+ 'Should match a whitelisted domain regardless of whitespace.'
23
+ assert !EmailVeracity::Domain.whitelisted?('iamnotwhitelisted.com'),
24
+ 'Should not match a non-whitelisted domain.'
25
+ end
26
+
27
+ def test_initializing_a_new_domain_with_whitespace
28
+ domain = new_domain(' heycarsten.com ')
29
+ assert_equal 'heycarsten.com', domain.name, 'Should strip whitespace.'
30
+ assert_respond_to domain, :to_s, 'Should have a to_s method.'
31
+ end
32
+
33
+ def test_a_valid_domain_for_address_servers
34
+ domain_name = 'gmail.com'
35
+ domain = new_domain(domain_name)
36
+ EmailVeracity::Resolver.expects(:get_servers_for).
37
+ with(domain_name, :a).returns(["mail.#{domain_name}"])
38
+ assert_not_empty domain.address_servers, 'Should contain address servers.'
39
+ end
40
+
41
+ def test_a_valid_domain_for_exchange_servers
42
+ domain_name = 'gmail.com'
43
+ domain = new_domain(domain_name)
44
+ EmailVeracity::Resolver.expects(:get_servers_for).
45
+ with(domain_name, :mx).returns(["mail.#{domain_name}"])
46
+ assert_not_empty domain.exchange_servers, 'Should contain mail servers.'
47
+ end
48
+
49
+ def test_an_invalid_domain_for_address_servers
50
+ domain = new_domain('i-surely-do-not.exist')
51
+ domain.expects(:servers_in).with(:a).returns([])
52
+ assert_empty domain.address_servers, 'Should not contain address servers.'
53
+ end
54
+
55
+ def test_an_invalid_domain_for_exchange_servers
56
+ domain = new_domain('i-surely-do-not.exist')
57
+ domain.expects(:servers_in).with(:mx).returns([])
58
+ assert_empty domain.exchange_servers, 'Should not contain exchange servers.'
59
+ end
60
+
61
+ def test_a_blank_domain_for_servers
62
+ domain = new_domain('')
63
+ assert_empty domain.exchange_servers, 'Should not contain exchange servers.'
64
+ assert_empty domain.address_servers, 'Should not contain address servers.'
65
+ end
66
+
67
+ def test_for_errors_on_a_valid_domain
68
+ domain = new_domain('yahoo.com')
69
+ assert_empty domain.errors, 'Should not have errors.'
70
+ end
71
+
72
+ context 'A domain with no address records or exchange records' do
73
+ setup do
74
+ @domain = new_domain('nothingtoseehere.org')
75
+ @domain.stubs(:address_servers).returns([])
76
+ @domain.stubs(:exchange_servers).returns([])
77
+ end
78
+
79
+ should 'not pass validation' do
80
+ assert !@domain.valid?
81
+ end
82
+
83
+ should 'indicate the appropriate error' do
84
+ assert @domain.errors.include?(:no_records)
85
+ end
86
+ end
87
+
88
+ private
89
+
90
+ def new_domain(name = 'heycarsten.com')
91
+ EmailVeracity::Domain.new(name)
92
+ end
93
+
94
+ end
@@ -0,0 +1,33 @@
1
+ require 'helper'
2
+
3
+ class TestResolver < Test::Unit::TestCase
4
+
5
+ DOMAIN_NAMES = %w[
6
+ viarails.net heycarsten.com yahoo.com gmail.com savvica.com
7
+ okayfail.com github.com google.com rogers.com amd.com adobe.com
8
+ unspace.ca xerox.com webkit.org cooltown.net aiderss.com delicious.com ]
9
+
10
+ def test_consecutive_queries
11
+ DOMAIN_NAMES.each do |domain_name|
12
+ EmailVeracity::Resolver.stubs(:get_resources_for).
13
+ with(domain_name, kind_of(Symbol)).returns(["mail.#{domain_name}"])
14
+ end
15
+ assert_nothing_raised do
16
+ DOMAIN_NAMES.each do |domain|
17
+ assert_instance_of Array, EmailVeracity::Resolver.get_servers_for(domain),
18
+ 'Should return an array of servers'
19
+ end
20
+ end
21
+ end
22
+
23
+ def test_timing_out_while_resolving_a_domain
24
+ domain = 'okayfail.com'
25
+ timeout_exception = Timeout::Error.new('The connection has timed out')
26
+ EmailVeracity::Resolver.stubs(:get_resources_for).
27
+ with(domain, kind_of(Symbol)).raises(timeout_exception)
28
+ assert_raise EmailVeracity::DomainResourcesTimeoutError, 'Should time out' do
29
+ EmailVeracity::Resolver.get_servers_for(domain)
30
+ end
31
+ end
32
+
33
+ end
@@ -0,0 +1,29 @@
1
+ require 'helper'
2
+
3
+ class TestServer < Test::Unit::TestCase
4
+
5
+ def test_creating_a_new_blank_server_object
6
+ new_server = EmailVeracity::Server.new
7
+ assert_equal '', new_server.to_s,
8
+ 'Should yield a blank string on call to to_s.'
9
+ assert_equal '', new_server.name,
10
+ 'Should yield a blank string on call to name.'
11
+ end
12
+
13
+ def test_creating_a_new_server_object_with_a_name_and_type
14
+ name = 'cooltown.ca'
15
+ new_server = EmailVeracity::Server.new(name)
16
+ assert_equal name, new_server.name,
17
+ 'Should yield the provided name on call to name.'
18
+ assert_equal name, new_server.to_s,
19
+ 'Should yield the provided name on call to to_s.'
20
+ end
21
+
22
+ def test_creating_a_new_blank_server_object_and_setting_its_name_after_initialization
23
+ new_server = EmailVeracity::Server.new('igvita.com')
24
+ assert_raise NoMethodError, 'Should fail miserably.' do
25
+ new_server.name = name
26
+ end
27
+ end
28
+
29
+ end
@@ -0,0 +1,12 @@
1
+ require 'helper'
2
+
3
+ class TestUtils < Test::Unit::TestCase
4
+
5
+ def test_blank
6
+ assert EmailVeracity::Utils.blank?([]), '[] should be blank.'
7
+ assert EmailVeracity::Utils.blank?(''), '"" should be blank.'
8
+ assert EmailVeracity::Utils.blank?(Hash.new), '{} should be blank.'
9
+ assert EmailVeracity::Utils.blank?(nil), 'nil should be blank.'
10
+ end
11
+
12
+ end
@@ -0,0 +1,35 @@
1
+ require 'helper'
2
+
3
+ class TestValidatability < Test::Unit::TestCase
4
+
5
+ def test_includes_proper_methods
6
+ %w[ valid? validate! clear_errors! add_error errors ].each do |method_name|
7
+ assert_respond_to ClassWithValidationMock.new, method_name
8
+ end
9
+ end
10
+
11
+ def test_add_error
12
+ mock = ClassWithValidationMock.new
13
+ mock.give_error = true
14
+ assert_equal 1, mock.errors.size, 'Should set one error.'
15
+ mock.give_errors = true
16
+ assert_equal [:one, :two, :three], mock.errors,
17
+ 'Should push tow new errors for a total of three.'
18
+ mock.give_array_of_errors = true
19
+ assert_equal [:one, :two, :three, :four, :five], mock.errors,
20
+ 'Should concat the array leaving two new errors for a total of five.'
21
+ end
22
+
23
+ def test_valid?
24
+ mock = ClassWithValidationMock.new
25
+ assert mock.valid?, 'Should be valid by default.'
26
+ mock.give_error = true
27
+ assert !mock.valid?, 'Should not be valid if errors are set.'
28
+ end
29
+
30
+ def test_errors
31
+ assert ClassWithValidationMock.new.errors.empty?,
32
+ 'Should be empty by default.'
33
+ end
34
+
35
+ end
metadata ADDED
@@ -0,0 +1,103 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: email_veracity
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.4.0
5
+ platform: ruby
6
+ authors:
7
+ - Carsten Nielsen
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+
12
+ date: 2009-12-12 00:00:00 -05:00
13
+ default_executable:
14
+ dependencies:
15
+ - !ruby/object:Gem::Dependency
16
+ name: mocha
17
+ type: :development
18
+ version_requirement:
19
+ version_requirements: !ruby/object:Gem::Requirement
20
+ requirements:
21
+ - - ">="
22
+ - !ruby/object:Gem::Version
23
+ version: 0.9.8
24
+ version:
25
+ - !ruby/object:Gem::Dependency
26
+ name: shoulda
27
+ type: :development
28
+ version_requirement:
29
+ version_requirements: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - ">="
32
+ - !ruby/object:Gem::Version
33
+ version: 2.10.2
34
+ version:
35
+ description: Email Veracity abstracts an email address into a series of objects which makes it easy to see if an address is invalid, and if so, why.
36
+ email: heycarsten@gmail.com
37
+ executables: []
38
+
39
+ extensions: []
40
+
41
+ extra_rdoc_files:
42
+ - LICENSE
43
+ - README.md
44
+ files:
45
+ - .gitignore
46
+ - LICENSE
47
+ - README.md
48
+ - Rakefile
49
+ - VERSION
50
+ - email_veracity.gemspec
51
+ - lib/email_veracity.rb
52
+ - lib/email_veracity/address.rb
53
+ - lib/email_veracity/config.rb
54
+ - lib/email_veracity/domain.rb
55
+ - lib/email_veracity/resolver.rb
56
+ - lib/email_veracity/server.rb
57
+ - lib/email_veracity/utils.rb
58
+ - lib/email_veracity/validatability.rb
59
+ - test/helper.rb
60
+ - test/test_address.rb
61
+ - test/test_config.rb
62
+ - test/test_domain.rb
63
+ - test/test_resolver.rb
64
+ - test/test_server.rb
65
+ - test/test_utils.rb
66
+ - test/test_validatability.rb
67
+ has_rdoc: true
68
+ homepage: http://github.com/heycarsten/email-veracity
69
+ licenses: []
70
+
71
+ post_install_message:
72
+ rdoc_options:
73
+ - --charset=UTF-8
74
+ require_paths:
75
+ - lib
76
+ required_ruby_version: !ruby/object:Gem::Requirement
77
+ requirements:
78
+ - - ">="
79
+ - !ruby/object:Gem::Version
80
+ version: "0"
81
+ version:
82
+ required_rubygems_version: !ruby/object:Gem::Requirement
83
+ requirements:
84
+ - - ">="
85
+ - !ruby/object:Gem::Version
86
+ version: "0"
87
+ version:
88
+ requirements: []
89
+
90
+ rubyforge_project:
91
+ rubygems_version: 1.3.5
92
+ signing_key:
93
+ specification_version: 3
94
+ summary: A simple library for checking the real-world validity of email addresses.
95
+ test_files:
96
+ - test/helper.rb
97
+ - test/test_address.rb
98
+ - test/test_config.rb
99
+ - test/test_domain.rb
100
+ - test/test_resolver.rb
101
+ - test/test_server.rb
102
+ - test/test_utils.rb
103
+ - test/test_validatability.rb