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.
Files changed (52) hide show
  1. data/Gemfile.lock +1 -1
  2. data/NEWS.md +34 -0
  3. data/README.md +14 -0
  4. data/features/activemodel_integration.feature +15 -0
  5. data/features/step_definitions/activemodel_steps.rb +21 -0
  6. data/gemfiles/3.0.gemfile.lock +1 -1
  7. data/gemfiles/3.1.gemfile.lock +1 -1
  8. data/gemfiles/3.2.gemfile.lock +1 -1
  9. data/gemfiles/4.0.0.gemfile.lock +1 -1
  10. data/gemfiles/4.0.1.gemfile.lock +1 -1
  11. data/gemfiles/4.1.gemfile.lock +1 -1
  12. data/lib/shoulda/matchers.rb +1 -0
  13. data/lib/shoulda/matchers/action_controller/callback_matcher.rb +11 -6
  14. data/lib/shoulda/matchers/action_controller/strong_parameters_matcher.rb +59 -95
  15. data/lib/shoulda/matchers/active_model/allow_value_matcher.rb +10 -18
  16. data/lib/shoulda/matchers/active_model/disallow_value_matcher.rb +10 -0
  17. data/lib/shoulda/matchers/active_model/ensure_inclusion_of_matcher.rb +60 -18
  18. data/lib/shoulda/matchers/active_model/errors.rb +9 -7
  19. data/lib/shoulda/matchers/active_model/numericality_matchers/comparison_matcher.rb +4 -0
  20. data/lib/shoulda/matchers/active_model/validate_presence_of_matcher.rb +24 -5
  21. data/lib/shoulda/matchers/doublespeak.rb +27 -0
  22. data/lib/shoulda/matchers/doublespeak/double.rb +74 -0
  23. data/lib/shoulda/matchers/doublespeak/double_collection.rb +54 -0
  24. data/lib/shoulda/matchers/doublespeak/double_implementation_registry.rb +27 -0
  25. data/lib/shoulda/matchers/doublespeak/object_double.rb +32 -0
  26. data/lib/shoulda/matchers/doublespeak/proxy_implementation.rb +30 -0
  27. data/lib/shoulda/matchers/doublespeak/structs.rb +8 -0
  28. data/lib/shoulda/matchers/doublespeak/stub_implementation.rb +34 -0
  29. data/lib/shoulda/matchers/doublespeak/world.rb +38 -0
  30. data/lib/shoulda/matchers/independent/delegate_matcher.rb +112 -61
  31. data/lib/shoulda/matchers/integrations/test_unit.rb +8 -6
  32. data/lib/shoulda/matchers/rails_shim.rb +16 -0
  33. data/lib/shoulda/matchers/version.rb +1 -1
  34. data/spec/shoulda/matchers/action_controller/callback_matcher_spec.rb +22 -19
  35. data/spec/shoulda/matchers/action_controller/strong_parameters_matcher_spec.rb +174 -65
  36. data/spec/shoulda/matchers/active_model/allow_value_matcher_spec.rb +14 -0
  37. data/spec/shoulda/matchers/active_model/ensure_inclusion_of_matcher_spec.rb +553 -211
  38. data/spec/shoulda/matchers/active_model/numericality_matchers/comparison_matcher_spec.rb +6 -0
  39. data/spec/shoulda/matchers/active_model/validate_numericality_of_matcher_spec.rb +22 -0
  40. data/spec/shoulda/matchers/active_model/validate_presence_of_matcher_spec.rb +23 -4
  41. data/spec/shoulda/matchers/doublespeak/double_collection_spec.rb +102 -0
  42. data/spec/shoulda/matchers/doublespeak/double_implementation_registry_spec.rb +21 -0
  43. data/spec/shoulda/matchers/doublespeak/double_spec.rb +144 -0
  44. data/spec/shoulda/matchers/doublespeak/object_double_spec.rb +77 -0
  45. data/spec/shoulda/matchers/doublespeak/proxy_implementation_spec.rb +40 -0
  46. data/spec/shoulda/matchers/doublespeak/stub_implementation_spec.rb +88 -0
  47. data/spec/shoulda/matchers/doublespeak/world_spec.rb +88 -0
  48. data/spec/shoulda/matchers/doublespeak_spec.rb +19 -0
  49. data/spec/shoulda/matchers/independent/delegate_matcher_spec.rb +105 -39
  50. data/spec/support/controller_builder.rb +18 -9
  51. data/spec/support/rails_versions.rb +4 -0
  52. metadata +34 -8
@@ -5,6 +5,12 @@ describe Shoulda::Matchers::ActiveModel::NumericalityMatchers::ComparisonMatcher
5
5
 
6
6
  it_behaves_like 'a numerical submatcher'
7
7
 
8
+ describe '#diff_to_compare' do
9
+ it { expect(subject.diff_to_compare).to eq 0.000_001 }
10
+ it { expect(described_class.new(matcher, 2**34, :>).diff_to_compare).to eq 1 }
11
+ it { expect(described_class.new(matcher, -2**34, :>).diff_to_compare).to eq 1 }
12
+ end
13
+
8
14
  context 'when initialized without correct numerical matcher' do
9
15
  it 'raises an argument error' do
10
16
  fake_matcher = matcher
@@ -236,6 +236,28 @@ describe Shoulda::Matchers::ActiveModel::ValidateNumericalityOfMatcher do
236
236
  end
237
237
  end
238
238
 
239
+ context 'with large numbers' do
240
+ it do
241
+ expect(validating_numericality(greater_than: 100_000))
242
+ .to matcher.is_greater_than(100_000)
243
+ end
244
+
245
+ it do
246
+ expect(validating_numericality(less_than: 100_000))
247
+ .to matcher.is_less_than(100_000)
248
+ end
249
+
250
+ it do
251
+ expect(validating_numericality(greater_than_or_equal_to: 100_000))
252
+ .to matcher.is_greater_than_or_equal_to(100_000)
253
+ end
254
+
255
+ it do
256
+ expect(validating_numericality(less_than_or_equal_to: 100_000))
257
+ .to matcher.is_less_than_or_equal_to(100_000)
258
+ end
259
+ end
260
+
239
261
  context 'with a custom validation message' do
240
262
  it 'accepts when the messages match' do
241
263
  expect(validating_numericality(message: 'custom')).
@@ -146,9 +146,9 @@ describe Shoulda::Matchers::ActiveModel::ValidatePresenceOfMatcher do
146
146
 
147
147
  if rails_4_x?
148
148
  context 'against a pre-set password in a model that has_secure_password' do
149
- it 'raises an error to instruct the user' do
149
+ it 'raises a CouldNotSetPasswordError exception' do
150
150
  user_class = define_model :user, password_digest: :string do
151
- has_secure_password
151
+ has_secure_password validations: false
152
152
  validates_presence_of :password
153
153
  end
154
154
 
@@ -156,9 +156,28 @@ describe Shoulda::Matchers::ActiveModel::ValidatePresenceOfMatcher do
156
156
  user.password = 'something'
157
157
 
158
158
  error_class = Shoulda::Matchers::ActiveModel::CouldNotSetPasswordError
159
- expect {
159
+ expect do
160
160
  expect(user).to validate_presence_of(:password)
161
- }.to raise_error(error_class)
161
+ end.to raise_error(error_class)
162
+ end
163
+ end
164
+ end
165
+
166
+ context 'when the attribute being tested intercepts the blank value we set on it (issue #479)' do
167
+ context 'for a non-collection attribute' do
168
+ it 'does not raise an error' do
169
+ record = define_model :example, attr: :string do
170
+ validates :attr, presence: true
171
+
172
+ def attr=(value)
173
+ value = '' if value.nil?
174
+ super(value)
175
+ end
176
+ end.new
177
+
178
+ expect do
179
+ expect(record).to validate_presence_of(:attr)
180
+ end.not_to raise_error
162
181
  end
163
182
  end
164
183
  end
@@ -0,0 +1,102 @@
1
+ require 'spec_helper'
2
+
3
+ module Shoulda::Matchers::Doublespeak
4
+ describe DoubleCollection do
5
+ describe '#register_stub' do
6
+ it 'calls DoubleImplementationRegistry.find correctly' do
7
+ double_collection = described_class.new(:klass)
8
+ DoubleImplementationRegistry.expects(:find).with(:stub)
9
+ double_collection.register_stub(:a_method)
10
+ end
11
+
12
+ it 'calls Double.new correctly' do
13
+ DoubleImplementationRegistry.stubs(:find).returns(:implementation)
14
+ double_collection = described_class.new(:klass)
15
+ Double.expects(:new).with(:klass, :a_method, :implementation)
16
+ double_collection.register_stub(:a_method)
17
+ end
18
+ end
19
+
20
+ describe '#register_proxy' do
21
+ it 'calls DoubleImplementationRegistry.find correctly' do
22
+ double_collection = described_class.new(:klass)
23
+ DoubleImplementationRegistry.expects(:find).with(:proxy)
24
+ double_collection.register_proxy(:a_method)
25
+ end
26
+
27
+ it 'calls Double.new correctly' do
28
+ DoubleImplementationRegistry.stubs(:find).returns(:implementation)
29
+ double_collection = described_class.new(:klass)
30
+ Double.expects(:new).with(:klass, :a_method, :implementation)
31
+ double_collection.register_proxy(:a_method)
32
+ end
33
+ end
34
+
35
+ describe '#activate' do
36
+ it 'replaces all registered methods with doubles' do
37
+ klass = create_class(first_method: 1, second_method: 2)
38
+ double_collection = described_class.new(klass)
39
+ double_collection.register_stub(:first_method)
40
+ double_collection.register_stub(:second_method)
41
+
42
+ double_collection.activate
43
+
44
+ instance = klass.new
45
+ expect(instance.first_method).to eq nil
46
+ expect(instance.second_method).to eq nil
47
+ end
48
+ end
49
+
50
+ describe '#deactivate' do
51
+ it 'restores the original methods that were doubled' do
52
+ klass = create_class(first_method: 1, second_method: 2)
53
+ double_collection = described_class.new(klass)
54
+ double_collection.register_stub(:first_method)
55
+ double_collection.register_stub(:second_method)
56
+
57
+ double_collection.activate
58
+ double_collection.deactivate
59
+
60
+ instance = klass.new
61
+ expect(instance.first_method).to eq 1
62
+ expect(instance.second_method).to eq 2
63
+ end
64
+ end
65
+
66
+ describe '#calls_to' do
67
+ it 'returns all calls to the given method' do
68
+ klass = create_class(a_method: nil)
69
+ double_collection = described_class.new(klass)
70
+ double_collection.register_stub(:a_method)
71
+ double_collection.activate
72
+
73
+ actual_calls = [
74
+ { args: [:some, :args, :here] },
75
+ { args: [:some, :args], block: -> { :whatever } }
76
+ ]
77
+ instance = klass.new
78
+ instance.a_method(*actual_calls[0][:args])
79
+ instance.a_method(*actual_calls[1][:args], &actual_calls[1][:block])
80
+
81
+ calls = double_collection.calls_to(:a_method)
82
+ expect(calls[0].args).to eq actual_calls[0][:args]
83
+ expect(calls[1].args).to eq actual_calls[1][:args]
84
+ expect(calls[1].block).to eq actual_calls[1][:block]
85
+ end
86
+
87
+ it 'returns an empty array if the method has never been doubled' do
88
+ klass = create_class
89
+ double_collection = described_class.new(klass)
90
+ expect(double_collection.calls_to(:non_existent_method)).to eq []
91
+ end
92
+ end
93
+
94
+ def create_class(methods = {})
95
+ Class.new.tap do |klass|
96
+ methods.each do |name, value|
97
+ klass.__send__(:define_method, name) { |*args| value }
98
+ end
99
+ end
100
+ end
101
+ end
102
+ end
@@ -0,0 +1,21 @@
1
+ require 'spec_helper'
2
+
3
+ module Shoulda::Matchers::Doublespeak
4
+ describe DoubleImplementationRegistry do
5
+ describe '.find' do
6
+ it 'returns an instance of StubImplementation if given :stub' do
7
+ expect(described_class.find(:stub)).to be_a(StubImplementation)
8
+ end
9
+
10
+ it 'returns ProxyImplementation if given :proxy' do
11
+ expect(described_class.find(:proxy)).to be_a(ProxyImplementation)
12
+ end
13
+
14
+ it 'raises an ArgumentError if not given a registered implementation' do
15
+ expect {
16
+ expect(described_class.find(:something_else))
17
+ }.to raise_error(ArgumentError)
18
+ end
19
+ end
20
+ end
21
+ end
@@ -0,0 +1,144 @@
1
+ require 'spec_helper'
2
+
3
+ module Shoulda::Matchers::Doublespeak
4
+ describe Double do
5
+ describe '#to_return' do
6
+ it 'tells its implementation to call the given block' do
7
+ sent_block = -> { }
8
+ actual_block = nil
9
+ implementation = stub
10
+ implementation.singleton_class.__send__(:define_method, :returns) do |&block|
11
+ actual_block = block
12
+ end
13
+ double = described_class.new(:klass, :a_method, implementation)
14
+ double.to_return(&sent_block)
15
+ expect(actual_block).to eq sent_block
16
+ end
17
+
18
+ it 'tells its implementation to return the given value' do
19
+ implementation = mock()
20
+ implementation.expects(:returns).with(:implementation)
21
+ double = described_class.new(:klass, :a_method, implementation)
22
+ double.to_return(:implementation)
23
+ end
24
+
25
+ it 'prefers a block over a non-block' do
26
+ sent_block = -> { }
27
+ actual_block = nil
28
+ implementation = stub
29
+ implementation.singleton_class.__send__(:define_method, :returns) do |&block|
30
+ actual_block = block
31
+ end
32
+ double = described_class.new(:klass, :a_method, implementation)
33
+ double.to_return(:value, &sent_block)
34
+ expect(actual_block).to eq sent_block
35
+ end
36
+ end
37
+
38
+ describe '#activate' do
39
+ it 'replaces the method with an implementation' do
40
+ implementation = stub
41
+ klass = create_class(a_method: 42)
42
+ instance = klass.new
43
+ double = described_class.new(klass, :a_method, implementation)
44
+ args = [:any, :args]
45
+ block = -> {}
46
+ implementation.expects(:call).with(double, instance, args, block)
47
+
48
+ double.activate
49
+ instance.a_method(*args, &block)
50
+ end
51
+ end
52
+
53
+ describe '#deactivate' do
54
+ it 'restores the original method after being doubled' do
55
+ implementation = stub(call: nil)
56
+ klass = create_class(a_method: 42)
57
+ instance = klass.new
58
+ double = described_class.new(klass, :a_method, implementation)
59
+
60
+ double.activate
61
+ double.deactivate
62
+ expect(instance.a_method).to eq 42
63
+ end
64
+
65
+ it 'still restores the original method if #activate was called twice' do
66
+ implementation = stub(call: nil)
67
+ klass = create_class(a_method: 42)
68
+ instance = klass.new
69
+ double = described_class.new(klass, :a_method, implementation)
70
+
71
+ double.activate
72
+ double.activate
73
+ double.deactivate
74
+ expect(instance.a_method).to eq 42
75
+ end
76
+
77
+ it 'does nothing if the method has not been doubled' do
78
+ implementation = stub(call: nil)
79
+ klass = create_class(a_method: 42)
80
+ instance = klass.new
81
+ double = described_class.new(klass, :a_method, implementation)
82
+
83
+ double.deactivate
84
+ expect(instance.a_method).to eq 42
85
+ end
86
+ end
87
+
88
+ describe '#record_call' do
89
+ it 'stores the arguments and block given to the method in calls' do
90
+ double = described_class.new(:klass, :a_method, :implementation)
91
+ calls = [
92
+ [:any, :args], :block,
93
+ [:more, :args]
94
+ ]
95
+ double.record_call(calls[0][0], calls[0][1])
96
+ double.record_call(calls[1][0], nil)
97
+
98
+ expect(double.calls[0].args).to eq calls[0][0]
99
+ expect(double.calls[0].block).to eq calls[0][1]
100
+ expect(double.calls[1].args).to eq calls[1][0]
101
+ end
102
+ end
103
+
104
+ describe '#call_original_method' do
105
+ it 'binds the stored method object to the class and calls it with the given args and block' do
106
+ klass = create_class(a_method: nil)
107
+ instance = klass.new
108
+ actual_args = actual_block = method_called = nil
109
+ expected_args = [:one, :two, :three]
110
+ expected_block = -> { }
111
+ double = described_class.new(klass, :a_method, :implementation)
112
+
113
+ klass.__send__(:define_method, :a_method) do |*args, &block|
114
+ actual_args = expected_args
115
+ actual_block = expected_block
116
+ method_called = true
117
+ end
118
+
119
+ double.activate
120
+ double.call_original_method(instance, expected_args, expected_block)
121
+
122
+ expect(expected_args).to eq actual_args
123
+ expect(expected_block).to eq actual_block
124
+ expect(method_called).to eq true
125
+ end
126
+
127
+ it 'does nothing if no method has been stored' do
128
+ double = described_class.new(:klass, :a_method, :implementation)
129
+
130
+ expect {
131
+ double.call_original_method(:instance, [:any, :args], nil)
132
+ }.not_to raise_error
133
+ end
134
+ end
135
+
136
+ def create_class(methods = {})
137
+ Class.new.tap do |klass|
138
+ methods.each do |name, value|
139
+ klass.__send__(:define_method, name) { |*args| value }
140
+ end
141
+ end
142
+ end
143
+ end
144
+ end
@@ -0,0 +1,77 @@
1
+ require 'spec_helper'
2
+
3
+ module Shoulda::Matchers::Doublespeak
4
+ describe ObjectDouble do
5
+ it 'responds to any method' do
6
+ double = described_class.new
7
+
8
+ expect(double.respond_to?(:foo)).to be_true
9
+ expect(double.respond_to?(:bar)).to be_true
10
+ expect(double.respond_to?(:baz)).to be_true
11
+ end
12
+
13
+ it 'returns nil from any method call' do
14
+ double = described_class.new
15
+
16
+ expect(double.foo).to be_nil
17
+ expect(double.bar).to be_nil
18
+ expect(double.baz).to be_nil
19
+ end
20
+
21
+ it 'records every method call' do
22
+ double = described_class.new
23
+
24
+ block = -> { :some_return_value }
25
+ double.foo
26
+ double.bar(42)
27
+ double.baz(:zing, :zang, &block)
28
+
29
+ expect(double.calls.size).to eq 3
30
+ double.calls[0].tap do |call|
31
+ expect(call.args).to eq []
32
+ expect(call.block).to eq nil
33
+ end
34
+ double.calls[1].tap do |call|
35
+ expect(call.args).to eq [42]
36
+ expect(call.block).to eq nil
37
+ end
38
+ double.calls[2].tap do |call|
39
+ expect(call.args).to eq [:zing, :zang]
40
+ expect(call.block).to eq block
41
+ end
42
+ end
43
+
44
+ describe '#calls_to' do
45
+ it 'returns all of the invocations of the given method and their arguments/block' do
46
+ double = described_class.new
47
+
48
+ block = -> { :some_return_value }
49
+ double.foo
50
+ double.foo(42)
51
+ double.foo(:zing, :zang, &block)
52
+ double.some_other_method(:doesnt_matter)
53
+
54
+ calls = double.calls_to(:foo)
55
+
56
+ expect(calls.size).to eq 3
57
+ calls[0].tap do |call|
58
+ expect(call.args).to eq []
59
+ expect(call.block).to eq nil
60
+ end
61
+ calls[1].tap do |call|
62
+ expect(call.args).to eq [42]
63
+ expect(call.block).to eq nil
64
+ end
65
+ calls[2].tap do |call|
66
+ expect(call.args).to eq [:zing, :zang]
67
+ expect(call.block).to eq block
68
+ end
69
+ end
70
+
71
+ it 'returns an empty array if the given method was never called' do
72
+ double = described_class.new
73
+ expect(double.calls_to(:unknown_method)).to eq []
74
+ end
75
+ end
76
+ end
77
+ end
@@ -0,0 +1,40 @@
1
+ require 'spec_helper'
2
+
3
+ module Shoulda::Matchers::Doublespeak
4
+ describe ProxyImplementation do
5
+ describe '#returns' do
6
+ it 'delegates to its stub_implementation' do
7
+ stub_implementation = build_stub_implementation
8
+ stub_implementation.expects(:returns).with(:value)
9
+ implementation = described_class.new(stub_implementation)
10
+ implementation.returns(:value)
11
+ end
12
+ end
13
+
14
+ describe '#call' do
15
+ it 'delegates to its stub_implementation' do
16
+ stub_implementation = build_stub_implementation
17
+ double = build_double
18
+ stub_implementation.expects(:call).with(double, :object, :args, :block)
19
+ implementation = described_class.new(stub_implementation)
20
+ implementation.call(double, :object, :args, :block)
21
+ end
22
+
23
+ it 'calls #call_original_method on the double' do
24
+ stub_implementation = build_stub_implementation
25
+ implementation = described_class.new(stub_implementation)
26
+ double = build_double
27
+ double.expects(:call_original_method).with(:object, :args, :block)
28
+ implementation.call(double, :object, :args, :block)
29
+ end
30
+ end
31
+
32
+ def build_stub_implementation
33
+ stub(returns: nil, call: nil)
34
+ end
35
+
36
+ def build_double
37
+ stub(call_original_method: nil)
38
+ end
39
+ end
40
+ end