shoulda-matchers 2.6.0 → 2.6.1.rc1
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/Gemfile.lock +1 -1
- data/NEWS.md +34 -0
- data/README.md +14 -0
- data/features/activemodel_integration.feature +15 -0
- data/features/step_definitions/activemodel_steps.rb +21 -0
- data/gemfiles/3.0.gemfile.lock +1 -1
- data/gemfiles/3.1.gemfile.lock +1 -1
- data/gemfiles/3.2.gemfile.lock +1 -1
- data/gemfiles/4.0.0.gemfile.lock +1 -1
- data/gemfiles/4.0.1.gemfile.lock +1 -1
- data/gemfiles/4.1.gemfile.lock +1 -1
- data/lib/shoulda/matchers.rb +1 -0
- data/lib/shoulda/matchers/action_controller/callback_matcher.rb +11 -6
- data/lib/shoulda/matchers/action_controller/strong_parameters_matcher.rb +59 -95
- data/lib/shoulda/matchers/active_model/allow_value_matcher.rb +10 -18
- data/lib/shoulda/matchers/active_model/disallow_value_matcher.rb +10 -0
- data/lib/shoulda/matchers/active_model/ensure_inclusion_of_matcher.rb +60 -18
- data/lib/shoulda/matchers/active_model/errors.rb +9 -7
- data/lib/shoulda/matchers/active_model/numericality_matchers/comparison_matcher.rb +4 -0
- data/lib/shoulda/matchers/active_model/validate_presence_of_matcher.rb +24 -5
- data/lib/shoulda/matchers/doublespeak.rb +27 -0
- data/lib/shoulda/matchers/doublespeak/double.rb +74 -0
- data/lib/shoulda/matchers/doublespeak/double_collection.rb +54 -0
- data/lib/shoulda/matchers/doublespeak/double_implementation_registry.rb +27 -0
- data/lib/shoulda/matchers/doublespeak/object_double.rb +32 -0
- data/lib/shoulda/matchers/doublespeak/proxy_implementation.rb +30 -0
- data/lib/shoulda/matchers/doublespeak/structs.rb +8 -0
- data/lib/shoulda/matchers/doublespeak/stub_implementation.rb +34 -0
- data/lib/shoulda/matchers/doublespeak/world.rb +38 -0
- data/lib/shoulda/matchers/independent/delegate_matcher.rb +112 -61
- data/lib/shoulda/matchers/integrations/test_unit.rb +8 -6
- data/lib/shoulda/matchers/rails_shim.rb +16 -0
- data/lib/shoulda/matchers/version.rb +1 -1
- data/spec/shoulda/matchers/action_controller/callback_matcher_spec.rb +22 -19
- data/spec/shoulda/matchers/action_controller/strong_parameters_matcher_spec.rb +174 -65
- data/spec/shoulda/matchers/active_model/allow_value_matcher_spec.rb +14 -0
- data/spec/shoulda/matchers/active_model/ensure_inclusion_of_matcher_spec.rb +553 -211
- data/spec/shoulda/matchers/active_model/numericality_matchers/comparison_matcher_spec.rb +6 -0
- data/spec/shoulda/matchers/active_model/validate_numericality_of_matcher_spec.rb +22 -0
- data/spec/shoulda/matchers/active_model/validate_presence_of_matcher_spec.rb +23 -4
- data/spec/shoulda/matchers/doublespeak/double_collection_spec.rb +102 -0
- data/spec/shoulda/matchers/doublespeak/double_implementation_registry_spec.rb +21 -0
- data/spec/shoulda/matchers/doublespeak/double_spec.rb +144 -0
- data/spec/shoulda/matchers/doublespeak/object_double_spec.rb +77 -0
- data/spec/shoulda/matchers/doublespeak/proxy_implementation_spec.rb +40 -0
- data/spec/shoulda/matchers/doublespeak/stub_implementation_spec.rb +88 -0
- data/spec/shoulda/matchers/doublespeak/world_spec.rb +88 -0
- data/spec/shoulda/matchers/doublespeak_spec.rb +19 -0
- data/spec/shoulda/matchers/independent/delegate_matcher_spec.rb +105 -39
- data/spec/support/controller_builder.rb +18 -9
- data/spec/support/rails_versions.rb +4 -0
- metadata +34 -8
data/Gemfile.lock
CHANGED
data/NEWS.md
CHANGED
@@ -1,3 +1,37 @@
|
|
1
|
+
# HEAD
|
2
|
+
|
3
|
+
* Fix `ComparisonMatcher` so that `validate_numericality_of` comparison matchers
|
4
|
+
work with large numbers.
|
5
|
+
|
6
|
+
* Fix so that ActiveRecord matchers aren't included when ActiveRecord
|
7
|
+
isn't defined (i.e. if you are using ActiveModel only).
|
8
|
+
|
9
|
+
* Revert the behavior of `allow_value` changed in 2.6.0 (it will no longer raise
|
10
|
+
CouldNotClearAttribute). This was originally done as a part of a fix for
|
11
|
+
`validate_presence_of` when used in conjunction with `has_secure_password`.
|
12
|
+
That fix has been updated so that it does not affect `allow_value`.
|
13
|
+
|
14
|
+
* Fix callback matchers and correct test coverage.
|
15
|
+
|
16
|
+
* Fix `permit` so that it does not interfere with different usages of `params`
|
17
|
+
in your controller action. Specifically, this will not raise an error:
|
18
|
+
`params.fetch(:foo, {}).permit(:bar, :baz)` (the `permit` will have no
|
19
|
+
problems recognizing that :bar and :baz are permitted params).
|
20
|
+
|
21
|
+
* Fix `permit` on Rails 4.1 to use PATCH by default for #update instead of PUT.
|
22
|
+
Previously you had to specify this manually.
|
23
|
+
|
24
|
+
* Fix `permit` so that it track multiple calls to #permit in your controller
|
25
|
+
action. Previously only the last usage of #permit would be considered in
|
26
|
+
determining whether the matcher matched.
|
27
|
+
|
28
|
+
* Fix `permit` so that if the route for your action requires params (such as id)
|
29
|
+
then you can now specify those params:
|
30
|
+
`permit(:first_name, :last_name).for(:update, params: { id: 42 })`.
|
31
|
+
|
32
|
+
* Fix `delegate_method` so that it does not stub the target method forever,
|
33
|
+
returning it to its original implementation after the match ends.
|
34
|
+
|
1
35
|
# 2.6.0
|
2
36
|
|
3
37
|
* The boolean argument to `have_db_index`'s `unique` option is now optional, for
|
data/README.md
CHANGED
@@ -18,6 +18,20 @@ group :test do
|
|
18
18
|
end
|
19
19
|
```
|
20
20
|
|
21
|
+
Note that if you're using a Rails preloader like Spring, you'll need to manually
|
22
|
+
require shoulda-matchers in your spec_helper after you require RSpec:
|
23
|
+
|
24
|
+
```ruby
|
25
|
+
# Gemfile
|
26
|
+
group :test do
|
27
|
+
gem 'shoulda-matchers', require: false
|
28
|
+
end
|
29
|
+
|
30
|
+
# spec_helper
|
31
|
+
require 'rspec/rails'
|
32
|
+
require 'shoulda/matchers'
|
33
|
+
```
|
34
|
+
|
21
35
|
### Test::Unit
|
22
36
|
|
23
37
|
shoulda-matchers was originally a component of
|
@@ -0,0 +1,15 @@
|
|
1
|
+
Feature: integration with ActiveModel
|
2
|
+
|
3
|
+
Scenario: create a new project using matchers
|
4
|
+
When I generate a new ActiveModel application
|
5
|
+
And I configure the application to use "shoulda-matchers" from this project
|
6
|
+
And I write to "load_dependencies.rb" with:
|
7
|
+
"""
|
8
|
+
require 'active_model'
|
9
|
+
require 'shoulda-matchers'
|
10
|
+
|
11
|
+
puts ActiveModel::VERSION::STRING
|
12
|
+
puts "Loaded all dependencies without errors"
|
13
|
+
"""
|
14
|
+
When I successfully run `bundle exec ruby load_dependencies.rb`
|
15
|
+
Then the output should contain "Loaded all dependencies without errors"
|
@@ -0,0 +1,21 @@
|
|
1
|
+
When 'I generate a new ActiveModel application' do
|
2
|
+
steps %{
|
3
|
+
When I run `mkdir #{APP_NAME}`
|
4
|
+
And I cd to "#{APP_NAME}"
|
5
|
+
And I run `bundle init`
|
6
|
+
}
|
7
|
+
|
8
|
+
# Figure out the ActiveModel version to use by reusing the Rails version from
|
9
|
+
# the Appraise gemfile.
|
10
|
+
if match = File.read(ENV['BUNDLE_GEMFILE']).match(/^gem "rails", "(.*)"/)
|
11
|
+
append_to_gemfile %(gem 'activemodel', '#{ match[1] }')
|
12
|
+
else
|
13
|
+
puts "Couldn't determine which ActiveModel version to load; using latest"
|
14
|
+
append_to_gemfile %(gem 'activemodel')
|
15
|
+
end
|
16
|
+
|
17
|
+
steps %{
|
18
|
+
And I set the "BUNDLE_GEMFILE" environment variable to "Gemfile"
|
19
|
+
And I install gems
|
20
|
+
}
|
21
|
+
end
|
data/gemfiles/3.0.gemfile.lock
CHANGED
data/gemfiles/3.1.gemfile.lock
CHANGED
data/gemfiles/3.2.gemfile.lock
CHANGED
data/gemfiles/4.0.0.gemfile.lock
CHANGED
data/gemfiles/4.0.1.gemfile.lock
CHANGED
data/gemfiles/4.1.gemfile.lock
CHANGED
data/lib/shoulda/matchers.rb
CHANGED
@@ -68,18 +68,20 @@ module Shoulda # :nodoc:
|
|
68
68
|
@callback_type = callback_type
|
69
69
|
end
|
70
70
|
|
71
|
-
def matches?(
|
72
|
-
@
|
71
|
+
def matches?(controller)
|
72
|
+
@controller = controller
|
73
|
+
@controller_class = controller.class
|
74
|
+
|
73
75
|
callbacks.map(&:filter).include?(method_name)
|
74
76
|
end
|
75
77
|
|
76
78
|
def failure_message
|
77
|
-
"Expected that #{
|
79
|
+
"Expected that #{controller_class.name} would have :#{method_name} as a #{kind}_#{callback_type}"
|
78
80
|
end
|
79
81
|
alias failure_message_for_should failure_message
|
80
82
|
|
81
83
|
def failure_message_when_negated
|
82
|
-
"Expected that #{
|
84
|
+
"Expected that #{controller_class.name} would not have :#{method_name} as a #{kind}_#{callback_type}"
|
83
85
|
end
|
84
86
|
alias failure_message_for_should_not failure_message_when_negated
|
85
87
|
|
@@ -90,10 +92,13 @@ module Shoulda # :nodoc:
|
|
90
92
|
private
|
91
93
|
|
92
94
|
def callbacks
|
93
|
-
|
95
|
+
controller_class._process_action_callbacks.select do |callback|
|
96
|
+
callback.kind == kind
|
97
|
+
end
|
94
98
|
end
|
95
99
|
|
96
|
-
attr_reader :method_name, :
|
100
|
+
attr_reader :method_name, :controller, :controller_class, :kind,
|
101
|
+
:callback_type
|
97
102
|
end
|
98
103
|
end
|
99
104
|
end
|
@@ -1,34 +1,34 @@
|
|
1
|
+
require 'delegate'
|
2
|
+
|
1
3
|
begin
|
2
4
|
require 'strong_parameters'
|
3
5
|
rescue LoadError
|
4
6
|
end
|
5
7
|
|
8
|
+
require 'active_support/hash_with_indifferent_access'
|
9
|
+
|
6
10
|
module Shoulda
|
7
11
|
module Matchers
|
8
12
|
module ActionController
|
9
|
-
def permit(*
|
10
|
-
StrongParametersMatcher.new(self
|
13
|
+
def permit(*params)
|
14
|
+
StrongParametersMatcher.new(params).in_context(self)
|
11
15
|
end
|
12
16
|
|
13
17
|
class StrongParametersMatcher
|
14
|
-
|
15
|
-
@stubbed_parameters_class ||= build_stubbed_parameters_class
|
16
|
-
end
|
18
|
+
attr_writer :stubbed_params
|
17
19
|
|
18
|
-
def
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
def initialize(context = nil, attributes)
|
25
|
-
@attributes = attributes
|
26
|
-
@context = context
|
20
|
+
def initialize(expected_permitted_params)
|
21
|
+
@action = nil
|
22
|
+
@verb = nil
|
23
|
+
@request_params = {}
|
24
|
+
@expected_permitted_params = expected_permitted_params
|
25
|
+
set_double_collection
|
27
26
|
end
|
28
27
|
|
29
28
|
def for(action, options = {})
|
30
29
|
@action = action
|
31
|
-
@verb = options
|
30
|
+
@verb = options.fetch(:verb, default_verb)
|
31
|
+
@request_params = options.fetch(:params, {})
|
32
32
|
self
|
33
33
|
end
|
34
34
|
|
@@ -38,128 +38,92 @@ module Shoulda
|
|
38
38
|
end
|
39
39
|
|
40
40
|
def description
|
41
|
-
"permit #{verb.upcase} ##{action} to receive parameters #{
|
41
|
+
"permit #{verb.upcase} ##{action} to receive parameters #{param_names_as_sentence}"
|
42
42
|
end
|
43
43
|
|
44
|
-
def matches?(controller
|
45
|
-
|
46
|
-
|
44
|
+
def matches?(controller)
|
45
|
+
@controller = controller
|
46
|
+
ensure_action_and_verb_present!
|
47
47
|
|
48
|
-
|
49
|
-
|
48
|
+
Doublespeak.with_doubles_activated do
|
49
|
+
context.__send__(verb, action, request_params)
|
50
|
+
end
|
51
|
+
|
52
|
+
unpermitted_params.empty?
|
50
53
|
end
|
51
54
|
|
52
55
|
def failure_message
|
53
|
-
"Expected controller to permit #{
|
56
|
+
"Expected controller to permit #{unpermitted_params.to_sentence}, but it did not."
|
54
57
|
end
|
55
58
|
alias failure_message_for_should failure_message
|
56
59
|
|
57
60
|
def failure_message_when_negated
|
58
|
-
"Expected controller not to permit #{
|
61
|
+
"Expected controller not to permit #{verified_permitted_params.to_sentence}, but it did."
|
59
62
|
end
|
60
63
|
alias failure_message_for_should_not failure_message_when_negated
|
61
64
|
|
62
65
|
private
|
63
66
|
|
64
|
-
attr_reader :
|
67
|
+
attr_reader :controller, :double_collection, :action, :verb,
|
68
|
+
:request_params, :expected_permitted_params, :context
|
65
69
|
|
66
|
-
def
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
begin
|
71
|
-
context.send(verb, action)
|
72
|
-
ensure
|
73
|
-
unstub_model_attributes
|
74
|
-
end
|
70
|
+
def set_double_collection
|
71
|
+
@double_collection =
|
72
|
+
Doublespeak.register_double_collection(::ActionController::Parameters)
|
75
73
|
|
76
|
-
|
74
|
+
@double_collection.register_stub(:require).to_return { |params| params }
|
75
|
+
@double_collection.register_proxy(:permit)
|
77
76
|
end
|
78
77
|
|
79
|
-
def
|
80
|
-
|
78
|
+
def actual_permitted_params
|
79
|
+
double_collection.calls_to(:permit).inject([]) do |all_param_names, call|
|
80
|
+
all_param_names + call.args
|
81
|
+
end.flatten
|
81
82
|
end
|
82
83
|
|
83
|
-
def
|
84
|
-
|
84
|
+
def permit_called?
|
85
|
+
actual_permitted_params.any?
|
85
86
|
end
|
86
87
|
|
87
|
-
def
|
88
|
-
|
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
|
88
|
+
def unpermitted_params
|
89
|
+
expected_permitted_params - actual_permitted_params
|
102
90
|
end
|
103
91
|
|
104
|
-
def
|
105
|
-
|
106
|
-
alias_method :[], :'shoulda_original_[]'
|
107
|
-
undef_method :'shoulda_original_[]'
|
108
|
-
end
|
92
|
+
def verified_permitted_params
|
93
|
+
expected_permitted_params & actual_permitted_params
|
109
94
|
end
|
110
95
|
|
111
96
|
def ensure_action_and_verb_present!
|
112
97
|
if action.blank?
|
113
98
|
raise ActionNotDefinedError
|
114
99
|
end
|
100
|
+
|
115
101
|
if verb.blank?
|
116
102
|
raise VerbNotDefinedError
|
117
103
|
end
|
118
104
|
end
|
119
105
|
|
120
|
-
def
|
121
|
-
|
122
|
-
|
123
|
-
|
124
|
-
|
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
|
106
|
+
def default_verb
|
107
|
+
case action
|
108
|
+
when :create then :post
|
109
|
+
when :update then RailsShim.verb_for_update
|
110
|
+
end
|
139
111
|
end
|
140
112
|
|
141
|
-
def
|
142
|
-
|
143
|
-
super
|
113
|
+
def param_names_as_sentence
|
114
|
+
expected_permitted_params.map(&:inspect).to_sentence
|
144
115
|
end
|
145
116
|
|
146
|
-
|
147
|
-
|
148
|
-
|
149
|
-
|
150
|
-
end
|
151
|
-
end
|
152
|
-
|
153
|
-
class StrongParametersMatcher::ActionNotDefinedError < StandardError
|
154
|
-
def message
|
155
|
-
'You must specify the controller action using the #for method.'
|
117
|
+
class ActionNotDefinedError < StandardError
|
118
|
+
def message
|
119
|
+
'You must specify the controller action using the #for method.'
|
120
|
+
end
|
156
121
|
end
|
157
|
-
end
|
158
122
|
|
159
|
-
|
160
|
-
|
161
|
-
|
162
|
-
|
123
|
+
class VerbNotDefinedError < StandardError
|
124
|
+
def message
|
125
|
+
'You must specify an HTTP verb when using a non-RESTful action. For example: for(:authorize, verb: :post)'
|
126
|
+
end
|
163
127
|
end
|
164
128
|
end
|
165
129
|
end
|
@@ -37,6 +37,7 @@ module Shoulda # :nodoc:
|
|
37
37
|
self.values_to_match = values
|
38
38
|
self.message_finder_factory = ValidationMessageFinder
|
39
39
|
self.options = {}
|
40
|
+
self.after_setting_value_callback = -> {}
|
40
41
|
end
|
41
42
|
|
42
43
|
def for(attribute)
|
@@ -63,12 +64,16 @@ module Shoulda # :nodoc:
|
|
63
64
|
self
|
64
65
|
end
|
65
66
|
|
67
|
+
def _after_setting_value(&callback) # :nodoc:
|
68
|
+
self.after_setting_value_callback = callback
|
69
|
+
end
|
70
|
+
|
66
71
|
def matches?(instance)
|
67
72
|
self.instance = instance
|
68
73
|
|
69
74
|
values_to_match.none? do |value|
|
70
75
|
self.value = value
|
71
|
-
|
76
|
+
set_value(value)
|
72
77
|
errors_match?
|
73
78
|
end
|
74
79
|
end
|
@@ -91,24 +96,11 @@ module Shoulda # :nodoc:
|
|
91
96
|
|
92
97
|
attr_accessor :values_to_match, :message_finder_factory,
|
93
98
|
:instance, :attribute_to_set, :attribute_to_check_message_against,
|
94
|
-
:context, :value, :matched_error
|
95
|
-
|
96
|
-
def set_and_double_check_attribute!(attribute_name, value)
|
97
|
-
instance.__send__("#{attribute_name}=", value)
|
99
|
+
:context, :value, :matched_error, :after_setting_value_callback
|
98
100
|
|
99
|
-
|
100
|
-
|
101
|
-
|
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
|
101
|
+
def set_value(value)
|
102
|
+
instance.__send__("#{attribute_to_set}=", value)
|
103
|
+
after_setting_value_callback.call
|
112
104
|
end
|
113
105
|
|
114
106
|
def errors_match?
|