pry-stack_explorer 0.6.1 → 0.6.2

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.
@@ -0,0 +1,353 @@
1
+ require_relative 'test_helper'
2
+
3
+ class Top
4
+ attr_accessor :method_list, :middle
5
+ def initialize method_list
6
+ @method_list = method_list
7
+ end
8
+ def bing
9
+ @middle = Middle.new method_list
10
+ @middle.bong
11
+ end
12
+ end
13
+
14
+ class Middle
15
+ attr_accessor :method_list, :bottom
16
+ def initialize method_list
17
+ @method_list = method_list
18
+ end
19
+ def bong
20
+ @bottom = Bottom.new method_list
21
+ @bottom.bang
22
+ end
23
+ end
24
+
25
+ class Bottom
26
+ attr_accessor :method_list
27
+ def initialize method_list
28
+ @method_list = method_list
29
+ end
30
+ def bang
31
+ Pry.start(binding)
32
+ end
33
+ end
34
+
35
+
36
+ describe "Commands" do
37
+ let(:bingbong){ BingBong.new }
38
+
39
+ include ResetHelper
40
+
41
+ before do
42
+ method_list = []
43
+ @top = Top.new method_list
44
+ end
45
+
46
+
47
+ describe "stack" do
48
+ it "outputs the call stack" do
49
+ output = issue_pry_commands("stack"){ bingbong.bing }
50
+
51
+ expect(output).to match(/bang.*?bong.*?bing/m)
52
+ end
53
+
54
+ it "supports 'show-stack' as an alias" do
55
+ output = issue_pry_commands("show-stack"){ bingbong.bing }
56
+
57
+ expect(output).to match(/bang.*?bong.*?bing/m)
58
+ end
59
+ end
60
+
61
+ describe "up" do
62
+ it 'should move up the call stack one frame at a time' do
63
+ redirect_pry_io(InputTester.new("@methods << __method__",
64
+ "up",
65
+ "@methods << __method__",
66
+ "up",
67
+ "@methods << __method__",
68
+ "exit-all"), out=StringIO.new) do
69
+ bingbong.bing
70
+ end
71
+
72
+ expect(bingbong.methods).to eq [:bang, :bong, :bing]
73
+ end
74
+
75
+ it 'should move up the call stack two frames at a time' do
76
+ redirect_pry_io(InputTester.new("@methods << __method__",
77
+ "up 2",
78
+ "@methods << __method__",
79
+ "exit-all"), out=StringIO.new) do
80
+ bingbong.bing
81
+ end
82
+
83
+ expect(bingbong.methods).to eq [:bang, :bing]
84
+ end
85
+
86
+ describe "by method name regex" do
87
+ it 'should move to the method name that matches the regex' do
88
+ redirect_pry_io(InputTester.new("@methods << __method__",
89
+ "up bi",
90
+ "@methods << __method__",
91
+ "exit-all"), out=StringIO.new) do
92
+ bingbong.bing
93
+ end
94
+
95
+ expect(bingbong.methods).to eq [:bang, :bing]
96
+ end
97
+
98
+ it 'should move through all methods that match regex in order' do
99
+ redirect_pry_io(InputTester.new("@methods << __method__",
100
+ "up b",
101
+ "@methods << __method__",
102
+ "up b",
103
+ "@methods << __method__",
104
+ "exit-all"), out=StringIO.new) do
105
+ bingbong.bing
106
+ end
107
+
108
+ expect(bingbong.methods).to eq [:bang, :bong, :bing]
109
+ end
110
+
111
+ it 'should error if it cant find frame to match regex' do
112
+ redirect_pry_io(InputTester.new("up conrad_irwin",
113
+ "exit-all"), out=StringIO.new) do
114
+ bingbong.bing
115
+ end
116
+
117
+ expect(out.string).to match(/Error: No frame that matches/)
118
+ end
119
+ end
120
+
121
+
122
+ describe 'by Class#method name regex' do
123
+ it 'should move to the method and class that matches the regex' do
124
+ redirect_pry_io(InputTester.new("@method_list << self.class.to_s + '#' + __method__.to_s",
125
+ 'up Middle#bong',
126
+ "@method_list << self.class.to_s + '#' + __method__.to_s",
127
+ "exit-all"), out=StringIO.new) do
128
+ @top.bing
129
+ end
130
+
131
+ expect(@top.method_list).to eq(['Bottom#bang', 'Middle#bong'])
132
+ end
133
+
134
+ ### ????? ###
135
+ # it 'should be case sensitive' do
136
+ # end
137
+ ### ????? ###
138
+
139
+ it 'should allow partial class names' do
140
+ redirect_pry_io(InputTester.new("@method_list << self.class.to_s + '#' + __method__.to_s",
141
+ 'up Mid#bong',
142
+ "@method_list << self.class.to_s + '#' + __method__.to_s",
143
+ "exit-all"), out=StringIO.new) do
144
+ @top.bing
145
+ end
146
+
147
+ expect(@top.method_list).to eq(['Bottom#bang', 'Middle#bong'])
148
+ end
149
+
150
+ it 'should allow partial method names' do
151
+ redirect_pry_io(InputTester.new("@method_list << self.class.to_s + '#' + __method__.to_s",
152
+ 'up Middle#bo',
153
+ "@method_list << self.class.to_s + '#' + __method__.to_s",
154
+ "exit-all"), out=StringIO.new) do
155
+ @top.bing
156
+ end
157
+
158
+ expect(@top.method_list).to eq(['Bottom#bang', 'Middle#bong'])
159
+ end
160
+
161
+ it 'should error if it cant find frame to match regex' do
162
+ redirect_pry_io(InputTester.new('up Conrad#irwin',
163
+ "exit-all"), out=StringIO.new) do
164
+ @top.bing
165
+ end
166
+
167
+ expect(out.string).to match(/Error: No frame that matches/)
168
+ end
169
+ end
170
+ end
171
+
172
+ describe "down" do
173
+ it 'should move down the call stack one frame at a time' do
174
+ def bingbong.bang() Pry.start(binding, :initial_frame => 1) end
175
+
176
+ redirect_pry_io(InputTester.new("@methods << __method__",
177
+ "down",
178
+ "@methods << __method__",
179
+ "exit-all"), out=StringIO.new) do
180
+ bingbong.bing
181
+ end
182
+
183
+ expect(bingbong.methods).to eq [:bong, :bang]
184
+ end
185
+
186
+ it 'should move down the call stack two frames at a time' do
187
+ def bingbong.bang() Pry.start(binding, :initial_frame => 2) end
188
+
189
+ redirect_pry_io(InputTester.new("@methods << __method__",
190
+ "down 2",
191
+ "@methods << __method__",
192
+ "exit-all"), out=StringIO.new) do
193
+ bingbong.bing
194
+ end
195
+
196
+ expect(bingbong.methods).to eq [:bing, :bang]
197
+ end
198
+
199
+ describe "by method name regex" do
200
+ it 'should move to the method name that matches the regex' do
201
+ redirect_pry_io(InputTester.new("frame -1",
202
+ "down bo",
203
+ "@methods << __method__",
204
+ "exit-all"), out=StringIO.new) do
205
+ bingbong.bing
206
+ end
207
+
208
+ expect(bingbong.methods[0]).to eq(:bong)
209
+ end
210
+
211
+ it 'should move through all methods that match regex in order' do
212
+ redirect_pry_io(InputTester.new("frame bing",
213
+ "@methods << __method__",
214
+ "down b",
215
+ "@methods << __method__",
216
+ "down b",
217
+ "@methods << __method__",
218
+ "exit-all"), out=StringIO.new) do
219
+ bingbong.bing
220
+ end
221
+
222
+ expect(bingbong.methods).to eq [:bing, :bong, :bang]
223
+ end
224
+
225
+ it 'should error if it cant find frame to match regex' do
226
+ redirect_pry_io(InputTester.new("frame -1",
227
+ "down conrad_irwin",
228
+ "exit-all"), out=StringIO.new) do
229
+ bingbong.bing
230
+ end
231
+
232
+ expect(out.string).to match(/Error: No frame that matches/)
233
+ end
234
+ end
235
+
236
+ describe 'by Class#method name regex' do
237
+ it 'should move to the method and class that matches the regex' do
238
+ redirect_pry_io(InputTester.new('frame Top#bing',
239
+ "@method_list << self.class.to_s + '#' + __method__.to_s",
240
+ 'down Middle#bong',
241
+ "@method_list << self.class.to_s + '#' + __method__.to_s",
242
+ "exit-all"), out=StringIO.new) do
243
+ @top.bing
244
+ end
245
+
246
+ expect(@top.method_list).to eq(['Top#bing', 'Middle#bong'])
247
+ end
248
+
249
+ ### ????? ###
250
+ # it 'should be case sensitive' do
251
+ # end
252
+ ### ????? ###
253
+
254
+ it 'should error if it cant find frame to match regex' do
255
+ redirect_pry_io(InputTester.new('down Conrad#irwin',
256
+ "exit-all"), out=StringIO.new) do
257
+ @top.bing
258
+ end
259
+
260
+ expect(out.string).to match(/Error: No frame that matches/)
261
+ end
262
+ end
263
+
264
+ end
265
+
266
+ describe "frame" do
267
+ describe "by method name regex" do
268
+ it 'should jump to correct stack frame when given method name' do
269
+ redirect_pry_io(InputTester.new("frame bi",
270
+ "@methods << __method__",
271
+ "exit-all"), out=StringIO.new) do
272
+ bingbong.bing
273
+ end
274
+
275
+ expect(bingbong.methods[0]).to eq(:bing)
276
+ end
277
+
278
+ it 'should NOT jump to frames lower down stack when given method name' do
279
+ redirect_pry_io(InputTester.new("frame -1",
280
+ "frame bang",
281
+ "exit-all"), out=StringIO.new) do
282
+ bingbong.bing
283
+ end
284
+
285
+ expect(out.string).to match(/Error: No frame that matches/)
286
+ end
287
+
288
+ end
289
+
290
+ it 'should move to the given frame in the call stack' do
291
+ redirect_pry_io(InputTester.new("frame 2",
292
+ "@methods << __method__",
293
+ "exit-all"), out=StringIO.new) do
294
+ bingbong.bing
295
+ end
296
+
297
+ expect(bingbong.methods[0]).to eq(:bing)
298
+ end
299
+
300
+ it 'should return info on current frame when given no parameters' do
301
+ redirect_pry_io(InputTester.new("frame",
302
+ "exit-all"), out=StringIO.new) do
303
+ bingbong.bing
304
+ end
305
+
306
+ expect(out.string).to match(/\#0.*?bang/)
307
+ expect(out.string).not_to match(/\#1/)
308
+ end
309
+
310
+ describe "negative indices" do
311
+ class AlphaBetaGamma
312
+ attr_accessor :frame, :frame_number
313
+
314
+ def alpha; binding; end
315
+ def beta; binding; end
316
+ def gamma; binding; end
317
+ end
318
+
319
+ let(:alphabetagamma){ AlphaBetaGamma.new }
320
+
321
+ it 'should work with negative frame numbers' do
322
+ o = AlphaBetaGamma.new
323
+
324
+ call_stack = [o.alpha, o.beta, o.gamma]
325
+ method_names = call_stack.map { |v| v.eval('__method__') }.reverse
326
+ (1..3).each_with_index do |v, idx|
327
+ redirect_pry_io(InputTester.new("frame -#{v}",
328
+ "@frame = __method__",
329
+ "exit-all"), out=StringIO.new) do
330
+ Pry.start(o, :call_stack => call_stack)
331
+ end
332
+ expect(o.frame).to eq(method_names[idx])
333
+ end
334
+ end
335
+
336
+ it 'should convert negative indices to their positive counterparts' do
337
+ o = AlphaBetaGamma.new
338
+
339
+ call_stack = [o.alpha, o.beta, o.gamma]
340
+
341
+ (1..3).each_with_index do |v, idx|
342
+ issue_pry_commands(
343
+ "frame -#{v}",
344
+ "@frame_number = PryStackExplorer.frame_manager(pry_instance).binding_index",
345
+ "exit-all"
346
+ ){ Pry.start(o, call_stack: call_stack) }
347
+
348
+ expect(o.frame_number).to eq(call_stack.size - v)
349
+ end
350
+ end
351
+ end
352
+ end
353
+ end
@@ -0,0 +1,68 @@
1
+ require_relative 'test_helper'
2
+
3
+ describe PryStackExplorer::FrameManager do
4
+ before :all do
5
+ redirect_pry_output!
6
+ end
7
+
8
+ before do
9
+ @pry_instance = Pry.new
10
+ @bindings = [binding, binding, binding, binding]
11
+ @bindings.each_with_index { |v, i| v.eval("x = #{i}") }
12
+ @pry_instance.binding_stack.push @bindings.last
13
+ @frame_manager = PE::FrameManager.new(@bindings, @pry_instance)
14
+ end
15
+
16
+ describe "creation" do
17
+ it "should make bindings accessible via 'bindings' method" do
18
+ expect(@frame_manager.bindings).to eq(@bindings)
19
+ end
20
+
21
+ it "should set binding_index to 0" do
22
+ expect(@frame_manager.binding_index).to eq(0)
23
+ end
24
+
25
+ it "should set current_frame to first frame" do
26
+ expect(@frame_manager.current_frame).to eq(@bindings.first)
27
+ end
28
+ end
29
+
30
+ describe "FrameManager#change_frame_to" do
31
+ it 'should change the frame to the given one' do
32
+ @frame_manager.change_frame_to(1)
33
+
34
+ expect(@frame_manager.binding_index).to eq(1)
35
+ expect(@frame_manager.current_frame).to eq(@bindings[1])
36
+ expect(@pry_instance.binding_stack.last).to eq(@frame_manager.current_frame)
37
+ end
38
+
39
+ it 'should accept negative indices when specifying frame' do
40
+ @frame_manager.change_frame_to(-1)
41
+
42
+ # negative index is converted to a positive one inside change_frame_to
43
+ expect(@frame_manager.binding_index).to eq(@bindings.size - 1)
44
+ expect(@frame_manager.current_frame).to eq(@bindings[-1])
45
+ expect(@pry_instance.binding_stack.last).to eq(@frame_manager.current_frame)
46
+ end
47
+ end
48
+
49
+ describe "FrameManager#refresh_frame" do
50
+ it 'should change the Pry frame to the active one in the FrameManager' do
51
+ @frame_manager.binding_index = 2
52
+ @frame_manager.refresh_frame
53
+
54
+ expect(@pry_instance.binding_stack.last).to eq(@frame_manager.current_frame)
55
+ end
56
+ end
57
+
58
+ describe "FrameManager is Enumerable" do
59
+ it 'should perform an Enumerable#map on the frames' do
60
+ result = @frame_manager.map { |v| v.eval("x") }
61
+
62
+ expect(result).to eq(
63
+ (0..(@bindings.size - 1)).to_a
64
+ )
65
+ end
66
+ end
67
+
68
+ end