much-stub 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: e5d7e06636c2654760be8dee2fbe8c80d9b86ef4
4
+ data.tar.gz: ebca2dede9dd9f9305548d3d8eb9db88a4ec1bae
5
+ SHA512:
6
+ metadata.gz: 6e4b733a9dccaa7babf00419d86f7e6d112d1a84cfe306c854509e9109bedbaae1c22f2ed4d83edd95f05c571c9ce804251bd0ca75a790478703bf4a703497d8
7
+ data.tar.gz: b41abee2b1ed680b2df84d1eb08c5854beb98001a5b774c4ef2311e583200b96cbdb2ccf1872068c98d050107a1e3fc23eecc02e283fe01cb8e211ce2365b875
data/.gitignore ADDED
@@ -0,0 +1,19 @@
1
+ *.gem
2
+ *.log
3
+ *.rbc
4
+ .rbx/
5
+ .bundle
6
+ .config
7
+ .yardoc
8
+ Gemfile.lock
9
+ InstalledFiles
10
+ _yardoc
11
+ coverage
12
+ doc/
13
+ lib/bundler/man
14
+ pkg
15
+ rdoc
16
+ spec/reports
17
+ test/tmp
18
+ test/version_tmp
19
+ tmp
data/Gemfile ADDED
@@ -0,0 +1,5 @@
1
+ source "https://rubygems.org"
2
+
3
+ gemspec
4
+
5
+ gem 'pry', "~> 0.9.0"
data/LICENSE ADDED
@@ -0,0 +1,22 @@
1
+ Copyright (c) 2018-Present Kelly Redding and Collin Redding
2
+
3
+ MIT License
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining
6
+ a copy of this software and associated documentation files (the
7
+ "Software"), to deal in the Software without restriction, including
8
+ without limitation the rights to use, copy, modify, merge, publish,
9
+ distribute, sublicense, and/or sell copies of the Software, and to
10
+ permit persons to whom the Software is furnished to do so, subject to
11
+ the following conditions:
12
+
13
+ The above copyright notice and this permission notice shall be
14
+ included in all copies or substantial portions of the Software.
15
+
16
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
20
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,88 @@
1
+ # MuchStub
2
+
3
+ MuchStub is a stubbing API for replacing method calls on objects in test runs. This is intended to be brought into testing environments and used in test runs to stub out external dependencies.
4
+
5
+ All it does is replace method calls. In general it tries to be friendly and complain if stubbing doesn't match up with the object/method being stubbed:
6
+
7
+ * each stub takes a block that is called in place of the method
8
+ * complains if you stub a method that the object doesn't respond to
9
+ * complains if you stub with an arity mismatch
10
+ * no methods are added to `Object` to support stubbing
11
+
12
+ Note: this was originally implemented in and extracted from [Assert](https://github.com/redding/assert).
13
+
14
+ ## Usage
15
+
16
+ ```ruby
17
+ myclass = Class.new do
18
+ def mymeth; 'meth'; end
19
+ def myval(val); val; end
20
+ end
21
+ myobj = myclass.new
22
+
23
+ myobj.mymeth
24
+ # => 'meth'
25
+ myobj.myval(123)
26
+ # => 123
27
+ myobj.myval(456)
28
+ # => 456
29
+
30
+ MuchStub.stub(myobj, :mymeth)
31
+ myobj.mymeth
32
+ # => StubError: `mymeth` not stubbed.
33
+ MuchStub.stub(myobj, :mymeth){ 'stub-meth' }
34
+ myobj.mymeth
35
+ # => 'stub-meth'
36
+ myobj.mymeth(123)
37
+ # => StubError: arity mismatch
38
+ MuchStub.stub(myobj, :mymeth).with(123){ 'stub-meth' }
39
+ # => StubError: arity mismatch
40
+ MuchStub.stub_send(myobj, :mymeth) # call to the original method post-stub
41
+ # => 'meth'
42
+
43
+ MuchStub.stub(myobj, :myval){ 'stub-meth' }
44
+ # => StubError: arity mismatch
45
+ MuchStub.stub(myobj, :myval).with(123){ |val| val.to_s }
46
+ myobj.myval
47
+ # => StubError: arity mismatch
48
+ myobj.myval(123)
49
+ # => '123'
50
+ myobj.myval(456)
51
+ # => StubError: `myval(456)` not stubbed.
52
+ MuchStub.stub_send(myobj, :myval, 123) # call to the original method post-stub
53
+ # => 123
54
+ MuchStub.stub_send(myobj, :myval, 456)
55
+ # => 456
56
+
57
+ MuchStub.unstub(myobj, :mymeth)
58
+ MuchStub.unstub(myobj, :myval)
59
+
60
+ myobj.mymeth
61
+ # => 'meth'
62
+ myobj.myval(123)
63
+ # => 123
64
+ myobj.myval(456)
65
+ # => 456
66
+ ```
67
+
68
+ ## Installation
69
+
70
+ Add this line to your application's Gemfile:
71
+
72
+ gem 'much-stub'
73
+
74
+ And then execute:
75
+
76
+ $ bundle
77
+
78
+ Or install it yourself as:
79
+
80
+ $ gem install much-stub
81
+
82
+ ## Contributing
83
+
84
+ 1. Fork it
85
+ 2. Create your feature branch (`git checkout -b my-new-feature`)
86
+ 3. Commit your changes (`git commit -am 'Added some feature'`)
87
+ 4. Push to the branch (`git push origin my-new-feature`)
88
+ 5. Create new Pull Request
data/lib/much-stub.rb ADDED
@@ -0,0 +1,216 @@
1
+ require "much-stub/version"
2
+
3
+ module MuchStub
4
+
5
+ def self.stubs
6
+ @stubs ||= {}
7
+ end
8
+
9
+ def self.stub(obj, meth, &block)
10
+ (self.stubs[MuchStub::Stub.key(obj, meth)] ||= begin
11
+ MuchStub::Stub.new(obj, meth, caller_locations)
12
+ end).tap{ |s| s.do = block }
13
+ end
14
+
15
+ def self.unstub(obj, meth)
16
+ (self.stubs.delete(MuchStub::Stub.key(obj, meth)) || MuchStub::NullStub.new).teardown
17
+ end
18
+
19
+ def self.unstub!
20
+ self.stubs.keys.each{ |key| self.stubs.delete(key).teardown }
21
+ end
22
+
23
+ def self.stub_send(obj, meth, *args, &block)
24
+ orig_caller = caller_locations
25
+ stub = self.stubs.fetch(MuchStub::Stub.key(obj, meth)) do
26
+ raise NotStubbedError, "`#{meth}` not stubbed.", orig_caller.map(&:to_s)
27
+ end
28
+ stub.call_method(args, &block)
29
+ end
30
+
31
+ class Stub
32
+
33
+ def self.key(object, method_name)
34
+ "--#{object.object_id}--#{method_name}--"
35
+ end
36
+
37
+ attr_reader :method_name, :name, :ivar_name, :do
38
+
39
+ def initialize(object, method_name, orig_caller = nil, &block)
40
+ orig_caller ||= caller_locations
41
+ @metaclass = class << object; self; end
42
+ @method_name = method_name.to_s
43
+ @name = "__muchstub_stub__#{object.object_id}_#{@method_name}"
44
+ @ivar_name = "@__muchstub_stub_#{object.object_id}_" \
45
+ "#{@method_name.to_sym.object_id}"
46
+
47
+ setup(object, orig_caller)
48
+
49
+ @do = block
50
+ @lookup = {}
51
+ end
52
+
53
+ def do=(block)
54
+ @do = block || @do
55
+ end
56
+
57
+ def call_method(args, &block)
58
+ @method.call(*args, &block)
59
+ end
60
+
61
+ def call(args, orig_caller = nil, &block)
62
+ orig_caller ||= caller_locations
63
+ unless arity_matches?(args)
64
+ msg = "arity mismatch on `#{@method_name}`: " \
65
+ "expected #{number_of_args(@method.arity)}, " \
66
+ "called with #{args.size}"
67
+ raise StubArityError, msg, orig_caller.map(&:to_s)
68
+ end
69
+ lookup(args, orig_caller).call(*args, &block)
70
+ rescue NotStubbedError => exception
71
+ @lookup.rehash
72
+ lookup(args, orig_caller).call(*args, &block)
73
+ end
74
+
75
+ def with(*args, &block)
76
+ orig_caller = caller_locations
77
+ unless arity_matches?(args)
78
+ msg = "arity mismatch on `#{@method_name}`: " \
79
+ "expected #{number_of_args(@method.arity)}, " \
80
+ "stubbed with #{args.size}"
81
+ raise StubArityError, msg, orig_caller.map(&:to_s)
82
+ end
83
+ @lookup[args] = block
84
+ end
85
+
86
+ def teardown
87
+ @metaclass.send(:undef_method, @method_name)
88
+ MuchStub.send(:remove_instance_variable, @ivar_name)
89
+ @metaclass.send(:alias_method, @method_name, @name)
90
+ @metaclass.send(:undef_method, @name)
91
+ end
92
+
93
+ def inspect
94
+ "#<#{self.class}:#{'0x0%x' % (object_id << 1)}" \
95
+ " @method_name=#{@method_name.inspect}" \
96
+ ">"
97
+ end
98
+
99
+ private
100
+
101
+ def setup(object, orig_caller)
102
+ unless object.respond_to?(@method_name)
103
+ msg = "#{object.inspect} does not respond to `#{@method_name}`"
104
+ raise StubError, msg, orig_caller.map(&:to_s)
105
+ end
106
+ is_constant = object.kind_of?(Module)
107
+ local_object_methods = object.methods(false).map(&:to_s)
108
+ all_object_methods = object.methods.map(&:to_s)
109
+ if (is_constant && !local_object_methods.include?(@method_name)) ||
110
+ (!is_constant && !all_object_methods.include?(@method_name))
111
+ params_list = ParameterList.new(object, @method_name)
112
+ @metaclass.class_eval <<-method
113
+ def #{@method_name}(#{params_list}); super; end
114
+ method
115
+ end
116
+
117
+ if !local_object_methods.include?(@name) # already stubbed
118
+ @metaclass.send(:alias_method, @name, @method_name)
119
+ end
120
+ @method = object.method(@name)
121
+
122
+ MuchStub.instance_variable_set(@ivar_name, self)
123
+ @metaclass.class_eval <<-stub_method
124
+ def #{@method_name}(*args, &block)
125
+ MuchStub.instance_variable_get("#{@ivar_name}").call(args, caller_locations, &block)
126
+ end
127
+ stub_method
128
+ end
129
+
130
+ def lookup(args, orig_caller)
131
+ @lookup.fetch(args) do
132
+ self.do || begin
133
+ msg = "#{inspect_call(args)} not stubbed."
134
+ inspect_lookup_stubs.tap do |stubs|
135
+ msg += "\nStubs:\n#{stubs}" if !stubs.empty?
136
+ end
137
+ raise NotStubbedError, msg, orig_caller.map(&:to_s)
138
+ end
139
+ end
140
+ end
141
+
142
+ def arity_matches?(args)
143
+ return true if @method.arity == args.size # mandatory args
144
+ return true if @method.arity < 0 && args.size >= (@method.arity+1).abs # variable args
145
+ return false
146
+ end
147
+
148
+ def inspect_lookup_stubs
149
+ @lookup.keys.map{ |args| " - #{inspect_call(args)}" }.join("\n")
150
+ end
151
+
152
+ def inspect_call(args)
153
+ "`#{@method_name}(#{args.map(&:inspect).join(',')})`"
154
+ end
155
+
156
+ def number_of_args(arity)
157
+ if arity < 0
158
+ "at least #{(arity + 1).abs}"
159
+ else
160
+ arity
161
+ end
162
+ end
163
+
164
+ end
165
+
166
+ StubError = Class.new(ArgumentError)
167
+ NotStubbedError = Class.new(StubError)
168
+ StubArityError = Class.new(StubError)
169
+
170
+ NullStub = Class.new do
171
+ def teardown; end # no-op
172
+ end
173
+
174
+ module ParameterList
175
+
176
+ LETTERS = ('a'..'z').to_a.freeze
177
+
178
+ def self.new(object, method_name)
179
+ arity = get_arity(object, method_name)
180
+ params = build_params_from_arity(arity)
181
+ params << '*args' if arity < 0
182
+ params << '&block'
183
+ params.join(', ')
184
+ end
185
+
186
+ private
187
+
188
+ def self.get_arity(object, method_name)
189
+ object.method(method_name).arity
190
+ rescue NameError
191
+ -1
192
+ end
193
+
194
+ def self.build_params_from_arity(arity)
195
+ number = arity < 0 ? (arity + 1).abs : arity
196
+ (0..(number - 1)).map{ |param_index| get_param_name(param_index) }
197
+ end
198
+
199
+ def self.get_param_name(param_index)
200
+ param_index += LETTERS.size # avoid getting 0 for the number of letters
201
+ number_of_letters, letter_index = param_index.divmod(LETTERS.size)
202
+ LETTERS[letter_index] * number_of_letters
203
+ end
204
+
205
+ end
206
+
207
+ end
208
+
209
+ # Kernel#caller_locations polyfill for pre ruby 2.0.0
210
+ if RUBY_VERSION =~ /\A1\..+/ && !Kernel.respond_to?(:caller_locations)
211
+ module Kernel
212
+ def caller_locations(start = 1, length = nil)
213
+ length ? caller[start, length] : caller[start..-1]
214
+ end
215
+ end
216
+ end
@@ -0,0 +1,3 @@
1
+ module MuchStub
2
+ VERSION = "0.1.0"
3
+ end
data/log/.gitkeep ADDED
File without changes
data/much-stub.gemspec ADDED
@@ -0,0 +1,23 @@
1
+ # -*- encoding: utf-8 -*-
2
+ lib = File.expand_path('../lib', __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require "much-stub/version"
5
+
6
+ Gem::Specification.new do |gem|
7
+ gem.name = "much-stub"
8
+ gem.version = MuchStub::VERSION
9
+ gem.authors = ["Kelly Redding", "Collin Redding"]
10
+ gem.email = ["kelly@kellyredding.com", "collin.redding@me.com"]
11
+ gem.summary = "Stubbing API for replacing method calls on objects in test runs."
12
+ gem.description = "Stubbing API for replacing method calls on objects in test runs."
13
+ gem.homepage = "https://github.com/redding/much-stub"
14
+ gem.license = 'MIT'
15
+
16
+ gem.files = `git ls-files`.split($/)
17
+ gem.executables = gem.files.grep(%r{^bin/}).map{ |f| File.basename(f) }
18
+ gem.test_files = gem.files.grep(%r{^(test|spec|features)/})
19
+ gem.require_paths = ["lib"]
20
+
21
+ gem.add_development_dependency("assert", ["~> 2.16.3"])
22
+
23
+ end
data/test/helper.rb ADDED
@@ -0,0 +1,25 @@
1
+ # this file is automatically required when you run `assert`
2
+ # put any test helpers here
3
+
4
+ # add the root dir to the load path
5
+ $LOAD_PATH.unshift(File.expand_path("../..", __FILE__))
6
+
7
+ # require pry for debugging (`binding.pry`)
8
+ require 'pry'
9
+
10
+ require 'test/support/factory'
11
+
12
+ # 1.8.7 backfills
13
+
14
+ # Array#sample
15
+ if !(a = Array.new).respond_to?(:sample) && a.respond_to?(:choice)
16
+ class Array
17
+ alias_method :sample, :choice
18
+ end
19
+ end
20
+
21
+ # unstub all test stubs automatically for Assert test suite
22
+ require 'assert'
23
+ class Assert::Context
24
+ teardown{ MuchStub.unstub! }
25
+ end
@@ -0,0 +1,6 @@
1
+ require 'assert/factory'
2
+
3
+ module Factory
4
+ extend Assert::Factory
5
+
6
+ end
@@ -0,0 +1,754 @@
1
+ require 'assert'
2
+ require 'much-stub'
3
+
4
+ module MuchStub
5
+
6
+ class SystemTests < Assert::Context
7
+ desc "MuchStub"
8
+
9
+ end
10
+
11
+ class InstanceTests < SystemTests
12
+ desc "for instance methods"
13
+ setup do
14
+ @instance = TestClass.new
15
+ MuchStub.stub(@instance, :noargs){ 'default' }
16
+ MuchStub.stub(@instance, :noargs).with{ 'none' }
17
+
18
+ MuchStub.stub(@instance, :withargs){ 'default' }
19
+ MuchStub.stub(@instance, :withargs).with(1){ 'one' }
20
+
21
+ MuchStub.stub(@instance, :anyargs){ 'default' }
22
+ MuchStub.stub(@instance, :anyargs).with(1, 2){ 'one-two' }
23
+
24
+ MuchStub.stub(@instance, :minargs){ 'default' }
25
+ MuchStub.stub(@instance, :minargs).with(1, 2){ 'one-two' }
26
+ MuchStub.stub(@instance, :minargs).with(1, 2, 3){ 'one-two-three' }
27
+
28
+ MuchStub.stub(@instance, :withblock){ 'default' }
29
+ end
30
+ subject{ @instance }
31
+
32
+ should "allow stubbing a method that doesn't take args" do
33
+ assert_equal 'none', subject.noargs
34
+ end
35
+
36
+ should "allow stubbing a method that takes args" do
37
+ assert_equal 'one', subject.withargs(1)
38
+ assert_equal 'default', subject.withargs(2)
39
+ end
40
+
41
+ should "allow stubbing a method that takes any args" do
42
+ assert_equal 'default', subject.anyargs
43
+ assert_equal 'default', subject.anyargs(1)
44
+ assert_equal 'one-two', subject.anyargs(1, 2)
45
+ end
46
+
47
+ should "allow stubbing a method that takes a minimum number of args" do
48
+ assert_equal 'one-two', subject.minargs(1, 2)
49
+ assert_equal 'one-two-three', subject.minargs(1, 2, 3)
50
+ assert_equal 'default', subject.minargs(1, 2, 4)
51
+ assert_equal 'default', subject.minargs(1, 2, 3, 4)
52
+ end
53
+
54
+ should "allow stubbing a method that takes a block" do
55
+ assert_equal 'default', subject.withblock
56
+ assert_equal 'default', subject.withblock{ 'my-block' }
57
+ end
58
+
59
+ should "not allow stubbing methods with invalid arity" do
60
+ assert_raises{ MuchStub.stub(subject, :noargs).with(1){ } }
61
+
62
+ assert_raises{ MuchStub.stub(subject, :withargs).with{ } }
63
+ assert_raises{ MuchStub.stub(subject, :withargs).with(1, 2){ } }
64
+
65
+ assert_raises{ MuchStub.stub(subject, :minargs).with{ } }
66
+ assert_raises{ MuchStub.stub(subject, :minargs).with(1){ } }
67
+
68
+ assert_raises{ MuchStub.stub(subject, :withblock).with(1){ } }
69
+ end
70
+
71
+ should "not allow calling methods with invalid arity" do
72
+ assert_raises{ subject.noargs(1) }
73
+
74
+ assert_raises{ subject.withargs }
75
+ assert_raises{ subject.withargs(1, 2) }
76
+
77
+ assert_raises{ subject.minargs }
78
+ assert_raises{ subject.minargs(1) }
79
+
80
+ assert_raises{ subject.withblock(1) }
81
+ end
82
+
83
+ end
84
+
85
+ class ClassTests < SystemTests
86
+ desc "for singleton methods on a class"
87
+ setup do
88
+ @class = TestClass
89
+ MuchStub.stub(@class, :noargs){ 'default' }
90
+ MuchStub.stub(@class, :noargs).with{ 'none' }
91
+
92
+ MuchStub.stub(@class, :withargs){ 'default' }
93
+ MuchStub.stub(@class, :withargs).with(1){ 'one' }
94
+
95
+ MuchStub.stub(@class, :anyargs){ 'default' }
96
+ MuchStub.stub(@class, :anyargs).with(1, 2){ 'one-two' }
97
+
98
+ MuchStub.stub(@class, :minargs){ 'default' }
99
+ MuchStub.stub(@class, :minargs).with(1, 2){ 'one-two' }
100
+ MuchStub.stub(@class, :minargs).with(1, 2, 3){ 'one-two-three' }
101
+
102
+ MuchStub.stub(@class, :withblock){ 'default' }
103
+ end
104
+ subject{ @class }
105
+
106
+ should "allow stubbing a method that doesn't take args" do
107
+ assert_equal 'none', subject.noargs
108
+ end
109
+
110
+ should "allow stubbing a method that takes args" do
111
+ assert_equal 'one', subject.withargs(1)
112
+ assert_equal 'default', subject.withargs(2)
113
+ end
114
+
115
+ should "allow stubbing a method that takes any args" do
116
+ assert_equal 'default', subject.anyargs
117
+ assert_equal 'default', subject.anyargs(1)
118
+ assert_equal 'one-two', subject.anyargs(1, 2)
119
+ end
120
+
121
+ should "allow stubbing a method that takes a minimum number of args" do
122
+ assert_equal 'one-two', subject.minargs(1, 2)
123
+ assert_equal 'one-two-three', subject.minargs(1, 2, 3)
124
+ assert_equal 'default', subject.minargs(1, 2, 4)
125
+ assert_equal 'default', subject.minargs(1, 2, 3, 4)
126
+ end
127
+
128
+ should "allow stubbing a method that takes a block" do
129
+ assert_equal 'default', subject.withblock
130
+ assert_equal 'default', subject.withblock{ 'my-block' }
131
+ end
132
+
133
+ should "not allow stubbing methods with invalid arity" do
134
+ assert_raises{ MuchStub.stub(subject, :noargs).with(1){ } }
135
+
136
+ assert_raises{ MuchStub.stub(subject, :withargs).with{ } }
137
+ assert_raises{ MuchStub.stub(subject, :withargs).with(1, 2){ } }
138
+
139
+ assert_raises{ MuchStub.stub(subject, :minargs).with{ } }
140
+ assert_raises{ MuchStub.stub(subject, :minargs).with(1){ } }
141
+
142
+ assert_raises{ MuchStub.stub(subject, :withblock).with(1){ } }
143
+ end
144
+
145
+ should "not allow calling methods with invalid arity" do
146
+ assert_raises{ subject.noargs(1) }
147
+
148
+ assert_raises{ subject.withargs }
149
+ assert_raises{ subject.withargs(1, 2) }
150
+
151
+ assert_raises{ subject.minargs }
152
+ assert_raises{ subject.minargs(1) }
153
+
154
+ assert_raises{ subject.withblock(1) }
155
+ end
156
+
157
+ end
158
+
159
+ class ModuleTests < SystemTests
160
+ desc "for singleton methods on a module"
161
+ setup do
162
+ @module = TestModule
163
+ MuchStub.stub(@module, :noargs){ 'default' }
164
+ MuchStub.stub(@module, :noargs).with{ 'none' }
165
+
166
+ MuchStub.stub(@module, :withargs){ 'default' }
167
+ MuchStub.stub(@module, :withargs).with(1){ 'one' }
168
+
169
+ MuchStub.stub(@module, :anyargs){ 'default' }
170
+ MuchStub.stub(@module, :anyargs).with(1, 2){ 'one-two' }
171
+
172
+ MuchStub.stub(@module, :minargs){ 'default' }
173
+ MuchStub.stub(@module, :minargs).with(1, 2){ 'one-two' }
174
+ MuchStub.stub(@module, :minargs).with(1, 2, 3){ 'one-two-three' }
175
+
176
+ MuchStub.stub(@module, :withblock){ 'default' }
177
+ end
178
+ subject{ @module }
179
+
180
+ should "allow stubbing a method that doesn't take args" do
181
+ assert_equal 'none', subject.noargs
182
+ end
183
+
184
+ should "allow stubbing a method that takes args" do
185
+ assert_equal 'one', subject.withargs(1)
186
+ assert_equal 'default', subject.withargs(2)
187
+ end
188
+
189
+ should "allow stubbing a method that takes any args" do
190
+ assert_equal 'default', subject.anyargs
191
+ assert_equal 'default', subject.anyargs(1)
192
+ assert_equal 'one-two', subject.anyargs(1, 2)
193
+ end
194
+
195
+ should "allow stubbing a method that takes a minimum number of args" do
196
+ assert_equal 'one-two', subject.minargs(1, 2)
197
+ assert_equal 'one-two-three', subject.minargs(1, 2, 3)
198
+ assert_equal 'default', subject.minargs(1, 2, 4)
199
+ assert_equal 'default', subject.minargs(1, 2, 3, 4)
200
+ end
201
+
202
+ should "allow stubbing a method that takes a block" do
203
+ assert_equal 'default', subject.withblock
204
+ assert_equal 'default', subject.withblock{ 'my-block' }
205
+ end
206
+
207
+ should "not allow stubbing methods with invalid arity" do
208
+ assert_raises{ MuchStub.stub(subject, :noargs).with(1){ } }
209
+
210
+ assert_raises{ MuchStub.stub(subject, :withargs).with{ } }
211
+ assert_raises{ MuchStub.stub(subject, :withargs).with(1, 2){ } }
212
+
213
+ assert_raises{ MuchStub.stub(subject, :minargs).with{ } }
214
+ assert_raises{ MuchStub.stub(subject, :minargs).with(1){ } }
215
+
216
+ assert_raises{ MuchStub.stub(subject, :withblock).with(1){ } }
217
+ end
218
+
219
+ should "not allow calling methods with invalid arity" do
220
+ assert_raises{ subject.noargs(1) }
221
+
222
+ assert_raises{ subject.withargs }
223
+ assert_raises{ subject.withargs(1, 2) }
224
+
225
+ assert_raises{ subject.minargs }
226
+ assert_raises{ subject.minargs(1) }
227
+
228
+ assert_raises{ subject.withblock(1) }
229
+ end
230
+
231
+ end
232
+
233
+ class ExtendedTests < SystemTests
234
+ desc "for extended methods"
235
+ setup do
236
+ @class = Class.new{ extend TestMixin }
237
+ MuchStub.stub(@class, :noargs){ 'default' }
238
+ MuchStub.stub(@class, :noargs).with{ 'none' }
239
+
240
+ MuchStub.stub(@class, :withargs){ 'default' }
241
+ MuchStub.stub(@class, :withargs).with(1){ 'one' }
242
+
243
+ MuchStub.stub(@class, :anyargs){ 'default' }
244
+ MuchStub.stub(@class, :anyargs).with(1, 2){ 'one-two' }
245
+
246
+ MuchStub.stub(@class, :minargs){ 'default' }
247
+ MuchStub.stub(@class, :minargs).with(1, 2){ 'one-two' }
248
+ MuchStub.stub(@class, :minargs).with(1, 2, 3){ 'one-two-three' }
249
+
250
+ MuchStub.stub(@class, :withblock){ 'default' }
251
+ end
252
+ subject{ @class }
253
+
254
+ should "allow stubbing a method that doesn't take args" do
255
+ assert_equal 'none', subject.noargs
256
+ end
257
+
258
+ should "allow stubbing a method that takes args" do
259
+ assert_equal 'one', subject.withargs(1)
260
+ assert_equal 'default', subject.withargs(2)
261
+ end
262
+
263
+ should "allow stubbing a method that takes any args" do
264
+ assert_equal 'default', subject.anyargs
265
+ assert_equal 'default', subject.anyargs(1)
266
+ assert_equal 'one-two', subject.anyargs(1, 2)
267
+ end
268
+
269
+ should "allow stubbing a method that takes a minimum number of args" do
270
+ assert_equal 'one-two', subject.minargs(1, 2)
271
+ assert_equal 'one-two-three', subject.minargs(1, 2, 3)
272
+ assert_equal 'default', subject.minargs(1, 2, 4)
273
+ assert_equal 'default', subject.minargs(1, 2, 3, 4)
274
+ end
275
+
276
+ should "allow stubbing a method that takes a block" do
277
+ assert_equal 'default', subject.withblock
278
+ assert_equal 'default', subject.withblock{ 'my-block' }
279
+ end
280
+
281
+ should "not allow stubbing methods with invalid arity" do
282
+ assert_raises{ MuchStub.stub(subject, :noargs).with(1){ } }
283
+
284
+ assert_raises{ MuchStub.stub(subject, :withargs).with{ } }
285
+ assert_raises{ MuchStub.stub(subject, :withargs).with(1, 2){ } }
286
+
287
+ assert_raises{ MuchStub.stub(subject, :minargs).with{ } }
288
+ assert_raises{ MuchStub.stub(subject, :minargs).with(1){ } }
289
+
290
+ assert_raises{ MuchStub.stub(subject, :withblock).with(1){ } }
291
+ end
292
+
293
+ should "not allow calling methods with invalid arity" do
294
+ assert_raises{ subject.noargs(1) }
295
+
296
+ assert_raises{ subject.withargs }
297
+ assert_raises{ subject.withargs(1, 2) }
298
+
299
+ assert_raises{ subject.minargs }
300
+ assert_raises{ subject.minargs(1) }
301
+
302
+ assert_raises{ subject.withblock(1) }
303
+ end
304
+
305
+ end
306
+
307
+ class IncludedTests < SystemTests
308
+ desc "for an included method"
309
+ setup do
310
+ @class = Class.new{ include TestMixin }
311
+ @instance = @class.new
312
+ MuchStub.stub(@instance, :noargs){ 'default' }
313
+ MuchStub.stub(@instance, :noargs).with{ 'none' }
314
+
315
+ MuchStub.stub(@instance, :withargs){ 'default' }
316
+ MuchStub.stub(@instance, :withargs).with(1){ 'one' }
317
+
318
+ MuchStub.stub(@instance, :anyargs){ 'default' }
319
+ MuchStub.stub(@instance, :anyargs).with(1, 2){ 'one-two' }
320
+
321
+ MuchStub.stub(@instance, :minargs){ 'default' }
322
+ MuchStub.stub(@instance, :minargs).with(1, 2){ 'one-two' }
323
+ MuchStub.stub(@instance, :minargs).with(1, 2, 3){ 'one-two-three' }
324
+
325
+ MuchStub.stub(@instance, :withblock){ 'default' }
326
+ end
327
+ subject{ @instance }
328
+
329
+ should "allow stubbing a method that doesn't take args" do
330
+ assert_equal 'none', subject.noargs
331
+ end
332
+
333
+ should "allow stubbing a method that takes args" do
334
+ assert_equal 'one', subject.withargs(1)
335
+ assert_equal 'default', subject.withargs(2)
336
+ end
337
+
338
+ should "allow stubbing a method that takes any args" do
339
+ assert_equal 'default', subject.anyargs
340
+ assert_equal 'default', subject.anyargs(1)
341
+ assert_equal 'one-two', subject.anyargs(1, 2)
342
+ end
343
+
344
+ should "allow stubbing a method that takes a minimum number of args" do
345
+ assert_equal 'one-two', subject.minargs(1, 2)
346
+ assert_equal 'one-two-three', subject.minargs(1, 2, 3)
347
+ assert_equal 'default', subject.minargs(1, 2, 4)
348
+ assert_equal 'default', subject.minargs(1, 2, 3, 4)
349
+ end
350
+
351
+ should "allow stubbing a method that takes a block" do
352
+ assert_equal 'default', subject.withblock
353
+ assert_equal 'default', subject.withblock{ 'my-block' }
354
+ end
355
+
356
+ should "not allow stubbing methods with invalid arity" do
357
+ assert_raises{ MuchStub.stub(subject, :noargs).with(1){ } }
358
+
359
+ assert_raises{ MuchStub.stub(subject, :withargs).with{ } }
360
+ assert_raises{ MuchStub.stub(subject, :withargs).with(1, 2){ } }
361
+
362
+ assert_raises{ MuchStub.stub(subject, :minargs).with{ } }
363
+ assert_raises{ MuchStub.stub(subject, :minargs).with(1){ } }
364
+
365
+ assert_raises{ MuchStub.stub(subject, :withblock).with(1){ } }
366
+ end
367
+
368
+ should "not allow calling methods with invalid arity" do
369
+ assert_raises{ subject.noargs(1) }
370
+
371
+ assert_raises{ subject.withargs }
372
+ assert_raises{ subject.withargs(1, 2) }
373
+
374
+ assert_raises{ subject.minargs }
375
+ assert_raises{ subject.minargs(1) }
376
+
377
+ assert_raises{ subject.withblock(1) }
378
+ end
379
+
380
+ end
381
+
382
+ class InheritedClassTests < SystemTests
383
+ desc "for an inherited class method"
384
+ setup do
385
+ @class = Class.new(TestClass)
386
+ MuchStub.stub(@class, :noargs){ 'default' }
387
+ MuchStub.stub(@class, :noargs).with{ 'none' }
388
+
389
+ MuchStub.stub(@class, :withargs){ 'default' }
390
+ MuchStub.stub(@class, :withargs).with(1){ 'one' }
391
+
392
+ MuchStub.stub(@class, :anyargs){ 'default' }
393
+ MuchStub.stub(@class, :anyargs).with(1, 2){ 'one-two' }
394
+
395
+ MuchStub.stub(@class, :minargs){ 'default' }
396
+ MuchStub.stub(@class, :minargs).with(1, 2){ 'one-two' }
397
+ MuchStub.stub(@class, :minargs).with(1, 2, 3){ 'one-two-three' }
398
+
399
+ MuchStub.stub(@class, :withblock){ 'default' }
400
+ end
401
+ subject{ @class }
402
+
403
+ should "allow stubbing a method that doesn't take args" do
404
+ assert_equal 'none', subject.noargs
405
+ end
406
+
407
+ should "allow stubbing a method that takes args" do
408
+ assert_equal 'one', subject.withargs(1)
409
+ assert_equal 'default', subject.withargs(2)
410
+ end
411
+
412
+ should "allow stubbing a method that takes any args" do
413
+ assert_equal 'default', subject.anyargs
414
+ assert_equal 'default', subject.anyargs(1)
415
+ assert_equal 'one-two', subject.anyargs(1, 2)
416
+ end
417
+
418
+ should "allow stubbing a method that takes a minimum number of args" do
419
+ assert_equal 'one-two', subject.minargs(1, 2)
420
+ assert_equal 'one-two-three', subject.minargs(1, 2, 3)
421
+ assert_equal 'default', subject.minargs(1, 2, 4)
422
+ assert_equal 'default', subject.minargs(1, 2, 3, 4)
423
+ end
424
+
425
+ should "allow stubbing a method that takes a block" do
426
+ assert_equal 'default', subject.withblock
427
+ assert_equal 'default', subject.withblock{ 'my-block' }
428
+ end
429
+
430
+ should "not allow stubbing methods with invalid arity" do
431
+ assert_raises{ MuchStub.stub(subject, :noargs).with(1){ } }
432
+
433
+ assert_raises{ MuchStub.stub(subject, :withargs).with{ } }
434
+ assert_raises{ MuchStub.stub(subject, :withargs).with(1, 2){ } }
435
+
436
+ assert_raises{ MuchStub.stub(subject, :minargs).with{ } }
437
+ assert_raises{ MuchStub.stub(subject, :minargs).with(1){ } }
438
+
439
+ assert_raises{ MuchStub.stub(subject, :withblock).with(1){ } }
440
+ end
441
+
442
+ should "not allow calling methods with invalid arity" do
443
+ assert_raises{ subject.noargs(1) }
444
+
445
+ assert_raises{ subject.withargs }
446
+ assert_raises{ subject.withargs(1, 2) }
447
+
448
+ assert_raises{ subject.minargs }
449
+ assert_raises{ subject.minargs(1) }
450
+
451
+ assert_raises{ subject.withblock(1) }
452
+ end
453
+
454
+ end
455
+
456
+ class InheritedInstanceTests < SystemTests
457
+ desc "for an inherited instance method"
458
+ setup do
459
+ @class = Class.new(TestClass)
460
+ @instance = @class.new
461
+ MuchStub.stub(@instance, :noargs){ 'default' }
462
+ MuchStub.stub(@instance, :noargs).with{ 'none' }
463
+
464
+ MuchStub.stub(@instance, :withargs){ 'default' }
465
+ MuchStub.stub(@instance, :withargs).with(1){ 'one' }
466
+
467
+ MuchStub.stub(@instance, :anyargs){ 'default' }
468
+ MuchStub.stub(@instance, :anyargs).with(1, 2){ 'one-two' }
469
+
470
+ MuchStub.stub(@instance, :minargs){ 'default' }
471
+ MuchStub.stub(@instance, :minargs).with(1, 2){ 'one-two' }
472
+ MuchStub.stub(@instance, :minargs).with(1, 2, 3){ 'one-two-three' }
473
+
474
+ MuchStub.stub(@instance, :withblock){ 'default' }
475
+ end
476
+ subject{ @instance }
477
+
478
+ should "allow stubbing a method that doesn't take args" do
479
+ assert_equal 'none', subject.noargs
480
+ end
481
+
482
+ should "allow stubbing a method that takes args" do
483
+ assert_equal 'one', subject.withargs(1)
484
+ assert_equal 'default', subject.withargs(2)
485
+ end
486
+
487
+ should "allow stubbing a method that takes any args" do
488
+ assert_equal 'default', subject.anyargs
489
+ assert_equal 'default', subject.anyargs(1)
490
+ assert_equal 'one-two', subject.anyargs(1, 2)
491
+ end
492
+
493
+ should "allow stubbing a method that takes a minimum number of args" do
494
+ assert_equal 'one-two', subject.minargs(1, 2)
495
+ assert_equal 'one-two-three', subject.minargs(1, 2, 3)
496
+ assert_equal 'default', subject.minargs(1, 2, 4)
497
+ assert_equal 'default', subject.minargs(1, 2, 3, 4)
498
+ end
499
+
500
+ should "allow stubbing a method that takes a block" do
501
+ assert_equal 'default', subject.withblock
502
+ assert_equal 'default', subject.withblock{ 'my-block' }
503
+ end
504
+
505
+ should "not allow stubbing methods with invalid arity" do
506
+ assert_raises{ MuchStub.stub(subject, :noargs).with(1){ } }
507
+
508
+ assert_raises{ MuchStub.stub(subject, :withargs).with{ } }
509
+ assert_raises{ MuchStub.stub(subject, :withargs).with(1, 2){ } }
510
+
511
+ assert_raises{ MuchStub.stub(subject, :minargs).with{ } }
512
+ assert_raises{ MuchStub.stub(subject, :minargs).with(1){ } }
513
+
514
+ assert_raises{ MuchStub.stub(subject, :withblock).with(1){ } }
515
+ end
516
+
517
+ should "not allow calling methods with invalid arity" do
518
+ assert_raises{ subject.noargs(1) }
519
+
520
+ assert_raises{ subject.withargs }
521
+ assert_raises{ subject.withargs(1, 2) }
522
+
523
+ assert_raises{ subject.minargs }
524
+ assert_raises{ subject.minargs(1) }
525
+
526
+ assert_raises{ subject.withblock(1) }
527
+ end
528
+
529
+ end
530
+
531
+ class DelegateClassTests < SystemTests
532
+ desc "a class that delegates another object"
533
+ setup do
534
+ @class = DelegateClass
535
+ MuchStub.stub(@class, :noargs){ 'default' }
536
+ MuchStub.stub(@class, :noargs).with{ 'none' }
537
+
538
+ MuchStub.stub(@class, :withargs){ 'default' }
539
+ MuchStub.stub(@class, :withargs).with(1){ 'one' }
540
+
541
+ MuchStub.stub(@class, :anyargs){ 'default' }
542
+ MuchStub.stub(@class, :anyargs).with(1, 2){ 'one-two' }
543
+
544
+ MuchStub.stub(@class, :minargs){ 'default' }
545
+ MuchStub.stub(@class, :minargs).with(1, 2){ 'one-two' }
546
+ MuchStub.stub(@class, :minargs).with(1, 2, 3){ 'one-two-three' }
547
+
548
+ MuchStub.stub(@class, :withblock){ 'default' }
549
+ end
550
+ subject{ @class }
551
+
552
+ should "allow stubbing a method that doesn't take args" do
553
+ assert_equal 'none', subject.noargs
554
+ end
555
+
556
+ should "allow stubbing a method that takes args" do
557
+ assert_equal 'one', subject.withargs(1)
558
+ assert_equal 'default', subject.withargs(2)
559
+ end
560
+
561
+ should "allow stubbing a method that takes any args" do
562
+ assert_equal 'default', subject.anyargs
563
+ assert_equal 'default', subject.anyargs(1)
564
+ assert_equal 'one-two', subject.anyargs(1, 2)
565
+ end
566
+
567
+ should "allow stubbing a method that takes a minimum number of args" do
568
+ assert_equal 'one-two', subject.minargs(1, 2)
569
+ assert_equal 'one-two-three', subject.minargs(1, 2, 3)
570
+ assert_equal 'default', subject.minargs(1, 2, 4)
571
+ assert_equal 'default', subject.minargs(1, 2, 3, 4)
572
+ end
573
+
574
+ should "allow stubbing a method that takes a block" do
575
+ assert_equal 'default', subject.withblock
576
+ assert_equal 'default', subject.withblock{ 'my-block' }
577
+ end
578
+
579
+ should "allow stubbing methods with invalid arity" do
580
+ assert_nothing_raised{ MuchStub.stub(subject, :noargs).with(1){ } }
581
+
582
+ assert_nothing_raised{ MuchStub.stub(subject, :withargs).with{ } }
583
+ assert_nothing_raised{ MuchStub.stub(subject, :withargs).with(1, 2){ } }
584
+
585
+ assert_nothing_raised{ MuchStub.stub(subject, :minargs).with{ } }
586
+ assert_nothing_raised{ MuchStub.stub(subject, :minargs).with(1){ } }
587
+
588
+ assert_nothing_raised{ MuchStub.stub(subject, :withblock).with(1){ } }
589
+ end
590
+
591
+ should "allow calling methods with invalid arity" do
592
+ assert_nothing_raised{ subject.noargs(1) }
593
+
594
+ assert_nothing_raised{ subject.withargs }
595
+ assert_nothing_raised{ subject.withargs(1, 2) }
596
+
597
+ assert_nothing_raised{ subject.minargs }
598
+ assert_nothing_raised{ subject.minargs(1) }
599
+
600
+ assert_nothing_raised{ subject.withblock(1) }
601
+ end
602
+
603
+ end
604
+
605
+ class DelegateInstanceTests < SystemTests
606
+ desc "an instance that delegates another object"
607
+ setup do
608
+ @instance = DelegateClass.new
609
+ MuchStub.stub(@instance, :noargs){ 'default' }
610
+ MuchStub.stub(@instance, :noargs).with{ 'none' }
611
+
612
+ MuchStub.stub(@instance, :withargs){ 'default' }
613
+ MuchStub.stub(@instance, :withargs).with(1){ 'one' }
614
+
615
+ MuchStub.stub(@instance, :anyargs){ 'default' }
616
+ MuchStub.stub(@instance, :anyargs).with(1, 2){ 'one-two' }
617
+
618
+ MuchStub.stub(@instance, :minargs){ 'default' }
619
+ MuchStub.stub(@instance, :minargs).with(1, 2){ 'one-two' }
620
+ MuchStub.stub(@instance, :minargs).with(1, 2, 3){ 'one-two-three' }
621
+
622
+ MuchStub.stub(@instance, :withblock){ 'default' }
623
+ end
624
+ subject{ @instance }
625
+
626
+ should "allow stubbing a method that doesn't take args" do
627
+ assert_equal 'none', subject.noargs
628
+ end
629
+
630
+ should "allow stubbing a method that takes args" do
631
+ assert_equal 'one', subject.withargs(1)
632
+ assert_equal 'default', subject.withargs(2)
633
+ end
634
+
635
+ should "allow stubbing a method that takes any args" do
636
+ assert_equal 'default', subject.anyargs
637
+ assert_equal 'default', subject.anyargs(1)
638
+ assert_equal 'one-two', subject.anyargs(1, 2)
639
+ end
640
+
641
+ should "allow stubbing a method that takes a minimum number of args" do
642
+ assert_equal 'one-two', subject.minargs(1, 2)
643
+ assert_equal 'one-two-three', subject.minargs(1, 2, 3)
644
+ assert_equal 'default', subject.minargs(1, 2, 4)
645
+ assert_equal 'default', subject.minargs(1, 2, 3, 4)
646
+ end
647
+
648
+ should "allow stubbing a method that takes a block" do
649
+ assert_equal 'default', subject.withblock
650
+ assert_equal 'default', subject.withblock{ 'my-block' }
651
+ end
652
+
653
+ should "allow stubbing methods with invalid arity" do
654
+ assert_nothing_raised{ MuchStub.stub(subject, :noargs).with(1){ } }
655
+
656
+ assert_nothing_raised{ MuchStub.stub(subject, :withargs).with{ } }
657
+ assert_nothing_raised{ MuchStub.stub(subject, :withargs).with(1, 2){ } }
658
+
659
+ assert_nothing_raised{ MuchStub.stub(subject, :minargs).with{ } }
660
+ assert_nothing_raised{ MuchStub.stub(subject, :minargs).with(1){ } }
661
+
662
+ assert_nothing_raised{ MuchStub.stub(subject, :withblock).with(1){ } }
663
+ end
664
+
665
+ should "allow calling methods with invalid arity" do
666
+ assert_nothing_raised{ subject.noargs(1) }
667
+
668
+ assert_nothing_raised{ subject.withargs }
669
+ assert_nothing_raised{ subject.withargs(1, 2) }
670
+
671
+ assert_nothing_raised{ subject.minargs }
672
+ assert_nothing_raised{ subject.minargs(1) }
673
+
674
+ assert_nothing_raised{ subject.withblock(1) }
675
+ end
676
+
677
+ end
678
+
679
+ class ParentAndChildClassTests < SystemTests
680
+ desc "for a parent method stubbed on both the parent and child"
681
+ setup do
682
+ @parent_class = Class.new
683
+ @child_class = Class.new(@parent_class)
684
+
685
+ MuchStub.stub(@parent_class, :new){ 'parent' }
686
+ MuchStub.stub(@child_class, :new){ 'child' }
687
+ end
688
+
689
+ should "allow stubbing the methods individually" do
690
+ assert_equal 'parent', @parent_class.new
691
+ assert_equal 'child', @child_class.new
692
+ end
693
+
694
+ end
695
+
696
+ class TestClass
697
+
698
+ def self.noargs; end
699
+ def self.withargs(a); end
700
+ def self.anyargs(*args); end
701
+ def self.minargs(a, b, *args); end
702
+ def self.withblock(&block); end
703
+
704
+ def noargs; end
705
+ def withargs(a); end
706
+ def anyargs(*args); end
707
+ def minargs(a, b, *args); end
708
+ def withblock(&block); end
709
+
710
+ end
711
+
712
+ module TestModule
713
+
714
+ def self.noargs; end
715
+ def self.withargs(a); end
716
+ def self.anyargs(*args); end
717
+ def self.minargs(a, b, *args); end
718
+ def self.withblock(&block); end
719
+
720
+ end
721
+
722
+ module TestMixin
723
+
724
+ def noargs; end
725
+ def withargs(a); end
726
+ def anyargs(*args); end
727
+ def minargs(a, b, *args); end
728
+ def withblock(&block); end
729
+
730
+ end
731
+
732
+ class DelegateClass
733
+ def self.respond_to?(*args)
734
+ TestClass.respond_to?(*args) || super
735
+ end
736
+
737
+ def self.method_missing(name, *args, &block)
738
+ TestClass.respond_to?(name) ? TestClass.send(name, *args, &block) : super
739
+ end
740
+
741
+ def initialize
742
+ @delegate = TestClass.new
743
+ end
744
+
745
+ def respond_to?(*args)
746
+ @delegate.respond_to?(*args) || super
747
+ end
748
+
749
+ def method_missing(name, *args, &block)
750
+ @delegate.respond_to?(name) ? @delegate.send(name, *args, &block) : super
751
+ end
752
+ end
753
+
754
+ end