schlick-active-matchers 0.3.1.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.
- data/LICENSE +20 -0
- data/Rakefile +56 -0
- data/init.rb +1 -0
- data/lib/active-matchers.rb +20 -0
- data/lib/active-matchers/assoc_reflection_methods.rb +10 -0
- data/lib/active-matchers/matchers.rb +113 -0
- data/lib/active-matchers/matchers/association_matcher.rb +57 -0
- data/lib/active-matchers/matchers/response_matchers.rb +105 -0
- data/lib/active-matchers/matchers/validation_matcher.rb +240 -0
- metadata +73 -0
data/LICENSE
ADDED
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
Copyright (c) 2007 Pat Allan & James Healy
|
|
2
|
+
|
|
3
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
|
4
|
+
a copy of this software and associated documentation files (the
|
|
5
|
+
"Software"), to deal in the Software without restriction, including
|
|
6
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
|
7
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
|
8
|
+
permit persons to whom the Software is furnished to do so, subject to
|
|
9
|
+
the following conditions:
|
|
10
|
+
|
|
11
|
+
The above copyright notice and this permission notice shall be
|
|
12
|
+
included in all copies or substantial portions of the Software.
|
|
13
|
+
|
|
14
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
|
15
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
|
16
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
|
17
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
|
18
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
|
19
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
|
20
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/Rakefile
ADDED
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
require 'rubygems'
|
|
2
|
+
require 'rake/gempackagetask'
|
|
3
|
+
require 'rubygems/specification'
|
|
4
|
+
require 'date'
|
|
5
|
+
|
|
6
|
+
$:.unshift File.join(File.dirname(__FILE__), 'lib')
|
|
7
|
+
|
|
8
|
+
require 'active-matchers'
|
|
9
|
+
|
|
10
|
+
GEM = "active-matchers"
|
|
11
|
+
GEM_VERSION = ActiveMatchers::Version::STRING
|
|
12
|
+
AUTHOR = "Pat Allan"
|
|
13
|
+
EMAIL = "pat@freelancing-gods.com"
|
|
14
|
+
HOMEPAGE = "http://am.freelancing-gods.com"
|
|
15
|
+
SUMMARY = "Helpful rspec matchers for testing validations and associations."
|
|
16
|
+
|
|
17
|
+
spec = Gem::Specification.new do |s|
|
|
18
|
+
s.name = GEM
|
|
19
|
+
s.version = GEM_VERSION
|
|
20
|
+
s.platform = Gem::Platform::RUBY
|
|
21
|
+
s.rubyforge_project = GEM
|
|
22
|
+
s.has_rdoc = true
|
|
23
|
+
s.extra_rdoc_files = ['README.textile','LICENSE']
|
|
24
|
+
s.summary = SUMMARY
|
|
25
|
+
s.description = s.summary
|
|
26
|
+
s.author = AUTHOR
|
|
27
|
+
s.email = EMAIL
|
|
28
|
+
s.homepage = HOMEPAGE
|
|
29
|
+
|
|
30
|
+
s.add_dependency 'activerecord'
|
|
31
|
+
|
|
32
|
+
s.require_path = 'lib'
|
|
33
|
+
s.files = %w(README.textile LICENSE Rakefile init.rb) + Dir.glob("{lib,specs}/**/*")
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
Rake::GemPackageTask.new(spec) do |pkg|
|
|
37
|
+
pkg.gem_spec = spec
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
desc "install the gem locally"
|
|
41
|
+
task :install => [:package] do
|
|
42
|
+
sh %{sudo gem install pkg/#{GEM}-#{GEM_VERSION}}
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
desc "create a gemspec file"
|
|
46
|
+
task :make_spec do
|
|
47
|
+
File.open("#{GEM}.gemspec", "w") do |file|
|
|
48
|
+
file.puts spec.to_ruby
|
|
49
|
+
end
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
Rake::GemPackageTask.new(spec) do |p|
|
|
53
|
+
p.gem_spec = spec
|
|
54
|
+
p.need_tar = true
|
|
55
|
+
p.need_zip = true
|
|
56
|
+
end
|
data/init.rb
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
require "active-matchers"
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
$:.unshift(File.dirname(__FILE__)) unless
|
|
2
|
+
$:.include?(File.dirname(__FILE__)) || $:.include?(File.expand_path(File.dirname(__FILE__)))
|
|
3
|
+
|
|
4
|
+
require "active_record"
|
|
5
|
+
require "active-matchers/assoc_reflection_methods"
|
|
6
|
+
require "active-matchers/matchers"
|
|
7
|
+
|
|
8
|
+
ActiveRecord::Reflection::AssociationReflection.send(:include,
|
|
9
|
+
ActiveMatchers::AssociationReflectionMethods)
|
|
10
|
+
|
|
11
|
+
module ActiveMatchers
|
|
12
|
+
module Version #:nodoc:
|
|
13
|
+
MAJOR = 0
|
|
14
|
+
MINOR = 3
|
|
15
|
+
TINY = 1
|
|
16
|
+
MICRO = 1
|
|
17
|
+
|
|
18
|
+
STRING = [MAJOR, MINOR, TINY, MICRO].join('.').freeze
|
|
19
|
+
end
|
|
20
|
+
end
|
|
@@ -0,0 +1,113 @@
|
|
|
1
|
+
require "active-matchers/matchers/association_matcher"
|
|
2
|
+
require "active-matchers/matchers/validation_matcher"
|
|
3
|
+
require "active-matchers/matchers/response_matchers"
|
|
4
|
+
|
|
5
|
+
module ActiveMatchers
|
|
6
|
+
module Matchers
|
|
7
|
+
# Test validates_presence_of :name
|
|
8
|
+
# Model.should need(:name).using(@valid_attributes)
|
|
9
|
+
#
|
|
10
|
+
# Test validates_uniqueness_of :name
|
|
11
|
+
# Model.should need(:name).to_be_unique.using(@valid_attributes)
|
|
12
|
+
#
|
|
13
|
+
# Test presence of at least one field being required
|
|
14
|
+
# Model.should need.one_of(:first_name, :last_name).using(@valid_attributes)
|
|
15
|
+
#
|
|
16
|
+
def need(*fields)
|
|
17
|
+
ValidationMatcher.new(:require, *fields).using(@base_attributes)
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
alias_method :mandate, :need
|
|
21
|
+
|
|
22
|
+
# Test validates_length_of :name matches database field length
|
|
23
|
+
# Model.should limit_length_of(:name).using(@valid_attributes)
|
|
24
|
+
#
|
|
25
|
+
# Test validates_length_of :name, :maximum => 255
|
|
26
|
+
# Model.should limit_length_of(:name).to(255).using(@valid_attributes)
|
|
27
|
+
#
|
|
28
|
+
def limit_length_of(*fields)
|
|
29
|
+
ValidationMatcher.new(:length, *fields).using(@base_attributes)
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
# Test belongs_to :parent
|
|
33
|
+
# Model.should belong_to(:parent)
|
|
34
|
+
#
|
|
35
|
+
# Test belongs_to :parent, :class_name => "CustomClass", :foreign_key => "some_id"
|
|
36
|
+
# Model.should belong_to(:parent).with_options(
|
|
37
|
+
# :class_name => "CustomClass", :foreign_key => "some_id")
|
|
38
|
+
#
|
|
39
|
+
def belong_to(*fields)
|
|
40
|
+
AssociationMatcher.new(:belongs_to, *fields)
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
# Test has_many :items
|
|
44
|
+
# Model.should have_many(:items)
|
|
45
|
+
#
|
|
46
|
+
# Test has_many :items, :class_name => "CustomClass", :foreign_key => "some_id"
|
|
47
|
+
# Model.should have_many(:items).with_options(
|
|
48
|
+
# :class_name => "CustomClass", :foreign_key => "some_id")
|
|
49
|
+
#
|
|
50
|
+
def have_many(*fields)
|
|
51
|
+
AssociationMatcher.new(:has_many, *fields)
|
|
52
|
+
end
|
|
53
|
+
|
|
54
|
+
# Test has_one :item
|
|
55
|
+
# Model.should have_one(:item)
|
|
56
|
+
#
|
|
57
|
+
# Test has_one :item, :class_name => "CustomClass", :foreign_key => "some_id"
|
|
58
|
+
# Model.should have_one(:item).with_options(
|
|
59
|
+
# :class_name => "CustomClass", :foreign_key => "some_id")
|
|
60
|
+
#
|
|
61
|
+
def have_one(*fields)
|
|
62
|
+
AssociationMatcher.new(:has_one, *fields)
|
|
63
|
+
end
|
|
64
|
+
|
|
65
|
+
# Test has_and_belongs_to_many :items
|
|
66
|
+
# Model.should have_and_belong_to_many(:items)
|
|
67
|
+
#
|
|
68
|
+
# Test has_and_belongs_to_many :items, :class_name => "CustomClass"
|
|
69
|
+
# Model.should have_one(:item).with_options(
|
|
70
|
+
# :class_name => "CustomClass")
|
|
71
|
+
#
|
|
72
|
+
def have_and_belong_to_many(*fields)
|
|
73
|
+
AssociationMatcher.new(:has_and_belongs_to_many, *fields)
|
|
74
|
+
end
|
|
75
|
+
|
|
76
|
+
# Useful for multiple requests using the same base attributes
|
|
77
|
+
#
|
|
78
|
+
# using(@valid_attributes) do
|
|
79
|
+
# Model.should need(:name)
|
|
80
|
+
# Model.should limit_length_of(:name).to(100)
|
|
81
|
+
# end
|
|
82
|
+
#
|
|
83
|
+
def using(base_attributes={}, &block)
|
|
84
|
+
@base_attributes = base_attributes
|
|
85
|
+
yield
|
|
86
|
+
@base_attributes= {}
|
|
87
|
+
end
|
|
88
|
+
|
|
89
|
+
#
|
|
90
|
+
def succeed
|
|
91
|
+
ResponseMatchers::SuccessMatcher.new(@controller)
|
|
92
|
+
end
|
|
93
|
+
|
|
94
|
+
# Use to confirm whether a response is/is not a 404
|
|
95
|
+
#
|
|
96
|
+
# response.should be_a_404
|
|
97
|
+
#
|
|
98
|
+
def be_a_404
|
|
99
|
+
ResponseMatchers::NotFoundMatcher.new
|
|
100
|
+
end
|
|
101
|
+
|
|
102
|
+
# Use to confirm whether a response redirected
|
|
103
|
+
#
|
|
104
|
+
# response.should redirect
|
|
105
|
+
# response.should_not redirect
|
|
106
|
+
# response.should redirect.to("url")
|
|
107
|
+
# response.should_not redirect.to("url")
|
|
108
|
+
#
|
|
109
|
+
def redirect
|
|
110
|
+
ResponseMatchers::RedirectMatcher.new
|
|
111
|
+
end
|
|
112
|
+
end
|
|
113
|
+
end
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
module ActiveMatchers
|
|
2
|
+
module Matchers
|
|
3
|
+
class AssociationMatcher
|
|
4
|
+
def initialize(macro, *attributes)
|
|
5
|
+
@macro = macro
|
|
6
|
+
@attributes = attributes
|
|
7
|
+
end
|
|
8
|
+
|
|
9
|
+
def matches?(model)
|
|
10
|
+
@model = model
|
|
11
|
+
confirm_association
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
def failure_message
|
|
15
|
+
"Error: #{@error}"
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
def with_options(options)
|
|
19
|
+
@options = options
|
|
20
|
+
self
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
def through(assoc)
|
|
24
|
+
@options ||= {}
|
|
25
|
+
@options[:through] = assoc
|
|
26
|
+
self
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
private
|
|
30
|
+
|
|
31
|
+
def confirm_association
|
|
32
|
+
return if @attributes.empty?
|
|
33
|
+
|
|
34
|
+
@options ||= {}
|
|
35
|
+
@options[:extend] ||= []
|
|
36
|
+
|
|
37
|
+
@attributes.each do |attribute|
|
|
38
|
+
assoc = @model.reflect_on_association(attribute)
|
|
39
|
+
if assoc.nil?
|
|
40
|
+
@error = "#{@model.name} is missing the association #{attribute}"
|
|
41
|
+
return false
|
|
42
|
+
end
|
|
43
|
+
if assoc.to_hash[:macro] != @macro
|
|
44
|
+
@error = "#{@model.name}.#{attribute} should be #{@macro}, but is #{assoc.to_hash[:macro]}"
|
|
45
|
+
return false
|
|
46
|
+
end
|
|
47
|
+
if assoc.to_hash[:options] != @options
|
|
48
|
+
@error = "#{@model.name}.#{attribute} should have options #{@options.inspect}, but has options #{assoc.to_hash[:options].inspect}"
|
|
49
|
+
return false
|
|
50
|
+
end
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
true
|
|
54
|
+
end
|
|
55
|
+
end
|
|
56
|
+
end
|
|
57
|
+
end
|
|
@@ -0,0 +1,105 @@
|
|
|
1
|
+
module ActiveMatchers
|
|
2
|
+
module Matchers
|
|
3
|
+
module ResponseMatchers
|
|
4
|
+
class SuccessMatcher
|
|
5
|
+
def initialize(controller)
|
|
6
|
+
@controller = controller
|
|
7
|
+
end
|
|
8
|
+
|
|
9
|
+
def matches?(response)
|
|
10
|
+
@response = response
|
|
11
|
+
if @template.nil?
|
|
12
|
+
@response.success?
|
|
13
|
+
else
|
|
14
|
+
@response.success? && full_path(@template) == full_path(@response.rendered_file)
|
|
15
|
+
end
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
def with_template(template)
|
|
19
|
+
@template = template
|
|
20
|
+
self
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
def failure_message
|
|
24
|
+
if @template.nil? || !@response.success?
|
|
25
|
+
"Response should have succeeded, but returned with code #{@response.response_code}."
|
|
26
|
+
else
|
|
27
|
+
"Response should have rendered #{@template}, but instead rendered #{@response.rendered_file}."
|
|
28
|
+
end
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
def negative_failure_message
|
|
32
|
+
if @response.success?
|
|
33
|
+
"Response should not have succeeded, but did."
|
|
34
|
+
else
|
|
35
|
+
"Response should not have rendered #{@template}, but did."
|
|
36
|
+
end
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
private
|
|
40
|
+
|
|
41
|
+
def full_path(path)
|
|
42
|
+
return nil if path.nil?
|
|
43
|
+
path.include?('/') ? path : "#{@controller.class.to_s.underscore.gsub('_controller','')}/#{path}"
|
|
44
|
+
end
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
class NotFoundMatcher
|
|
48
|
+
def matches?(response)
|
|
49
|
+
@response = response
|
|
50
|
+
response.response_code == 404
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
def failure_message
|
|
54
|
+
"Response should have had a status of 404 Not Found, but had #{@response.response_code}."
|
|
55
|
+
end
|
|
56
|
+
|
|
57
|
+
def negative_failure_message
|
|
58
|
+
"Response should not have a status of 404 Not Found, but does."
|
|
59
|
+
end
|
|
60
|
+
end
|
|
61
|
+
|
|
62
|
+
class RedirectMatcher
|
|
63
|
+
def initialize
|
|
64
|
+
@action = :what
|
|
65
|
+
end
|
|
66
|
+
|
|
67
|
+
def matches?(response)
|
|
68
|
+
@response = response
|
|
69
|
+
case @action
|
|
70
|
+
when :what
|
|
71
|
+
@response.redirect?
|
|
72
|
+
when :where
|
|
73
|
+
@response.redirect? && @response.redirect_url == @url
|
|
74
|
+
else
|
|
75
|
+
false
|
|
76
|
+
end
|
|
77
|
+
end
|
|
78
|
+
|
|
79
|
+
def to(url)
|
|
80
|
+
@action = :where
|
|
81
|
+
@url = url
|
|
82
|
+
self
|
|
83
|
+
end
|
|
84
|
+
|
|
85
|
+
def failure_message
|
|
86
|
+
case @action
|
|
87
|
+
when :what
|
|
88
|
+
"Response should have redirected, but didn't."
|
|
89
|
+
when :where
|
|
90
|
+
"Response should have redirected to #{@url}, but didn't."
|
|
91
|
+
end
|
|
92
|
+
end
|
|
93
|
+
|
|
94
|
+
def negative_failure_message
|
|
95
|
+
case @action
|
|
96
|
+
when :what
|
|
97
|
+
"Response shouldn't have redirected, but did."
|
|
98
|
+
when :where
|
|
99
|
+
"Response shouldn't have redirected to #{@url}, but did."
|
|
100
|
+
end
|
|
101
|
+
end
|
|
102
|
+
end
|
|
103
|
+
end
|
|
104
|
+
end
|
|
105
|
+
end
|
|
@@ -0,0 +1,240 @@
|
|
|
1
|
+
module ActiveMatchers
|
|
2
|
+
module Matchers
|
|
3
|
+
class ValidationMatcher
|
|
4
|
+
def initialize(type, *attributes)
|
|
5
|
+
@type = type
|
|
6
|
+
@attributes = attributes
|
|
7
|
+
@create_action = 'create'
|
|
8
|
+
@new_action = 'new'
|
|
9
|
+
end
|
|
10
|
+
|
|
11
|
+
def matches?(model)
|
|
12
|
+
@model = model
|
|
13
|
+
case @type
|
|
14
|
+
when :require
|
|
15
|
+
confirm_required(&@if)
|
|
16
|
+
when :unique
|
|
17
|
+
confirm_unique
|
|
18
|
+
when :one_of_many
|
|
19
|
+
confirm_one_of_many
|
|
20
|
+
when :length
|
|
21
|
+
confirm_length
|
|
22
|
+
when :numeric
|
|
23
|
+
confirm_numericality
|
|
24
|
+
when :unsigned
|
|
25
|
+
confirm_zero_or_greater
|
|
26
|
+
else
|
|
27
|
+
false
|
|
28
|
+
end
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
def failure_message
|
|
32
|
+
"Error: #{@error}"
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
def to_be_unique
|
|
36
|
+
@type = :unique
|
|
37
|
+
self
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
def to_be_numeric
|
|
41
|
+
@type = :numeric
|
|
42
|
+
self
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
def to_be_unsigned
|
|
46
|
+
@type = :unsigned
|
|
47
|
+
self
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
def using(attributes={})
|
|
51
|
+
@base_attributes = attributes
|
|
52
|
+
self
|
|
53
|
+
end
|
|
54
|
+
|
|
55
|
+
def if(&block)
|
|
56
|
+
@if = block
|
|
57
|
+
self
|
|
58
|
+
end
|
|
59
|
+
|
|
60
|
+
def one_of(*attributes)
|
|
61
|
+
@attributes = attributes
|
|
62
|
+
@type = :one_of_many
|
|
63
|
+
self
|
|
64
|
+
end
|
|
65
|
+
|
|
66
|
+
def to(upper_limit)
|
|
67
|
+
@upper_limit = upper_limit
|
|
68
|
+
self
|
|
69
|
+
end
|
|
70
|
+
|
|
71
|
+
def from(lower_limit)
|
|
72
|
+
@lower_limit = lower_limit
|
|
73
|
+
self
|
|
74
|
+
end
|
|
75
|
+
|
|
76
|
+
# Override the assumed default 'create' action and allow another one to be used.
|
|
77
|
+
# This makes it possible to use an 'unsafe' create to bypass attr_accessible and friends.
|
|
78
|
+
def with_create(action)
|
|
79
|
+
@create_action = action
|
|
80
|
+
self
|
|
81
|
+
end
|
|
82
|
+
|
|
83
|
+
# Override the assumed default 'new' action and allow another one to be used.
|
|
84
|
+
# This makes it possible to use an 'unsafe' new to bypass attr_accessible and friends.
|
|
85
|
+
def with_new(action)
|
|
86
|
+
@new_action = action
|
|
87
|
+
self
|
|
88
|
+
end
|
|
89
|
+
|
|
90
|
+
private
|
|
91
|
+
|
|
92
|
+
def confirm_required
|
|
93
|
+
return true if @attributes.empty?
|
|
94
|
+
|
|
95
|
+
@attributes.each do |attribute|
|
|
96
|
+
obj = @model.send @new_action, @base_attributes.except(*attribute)
|
|
97
|
+
yield obj if block_given?
|
|
98
|
+
|
|
99
|
+
if obj.valid?
|
|
100
|
+
@error = "#{@model.name}.valid? should be false without #{attribute}, but returned true"
|
|
101
|
+
return false
|
|
102
|
+
end
|
|
103
|
+
if obj.errors.on(attribute).empty?
|
|
104
|
+
@error = "#{@model.name} should have errors on #{attribute} when #{attribute} is missing"
|
|
105
|
+
return false
|
|
106
|
+
end
|
|
107
|
+
obj.send "#{attribute.to_s}=", @base_attributes[attribute]
|
|
108
|
+
unless obj.valid?
|
|
109
|
+
@error = "#{@model.name} should be valid when #{attribute} is supplied"
|
|
110
|
+
return false
|
|
111
|
+
end
|
|
112
|
+
end
|
|
113
|
+
|
|
114
|
+
true
|
|
115
|
+
end
|
|
116
|
+
|
|
117
|
+
def confirm_unique
|
|
118
|
+
return true if @attributes.empty?
|
|
119
|
+
|
|
120
|
+
# Create first
|
|
121
|
+
@model.send @create_action, @base_attributes
|
|
122
|
+
# Create second, which will be invalid because unique values
|
|
123
|
+
# are duplicated
|
|
124
|
+
obj = @model.send @new_action, @base_attributes
|
|
125
|
+
if obj.valid?
|
|
126
|
+
@error = "#{@model.name} should not be valid when it is a duplicate"
|
|
127
|
+
return false
|
|
128
|
+
end
|
|
129
|
+
# Change the values of the unique attributes to remove collisions
|
|
130
|
+
@attributes.each do |attribute|
|
|
131
|
+
if obj.errors.on(attribute).empty?
|
|
132
|
+
@error = "#{@model.name} should have a value collision for #{attribute}"
|
|
133
|
+
return false
|
|
134
|
+
end
|
|
135
|
+
obj.send "#{attribute.to_s}=", "#{@base_attributes[attribute]} - Edit"
|
|
136
|
+
end
|
|
137
|
+
unless obj.valid?
|
|
138
|
+
@error = "#{@model.name} should be valid without duplicate values"
|
|
139
|
+
return false
|
|
140
|
+
end
|
|
141
|
+
true
|
|
142
|
+
end
|
|
143
|
+
|
|
144
|
+
def confirm_one_of_many
|
|
145
|
+
return true if @attributes.empty?
|
|
146
|
+
|
|
147
|
+
obj = @model.send @new_action, @base_attributes.except(*@attributes)
|
|
148
|
+
return false if obj.valid?
|
|
149
|
+
@attributes.each do |attribute|
|
|
150
|
+
obj.send "#{attribute.to_s}=", @base_attributes[attribute]
|
|
151
|
+
return false unless obj.valid?
|
|
152
|
+
obj.send "#{attribute.to_s}=", nil
|
|
153
|
+
return false if obj.valid?
|
|
154
|
+
end
|
|
155
|
+
|
|
156
|
+
true
|
|
157
|
+
end
|
|
158
|
+
|
|
159
|
+
def confirm_length
|
|
160
|
+
return true if @attributes.empty?
|
|
161
|
+
|
|
162
|
+
error_msgs = []
|
|
163
|
+
@lower_limit ||= 0
|
|
164
|
+
|
|
165
|
+
@attributes.each do |attribute|
|
|
166
|
+
obj = @model.send @new_action, @base_attributes.except(attribute)
|
|
167
|
+
|
|
168
|
+
if @lower_limit > 0
|
|
169
|
+
obj.send "#{attribute.to_s}=", 'a'*(@lower_limit)
|
|
170
|
+
error_msgs << "#{@model.name}.valid? should be true when #{attribute} has a length of #{@lower_limit}, but returned false" unless obj.valid?
|
|
171
|
+
|
|
172
|
+
obj.send "#{attribute.to_s}=", 'a'*(@lower_limit-1)
|
|
173
|
+
error_msgs << "#{@model.name}.valid? should be false when #{attribute} has a length less than #{@lower_limit}, but returned true" if obj.valid?
|
|
174
|
+
end
|
|
175
|
+
|
|
176
|
+
@upper_limit ||= @model.columns_hash[attribute.to_s].limit unless @lower_limit > 0
|
|
177
|
+
|
|
178
|
+
if @upper_limit
|
|
179
|
+
obj.send "#{attribute.to_s}=", 'a'*(@upper_limit)
|
|
180
|
+
error_msgs << "#{@model.name}.valid? should be true when #{attribute} has a length of #{@upper_limit}, but returned false" unless obj.valid?
|
|
181
|
+
|
|
182
|
+
obj.send "#{attribute.to_s}=", 'a'*(@upper_limit+1)
|
|
183
|
+
error_msgs << "#{@model.name}.valid? should be false when #{attribute} has a length greater than #{@upper_limit}, but returned true" if obj.valid?
|
|
184
|
+
end
|
|
185
|
+
|
|
186
|
+
unless error_msgs.empty?
|
|
187
|
+
@error = "#{@model.name} " + error_msgs.join(' and ')
|
|
188
|
+
return false
|
|
189
|
+
end
|
|
190
|
+
end
|
|
191
|
+
|
|
192
|
+
true
|
|
193
|
+
end
|
|
194
|
+
|
|
195
|
+
def confirm_numericality
|
|
196
|
+
return true if @attributes.empty?
|
|
197
|
+
|
|
198
|
+
obj = @model.send @new_action, @base_attributes
|
|
199
|
+
|
|
200
|
+
@attributes.each do |attribute|
|
|
201
|
+
|
|
202
|
+
unless obj.valid?
|
|
203
|
+
@error = "#{@model.name}.valid? should be true when #{attribute} is numeric, but returned false"
|
|
204
|
+
return false
|
|
205
|
+
end
|
|
206
|
+
|
|
207
|
+
# Change the attribute to a string
|
|
208
|
+
obj.send "#{attribute.to_s}=", "String"
|
|
209
|
+
if obj.valid?
|
|
210
|
+
@error = "#{@model.name}.valid? should be false when #{attribute} is not numeric, but returned true"
|
|
211
|
+
return false
|
|
212
|
+
end
|
|
213
|
+
|
|
214
|
+
obj.send "#{attribute.to_s}=", @base_attributes[attribute]
|
|
215
|
+
end
|
|
216
|
+
|
|
217
|
+
true
|
|
218
|
+
end
|
|
219
|
+
|
|
220
|
+
def confirm_zero_or_greater
|
|
221
|
+
return true if @attributes.empty?
|
|
222
|
+
|
|
223
|
+
obj = @model.send @new_action, @base_attributes
|
|
224
|
+
|
|
225
|
+
@attributes.each do |attribute|
|
|
226
|
+
obj.send("#{attribute.to_s}=",-1)
|
|
227
|
+
if obj.valid?
|
|
228
|
+
@error = "#{@model.name}.valid? should be false when #{attribute} is less than zero, but returned true"
|
|
229
|
+
return false
|
|
230
|
+
end
|
|
231
|
+
|
|
232
|
+
obj.send "#{attribute.to_s}=", @base_attributes[attribute]
|
|
233
|
+
end
|
|
234
|
+
|
|
235
|
+
true
|
|
236
|
+
end
|
|
237
|
+
|
|
238
|
+
end
|
|
239
|
+
end
|
|
240
|
+
end
|
metadata
ADDED
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
|
2
|
+
name: schlick-active-matchers
|
|
3
|
+
version: !ruby/object:Gem::Version
|
|
4
|
+
version: 0.3.1.1
|
|
5
|
+
platform: ruby
|
|
6
|
+
authors:
|
|
7
|
+
- Pat Allan
|
|
8
|
+
autorequire: active-matchers
|
|
9
|
+
bindir: bin
|
|
10
|
+
cert_chain: []
|
|
11
|
+
|
|
12
|
+
date: 2008-07-02 00:00:00 -07:00
|
|
13
|
+
default_executable:
|
|
14
|
+
dependencies:
|
|
15
|
+
- !ruby/object:Gem::Dependency
|
|
16
|
+
name: activerecord
|
|
17
|
+
version_requirement:
|
|
18
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
19
|
+
requirements:
|
|
20
|
+
- - ">="
|
|
21
|
+
- !ruby/object:Gem::Version
|
|
22
|
+
version: "0"
|
|
23
|
+
version:
|
|
24
|
+
description: Helpful rspec matchers for testing validations and associations.
|
|
25
|
+
email: pat@freelancing-gods.com
|
|
26
|
+
executables: []
|
|
27
|
+
|
|
28
|
+
extensions: []
|
|
29
|
+
|
|
30
|
+
extra_rdoc_files:
|
|
31
|
+
- README
|
|
32
|
+
- LICENSE
|
|
33
|
+
files:
|
|
34
|
+
- README
|
|
35
|
+
- LICENSE
|
|
36
|
+
- Rakefile
|
|
37
|
+
- init.rb
|
|
38
|
+
- lib/active-matchers
|
|
39
|
+
- lib/active-matchers/assoc_reflection_methods.rb
|
|
40
|
+
- lib/active-matchers/matchers
|
|
41
|
+
- lib/active-matchers/matchers/association_matcher.rb
|
|
42
|
+
- lib/active-matchers/matchers/response_matchers.rb
|
|
43
|
+
- lib/active-matchers/matchers/validation_matcher.rb
|
|
44
|
+
- lib/active-matchers/matchers.rb
|
|
45
|
+
- lib/active-matchers.rb
|
|
46
|
+
has_rdoc: true
|
|
47
|
+
homepage: http://am.freelancing-gods.com
|
|
48
|
+
post_install_message:
|
|
49
|
+
rdoc_options: []
|
|
50
|
+
|
|
51
|
+
require_paths:
|
|
52
|
+
- lib
|
|
53
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
|
54
|
+
requirements:
|
|
55
|
+
- - ">="
|
|
56
|
+
- !ruby/object:Gem::Version
|
|
57
|
+
version: "0"
|
|
58
|
+
version:
|
|
59
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
|
60
|
+
requirements:
|
|
61
|
+
- - ">="
|
|
62
|
+
- !ruby/object:Gem::Version
|
|
63
|
+
version: "0"
|
|
64
|
+
version:
|
|
65
|
+
requirements: []
|
|
66
|
+
|
|
67
|
+
rubyforge_project:
|
|
68
|
+
rubygems_version: 1.2.0
|
|
69
|
+
signing_key:
|
|
70
|
+
specification_version: 2
|
|
71
|
+
summary: Helpful rspec matchers for testing validations and associations.
|
|
72
|
+
test_files: []
|
|
73
|
+
|