rb-threadframe 0.32

Sign up to get free protection for your applications and to get access to all the features.
@@ -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 }