rb-threadframe 0.32

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,23 @@
1
+ # Test of additional proc and method
2
+ require 'test/unit'
3
+ require_relative '../../ext/thread_frame'
4
+
5
+ class TestProcAndMethod < Test::Unit::TestCase
6
+ def test_proc_iseq
7
+ assert_equal(true,
8
+ Proc.new{|x,y| x+y}.iseq.is_a?(RubyVM::InstructionSequence))
9
+ end
10
+ def test_method_extra
11
+ m = self.method :test_method_extra
12
+ assert_equal(1, m.alias_count)
13
+ assert_equal(:test_method_extra, m.original_id)
14
+ self.instance_eval { assert_equal(1, m.alias_count) }
15
+ assert_equal(1, m.alias_count)
16
+ self.instance_eval { alias :two :test_method_extra }
17
+ assert_equal(2, m.alias_count)
18
+ assert_equal(3, self.method(:test_method_extra).alias_count)
19
+ assert_equal(3, m.alias_count)
20
+ assert_equal(4, self.method(:two).alias_count)
21
+ assert_equal(:test_method_extra, self.method(:two).original_id)
22
+ end
23
+ end
@@ -0,0 +1,64 @@
1
+ require 'test/unit'
2
+
3
+ # require 'thread_frame' # To compare with previous version
4
+ require_relative '../../ext/thread_frame'
5
+
6
+ # Test source_location and source_container.
7
+ class TestReturnStop < Test::Unit::TestCase
8
+
9
+ def setup
10
+ @tuples = []
11
+ @p = Proc.new { |event, file, lineno, mid, binding, klass|
12
+ # RubyVM::ThreadFrame.current.trace_off = true
13
+ @tuples << [event, lineno, mid, klass]
14
+ # p [event, lineno, mid, klass]
15
+ }
16
+ end
17
+
18
+ # Another method to call used to make sure we have turned off
19
+ # tracing.
20
+ def five; 5 end
21
+
22
+ def recurse(a, trace_off)
23
+ tf = RubyVM::ThreadFrame::current
24
+ if a==1
25
+ assert_equal false, tf.return_stop?
26
+ tf.return_stop=trace_off
27
+ assert_equal trace_off, tf.return_stop?
28
+ tf.trace_off=true
29
+ assert_equal true, tf.trace_off?
30
+ set_trace_func(@p)
31
+ return recurse(2, trace_off)
32
+ else
33
+ five
34
+ end
35
+ end
36
+
37
+ def tup_to_s(tuples)
38
+ tuples.map do |t|
39
+ '[' + t.map{|t2| t2.inspect}.join(', ') + ']'
40
+ end.join("\n")
41
+ end
42
+
43
+ def test_return_stop
44
+ recurse(1, true)
45
+ set_trace_func(nil)
46
+ first = @tuples.dup
47
+ assert_equal('return', @tuples[0][0],
48
+ "First tuple recorded should have been a return event," +
49
+ "got: #{ tup_to_s(@tuples)}")
50
+ recurse(1, false)
51
+ set_trace_func(nil)
52
+
53
+ assert_equal(true, @tuples.size > first.size,
54
+ 'should have gotten more tuples recorded')
55
+ assert_equal(true, @tuples.member?(first[0]),
56
+ 'should find "return" event in longer trace')
57
+ # puts tup_to_s(first)
58
+ # puts '-' * 30
59
+ # puts tup_to_s(@tuples)
60
+ # assert_equal(true, @tuples.index(first[0]) > 0,
61
+ # 'should not find "return" event as the first event')
62
+ end
63
+
64
+ end
@@ -0,0 +1,315 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ # This program is from Ruby 1.9. We run it here (again) just in case we didn't
4
+ # run as part of checking Ruby 1.9 sanity.
5
+
6
+ require 'test/unit'
7
+
8
+ class TestSetTraceFunc < Test::Unit::TestCase
9
+ def setup
10
+ @original_compile_option = RubyVM::InstructionSequence.compile_option
11
+ RubyVM::InstructionSequence.compile_option = {
12
+ :trace_instruction => true,
13
+ :specialized_instruction => false
14
+ }
15
+ @events = []
16
+ end
17
+
18
+ def teardown
19
+ set_trace_func(nil)
20
+ RubyVM::InstructionSequence.compile_option = @original_compile_option
21
+ end
22
+
23
+ def chunk(list, char='-')
24
+ sep = char * 30 + "\n"
25
+ sep + list.map{|e| e.join(' ')}.join("\n") + "\n"
26
+ end
27
+
28
+ def showit(actual, expected)
29
+ chunk(actual, '-') + chunk(expected, '=')
30
+ end
31
+
32
+ def checkit(actual, expected)
33
+ actual.each_with_index do |e, i|
34
+ assert_equal(e, actual[i], showit(actual, expected))
35
+ end
36
+ assert_equal(expected.size, actual.size, showit(actual, expected))
37
+ end
38
+
39
+ def test_c_call
40
+ eval <<-EOF.gsub(/^.*?: /, '')
41
+ 1: set_trace_func(Proc.new { |event, file, lineno, mid, binding, klass|
42
+ 2: @events << [lineno, event, mid, klass]
43
+ 3: })
44
+ 4: x = 1 + 1
45
+ 5: set_trace_func(nil)
46
+ EOF
47
+
48
+ expected = [[4, 'line', __method__, self.class],
49
+ [4, "c-call", :+, Fixnum],
50
+ [4, "c-return", :+, Fixnum],
51
+ [5, "line", __method__, self.class],
52
+ [5, "c-call", :set_trace_func, Kernel]]
53
+ checkit(@events, expected)
54
+ end
55
+
56
+ def test_call
57
+ eval <<-EOF.gsub(/^.*?: /, '')
58
+ 1: set_trace_func(Proc.new { |event, file, lineno, mid, binding, klass|
59
+ 2: @events << [lineno, event, mid, klass]
60
+ 3: })
61
+ 4: def add(x, y)
62
+ 5: x + y
63
+ 6: end
64
+ 7: x = add(1, 1)
65
+ 8: set_trace_func(nil)
66
+ EOF
67
+
68
+ expected = [[4, 'line', __method__, self.class],
69
+ [4, 'c-call', :method_added, Module],
70
+ [4, 'c-return', :method_added, Module],
71
+ [7, 'line', __method__, self.class],
72
+ [4, 'call', :add, self.class],
73
+ [5, 'line', :add, self.class],
74
+ [5, 'c-call', :+, Fixnum],
75
+ [5, 'c-return', :+, Fixnum],
76
+ [6, 'return', :add, self.class],
77
+ [8, 'line', __method__, self.class],
78
+ [8, 'c-call', :set_trace_func, Kernel]]
79
+ checkit(@events, expected)
80
+ end
81
+
82
+ def test_class
83
+ eval <<-EOF.gsub(/^.*?: /, '')
84
+ 1: set_trace_func(Proc.new { |event, file, lineno, mid, binding, klass|
85
+ 2: @events << [lineno, event, mid, klass]
86
+ 3: })
87
+ 4: class Foo
88
+ 5: def bar
89
+ 6: end
90
+ 7: end
91
+ 8: x = Foo.new.bar
92
+ 9: clear_trace_func()
93
+ EOF
94
+ expected = [[4, 'line', __method__, self.class],
95
+ [4, 'c-call', :inherited, Class],
96
+ [4, 'c-return', :inherited, Class],
97
+ [4, 'class', nil, nil],
98
+ [5, 'line', nil, nil],
99
+ [5, 'c-call', :method_added, Module],
100
+ [5, 'c-return', :method_added, Module],
101
+ [7, 'end', nil, nil],
102
+ [8, 'line', __method__, self.class],
103
+ [8, 'c-call', :new, Class],
104
+ [8, 'c-call', :initialize, BasicObject],
105
+ [8, 'c-return', :initialize, BasicObject],
106
+ [8, 'c-return', :new, Class],
107
+ [5, 'call', :bar, Foo],
108
+ [6, 'return', :bar, Foo],
109
+ [9, 'line', __method__, self.class],
110
+ [9, 'c-call', :clear_trace_func, Kernel]]
111
+ checkit(@events, expected)
112
+ end
113
+
114
+ def test_return # [ruby-dev:38701]
115
+ eval <<-EOF.gsub(/^.*?: /, '')
116
+ 1: add_trace_func(Proc.new { |event, file, lineno, mid, binding, klass|
117
+ 2: @events << [lineno, event, mid, klass]
118
+ 3: })
119
+ 4: def foo(a)
120
+ 5: return if a
121
+ 6: return
122
+ 7: end
123
+ 8: foo(true)
124
+ 9: foo(false)
125
+ 10: set_trace_func(nil)
126
+ EOF
127
+ expected = [[ 4, 'line', __method__, self.class],
128
+ [ 4, 'c-call', :method_added, Module],
129
+ [ 4, 'c-return', :method_added, Module],
130
+ [ 8, 'line', __method__, self.class],
131
+ [ 4, 'call', :foo, self.class],
132
+ [ 5, 'line', :foo, self.class],
133
+ [ 5, 'return', :foo, self.class],
134
+ [ 9, 'line', :test_return, self.class],
135
+ [ 4, 'call', :foo, self.class],
136
+ [ 5, 'line', :foo, self.class],
137
+ [ 7, 'return', :foo, self.class],
138
+ [10, 'line', :test_return, self.class],
139
+ [10, 'c-call', :set_trace_func, Kernel]]
140
+ checkit(@events, expected)
141
+ end
142
+
143
+ def test_return2 # [ruby-core:24463]
144
+ eval <<-EOF.gsub(/^.*?: /, '')
145
+ 1: set_trace_func(Proc.new { |event, file, lineno, mid, binding, klass|
146
+ 2: @events << [lineno, event, mid, klass]
147
+ 3: })
148
+ 4: def foo
149
+ 5: a = 5
150
+ 6: return a
151
+ 7: end
152
+ 8: foo
153
+ 9: set_trace_func(nil)
154
+ EOF
155
+
156
+ expected = [[4, 'line', __method__, self.class],
157
+ [4, 'c-call', :method_added, Module],
158
+ [4, 'c-return', :method_added, Module],
159
+ [8, 'line', __method__, self.class],
160
+ [4, 'call', :foo, self.class],
161
+ [5, 'line', :foo, self.class],
162
+ [6, 'line', :foo, self.class],
163
+ [7, 'return', :foo, self.class],
164
+ [9, 'line', :test_return2, self.class],
165
+ [9, 'c-call', :set_trace_func, Kernel]]
166
+ @events.each_with_index{|e, i|
167
+ assert_equal(e, @events[i], showit(@events, expected))}
168
+ assert_equal(expected.size, @events.size, showit(@events, expected))
169
+ end
170
+
171
+ def test_raise
172
+ events = []
173
+ eval <<-EOF.gsub(/^.*?: /, '')
174
+ 1: set_trace_func(Proc.new { |event, file, lineno, mid, binding, klass|
175
+ 2: events << [event, lineno, mid, klass]
176
+ 3: })
177
+ 4: begin
178
+ 5: raise TypeError, 'error'
179
+ 6: rescue TypeError => $e
180
+ 7: end
181
+ 8: set_trace_func(nil)
182
+ EOF
183
+
184
+ expected = [[4, 'line', __method__, self.class],
185
+ [5, 'line', __method__, self.class],
186
+ [5, 'c-call', :raise, Kernel],
187
+ [5, 'c-call', :exception, Exception],
188
+ [5, 'c-call', :initialize, Exception],
189
+ [5, 'c-return', :initialize, Exception],
190
+ [5, 'c-return', :exception, Exception],
191
+ [5, 'c-call', :backtrace, Exception],
192
+ [5, 'c-return', :backtrace, Exception],
193
+ [5, 'c-call', :set_backtrace, Exception],
194
+ [5, 'c-return', :set_backtrace, Exception],
195
+ [5, 'raise', :test_raise, $e],
196
+ [5, 'c-return', :raise, Kernel],
197
+ [6, 'c-call', :===, Module],
198
+ [6, 'c-return', :===, Module],
199
+ [8, 'line', __method__, self.class],
200
+ [8, 'c-call', :set_trace_func, Kernel]]
201
+ checkit(events, expected)
202
+ end
203
+
204
+ def test_break # [ruby-core:27606] [Bug #2610]
205
+ events = []
206
+ eval <<-EOF.gsub(/^.*?: /, '')
207
+ 1: set_trace_func(Proc.new { |event, file, lineno, mid, binding, klass|
208
+ 2: events << [lineno, event, mid, klass]
209
+ 3: })
210
+ 4: [1,2,3].any? {|n| n}
211
+ 8: set_trace_func(nil)
212
+ EOF
213
+
214
+ expected = [[4, 'line', __method__, self.class],
215
+ [4, 'c-call', :any?, Enumerable],
216
+ [4, 'c-call', :each, Array],
217
+ [4, 'line', __method__, self.class],
218
+ [4, 'c-return', :each, Array],
219
+ [4, 'c-return', :any?, Enumerable],
220
+ [5, 'line', __method__, self.class],
221
+ [5, 'c-call', :set_trace_func, Kernel]]
222
+ checkit(events, expected)
223
+ end
224
+
225
+ def test_invalid_proc
226
+ assert_raise(TypeError) { set_trace_func(1) }
227
+ end
228
+
229
+ def test_raise_in_trace
230
+ set_trace_func proc {raise rescue nil}
231
+ assert_equal(42, (raise rescue 42), '[ruby-core:24118]')
232
+ end
233
+
234
+ def test_thread_trace
235
+ events = {:set => [], :add => []}
236
+ prc = Proc.new { |event, file, lineno, mid, binding, klass|
237
+ events[:set] << [lineno, event, mid, klass, :set]
238
+ }
239
+ prc2 = Proc.new { |event, file, lineno, mid, binding, klass|
240
+ events[:add] << [lineno, event, mid, klass, :add]
241
+ }
242
+
243
+ th = Thread.new do
244
+ th = Thread.current
245
+ eval <<-EOF.gsub(/^.*?: /, '')
246
+ 1: th.set_trace_func(prc)
247
+ 2: th.add_trace_func(prc2)
248
+ 3: class ThreadTraceInnerClass
249
+ 4: def foo
250
+ 5: x = 1 + 1
251
+ 6: end
252
+ 7: end
253
+ 8: ThreadTraceInnerClass.new.foo
254
+ 9: th.set_trace_func(nil)
255
+ EOF
256
+ end
257
+ th.join
258
+
259
+ expected = [[1, 'c-return', :set_trace_func, Thread, :set],
260
+ [2, 'line', __method__, self.class, :set],
261
+ [2, 'c-call', :add_trace_func, Thread, :set]]
262
+ expected.each do |e|
263
+ assert_equal(e, events[:set].shift, showit(events, expected))
264
+ end
265
+
266
+ [[2, 'c-return', :add_trace_func, Thread],
267
+ [3, 'line', __method__, self.class],
268
+ [3, 'c-call', :inherited, Class],
269
+ [3, 'c-return', :inherited, Class],
270
+ [3, 'class', nil, nil],
271
+ [4, 'line', nil, nil],
272
+ [4, 'c-call', :method_added, Module],
273
+ [4, 'c-return', :method_added, Module],
274
+ [7, 'end', nil, nil],
275
+ [8, 'line', __method__, self.class],
276
+ [8, 'c-call', :new, Class],
277
+ [8, 'c-call', :initialize, BasicObject],
278
+ [8, 'c-return', :initialize, BasicObject],
279
+ [8, 'c-return', :new, Class],
280
+ [4, 'call', :foo, ThreadTraceInnerClass],
281
+ [5, 'line', :foo, ThreadTraceInnerClass],
282
+ [5, 'c-call', :+, Fixnum],
283
+ [5, 'c-return', :+, Fixnum],
284
+ [6, 'return', :foo, ThreadTraceInnerClass],
285
+ [9, 'line', __method__, self.class],
286
+ [9, 'c-call', :set_trace_func, Thread]].each do |e|
287
+ [:set, :add].each do |type|
288
+ assert_equal(e + [type], events[type].shift)
289
+ end
290
+ end
291
+ assert_equal([], events[:set])
292
+ assert_equal([], events[:add])
293
+ end
294
+
295
+ def test_trace_proc_that_raises_exception_recovery
296
+ $first_time = true
297
+ $traced = []
298
+ s = Proc.new {|event|
299
+ if $first_time
300
+ $first_time = false
301
+ raise RuntimeError
302
+ end
303
+ $traced << event
304
+ }
305
+ begin
306
+ set_trace_func(s)
307
+ assert_equal(false, 'hook should have raised error')
308
+ rescue RuntimeError
309
+ x = 1
310
+ set_trace_func(nil)
311
+ assert_equal(false, $traced.empty?, $traced)
312
+ end
313
+ end
314
+
315
+ end
@@ -0,0 +1,104 @@
1
+ require 'test/unit'
2
+
3
+ # require 'thread_frame' # To compare with previous version
4
+ require_relative '../../ext/thread_frame'
5
+
6
+ # Test source_location and source_container.
7
+ class TestSource < Test::Unit::TestCase
8
+
9
+ def test_iseq_source_container
10
+ test_basic_lineno = __LINE__ - 1
11
+ tup = method(:test_iseq_source_container).iseq.source_container
12
+ tup[1] = File.basename(tup[1])
13
+ assert_equal(['file', File.basename(__FILE__)], tup)
14
+
15
+ eval('def foo; 5 end')
16
+ tup = method(:foo).iseq.source_container
17
+ assert_equal('string', tup[0])
18
+ # puts tup[1]
19
+
20
+ iseq = RubyVM::InstructionSequence.compile("1+2")
21
+ assert_equal('string', iseq.source_container[0])
22
+ # puts iseq.source_container[1]
23
+
24
+ eval_str = ' RubyVM::ThreadFrame.current.source_container # test'
25
+ tuple = eval(eval_str)
26
+ assert_equal('string', tuple[0])
27
+ assert_equal(eval_str, tuple[1])
28
+
29
+ end
30
+
31
+ def test_basic
32
+ tf = RubyVM::ThreadFrame::current
33
+ # Is this too specific to test/unit.rb implementation details?
34
+ tup = tf.source_container
35
+ tup[1] = File.basename(tup[1])
36
+ assert_equal(['file', File.basename(__FILE__)], tup)
37
+ assert_equal(__LINE__, tf.source_location[0])
38
+
39
+ # 1.times creates a C frame.
40
+ 1.times do
41
+ expect_line = __LINE__ - 1
42
+ tf = RubyVM::ThreadFrame::current
43
+ tup = tf.source_container
44
+ tup[1] = File.basename(tup[1])
45
+ assert_equal(['file', File.basename(__FILE__)], tup)
46
+ assert_equal(tf.source_location[0], __LINE__)
47
+ tf = tf.prev
48
+ assert_equal('CFUNC', tf.type)
49
+ tup = tf.source_container
50
+ tup[1] = File.basename(tup[1])
51
+ assert_equal(expect_line, tf.source_location[0])
52
+ end
53
+
54
+ # 1.upto also creates a C frame.
55
+ 1.upto(1) do
56
+ expect_line = __LINE__ - 1
57
+ tf = RubyVM::ThreadFrame::current
58
+ assert_equal('BLOCK', tf.type)
59
+ tup = tf.source_container
60
+ tup[1] = File.basename(tup[1])
61
+ assert_equal(['file', File.basename(__FILE__)], tup)
62
+ assert_equal(__LINE__, tf.source_location[0])
63
+ tf = tf.prev
64
+ assert_equal('CFUNC', tf.type)
65
+ tup = tf.source_container
66
+ tup[1] = File.basename(tup[1])
67
+ assert_equal(expect_line, tf.source_location[0])
68
+ end
69
+
70
+ x = lambda do |expect_line|
71
+ tf = RubyVM::ThreadFrame::current
72
+ assert_equal('LAMBDA', tf.type)
73
+ tup = tf.source_container
74
+ tup[1] = File.basename(tup[1])
75
+ assert_equal(['file', File.basename(__FILE__)], tup)
76
+ assert_equal(__LINE__, tf.source_location[0])
77
+ tf = tf.prev
78
+ assert_equal('CFUNC', tf.type)
79
+ tup = tf.source_container
80
+ tup[1] = File.basename(tup[1])
81
+ assert_equal(expect_line, tf.source_location[0])
82
+ end
83
+ x.call(__LINE__)
84
+
85
+ x = Proc.new do |expect_line|
86
+ tf = RubyVM::ThreadFrame::current
87
+ tup = tf.source_container
88
+ tup[1] = File.basename(tup[1])
89
+ assert_equal(['file', File.basename(__FILE__)], tup)
90
+ assert_equal(__LINE__, tf.source_location[0])
91
+ tf = tf.prev
92
+ tup = tf.source_container
93
+ tup[1] = File.basename(tup[1])
94
+ # FIXME?
95
+ # assert_equal(['file', File.basename(__FILE__)], tup)
96
+ assert_equal(expect_line, tf.source_location[0])
97
+ end
98
+ x.call(__LINE__)
99
+ end
100
+ end
101
+
102
+ # We want to double-check we didn't mess up any pointers somewhere along
103
+ # the line.
104
+ at_exit { GC.start }