shoulda-matchers 2.6.0 → 2.6.1.rc1
Sign up to get free protection for your applications and to get access to all the features.
- 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?
|