much-stub 0.1.0

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