File: test_subroutine.rb

package info (click to toggle)
ruby-spy 1.0.1-1
  • links: PTS, VCS
  • area: main
  • in suites: bookworm
  • size: 360 kB
  • sloc: ruby: 3,101; makefile: 2
file content (284 lines) | stat: -rw-r--r-- 8,374 bytes parent folder | download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
require 'test_helper'

module Spy
  class TestSubroutine < Minitest::Test
    def spy_on(base_object, method_name)
      Subroutine.new(base_object, method_name).hook
    end

    def setup
      @pen = Pen.new
    end

    def teardown
      Spy::Agency.instance.dissolve!
    end

    def test_spy_on_hook_and_saves_spy
      pen_write_spy = spy_on(@pen, :write).and_return("hello")
      assert_equal "hello", @pen.write(nil)
      assert_kind_of Subroutine, pen_write_spy
      assert_equal [pen_write_spy], Agency.instance.spies
      assert pen_write_spy.has_been_called?
    end

    def test_spy_can_hook_and_record_a_method_call
      pen_write_spy = spy_on(@pen, :write)
      refute pen_write_spy.has_been_called?
      @pen.write("hello")
      assert pen_write_spy.has_been_called?
      assert_empty @pen.written
    end

    def test_spy_can_hook_and_record_a_method_call_on_a_constant
      another_spy = spy_on(Pen, :another)
      refute another_spy.has_been_called?
      assert_nil Pen.another
      assert another_spy.has_been_called?
      another_spy.unhook
      assert_equal "another", Pen.another
    end

    def test_spy_can_hook_and_record_a_meta_method_call_on_a_constant
      assert_equal "meta_class_method", Pen.meta_class_method
      meta_spy = spy_on(Pen, :meta_class_method)
      refute meta_spy.has_been_called?
      assert_nil Pen.meta_class_method
      assert meta_spy.has_been_called?
      meta_spy.unhook
      assert_equal "meta_class_method", Pen.meta_class_method
    end

    def test_spy_can_hook_record_and_unhook_a_meta_method
      assert_equal "meta_method", @pen.meta_method
      meta_spy = spy_on(@pen, :meta_method)
      refute meta_spy.has_been_called?
      assert_nil @pen.meta_method
      assert meta_spy.has_been_called?
      meta_spy.unhook
      assert_equal "meta_method", @pen.meta_method
    end

    def test_spy_can_unhook_a_method
      pen_write_spy = spy_on(@pen, :write)
      pen_write_spy.unhook
      assert_equal "hello", @pen.write("hello")
      refute pen_write_spy.has_been_called?
    end

    def test_spy_cannot_hook_a_non_existent_method
      spy = Subroutine.new(@pen, :no_method)
      assert_raises NameError do
        spy.hook
      end
    end

    def test_spy_can_hook_a_non_existent_method_if_param_set
      Subroutine.new(@pen, :no_method).hook(force:true).and_return(:yep)
      assert_equal :yep, @pen.no_method
    end

    def test_spy_and_return_returns_the_set_value
      result = "hello world"

      spy_on(@pen, :write).and_return(result)

      assert_equal result, @pen.write(nil)
    end

    def test_spy_and_raise_raises_the_set_exception
      pen_write_spy = spy_on(@pen, :write).and_raise(ArgumentError, "problems!")
      assert_kind_of Subroutine, pen_write_spy
      assert_equal [pen_write_spy], Agency.instance.spies

      e = assert_raises ArgumentError do
        @pen.write(nil)
      end
      assert_equal "problems!", e.message
      assert pen_write_spy.has_been_called?
    end

    def test_spy_and_return_can_call_a_block
      result = "hello world"

      spy_on(@pen, :write).and_return {}.and_return do |string|
        string.reverse
      end

      assert_equal result.reverse, @pen.write(result)
      assert_empty @pen.written
    end

    def test_spy_and_return_can_call_a_block_raises_when_there_is_an_arity_mismatch
      write_spy = spy_on(@pen, :write)
      write_spy.and_return do |*args|
      end
      write_spy.and_return do |string, *args|
      end
      assert_raises ArgumentError do
        write_spy.and_return do |string, b|
        end
      end

      write_spy.and_return(force: true) do |string, b|
      end
    end

    def test_spy_and_return_can_call_a_block_that_recieves_a_block
      string = "hello world"

      spy_on(@pen, :write_block).and_return do |&block|
        block.call
      end

      result = @pen.write_block do
        string
      end
      assert_equal string, result
    end

    def test_spy_hook_records_number_of_calls
      pen_write_spy = spy_on(@pen, :write)
      assert_equal 0, pen_write_spy.calls.size
      5.times do |i|
        @pen.write("hello world")
        assert_equal i + 1, pen_write_spy.calls.size
      end
    end

    def test_has_been_called_with?
      pen_write_spy = spy_on(@pen, :write)
      refute pen_write_spy.has_been_called_with?("hello")
      @pen.write("hello")
      assert pen_write_spy.has_been_called_with?("hello")
      @pen.write("world")
      assert pen_write_spy.has_been_called_with?("hello")
      @pen.write("hello world")
      assert pen_write_spy.has_been_called_with?("hello")
    end

    def test_spy_hook_records_number_of_calls2
      args = ["hello world"]
      block = Proc.new {}
      pen_write_spy = spy_on(@pen, :write)
      called_from = "#{__FILE__}:#{__LINE__ + 1}:in `#{__method__}'"
      @pen.write(*args, &block)
      call_log = pen_write_spy.calls.first
      assert_equal @pen, call_log.object
      assert_equal args, call_log.args
      assert_equal block, call_log.block
      assert_equal called_from, call_log.called_from
    end

    def test_that_method_spy_keeps_arity
      spy_on(@pen, :write)
      @pen.write("hello world")
      assert_raises ArgumentError do
        @pen.write("hello", "world")
      end

      spy_on(@pen, :write_hello)
      @pen.write_hello
      assert_raises ArgumentError do
        @pen.write_hello("hello")
      end

      spy_on(@pen, :write_array)
      @pen.write_hello
      assert_raises ArgumentError do
        @pen.write_hello("hello")
      end

      spy_on(@pen, :greet)
      @pen.greet("bob")
      assert_raises ArgumentError do
        @pen.greet
      end
      assert_raises ArgumentError do
        @pen.greet("hello", "bob", "error")
      end
    end

    def test_that_method_spy_keeps_arity_with_optional_keyword_args
      spy_on(@pen, :opt_kwargs)
      @pen.opt_kwargs(:pos1)
      @pen.opt_kwargs(:pos1, opt: 1, opt2: 2)
      assert_raises ArgumentError do
        @pen.opt_kwargs
      end
      assert_raises ArgumentError do
        @pen.opt_kwargs(:pos1, :pos2, opt: 1)
      end
    end

    def test_that_method_spy_keeps_arity_with_keyword_splat
      spy_on(@pen, :keyrest)
      @pen.keyrest
      @pen.keyrest(a: 1, b: 2)
      assert_raises ArgumentError do
        @pen.keyrest(:pos1, :pos2)
      end
    end

    def test_that_method_spy_keeps_arity_with_required_keyword_args
      spy_on(@pen, :req_kwargs)
      @pen.req_kwargs(req1: 1, req2: 2)
      assert_raises ArgumentError do
        @pen.req_kwargs
      end
      assert_raises ArgumentError do
        @pen.req_kwargs(:pos1, :pos2)
      end
    end

    def test_hook_mimics_public_visibility
      spy_on(@pen, :public_method)
      assert @pen.singleton_class.public_method_defined? :public_method
    end

    def test_hook_mimics_protected_visibility
      spy_on(@pen, :protected_method)
      assert @pen.singleton_class.protected_method_defined? :protected_method
    end

    def test_hook_mimics_private_visibility
      spy_on(@pen, :private_method)
      assert @pen.singleton_class.private_method_defined? :private_method
    end

    def test_hook_mimics_class_public_visibility
      spy_on(Pen, :public_method)
      assert Pen.public_method_defined? :public_method
      Spy.off(Pen, :public_method)
      assert Pen.public_method_defined? :public_method
    end

    def test_hook_mimics_class_protected_visibility
      spy_on(Pen, :protected_method)
      assert Pen.protected_method_defined? :protected_method
      Spy.off(Pen, :protected_method)
      assert Pen.protected_method_defined? :protected_method
    end

    def test_hook_mimics_class_private_visibility
      spy_on(Pen, :private_method)
      assert Pen.private_method_defined? :private_method
      Spy.off(Pen, :private_method)
      assert Pen.private_method_defined? :private_method
    end

    def test_spy_get_can_retrieve_a_spy
      pen_write_spy = spy_on(@pen, :write).and_return(:hello)
      assert_equal :hello, @pen.write(:world)
      assert Subroutine.get(@pen, :write).has_been_called?
      assert_same pen_write_spy, Subroutine.get(@pen, :write)
    end

    def test_spy_hook_raises_an_error_on_an_already_hooked_method
      spy_on(@pen, :write)
      assert_raises AlreadyHookedError do
        spy_on(@pen, :write)
      end
    end
  end
end