shoulda-matchers 2.5.0 → 2.6.0
Sign up to get free protection for your applications and to get access to all the features.
- data/.gitignore +8 -7
- data/.travis.yml +4 -0
- data/Appraisals +8 -0
- data/CONTRIBUTING.md +1 -1
- data/Gemfile +1 -1
- data/Gemfile.lock +77 -66
- data/MIT-LICENSE +1 -1
- data/NEWS.md +63 -1
- data/README.md +189 -33
- data/Rakefile +6 -5
- data/features/rails_integration.feature +1 -1
- data/features/step_definitions/rails_steps.rb +7 -6
- data/gemfiles/3.0.gemfile +2 -2
- data/gemfiles/3.0.gemfile.lock +14 -5
- data/gemfiles/3.1.gemfile +2 -2
- data/gemfiles/3.1.gemfile.lock +14 -5
- data/gemfiles/3.2.gemfile +2 -2
- data/gemfiles/3.2.gemfile.lock +16 -7
- data/gemfiles/4.0.0.gemfile +2 -2
- data/gemfiles/4.0.0.gemfile.lock +15 -6
- data/gemfiles/4.0.1.gemfile +2 -2
- data/gemfiles/4.0.1.gemfile.lock +15 -6
- data/gemfiles/4.1.gemfile +19 -0
- data/gemfiles/4.1.gemfile.lock +176 -0
- data/lib/shoulda/matchers.rb +17 -1
- data/lib/shoulda/matchers/action_controller.rb +4 -2
- data/lib/shoulda/matchers/action_controller/callback_matcher.rb +100 -0
- data/lib/shoulda/matchers/action_controller/redirect_to_matcher.rb +1 -1
- data/lib/shoulda/matchers/action_controller/render_template_matcher.rb +4 -4
- data/lib/shoulda/matchers/action_controller/rescue_from_matcher.rb +1 -1
- data/lib/shoulda/matchers/action_controller/route_matcher.rb +12 -12
- data/lib/shoulda/matchers/action_controller/route_params.rb +1 -1
- data/lib/shoulda/matchers/action_controller/set_the_flash_matcher.rb +2 -1
- data/lib/shoulda/matchers/action_controller/strong_parameters_matcher.rb +167 -0
- data/lib/shoulda/matchers/active_model.rb +4 -2
- data/lib/shoulda/matchers/active_model/allow_value_matcher.rb +23 -5
- data/lib/shoulda/matchers/active_model/disallow_value_matcher.rb +0 -4
- data/lib/shoulda/matchers/active_model/ensure_inclusion_of_matcher.rb +66 -14
- data/lib/shoulda/matchers/active_model/ensure_length_of_matcher.rb +8 -8
- data/lib/shoulda/matchers/active_model/errors.rb +40 -0
- data/lib/shoulda/matchers/active_model/helpers.rb +6 -6
- data/lib/shoulda/matchers/active_model/numericality_matchers/comparison_matcher.rb +33 -14
- data/lib/shoulda/matchers/active_model/numericality_matchers/even_number_matcher.rb +26 -0
- data/lib/shoulda/matchers/active_model/numericality_matchers/{odd_even_number_matcher.rb → numeric_type_matcher.rb} +9 -20
- data/lib/shoulda/matchers/active_model/numericality_matchers/odd_number_matcher.rb +26 -0
- data/lib/shoulda/matchers/active_model/numericality_matchers/only_integer_matcher.rb +5 -21
- data/lib/shoulda/matchers/active_model/validate_confirmation_of_matcher.rb +1 -1
- data/lib/shoulda/matchers/active_model/validate_numericality_of_matcher.rb +71 -22
- data/lib/shoulda/matchers/active_model/validate_presence_of_matcher.rb +6 -1
- data/lib/shoulda/matchers/active_model/validate_uniqueness_of_matcher.rb +25 -6
- data/lib/shoulda/matchers/active_record.rb +1 -0
- data/lib/shoulda/matchers/active_record/association_matcher.rb +67 -13
- data/lib/shoulda/matchers/active_record/association_matchers/inverse_of_matcher.rb +40 -0
- data/lib/shoulda/matchers/active_record/association_matchers/model_reflection.rb +24 -1
- data/lib/shoulda/matchers/active_record/association_matchers/model_reflector.rb +1 -1
- data/lib/shoulda/matchers/active_record/have_db_column_matcher.rb +1 -1
- data/lib/shoulda/matchers/active_record/have_db_index_matcher.rb +1 -1
- data/lib/shoulda/matchers/assertion_error.rb +7 -2
- data/lib/shoulda/matchers/error.rb +24 -0
- data/lib/shoulda/matchers/independent.rb +10 -0
- data/lib/shoulda/matchers/independent/delegate_matcher.rb +157 -0
- data/lib/shoulda/matchers/independent/delegate_matcher/stubbed_target.rb +34 -0
- data/lib/shoulda/matchers/integrations/nunit_test_case_detection.rb +36 -0
- data/lib/shoulda/matchers/integrations/rspec.rb +13 -14
- data/lib/shoulda/matchers/integrations/test_unit.rb +11 -9
- data/lib/shoulda/matchers/version.rb +1 -1
- data/lib/shoulda/matchers/warn.rb +7 -0
- data/shoulda-matchers.gemspec +2 -1
- data/spec/shoulda/matchers/action_controller/callback_matcher_spec.rb +79 -0
- data/spec/shoulda/matchers/action_controller/filter_param_matcher_spec.rb +3 -3
- data/spec/shoulda/matchers/action_controller/redirect_to_matcher_spec.rb +11 -11
- data/spec/shoulda/matchers/action_controller/render_template_matcher_spec.rb +21 -21
- data/spec/shoulda/matchers/action_controller/render_with_layout_matcher_spec.rb +10 -10
- data/spec/shoulda/matchers/action_controller/rescue_from_matcher_spec.rb +45 -18
- data/spec/shoulda/matchers/action_controller/respond_with_matcher_spec.rb +8 -8
- data/spec/shoulda/matchers/action_controller/route_matcher_spec.rb +19 -19
- data/spec/shoulda/matchers/action_controller/route_params_spec.rb +6 -6
- data/spec/shoulda/matchers/action_controller/set_session_matcher_spec.rb +11 -11
- data/spec/shoulda/matchers/action_controller/set_the_flash_matcher_spec.rb +44 -44
- data/spec/shoulda/matchers/action_controller/strong_parameters_matcher_spec.rb +205 -0
- data/spec/shoulda/matchers/active_model/allow_mass_assignment_of_matcher_spec.rb +24 -24
- data/spec/shoulda/matchers/active_model/allow_value_matcher_spec.rb +37 -37
- data/spec/shoulda/matchers/active_model/disallow_value_matcher_spec.rb +17 -21
- data/spec/shoulda/matchers/active_model/ensure_exclusion_of_matcher_spec.rb +24 -24
- data/spec/shoulda/matchers/active_model/ensure_inclusion_of_matcher_spec.rb +173 -67
- data/spec/shoulda/matchers/active_model/ensure_length_of_matcher_spec.rb +40 -40
- data/spec/shoulda/matchers/active_model/exception_message_finder_spec.rb +20 -20
- data/spec/shoulda/matchers/active_model/helpers_spec.rb +27 -25
- data/spec/shoulda/matchers/active_model/numericality_matchers/comparison_matcher_spec.rb +126 -13
- data/spec/shoulda/matchers/active_model/numericality_matchers/even_number_matcher_spec.rb +59 -0
- data/spec/shoulda/matchers/active_model/numericality_matchers/odd_number_matcher_spec.rb +59 -0
- data/spec/shoulda/matchers/active_model/numericality_matchers/only_integer_matcher_spec.rb +27 -26
- data/spec/shoulda/matchers/active_model/validate_absence_of_matcher_spec.rb +15 -15
- data/spec/shoulda/matchers/active_model/validate_acceptance_of_matcher_spec.rb +8 -8
- data/spec/shoulda/matchers/active_model/validate_confirmation_of_matcher_spec.rb +9 -9
- data/spec/shoulda/matchers/active_model/validate_numericality_of_matcher_spec.rb +229 -44
- data/spec/shoulda/matchers/active_model/validate_presence_of_matcher_spec.rb +44 -25
- data/spec/shoulda/matchers/active_model/validate_uniqueness_of_matcher_spec.rb +110 -62
- data/spec/shoulda/matchers/active_model/validation_message_finder_spec.rb +19 -19
- data/spec/shoulda/matchers/active_record/accept_nested_attributes_for_matcher_spec.rb +30 -30
- data/spec/shoulda/matchers/active_record/association_matcher_spec.rb +378 -192
- data/spec/shoulda/matchers/active_record/association_matchers/model_reflection_spec.rb +4 -0
- data/spec/shoulda/matchers/active_record/have_db_column_matcher_spec.rb +33 -33
- data/spec/shoulda/matchers/active_record/have_db_index_matcher_spec.rb +21 -17
- data/spec/shoulda/matchers/active_record/have_readonly_attributes_matcher_spec.rb +8 -8
- data/spec/shoulda/matchers/active_record/serialize_matcher_spec.rb +14 -14
- data/spec/shoulda/matchers/independent/delegate_matcher/stubbed_target_spec.rb +43 -0
- data/spec/shoulda/matchers/independent/delegate_matcher_spec.rb +184 -0
- data/spec/spec_helper.rb +4 -0
- data/spec/support/activemodel_helpers.rb +2 -2
- data/spec/support/capture_helpers.rb +19 -0
- data/spec/support/controller_builder.rb +22 -3
- data/spec/support/fail_with_message_including_matcher.rb +33 -0
- data/spec/support/model_builder.rb +1 -1
- data/spec/support/shared_examples/numerical_submatcher.rb +19 -0
- data/spec/support/shared_examples/numerical_type_submatcher.rb +17 -0
- data/spec/support/test_application.rb +23 -0
- metadata +90 -22
- checksums.yaml +0 -7
- data/spec/shoulda/matchers/active_model/numericality_matchers/odd_even_number_matcher_spec.rb +0 -97
- data/spec/support/shared_examples/numerical_submatcher_spec.rb +0 -23
@@ -46,7 +46,7 @@ module Shoulda # :nodoc:
|
|
46
46
|
|
47
47
|
def redirects_to_url?
|
48
48
|
begin
|
49
|
-
@context.
|
49
|
+
@context.__send__(:assert_redirected_to, url)
|
50
50
|
@failure_message_when_negated = "Didn't expect to redirect to #{url}"
|
51
51
|
true
|
52
52
|
rescue Shoulda::Matchers::AssertionError => error
|
@@ -8,13 +8,13 @@ module Shoulda # :nodoc:
|
|
8
8
|
# it { should render_template(:show) }
|
9
9
|
#
|
10
10
|
# assert that the "_customer" partial was rendered
|
11
|
-
# it { should render_template(:
|
11
|
+
# it { should render_template(partial: '_customer') }
|
12
12
|
#
|
13
13
|
# assert that the "_customer" partial was rendered twice
|
14
|
-
# it { should render_template(:
|
14
|
+
# it { should render_template(partial: '_customer', count: 2) }
|
15
15
|
#
|
16
16
|
# assert that no partials were rendered
|
17
|
-
# it { should render_template(:
|
17
|
+
# it { should render_template(partial: false) }
|
18
18
|
def render_template(options = {}, message = nil)
|
19
19
|
RenderTemplateMatcher.new(options, message, self)
|
20
20
|
end
|
@@ -50,7 +50,7 @@ module Shoulda # :nodoc:
|
|
50
50
|
|
51
51
|
def renders_template?
|
52
52
|
begin
|
53
|
-
@context.
|
53
|
+
@context.__send__(:assert_template, @options, @message)
|
54
54
|
@failure_message_when_negated = "Didn't expect to render #{@template}"
|
55
55
|
true
|
56
56
|
rescue Shoulda::Matchers::AssertionError => error
|
@@ -12,20 +12,20 @@ module Shoulda # :nodoc:
|
|
12
12
|
# Examples:
|
13
13
|
#
|
14
14
|
# it { should route(:get, '/posts').
|
15
|
-
# to(:
|
15
|
+
# to(controller: :posts, action: :index) }
|
16
16
|
# it { should route(:get, '/posts').to('posts#index') }
|
17
|
-
# it { should route(:get, '/posts/new').to(:
|
18
|
-
# it { should route(:post, '/posts').to(:
|
19
|
-
# it { should route(:get, '/posts/1').to(:
|
20
|
-
# it { should route(:get, '/posts/1').to('posts#show', :
|
21
|
-
# it { should route(:get, '/posts/1/edit').to(:
|
22
|
-
# it { should route(:put, '/posts/1').to(:
|
17
|
+
# it { should route(:get, '/posts/new').to(action: :new) }
|
18
|
+
# it { should route(:post, '/posts').to(action: :create) }
|
19
|
+
# it { should route(:get, '/posts/1').to(action: :show, id: 1) }
|
20
|
+
# it { should route(:get, '/posts/1').to('posts#show', id: 1) }
|
21
|
+
# it { should route(:get, '/posts/1/edit').to(action: :edit, id: 1) }
|
22
|
+
# it { should route(:put, '/posts/1').to(action: :update, id: 1) }
|
23
23
|
# it { should route(:delete, '/posts/1').
|
24
|
-
# to(:
|
24
|
+
# to(action: :destroy, id: 1) }
|
25
25
|
# it { should route(:get, '/users/1/posts/1').
|
26
|
-
# to(:
|
26
|
+
# to(action: :show, id: 1, user_id: 1) }
|
27
27
|
# it { should route(:get, '/users/1/posts/1').
|
28
|
-
# to('posts#show', :
|
28
|
+
# to('posts#show', id: 1, user_id: 1) }
|
29
29
|
def route(method, path)
|
30
30
|
RouteMatcher.new(method, path, self)
|
31
31
|
end
|
@@ -70,8 +70,8 @@ module Shoulda # :nodoc:
|
|
70
70
|
|
71
71
|
def route_recognized?
|
72
72
|
begin
|
73
|
-
@context.
|
74
|
-
{ :
|
73
|
+
@context.__send__(:assert_routing,
|
74
|
+
{ method: @method, path: @path },
|
75
75
|
@params)
|
76
76
|
|
77
77
|
@failure_message_when_negated = "Didn't expect to #{description}"
|
@@ -25,7 +25,7 @@ module Shoulda # :nodoc:
|
|
25
25
|
def extract_params_from_string
|
26
26
|
params = args[1] || {}
|
27
27
|
controller, action = args[0].split('#')
|
28
|
-
params.merge!(:
|
28
|
+
params.merge!(controller: controller, action: action)
|
29
29
|
end
|
30
30
|
|
31
31
|
def stringify_params
|
@@ -0,0 +1,167 @@
|
|
1
|
+
begin
|
2
|
+
require 'strong_parameters'
|
3
|
+
rescue LoadError
|
4
|
+
end
|
5
|
+
|
6
|
+
module Shoulda
|
7
|
+
module Matchers
|
8
|
+
module ActionController
|
9
|
+
def permit(*attributes)
|
10
|
+
StrongParametersMatcher.new(self, attributes)
|
11
|
+
end
|
12
|
+
|
13
|
+
class StrongParametersMatcher
|
14
|
+
def self.stubbed_parameters_class
|
15
|
+
@stubbed_parameters_class ||= build_stubbed_parameters_class
|
16
|
+
end
|
17
|
+
|
18
|
+
def self.build_stubbed_parameters_class
|
19
|
+
Class.new(::ActionController::Parameters) do
|
20
|
+
include StubbedParameters
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
def initialize(context = nil, attributes)
|
25
|
+
@attributes = attributes
|
26
|
+
@context = context
|
27
|
+
end
|
28
|
+
|
29
|
+
def for(action, options = {})
|
30
|
+
@action = action
|
31
|
+
@verb = options[:verb] || verb_for_action
|
32
|
+
self
|
33
|
+
end
|
34
|
+
|
35
|
+
def in_context(context)
|
36
|
+
@context = context
|
37
|
+
self
|
38
|
+
end
|
39
|
+
|
40
|
+
def description
|
41
|
+
"permit #{verb.upcase} ##{action} to receive parameters #{attributes_as_sentence}"
|
42
|
+
end
|
43
|
+
|
44
|
+
def matches?(controller = nil)
|
45
|
+
simulate_controller_action && parameters_difference.empty?
|
46
|
+
end
|
47
|
+
|
48
|
+
def does_not_match?(controller = nil)
|
49
|
+
simulate_controller_action && parameters_intersection.empty?
|
50
|
+
end
|
51
|
+
|
52
|
+
def failure_message
|
53
|
+
"Expected controller to permit #{parameters_difference.to_sentence}, but it did not."
|
54
|
+
end
|
55
|
+
alias failure_message_for_should failure_message
|
56
|
+
|
57
|
+
def failure_message_when_negated
|
58
|
+
"Expected controller not to permit #{parameters_intersection.to_sentence}, but it did."
|
59
|
+
end
|
60
|
+
alias failure_message_for_should_not failure_message_when_negated
|
61
|
+
|
62
|
+
private
|
63
|
+
|
64
|
+
attr_reader :verb, :action, :attributes, :context
|
65
|
+
|
66
|
+
def simulate_controller_action
|
67
|
+
ensure_action_and_verb_present!
|
68
|
+
stub_model_attributes
|
69
|
+
|
70
|
+
begin
|
71
|
+
context.send(verb, action)
|
72
|
+
ensure
|
73
|
+
unstub_model_attributes
|
74
|
+
end
|
75
|
+
|
76
|
+
verify_permit_call
|
77
|
+
end
|
78
|
+
|
79
|
+
def verify_permit_call
|
80
|
+
@model_attrs.permit_was_called
|
81
|
+
end
|
82
|
+
|
83
|
+
def parameters_difference
|
84
|
+
attributes - @model_attrs.shoulda_permitted_params
|
85
|
+
end
|
86
|
+
|
87
|
+
def parameters_intersection
|
88
|
+
attributes & @model_attrs.shoulda_permitted_params
|
89
|
+
end
|
90
|
+
|
91
|
+
def stub_model_attributes
|
92
|
+
@model_attrs = self.class.stubbed_parameters_class.new(arbitrary_attributes)
|
93
|
+
|
94
|
+
local_model_attrs = @model_attrs
|
95
|
+
::ActionController::Parameters.class_eval do
|
96
|
+
alias_method :'shoulda_original_[]', :[]
|
97
|
+
|
98
|
+
define_method :[] do |*args|
|
99
|
+
local_model_attrs
|
100
|
+
end
|
101
|
+
end
|
102
|
+
end
|
103
|
+
|
104
|
+
def unstub_model_attributes
|
105
|
+
::ActionController::Parameters.class_eval do
|
106
|
+
alias_method :[], :'shoulda_original_[]'
|
107
|
+
undef_method :'shoulda_original_[]'
|
108
|
+
end
|
109
|
+
end
|
110
|
+
|
111
|
+
def ensure_action_and_verb_present!
|
112
|
+
if action.blank?
|
113
|
+
raise ActionNotDefinedError
|
114
|
+
end
|
115
|
+
if verb.blank?
|
116
|
+
raise VerbNotDefinedError
|
117
|
+
end
|
118
|
+
end
|
119
|
+
|
120
|
+
def arbitrary_attributes
|
121
|
+
{any_key: 'any_value'}
|
122
|
+
end
|
123
|
+
|
124
|
+
def verb_for_action
|
125
|
+
verb_lookup = { create: :post, update: :put }
|
126
|
+
verb_lookup[action]
|
127
|
+
end
|
128
|
+
|
129
|
+
def attributes_as_sentence
|
130
|
+
attributes.map(&:inspect).to_sentence
|
131
|
+
end
|
132
|
+
end
|
133
|
+
|
134
|
+
module StrongParametersMatcher::StubbedParameters
|
135
|
+
extend ActiveSupport::Concern
|
136
|
+
|
137
|
+
included do
|
138
|
+
attr_accessor :permit_was_called, :shoulda_permitted_params
|
139
|
+
end
|
140
|
+
|
141
|
+
def initialize(*)
|
142
|
+
@permit_was_called = false
|
143
|
+
super
|
144
|
+
end
|
145
|
+
|
146
|
+
def permit(*args)
|
147
|
+
self.shoulda_permitted_params = args
|
148
|
+
self.permit_was_called = true
|
149
|
+
nil
|
150
|
+
end
|
151
|
+
end
|
152
|
+
|
153
|
+
class StrongParametersMatcher::ActionNotDefinedError < StandardError
|
154
|
+
def message
|
155
|
+
'You must specify the controller action using the #for method.'
|
156
|
+
end
|
157
|
+
end
|
158
|
+
|
159
|
+
class StrongParametersMatcher::VerbNotDefinedError < StandardError
|
160
|
+
def message
|
161
|
+
'You must specify an HTTP verb when using a non-RESTful action.' +
|
162
|
+
' e.g. for(:authorize, verb: :post)'
|
163
|
+
end
|
164
|
+
end
|
165
|
+
end
|
166
|
+
end
|
167
|
+
end
|
@@ -13,8 +13,10 @@ require 'shoulda/matchers/active_model/validate_uniqueness_of_matcher'
|
|
13
13
|
require 'shoulda/matchers/active_model/validate_acceptance_of_matcher'
|
14
14
|
require 'shoulda/matchers/active_model/validate_confirmation_of_matcher'
|
15
15
|
require 'shoulda/matchers/active_model/validate_numericality_of_matcher'
|
16
|
+
require 'shoulda/matchers/active_model/numericality_matchers/numeric_type_matcher'
|
16
17
|
require 'shoulda/matchers/active_model/numericality_matchers/comparison_matcher'
|
17
|
-
require 'shoulda/matchers/active_model/numericality_matchers/
|
18
|
+
require 'shoulda/matchers/active_model/numericality_matchers/odd_number_matcher'
|
19
|
+
require 'shoulda/matchers/active_model/numericality_matchers/even_number_matcher'
|
18
20
|
require 'shoulda/matchers/active_model/numericality_matchers/only_integer_matcher'
|
19
21
|
require 'shoulda/matchers/active_model/allow_mass_assignment_of_matcher'
|
20
22
|
require 'shoulda/matchers/active_model/errors'
|
@@ -44,7 +46,7 @@ module Shoulda
|
|
44
46
|
# class User < ActiveRecord::Base
|
45
47
|
# validates_presence_of :name
|
46
48
|
# validates_presence_of :phone_number
|
47
|
-
# validates_inclusion_of :status, :
|
49
|
+
# validates_inclusion_of :status, in: %w(Activated Pending), strict: true
|
48
50
|
# attr_accessible :name, :phone_number
|
49
51
|
# end
|
50
52
|
module ActiveModel
|
@@ -13,7 +13,7 @@ module Shoulda # :nodoc:
|
|
13
13
|
# the test looks for any errors in <tt>errors.on(:attribute)</tt>.
|
14
14
|
# * <tt>strict</tt> - expects the model to raise an exception when the
|
15
15
|
# validation fails rather than adding to the errors collection. Used for
|
16
|
-
# testing `validates!` and the
|
16
|
+
# testing `validates!` and the `strict: true` validation options.
|
17
17
|
#
|
18
18
|
# Example:
|
19
19
|
# it { should_not allow_value('bad').for(:isbn) }
|
@@ -68,7 +68,7 @@ module Shoulda # :nodoc:
|
|
68
68
|
|
69
69
|
values_to_match.none? do |value|
|
70
70
|
self.value = value
|
71
|
-
|
71
|
+
set_and_double_check_attribute!(attribute_to_set, value)
|
72
72
|
errors_match?
|
73
73
|
end
|
74
74
|
end
|
@@ -93,6 +93,24 @@ module Shoulda # :nodoc:
|
|
93
93
|
:instance, :attribute_to_set, :attribute_to_check_message_against,
|
94
94
|
:context, :value, :matched_error
|
95
95
|
|
96
|
+
def set_and_double_check_attribute!(attribute_name, value)
|
97
|
+
instance.__send__("#{attribute_name}=", value)
|
98
|
+
|
99
|
+
if value.nil?
|
100
|
+
ensure_attribute_was_cleared!(attribute_name)
|
101
|
+
end
|
102
|
+
end
|
103
|
+
|
104
|
+
def ensure_attribute_was_cleared!(attribute_name)
|
105
|
+
if instance.respond_to?(attribute_name)
|
106
|
+
actual_value = instance.__send__(attribute_name)
|
107
|
+
|
108
|
+
if !actual_value.nil?
|
109
|
+
raise Shoulda::Matchers::ActiveModel::CouldNotClearAttribute.create(actual_value)
|
110
|
+
end
|
111
|
+
end
|
112
|
+
end
|
113
|
+
|
96
114
|
def errors_match?
|
97
115
|
has_messages? && errors_for_attribute_match?
|
98
116
|
end
|
@@ -163,9 +181,9 @@ module Shoulda # :nodoc:
|
|
163
181
|
def default_attribute_message
|
164
182
|
default_error_message(
|
165
183
|
options[:expected_message],
|
166
|
-
:
|
167
|
-
:
|
168
|
-
:
|
184
|
+
model_name: model_name,
|
185
|
+
instance: instance,
|
186
|
+
attribute: attribute_to_set
|
169
187
|
)
|
170
188
|
end
|
171
189
|
|
@@ -25,6 +25,25 @@ module Shoulda # :nodoc:
|
|
25
25
|
ARBITRARY_OUTSIDE_STRING = 'shouldamatchersteststring'
|
26
26
|
ARBITRARY_OUTSIDE_FIXNUM = 123456789
|
27
27
|
ARBITRARY_OUTSIDE_DECIMAL = 0.123456789
|
28
|
+
BOOLEAN_ALLOWS_BOOLEAN_MESSAGE = <<EOT
|
29
|
+
You are using `ensure_inclusion_of` to assert that a boolean column allows
|
30
|
+
boolean values and disallows non-boolean ones. Assuming you are using
|
31
|
+
`validates_format_of` in your model, be aware that it is not possible to fully
|
32
|
+
test this, and in fact the validation is superfluous, as boolean columns will
|
33
|
+
automatically convert non-boolean values to boolean ones. Hence, you should
|
34
|
+
consider removing this test and the corresponding validation.
|
35
|
+
EOT
|
36
|
+
BOOLEAN_ALLOWS_NIL_MESSAGE = <<EOT
|
37
|
+
You are using `ensure_inclusion_of` to assert that a boolean column allows nil.
|
38
|
+
Be aware that it is not possible to fully test this, as anything other than
|
39
|
+
true, false or nil will be converted to false. Hence, you should consider
|
40
|
+
removing this test and the corresponding validation.
|
41
|
+
EOT
|
42
|
+
BOOLEAN_ALLOWS_NIL_WITH_NOT_NULL_MESSAGE = <<EOT
|
43
|
+
You have specified that your model's #{@attribute} should ensure inclusion of nil.
|
44
|
+
However, #{@attribute} is a boolean column which does not allow null values.
|
45
|
+
Hence, this test will fail and there is no way to make it pass.
|
46
|
+
EOT
|
28
47
|
|
29
48
|
def initialize(attribute)
|
30
49
|
super(attribute)
|
@@ -142,30 +161,63 @@ module Shoulda # :nodoc:
|
|
142
161
|
end
|
143
162
|
|
144
163
|
def disallows_value_outside_of_array?
|
145
|
-
|
164
|
+
if attribute_column.type == :boolean
|
165
|
+
case @array
|
166
|
+
when [true, false]
|
167
|
+
Shoulda::Matchers.warn BOOLEAN_ALLOWS_BOOLEAN_MESSAGE
|
168
|
+
return true
|
169
|
+
when [nil]
|
170
|
+
if attribute_column.null
|
171
|
+
Shoulda::Matchers.warn BOOLEAN_ALLOWS_NIL_MESSAGE
|
172
|
+
return true
|
173
|
+
else
|
174
|
+
raise NonNullableBooleanError, BOOLEAN_ALLOWS_NIL_WITH_NOT_NULL_MESSAGE
|
175
|
+
end
|
176
|
+
end
|
177
|
+
end
|
178
|
+
|
179
|
+
!allows_value_of(*values_outside_of_array)
|
146
180
|
end
|
147
181
|
|
148
|
-
def
|
149
|
-
if @array.
|
182
|
+
def values_outside_of_array
|
183
|
+
if !(@array & outside_values).empty?
|
150
184
|
raise CouldNotDetermineValueOutsideOfArray
|
151
185
|
else
|
152
|
-
|
186
|
+
outside_values
|
153
187
|
end
|
154
188
|
end
|
155
189
|
|
156
|
-
def
|
157
|
-
|
190
|
+
def outside_values
|
191
|
+
case attribute_column.type
|
192
|
+
when :boolean
|
193
|
+
boolean_outside_values
|
194
|
+
when :integer, :float
|
195
|
+
[ARBITRARY_OUTSIDE_FIXNUM]
|
196
|
+
when :decimal
|
197
|
+
[ARBITRARY_OUTSIDE_DECIMAL]
|
198
|
+
else
|
199
|
+
[ARBITRARY_OUTSIDE_STRING]
|
200
|
+
end
|
158
201
|
end
|
159
202
|
|
160
|
-
def
|
161
|
-
|
162
|
-
|
163
|
-
|
164
|
-
|
165
|
-
|
166
|
-
|
167
|
-
|
203
|
+
def boolean_outside_values
|
204
|
+
values = []
|
205
|
+
|
206
|
+
values << case @array
|
207
|
+
when [true] then false
|
208
|
+
when [false] then true
|
209
|
+
else raise CouldNotDetermineValueOutsideOfArray
|
210
|
+
end
|
211
|
+
|
212
|
+
if attribute_column.null
|
213
|
+
values << nil
|
168
214
|
end
|
215
|
+
|
216
|
+
values
|
217
|
+
end
|
218
|
+
|
219
|
+
def attribute_column
|
220
|
+
@subject.class.columns_hash[@attribute.to_s]
|
169
221
|
end
|
170
222
|
end
|
171
223
|
end
|