mcmire-shoulda-matchers 2.5.0 → 2.6.1.docs.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.gitignore +1 -0
- data/.travis.yml +9 -0
- data/.yardopts +2 -1
- data/Appraisals +62 -22
- data/Gemfile +1 -1
- data/Gemfile.lock +3 -3
- data/NEWS.md +87 -4
- data/README.md +2 -2
- data/Rakefile +18 -0
- data/features/activemodel_integration.feature +15 -0
- data/features/rails_integration.feature +1 -1
- data/features/step_definitions/activemodel_steps.rb +21 -0
- data/features/step_definitions/rails_steps.rb +5 -4
- data/gemfiles/3.0.gemfile +6 -3
- data/gemfiles/3.0.gemfile.lock +14 -4
- data/gemfiles/3.1.gemfile +10 -4
- data/gemfiles/3.1.gemfile.lock +32 -5
- data/gemfiles/3.1_1.9.2.gemfile +21 -0
- data/gemfiles/3.1_1.9.2.gemfile.lock +191 -0
- data/gemfiles/3.2.gemfile +9 -4
- data/gemfiles/3.2.gemfile.lock +28 -5
- data/gemfiles/4.0.0.gemfile +11 -3
- data/gemfiles/4.0.0.gemfile.lock +42 -5
- data/gemfiles/4.0.1.gemfile +11 -3
- data/gemfiles/4.0.1.gemfile.lock +42 -5
- data/gemfiles/4.1.gemfile +37 -0
- data/gemfiles/4.1.gemfile.lock +216 -0
- data/lib/shoulda/matchers/action_controller/callback_matcher.rb +202 -0
- data/lib/shoulda/matchers/action_controller/rescue_from_matcher.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 +165 -0
- data/lib/shoulda/matchers/action_controller.rb +2 -0
- data/lib/shoulda/matchers/active_model/allow_value_matcher.rb +26 -4
- data/lib/shoulda/matchers/active_model/disallow_value_matcher.rb +6 -0
- data/lib/shoulda/matchers/active_model/ensure_exclusion_of_matcher.rb +2 -0
- data/lib/shoulda/matchers/active_model/ensure_inclusion_of_matcher.rb +60 -18
- data/lib/shoulda/matchers/active_model/errors.rb +43 -1
- data/lib/shoulda/matchers/active_model/numericality_matchers/comparison_matcher.rb +14 -3
- data/lib/shoulda/matchers/active_model/validate_absence_of_matcher.rb +2 -1
- data/lib/shoulda/matchers/active_model/validate_numericality_of_matcher.rb +100 -45
- data/lib/shoulda/matchers/active_model/validate_presence_of_matcher.rb +38 -5
- data/lib/shoulda/matchers/active_model/validate_uniqueness_of_matcher.rb +27 -20
- data/lib/shoulda/matchers/active_record/association_matcher.rb +12 -2
- data/lib/shoulda/matchers/active_record/association_matchers/inverse_of_matcher.rb +41 -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_index_matcher.rb +1 -1
- data/lib/shoulda/matchers/active_record.rb +1 -0
- data/lib/shoulda/matchers/assertion_error.rb +8 -3
- data/lib/shoulda/matchers/doublespeak/double.rb +75 -0
- data/lib/shoulda/matchers/doublespeak/double_collection.rb +55 -0
- data/lib/shoulda/matchers/doublespeak/double_implementation_registry.rb +28 -0
- data/lib/shoulda/matchers/doublespeak/object_double.rb +33 -0
- data/lib/shoulda/matchers/doublespeak/proxy_implementation.rb +31 -0
- data/lib/shoulda/matchers/doublespeak/structs.rb +10 -0
- data/lib/shoulda/matchers/doublespeak/stub_implementation.rb +35 -0
- data/lib/shoulda/matchers/doublespeak/world.rb +39 -0
- data/lib/shoulda/matchers/doublespeak.rb +28 -0
- data/lib/shoulda/matchers/error.rb +20 -1
- data/lib/shoulda/matchers/independent/delegate_matcher/stubbed_target.rb +35 -0
- data/lib/shoulda/matchers/independent/delegate_matcher.rb +293 -0
- data/lib/shoulda/matchers/independent.rb +10 -0
- data/lib/shoulda/matchers/integrations/nunit_test_case_detection.rb +38 -0
- data/lib/shoulda/matchers/integrations/rspec.rb +13 -14
- data/lib/shoulda/matchers/integrations/test_unit.rb +19 -15
- data/lib/shoulda/matchers/integrations.rb +13 -0
- data/lib/shoulda/matchers/rails_shim.rb +16 -0
- data/lib/shoulda/matchers/version.rb +1 -1
- data/lib/shoulda/matchers.rb +15 -3
- data/spec/shoulda/matchers/action_controller/callback_matcher_spec.rb +82 -0
- data/spec/shoulda/matchers/action_controller/redirect_to_matcher_spec.rb +2 -2
- data/spec/shoulda/matchers/action_controller/render_template_matcher_spec.rb +5 -5
- data/spec/shoulda/matchers/action_controller/render_with_layout_matcher_spec.rb +4 -4
- data/spec/shoulda/matchers/action_controller/rescue_from_matcher_spec.rb +38 -11
- data/spec/shoulda/matchers/action_controller/respond_with_matcher_spec.rb +1 -1
- data/spec/shoulda/matchers/action_controller/set_session_matcher_spec.rb +1 -1
- data/spec/shoulda/matchers/action_controller/set_the_flash_matcher_spec.rb +6 -6
- data/spec/shoulda/matchers/action_controller/strong_parameters_matcher_spec.rb +314 -0
- data/spec/shoulda/matchers/active_model/allow_value_matcher_spec.rb +32 -0
- data/spec/shoulda/matchers/active_model/ensure_inclusion_of_matcher_spec.rb +553 -211
- 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 +38 -0
- data/spec/shoulda/matchers/active_model/validate_uniqueness_of_matcher_spec.rb +42 -36
- data/spec/shoulda/matchers/active_record/association_matcher_spec.rb +15 -1
- data/spec/shoulda/matchers/active_record/association_matchers/model_reflection_spec.rb +4 -0
- data/spec/shoulda/matchers/active_record/have_db_index_matcher_spec.rb +4 -0
- 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/stubbed_target_spec.rb +43 -0
- data/spec/shoulda/matchers/independent/delegate_matcher_spec.rb +250 -0
- data/spec/spec_helper.rb +15 -0
- data/spec/support/activemodel_helpers.rb +6 -2
- data/spec/support/controller_builder.rb +29 -1
- data/spec/support/rails_versions.rb +4 -0
- data/spec/support/test_application.rb +1 -1
- metadata +59 -10
@@ -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')).
|
@@ -144,6 +144,44 @@ describe Shoulda::Matchers::ActiveModel::ValidatePresenceOfMatcher do
|
|
144
144
|
end
|
145
145
|
end
|
146
146
|
|
147
|
+
if rails_4_x?
|
148
|
+
context 'against a pre-set password in a model that has_secure_password' do
|
149
|
+
it 'raises a CouldNotSetPasswordError exception' do
|
150
|
+
user_class = define_model :user, password_digest: :string do
|
151
|
+
has_secure_password validations: false
|
152
|
+
validates_presence_of :password
|
153
|
+
end
|
154
|
+
|
155
|
+
user = user_class.new
|
156
|
+
user.password = 'something'
|
157
|
+
|
158
|
+
error_class = Shoulda::Matchers::ActiveModel::CouldNotSetPasswordError
|
159
|
+
expect do
|
160
|
+
expect(user).to validate_presence_of(:password)
|
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
|
181
|
+
end
|
182
|
+
end
|
183
|
+
end
|
184
|
+
|
147
185
|
def matcher
|
148
186
|
validate_presence_of(:attr)
|
149
187
|
end
|
@@ -122,6 +122,40 @@ describe Shoulda::Matchers::ActiveModel::ValidateUniquenessOfMatcher do
|
|
122
122
|
not_to matcher.scoped_to(:fake)
|
123
123
|
end
|
124
124
|
|
125
|
+
if rails_gte_4_1?
|
126
|
+
context 'when the scoped attribute is an enum' do
|
127
|
+
it 'accepts' do
|
128
|
+
expect(validating_scoped_uniqueness_with_enum([:scope1], scope1: 0)).
|
129
|
+
to matcher.scoped_to(:scope1)
|
130
|
+
end
|
131
|
+
|
132
|
+
context 'with a nil value' do
|
133
|
+
it 'accepts' do
|
134
|
+
expect(validating_scoped_uniqueness_with_enum([:scope1], scope1: nil)).
|
135
|
+
to matcher.scoped_to(:scope1)
|
136
|
+
end
|
137
|
+
end
|
138
|
+
|
139
|
+
context 'when too narrow of a scope is specified' do
|
140
|
+
it 'rejects' do
|
141
|
+
expect(validating_scoped_uniqueness_with_enum_with_two_scopes).
|
142
|
+
not_to matcher.scoped_to(:scope1, :scope2, :other)
|
143
|
+
end
|
144
|
+
end
|
145
|
+
|
146
|
+
context 'when too broad of a scope is specified' do
|
147
|
+
it 'rejects' do
|
148
|
+
expect(validating_scoped_uniqueness_with_enum_with_two_scopes).
|
149
|
+
not_to matcher.scoped_to(:scope1)
|
150
|
+
end
|
151
|
+
end
|
152
|
+
|
153
|
+
def validating_scoped_uniqueness_with_enum_with_two_scopes
|
154
|
+
validating_scoped_uniqueness_with_enum([:scope1, :scope2], scope1: 0, scope2: 0)
|
155
|
+
end
|
156
|
+
end
|
157
|
+
end
|
158
|
+
|
125
159
|
context 'when the scoped attribute is a date' do
|
126
160
|
it "accepts" do
|
127
161
|
expect(validating_scoped_uniqueness([:scope1], :date, scope1: Date.today)).
|
@@ -250,6 +284,14 @@ describe Shoulda::Matchers::ActiveModel::ValidateUniquenessOfMatcher do
|
|
250
284
|
model
|
251
285
|
end
|
252
286
|
|
287
|
+
def validating_scoped_uniqueness_with_enum(*args)
|
288
|
+
attributes = args.extract_options!
|
289
|
+
model = define_scoped_model(*args)
|
290
|
+
model.enum scope1: [:foo, :bar]
|
291
|
+
create_existing_record(attributes)
|
292
|
+
model.new
|
293
|
+
end
|
294
|
+
|
253
295
|
def validating_scoped_uniqueness_with_conflicting_next(*args)
|
254
296
|
attributes = args.extract_options!
|
255
297
|
model = define_scoped_model(*args).new
|
@@ -341,42 +383,6 @@ describe Shoulda::Matchers::ActiveModel::ValidateUniquenessOfMatcher do
|
|
341
383
|
end
|
342
384
|
end
|
343
385
|
|
344
|
-
context "a model with non-nullable attribute" do
|
345
|
-
context "of type" do
|
346
|
-
[:string, :text, :integer, :float, :decimal, :datetime, :timestamp, :time, :date, :binary, :boolean].each do |type|
|
347
|
-
context type do
|
348
|
-
it "does not raise an error" do
|
349
|
-
model = define_model_with_non_nullable(type)
|
350
|
-
expect { expect(model).to matcher }.not_to raise_error
|
351
|
-
end
|
352
|
-
end
|
353
|
-
end
|
354
|
-
end
|
355
|
-
|
356
|
-
context "that is a primary key" do
|
357
|
-
it "does not cause duplicate entry errors by re-using default values for primary keys" do
|
358
|
-
create_table :examples, id: false do |t|
|
359
|
-
t.string :attr
|
360
|
-
t.integer :non_nullable, primary: true
|
361
|
-
end
|
362
|
-
model_class = define_model(:example, attr: :string) do
|
363
|
-
validates_uniqueness_of :attr
|
364
|
-
end
|
365
|
-
model_1 = model_class.new
|
366
|
-
model_2 = model_class.new
|
367
|
-
expect(model_1).to matcher
|
368
|
-
expect { expect(model_2).to matcher }.not_to raise_error
|
369
|
-
end
|
370
|
-
end
|
371
|
-
|
372
|
-
def define_model_with_non_nullable(type)
|
373
|
-
define_model(:example, attr: :string, non_nullable: { type: type, options: { null: false } }) do
|
374
|
-
attr_accessible :attr, :non_nullable
|
375
|
-
validates_uniqueness_of :attr
|
376
|
-
end.new
|
377
|
-
end
|
378
|
-
end
|
379
|
-
|
380
386
|
def case_sensitive_validation_with_existing_value(attr_type)
|
381
387
|
model = define_model(:example, attr: attr_type) do
|
382
388
|
attr_accessible :attr
|
@@ -30,7 +30,6 @@ describe Shoulda::Matchers::ActiveRecord::AssociationMatcher do
|
|
30
30
|
end
|
31
31
|
|
32
32
|
it 'accepts a polymorphic association' do
|
33
|
-
define_model :parent
|
34
33
|
define_model :child, parent_type: :string, parent_id: :integer do
|
35
34
|
belongs_to :parent, polymorphic: true
|
36
35
|
end
|
@@ -66,6 +65,21 @@ describe Shoulda::Matchers::ActiveRecord::AssociationMatcher do
|
|
66
65
|
expect(belonging_to_parent).not_to belong_to(:parent).counter_cache
|
67
66
|
end
|
68
67
|
|
68
|
+
it 'accepts an association with a valid :inverse_of option' do
|
69
|
+
expect(belonging_to_parent(inverse_of: :children))
|
70
|
+
.to belong_to(:parent).inverse_of(:children)
|
71
|
+
end
|
72
|
+
|
73
|
+
it 'rejects an association with a bad :inverse_of option' do
|
74
|
+
expect(belonging_to_parent(inverse_of: :other_children))
|
75
|
+
.not_to belong_to(:parent).inverse_of(:children)
|
76
|
+
end
|
77
|
+
|
78
|
+
it 'rejects an association that has no :inverse_of option' do
|
79
|
+
expect(belonging_to_parent)
|
80
|
+
.not_to belong_to(:parent).inverse_of(:children)
|
81
|
+
end
|
82
|
+
|
69
83
|
it 'accepts an association with a valid :conditions option' do
|
70
84
|
define_model :parent, adopter: :boolean
|
71
85
|
define_model(:child, parent_id: :integer).tap do |model|
|
@@ -57,6 +57,10 @@ describe Shoulda::Matchers::ActiveRecord::AssociationMatchers::ModelReflection d
|
|
57
57
|
describe '#join_table' do
|
58
58
|
context 'when the association was defined with a :join_table option' do
|
59
59
|
it 'returns the value of the option' do
|
60
|
+
create_table :foos, id: false do |t|
|
61
|
+
t.integer :person_id
|
62
|
+
t.integer :country_id
|
63
|
+
end
|
60
64
|
define_model(:person, country_id: :integer)
|
61
65
|
country_model = define_model(:country) do
|
62
66
|
has_and_belongs_to_many :people, join_table: 'foos'
|
@@ -52,6 +52,10 @@ describe Shoulda::Matchers::ActiveRecord::HaveDbIndexMatcher do
|
|
52
52
|
expect(have_db_index(:user_id).unique(true).description).to match(/a unique index/)
|
53
53
|
end
|
54
54
|
|
55
|
+
it 'describes a unique index as unique when no argument is given' do
|
56
|
+
expect(have_db_index(:user_id).unique.description).to match(/a unique index/)
|
57
|
+
end
|
58
|
+
|
55
59
|
it 'describes a non-unique index as non-unique' do
|
56
60
|
expect(have_db_index(:user_id).unique(false).description).to match(/a non-unique index/)
|
57
61
|
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
|