much-stub 0.1.2 → 0.1.3

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 948b3a6fa21e50a2a221b167fe768a5d65c7a61c135622fe6ced882a5e406b03
4
- data.tar.gz: 700d700fab285da4620cb4fbd3b521a58a9ffeaf8d50afdcc96780810091e301
3
+ metadata.gz: 25518cd79915a42ef00d555f2f09db36b19ec52237054c1fb763667ff0a5c4d0
4
+ data.tar.gz: edbd7bd553731a3084806768ad3d956b7f086212b095dfaf63e9eff0ba56cc4e
5
5
  SHA512:
6
- metadata.gz: fecb7b76d76bc9ff338461c7ec6a48ac3bf1833bd77f4f248c9d4a145fa0b0177b3ce9d99d01add632266d7f9c5731441f0ad553f14775e7cf704aaffc80099a
7
- data.tar.gz: 55308114a2f7aac2294ba44aac2adf84152cc2213a40a9ff0118b3fe2e8d43738cbc617fb19855c63515e915bc46754fc915d86b568d7a9c97356fb619420156
6
+ metadata.gz: eb69a558eb21bbd717bb9164a5142c318697ea512e0234dd110c0127eaa9eef68a25abd13c2d9c4136dc9474712312a85fb5af8a30fc7dcaf8c7b1cc6d8606c4
7
+ data.tar.gz: 390126be543ddf6c36fcf7dd3c0491c5530ba8535b049b91edf9de6a3461895f5b4f673d2ef0b5b920af30880e71ea705f1043648edef75ede03b9c1af74b311
data/README.md CHANGED
@@ -110,24 +110,43 @@ my_object = my_class.new
110
110
 
111
111
  basic_method_called_with = nil
112
112
  MuchStub.(my_object, :basic_method) { |*args|
113
- basic_method_called_with = args
113
+ basic_method_called_with = MuchStub::Call.new(*args)
114
+ }
115
+ # OR
116
+ MuchStub.(my_object, :basic_method).on_call { |call|
117
+ basic_method_called_with = call
114
118
  }
115
119
 
116
120
  my_object.basic_method(123)
117
- basic_method_called_with
121
+ basic_method_called_with.args
118
122
  # => [123]
119
123
 
120
- iterator_method_call_args = nil
121
- iterator_method_call_block = nil
124
+ basic_method_called_with = nil
125
+ MuchStub.(my_object, :basic_method).with(4, 5, 6) { |*args|
126
+ basic_method_called_with = MuchStub::Call.new(*args)
127
+ }
128
+ # OR
129
+ MuchStub.(my_object, :basic_method).with(4, 5, 6).on_call { |call|
130
+ basic_method_called_with = call
131
+ }
132
+
133
+ my_object.basic_method(4, 5, 6)
134
+ basic_method_called_with.args
135
+ # => [4,5,6]
136
+
137
+ iterator_method_called_with = nil
122
138
  MuchStub.(my_object, :iterator_method) { |*args, &block|
123
- iterator_method_call_args = args
124
- iterator_method_call_block = block
139
+ iterator_method_called_with = MuchStub::Call.new(*args)
140
+ }
141
+ # OR
142
+ MuchStub.(my_object, :iterator_method).on_call { |call|
143
+ iterator_method_called_with = call
125
144
  }
126
145
 
127
146
  my_object.iterator_method([1, 2, 3], &:to_s)
128
- iterator_method_call_args
147
+ iterator_method_called_with.args
129
148
  # => [[1, 2, 3]]
130
- iterator_method_call_block
149
+ iterator_method_called_with.block
131
150
  # => #<Proc:0x00007fb083a6feb0(&:to_s)>
132
151
 
133
152
  # Count method calls for spying.
@@ -145,13 +164,17 @@ basic_method_call_count
145
164
 
146
165
  basic_method_calls = []
147
166
  MuchStub.(my_object, :basic_method) { |*args|
148
- basic_method_calls << args
167
+ basic_method_calls << MuchStub::Call.new(*args)
168
+ }
169
+ # OR
170
+ MuchStub.(my_object, :basic_method).on_call { |call|
171
+ basic_method_calls << call
149
172
  }
150
173
 
151
174
  my_object.basic_method(123)
152
175
  basic_method_calls.size
153
176
  # => 1
154
- basic_method_calls.first
177
+ basic_method_calls.first.args
155
178
  # => [123]
156
179
  ```
157
180
 
@@ -218,12 +241,16 @@ basic_method_called_with
218
241
 
219
242
  basic_method_called_with = nil
220
243
  MuchStub.tap(my_object, :basic_method) { |value, *args|
221
- basic_method_called_with = args
244
+ basic_method_called_with = MuchStub::Call.new(*args)
245
+ }
246
+ # OR
247
+ MuchStub.tap_on_call(my_object, :basic_method) { |value, call|
248
+ basic_method_called_with = call
222
249
  }
223
250
 
224
251
  my_object.basic_method(123)
225
252
  # => "123"
226
- basic_method_called_with
253
+ basic_method_called_with.args
227
254
  # => [123]
228
255
  ```
229
256
 
@@ -266,6 +293,39 @@ thing.value
266
293
  # => 456
267
294
  ```
268
295
 
296
+ ### `MuchStub.spy`
297
+
298
+ Use the `.spy` method to spy on method calls. This is especially helpful for spying on _chained_ method calls.
299
+
300
+ ```ruby
301
+ # Given this object/API
302
+
303
+ myclass = Class.new do
304
+ def one; self; end
305
+ def two(val); self; end
306
+ def three; self; end
307
+ def ready?; false; end
308
+ end
309
+ myobj = myclass.new
310
+
311
+ spy =
312
+ MuchStub.spy(myobj :one, :two, :three, ready?: true)
313
+
314
+ assert_equal spy, myobj.one
315
+ assert_equal spy, myobj.two("a")
316
+ assert_equal spy, myobj.three
317
+
318
+ assert_true myobj.one.two("b").three.ready?
319
+
320
+ assert_kind_of MuchStub::CallSpy, spy
321
+ assert_equal 2, spy.one_call_count
322
+ assert_equal 2, spy.two_call_count
323
+ assert_equal 2, spy.three_call_count
324
+ assert_equal 1, spy.ready_predicate_call_count
325
+ assert_equal ["b"], spy.two_last_called_with.args
326
+ assert_true spy.ready_predicate_called?
327
+ ```
328
+
269
329
  ## Installation
270
330
 
271
331
  Add this line to your application's Gemfile:
@@ -1,5 +1,8 @@
1
1
  require "much-stub/version"
2
2
 
3
+ require "much-stub/call"
4
+ require "much-stub/call_spy"
5
+
3
6
  module MuchStub
4
7
  def self.stubs
5
8
  @stubs ||= {}
@@ -9,6 +12,12 @@ module MuchStub
9
12
  MuchStub::Stub.key(obj, meth)
10
13
  end
11
14
 
15
+ def self.arity_matches?(method, args)
16
+ return true if method.arity == args.size # mandatory args
17
+ return true if method.arity < 0 && args.size >= (method.arity+1).abs # variable args
18
+ return false
19
+ end
20
+
12
21
  def self.call(*args, &block)
13
22
  self.stub(*args, &block)
14
23
  end
@@ -44,6 +53,22 @@ module MuchStub
44
53
  }
45
54
  end
46
55
 
56
+ def self.tap_on_call(obj, meth, &on_call_block)
57
+ self.tap(obj, meth) { |value, *args, &block|
58
+ on_call_block.call(value, MuchStub::Call.new(*args, &block)) if on_call_block
59
+ }
60
+ end
61
+
62
+ def self.spy(obj, *meths, **return_values)
63
+ MuchStub::CallSpy.new(**return_values).tap do |spy|
64
+ meths.each do |meth|
65
+ self.stub(obj, meth) { |*args, &block|
66
+ spy.public_send(meth, *args, &block)
67
+ }
68
+ end
69
+ end
70
+ end
71
+
47
72
  class Stub
48
73
  def self.key(object, method_name)
49
74
  "--#{object.object_id}--#{method_name}--"
@@ -75,11 +100,13 @@ module MuchStub
75
100
 
76
101
  def call(args, orig_caller = nil, &block)
77
102
  orig_caller ||= caller_locations
78
- unless arity_matches?(args)
79
- msg = "arity mismatch on `#{@method_name}`: " \
80
- "expected #{number_of_args(@method.arity)}, " \
81
- "called with #{args.size}"
82
- raise StubArityError, msg, orig_caller.map(&:to_s)
103
+ unless MuchStub.arity_matches?(@method, args)
104
+ raise(
105
+ StubArityError.new(
106
+ @method,
107
+ args,
108
+ method_name: @method_name,
109
+ backtrace: orig_caller))
83
110
  end
84
111
  lookup(args, orig_caller).call(*args, &block)
85
112
  rescue NotStubbedError
@@ -89,13 +116,29 @@ module MuchStub
89
116
 
90
117
  def with(*args, &block)
91
118
  orig_caller = caller_locations
92
- unless arity_matches?(args)
93
- msg = "arity mismatch on `#{@method_name}`: " \
94
- "expected #{number_of_args(@method.arity)}, " \
95
- "stubbed with #{args.size}"
96
- raise StubArityError, msg, orig_caller.map(&:to_s)
119
+ unless MuchStub.arity_matches?(@method, args)
120
+ raise(
121
+ StubArityError.new(
122
+ @method,
123
+ args,
124
+ method_name: @method_name,
125
+ backtrace: orig_caller))
97
126
  end
98
127
  @lookup[args] = block
128
+ self
129
+ end
130
+
131
+ def on_call(&on_call_block)
132
+ stub_block =
133
+ ->(*args, &block) {
134
+ on_call_block.call(MuchStub::Call.new(*args, &block)) if on_call_block
135
+ }
136
+ if @lookup.empty?
137
+ @do = stub_block
138
+ elsif @lookup.has_value?(nil)
139
+ @lookup.transform_values!{ |value| value.nil? ? stub_block : value }
140
+ end
141
+ self
99
142
  end
100
143
 
101
144
  def teardown
@@ -143,7 +186,7 @@ module MuchStub
143
186
  end
144
187
 
145
188
  def lookup(args, orig_caller)
146
- @lookup.fetch(args) do
189
+ @lookup.fetch(args) {
147
190
  self.do || begin
148
191
  msg = "#{inspect_call(args)} not stubbed."
149
192
  inspect_lookup_stubs.tap do |stubs|
@@ -151,13 +194,11 @@ module MuchStub
151
194
  end
152
195
  raise NotStubbedError, msg, orig_caller.map(&:to_s)
153
196
  end
154
- end
155
- end
156
-
157
- def arity_matches?(args)
158
- return true if @method.arity == args.size # mandatory args
159
- return true if @method.arity < 0 && args.size >= (@method.arity+1).abs # variable args
160
- return false
197
+ } ||
198
+ raise(
199
+ StubError,
200
+ "#{inspect_call(args)} stubbed with no block.",
201
+ orig_caller.map(&:to_s))
161
202
  end
162
203
 
163
204
  def inspect_lookup_stubs
@@ -167,19 +208,31 @@ module MuchStub
167
208
  def inspect_call(args)
168
209
  "`#{@method_name}(#{args.map(&:inspect).join(",")})`"
169
210
  end
170
-
171
- def number_of_args(arity)
172
- if arity < 0
173
- "at least #{(arity + 1).abs}"
174
- else
175
- arity
176
- end
177
- end
178
211
  end
179
212
 
180
213
  StubError = Class.new(ArgumentError)
181
214
  NotStubbedError = Class.new(StubError)
182
- StubArityError = Class.new(StubError)
215
+ StubArityError =
216
+ Class.new(StubError) do
217
+ def initialize(method, args, method_name:, backtrace:)
218
+ msg = "arity mismatch on `#{method_name}`: " \
219
+ "expected #{number_of_args(method.arity)}, " \
220
+ "called with #{args.size}"
221
+
222
+ super(msg)
223
+ set_backtrace(Array(backtrace).map(&:to_s))
224
+ end
225
+
226
+ private
227
+
228
+ def number_of_args(arity)
229
+ if arity < 0
230
+ "at least #{(arity + 1).abs}"
231
+ else
232
+ arity
233
+ end
234
+ end
235
+ end
183
236
 
184
237
  NullStub = Class.new do
185
238
  def teardown; end # no-op
@@ -0,0 +1,15 @@
1
+ module MuchStub
2
+ class Call
3
+ attr_reader :pargs, :kargs, :block
4
+
5
+ def initialize(*pargs, **kargs, &block)
6
+ @pargs = pargs.empty? ? nil : pargs
7
+ @kargs = kargs.empty? ? nil : kargs
8
+ @block = block
9
+ end
10
+
11
+ def args
12
+ @args ||= [*pargs, kargs].compact
13
+ end
14
+ end
15
+ end
@@ -0,0 +1,91 @@
1
+ require "much-stub/call"
2
+
3
+ module MuchStub
4
+ class CallSpy
5
+ METHOD_NAME_REPLACEMENTS = {
6
+ "!" => "_bang",
7
+ "?" => "_predicate"
8
+ }.freeze
9
+
10
+ def initialize(**return_values)
11
+ @call_spy_return_values = return_values.transform_keys{ |key| key.to_s }
12
+
13
+ @call_spy_method_calls = Hash.new { |hash, key| hash[key] = [] }
14
+ @call_spy_method_return_values =
15
+ Hash.new { |hash, key| hash[key] = call_spy_return_value_proc(key) }
16
+ end
17
+
18
+ private
19
+
20
+ def call_spy_method_return_value(method_name, much_stub_call)
21
+ @call_spy_method_return_values[method_name.to_s].call(much_stub_call)
22
+ end
23
+
24
+ def call_spy_return_value_proc(method_name)
25
+ value = @call_spy_return_values[method_name]
26
+ return value if value.respond_to?(:call)
27
+
28
+ ->(*) { value.nil? ? self : value }
29
+ end
30
+
31
+ def call_spy_normalize_method_name(name)
32
+ METHOD_NAME_REPLACEMENTS.reduce(name.to_s) { |acc, (source, replacement)|
33
+ acc.gsub(source, replacement)
34
+ }
35
+ end
36
+
37
+ def call_spy_define_spied_method(name)
38
+ method_name = call_spy_normalize_method_name(name)
39
+ self.define_singleton_method(name) do |*args, &block|
40
+ call = MuchStub::Call.new(*args, &block)
41
+ @call_spy_method_calls[method_name] << call
42
+ call_spy_method_return_value(name, call)
43
+ end
44
+ end
45
+
46
+ def call_spy_define_query_method(query_method_match)
47
+ spied_method_name = query_method_match[1]
48
+ query_method_suffix = query_method_match[2]
49
+ method_name = call_spy_normalize_method_name(spied_method_name)
50
+ self.define_singleton_method("#{method_name}#{query_method_suffix}") do
51
+ yield(method_name) if block_given?
52
+ end
53
+ end
54
+
55
+ def method_missing(name, *args, &block)
56
+ if (match = name.match(/(\w+)(_calls)\z/))
57
+ call_spy_define_query_method(match) do |method_name|
58
+ @call_spy_method_calls[method_name]
59
+ end
60
+ self.send(name, *args, &block)
61
+ elsif (match = name.match(/(\w+)(_last_called_with)\z/))
62
+ call_spy_define_query_method(match) do |method_name|
63
+ self.send("#{method_name}_calls").last
64
+ end
65
+ self.send(name, *args, &block)
66
+ elsif (match = name.match(/(\w+)(_called_with)\z/))
67
+ call_spy_define_query_method(match) do |method_name|
68
+ self.send("#{method_name}_last_called_with")
69
+ end
70
+ self.send(name, *args, &block)
71
+ elsif (match = name.match(/(\w+)(_call_count)\z/))
72
+ call_spy_define_query_method(match) do |method_name|
73
+ self.send("#{method_name}_calls").size
74
+ end
75
+ self.send(name, *args, &block)
76
+ elsif (match = name.match(/(\w+)(_called\?)\z/))
77
+ call_spy_define_query_method(match) do |method_name|
78
+ self.send("#{method_name}_call_count") > 0
79
+ end
80
+ self.send(name, *args, &block)
81
+ else
82
+ call_spy_define_spied_method(name)
83
+ self.send(name, *args, &block)
84
+ end
85
+ end
86
+
87
+ def respond_to_missing?(*args)
88
+ super
89
+ end
90
+ end
91
+ end
@@ -1,3 +1,3 @@
1
1
  module MuchStub
2
- VERSION = "0.1.2"
2
+ VERSION = "0.1.3"
3
3
  end
@@ -18,6 +18,8 @@ Gem::Specification.new do |gem|
18
18
  gem.test_files = gem.files.grep(%r{^(test|spec|features)/})
19
19
  gem.require_paths = ["lib"]
20
20
 
21
- gem.add_development_dependency("assert", ["~> 2.18.0"])
21
+ gem.required_ruby_version = "~> 2.5"
22
+
23
+ gem.add_development_dependency("assert", ["~> 2.18.1"])
22
24
 
23
25
  end
@@ -0,0 +1,96 @@
1
+ require "assert"
2
+ require "much-stub/call_spy"
3
+
4
+ require "test/support/factory"
5
+
6
+ class MuchStub::CallSpy
7
+ class UnitTests < Assert::Context
8
+ desc "MuchStub::CallSpy"
9
+ setup do
10
+ @unit_class = MuchStub::CallSpy
11
+ end
12
+ end
13
+
14
+ class InitTests < UnitTests
15
+ desc "when init"
16
+ before do
17
+ @spy = @unit_class.new
18
+ end
19
+ subject{ @spy }
20
+
21
+ should "spy on method calls and return itself" do
22
+ assert_false subject.respond_to?(:get)
23
+
24
+ assert_equal [], subject.get_calls
25
+ assert_nil subject.get_last_called_with
26
+ assert_nil subject.get_called_with
27
+ assert_equal 0, subject.get_call_count
28
+ assert_false subject.get_called?
29
+
30
+ assert_same subject, subject.get
31
+
32
+ assert_true subject.respond_to?(:get)
33
+
34
+ assert_kind_of Array, subject.get_calls
35
+ assert_kind_of MuchStub::Call, subject.get_last_called_with
36
+ assert_equal [], subject.get_last_called_with.args
37
+ assert_equal subject.get_last_called_with, subject.get_called_with
38
+ assert_equal 1, subject.get_call_count
39
+ assert_true subject.get_called?
40
+
41
+ assert_same subject, subject.set!("value1")
42
+ assert_same subject, subject.set!("value2")
43
+
44
+ assert_kind_of Array, subject.set_bang_calls
45
+ assert_kind_of MuchStub::Call, subject.set_bang_last_called_with
46
+ assert_equal ["value2"], subject.set_bang_last_called_with.args
47
+ assert_equal 2, subject.set_bang_call_count
48
+ assert_true subject.set_bang_called?
49
+ end
50
+
51
+ should "normalize method names in call query methods" do
52
+ assert_same subject, subject.set!("value1")
53
+ assert_kind_of Array, subject.set_bang_calls
54
+ assert_kind_of MuchStub::Call, subject.set_bang_last_called_with
55
+ assert_equal ["value1"], subject.set_bang_last_called_with.args
56
+ assert_equal ["value1"], subject.set_bang_called_with.args
57
+ assert_equal 1, subject.set_bang_call_count
58
+ assert_true subject.set_bang_called?
59
+
60
+ assert_same subject, subject.any?
61
+ assert_kind_of Array, subject.any_predicate_calls
62
+ assert_kind_of MuchStub::Call, subject.any_predicate_last_called_with
63
+ assert_kind_of MuchStub::Call, subject.any_predicate_called_with
64
+ assert_equal 1, subject.any_predicate_call_count
65
+ assert_true subject.any_predicate_called?
66
+ end
67
+ end
68
+
69
+ class InitWithReturnValuesTests < UnitTests
70
+ desc "when init with return values"
71
+ setup do
72
+ @spy = @unit_class.new(any?: false)
73
+ end
74
+ subject{ @spy }
75
+
76
+ should "return the given values instead of itself if that method is called" do
77
+ assert_false subject.get.set!("value1").any?
78
+ assert_true subject.get_called?
79
+ assert_equal ["value1"], subject.set_bang_called_with.args
80
+ assert_true subject.any_predicate_called?
81
+ end
82
+ end
83
+
84
+ class InitWithReturnValueProcsTests < UnitTests
85
+ desc "when init with return value procs"
86
+ setup do
87
+ @result = Factory.boolean
88
+ @spy = @unit_class.new(any?: ->(call) { @result })
89
+ end
90
+ subject{ @spy }
91
+
92
+ should "return the value of calling the procs instead of itself" do
93
+ assert_equal @result, subject.get.set!("value1").any?
94
+ end
95
+ end
96
+ end
@@ -0,0 +1,68 @@
1
+ require "assert"
2
+ require "much-stub/call"
3
+
4
+ require "test/support/factory"
5
+
6
+ class MuchStub::Call
7
+ class UnitTests < Assert::Context
8
+ desc "MuchStub::Call"
9
+ setup do
10
+ @unit_class = MuchStub::Call
11
+
12
+ @pargs = [Factory.string, Factory.integer]
13
+ @kargs = {
14
+ one: 1,
15
+ two: 2
16
+ }
17
+ @block = -> {}
18
+ end
19
+ end
20
+
21
+ class InitWithNoArgsTests < UnitTests
22
+ desc "when init with no args"
23
+ subject{ @unit_class.new }
24
+
25
+ should "know its attrs" do
26
+ assert_nil subject.pargs
27
+ assert_nil subject.kargs
28
+ assert_equal [], subject.args
29
+ assert_nil subject.block
30
+ end
31
+ end
32
+
33
+ class InitWithOnlyPositionalArgsTests < UnitTests
34
+ desc "when init with only positional args"
35
+ subject{ @unit_class.new(*@pargs) }
36
+
37
+ should "know its attrs" do
38
+ assert_equal @pargs, subject.pargs
39
+ assert_nil subject.kargs
40
+ assert_equal [*@pargs], subject.args
41
+ assert_nil subject.block
42
+ end
43
+ end
44
+
45
+ class InitWithOnlyKeywordArgsTests < UnitTests
46
+ desc "when init with only keyword args"
47
+ subject{ @unit_class.new(**@kargs) }
48
+
49
+ should "know its attrs" do
50
+ assert_nil subject.pargs
51
+ assert_equal @kargs, subject.kargs
52
+ assert_equal [@kargs], subject.args
53
+ assert_nil subject.block
54
+ end
55
+ end
56
+
57
+ class InitWithBothPositionalAndKeywordArgsTests < UnitTests
58
+ desc "when init with only keyword args"
59
+ subject{ @unit_class.new(*@pargs, **@kargs, &@block) }
60
+
61
+ should "know its attrs" do
62
+ assert_equal @pargs, subject.pargs
63
+ assert_equal @kargs, subject.kargs
64
+ assert_equal [*@pargs, @kargs], subject.args
65
+ assert_equal @block, subject.block
66
+ end
67
+ end
68
+ end
@@ -86,6 +86,48 @@ module MuchStub
86
86
  assert_equal @orig_value, @myobj.mymeth
87
87
  assert_equal [], my_meth_called_with
88
88
  end
89
+
90
+ should "be able to add a stub tap with an on_call block" do
91
+ my_meth_called_with = nil
92
+ MuchStub.tap_on_call(@myobj, :mymeth){ |value, call|
93
+ my_meth_called_with = call
94
+ }
95
+
96
+ assert_equal @orig_value, @myobj.mymeth
97
+ assert_equal [], my_meth_called_with.args
98
+ end
99
+
100
+ should "be able to add a stubbed spy" do
101
+ myclass = Class.new do
102
+ def one; self; end
103
+ def two(val); self; end
104
+ def three; self; end
105
+ def ready?; false; end
106
+ end
107
+ myobj = myclass.new
108
+
109
+ spy =
110
+ MuchStub.spy(
111
+ myobj,
112
+ :one,
113
+ :two,
114
+ :three,
115
+ ready?: true)
116
+
117
+ assert_equal spy, myobj.one
118
+ assert_equal spy, myobj.two("a")
119
+ assert_equal spy, myobj.three
120
+
121
+ assert_true myobj.one.two("b").three.ready?
122
+
123
+ assert_kind_of MuchStub::CallSpy, spy
124
+ assert_equal 2, spy.one_call_count
125
+ assert_equal 2, spy.two_call_count
126
+ assert_equal 2, spy.three_call_count
127
+ assert_equal 1, spy.ready_predicate_call_count
128
+ assert_equal ["b"], spy.two_last_called_with.args
129
+ assert_true spy.ready_predicate_called?
130
+ end
89
131
  end
90
132
 
91
133
  class StubTests < UnitTests
@@ -134,21 +176,26 @@ module MuchStub
134
176
  @myobj.mymeth
135
177
  end
136
178
 
179
+ MuchStub::Stub.new(@myobj, :mymeth){ "mymeth" }
137
180
  assert_nothing_raised do
138
- MuchStub::Stub.new(@myobj, :mymeth){ "mymeth" }
181
+ @myobj.mymeth
139
182
  end
140
183
  end
141
184
 
185
+ should "complain when called if no lookup block was given" do
186
+ MuchStub::Stub.new(@myobj, :myval).with(1)
187
+
188
+ err = assert_raises(MuchStub::StubError){ @myobj.myval(1) }
189
+ assert_includes "stubbed with no block.", err.message
190
+ assert_includes "test/unit/much-stub_tests.rb", err.backtrace.first
191
+ end
192
+
142
193
  should "complain if stubbing a method that the object doesn't respond to" do
143
194
  err = assert_raises(MuchStub::StubError){ MuchStub::Stub.new(@myobj, :some_other_meth) }
144
195
  assert_includes "does not respond to", err.message
145
196
  assert_includes "test/unit/much-stub_tests.rb", err.backtrace.first
146
197
  end
147
198
 
148
- should "complain if stubbed and called with no `do` proc given" do
149
- assert_raises(MuchStub::NotStubbedError){ @myobj.mymeth }
150
- end
151
-
152
199
  should "complain if stubbed and called with mismatched arity" do
153
200
  MuchStub::Stub.new(@myobj, :myval){ "myval" }
154
201
  err = assert_raises(MuchStub::StubArityError){ @myobj.myval }
@@ -227,20 +274,29 @@ module MuchStub
227
274
 
228
275
  should "stub methods with variable args" do
229
276
  assert_equal [1,2], @myobj.myargs(1,2)
277
+
230
278
  stub = MuchStub::Stub.new(@myobj, :myargs){ |*args| args.join(",") }
231
- assert_equal "1,2", @myobj.myargs(1,2)
232
- assert_equal "3,4,5", @myobj.myargs(3,4,5)
233
- stub.with(3,4,5){ "three-four-five" }
234
- assert_equal "three-four-five", @myobj.myargs(3,4,5)
279
+ assert_equal "1,2,3", @myobj.myargs(1,2,3)
280
+ stub.with(3,4,5){ |*args| args.join(":") }
281
+ assert_equal "3:4:5", @myobj.myargs(3,4,5)
282
+
283
+ stub = MuchStub::Stub.new(@myobj, :myargs).on_call{ |call| call.args.join(",") }
284
+ assert_equal "1,2,3", @myobj.myargs(1,2,3)
285
+ stub.with(3,4,5).on_call{ |call| call.args.join(":") }
286
+ assert_equal "3:4:5", @myobj.myargs(3,4,5)
235
287
  end
236
288
 
237
289
  should "stub methods with required args and variable args" do
238
290
  assert_equal [1,2, [3]], @myobj.myvalargs(1,2,3)
239
291
  stub = MuchStub::Stub.new(@myobj, :myvalargs){ |*args| args.join(",") }
240
292
  assert_equal "1,2,3", @myobj.myvalargs(1,2,3)
241
- assert_equal "3,4,5", @myobj.myvalargs(3,4,5)
242
- stub.with(3,4,5){ "three-four-five" }
243
- assert_equal "three-four-five", @myobj.myvalargs(3,4,5)
293
+ stub.with(3,4,5){ |*args| args.join(":") }
294
+ assert_equal "3:4:5", @myobj.myvalargs(3,4,5)
295
+
296
+ stub = MuchStub::Stub.new(@myobj, :myvalargs).on_call{ |call| call.args.join(",") }
297
+ assert_equal "1,2,3", @myobj.myvalargs(1,2,3)
298
+ stub.with(3,4,5).on_call{ |call| call.args.join(":") }
299
+ assert_equal "3:4:5", @myobj.myvalargs(3,4,5)
244
300
  end
245
301
 
246
302
  should "stub methods that yield blocks" do
@@ -325,7 +381,7 @@ module MuchStub
325
381
  assert_equal true, blkcalled
326
382
  end
327
383
 
328
- should "store and remove itself on asserts main module" do
384
+ should "store and remove itself" do
329
385
  assert_equal subject, MuchStub.instance_variable_get(subject.ivar_name)
330
386
  subject.teardown
331
387
  assert_nil MuchStub.instance_variable_get(subject.ivar_name)
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: much-stub
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.2
4
+ version: 0.1.3
5
5
  platform: ruby
6
6
  authors:
7
7
  - Kelly Redding
@@ -9,7 +9,7 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2020-01-13 00:00:00.000000000 Z
12
+ date: 2020-07-13 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: assert
@@ -17,14 +17,14 @@ dependencies:
17
17
  requirements:
18
18
  - - "~>"
19
19
  - !ruby/object:Gem::Version
20
- version: 2.18.0
20
+ version: 2.18.1
21
21
  type: :development
22
22
  prerelease: false
23
23
  version_requirements: !ruby/object:Gem::Requirement
24
24
  requirements:
25
25
  - - "~>"
26
26
  - !ruby/object:Gem::Version
27
- version: 2.18.0
27
+ version: 2.18.1
28
28
  description: Stubbing API for replacing method calls on objects in test runs.
29
29
  email:
30
30
  - kelly@kellyredding.com
@@ -38,12 +38,16 @@ files:
38
38
  - LICENSE
39
39
  - README.md
40
40
  - lib/much-stub.rb
41
+ - lib/much-stub/call.rb
42
+ - lib/much-stub/call_spy.rb
41
43
  - lib/much-stub/version.rb
42
44
  - log/.gitkeep
43
45
  - much-stub.gemspec
44
46
  - test/helper.rb
45
47
  - test/support/factory.rb
46
48
  - test/system/much-stub_tests.rb
49
+ - test/unit/call_spy_tests.rb
50
+ - test/unit/call_tests.rb
47
51
  - test/unit/much-stub_tests.rb
48
52
  - tmp/.gitkeep
49
53
  homepage: https://github.com/redding/much-stub
@@ -56,17 +60,16 @@ require_paths:
56
60
  - lib
57
61
  required_ruby_version: !ruby/object:Gem::Requirement
58
62
  requirements:
59
- - - ">="
63
+ - - "~>"
60
64
  - !ruby/object:Gem::Version
61
- version: '0'
65
+ version: '2.5'
62
66
  required_rubygems_version: !ruby/object:Gem::Requirement
63
67
  requirements:
64
68
  - - ">="
65
69
  - !ruby/object:Gem::Version
66
70
  version: '0'
67
71
  requirements: []
68
- rubyforge_project:
69
- rubygems_version: 2.7.6.2
72
+ rubygems_version: 3.1.2
70
73
  signing_key:
71
74
  specification_version: 4
72
75
  summary: Stubbing API for replacing method calls on objects in test runs.
@@ -74,4 +77,6 @@ test_files:
74
77
  - test/helper.rb
75
78
  - test/support/factory.rb
76
79
  - test/system/much-stub_tests.rb
80
+ - test/unit/call_spy_tests.rb
81
+ - test/unit/call_tests.rb
77
82
  - test/unit/much-stub_tests.rb