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.
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