3 # Unit and regression tests for backtraces.
4 # Note: The tests follow MRI 1.8.6 behavior.
5 # Behavior of MRI 1.9 is different:
6 # http://blade.nagaokaut.ac.jp/cgi-bin/scat.rb/ruby/ruby-core/15589
7 class TestBacktraces < Test::Unit::TestCase
12 # Convenience method to obtain the exception,
13 # and to print the stack trace, if needed.
14 def get_exception(verbose=false)
16 @get_exception_yield_line = __LINE__ + 1
18 rescue Exception => ex
19 puts ex.backtrace.join("\n") if verbose
24 # Main verification method that performs actual checks
26 def check(expectations, exception)
28 expectations.strip.split("\n").each { |line|
31 # if line starts with +nnn, we prepend
32 # the current file and offset
33 md = line.match(/^\+(\d+)(:.*)/)
35 flunk("@offset is not defined in the test case") unless @offset
36 line = "#{__FILE__}:#{$1.to_i + @offset}#{$2}"
39 backtrace << line.strip
41 backtrace.each_with_index { |expected, idx|
42 assert_equal(expected, exception.backtrace[idx])
46 def test_simple_exception
48 raise RuntimeError.new("Test")
49 rescue Exception => ex
50 expectation = "+1:in `test_simple_exception'"
51 check(expectation, ex)
54 def test_simple_exception_recursive
57 raise RuntimeError.new("Test") if n == 10
62 rescue Exception => ex
66 +6:in `test_simple_exception_recursive'
68 check(expectation, ex)
71 def test_native_exception_recursive
74 raise "hello".sub(/l/, 5) if n == 10
79 rescue Exception => ex
84 +6:in `test_native_exception_recursive'
86 check(expectation, ex)
89 def test_exception_from_block
97 foo { bar { raise TypeError.new("HEH") } }
98 rescue Exception => ex
100 +7:in `test_exception_from_block'
102 +7:in `test_exception_from_block'
104 +7:in `test_exception_from_block'
106 check(expectation, ex)
109 def test_exception_from_for
115 rescue Exception => ex
117 +2:in `test_exception_from_for'
119 +1:in `test_exception_from_for'
121 check(expectation, ex)
124 def test_exception_from_proc
127 raise StandardError.new
130 rescue Exception => ex
132 +1:in `test_exception_from_proc'
134 +3:in `test_exception_from_proc'
136 check(expectation, ex)
139 def test_exception_from_lambda
142 raise StandardError.new
145 rescue Exception => ex
147 +1:in `test_exception_from_lambda'
149 +3:in `test_exception_from_lambda'
151 check(expectation, ex)
154 def test_exception_from_array_plus
157 rescue Exception => ex
160 +1:in `test_exception_from_array_plus'
162 check(expectation, ex)
166 def test_exception_from_string_plus
169 rescue Exception => ex
172 +1:in `test_exception_from_string_plus'
174 check(expectation, ex)
177 def test_exception_from_string_sub
180 rescue Exception => ex
183 +1:in `test_exception_from_string_sub'
185 check(expectation, ex)
188 def test_zero_devision_exception
191 rescue Exception => ex
194 +1:in `test_zero_devision_exception'
196 check(expectation, ex)
199 def test_exeption_from_object_send
201 "hello".__send__(:sub, /l/, 5)
202 rescue Exception => ex
206 +1:in `test_exeption_from_object_send'
208 check(expectation, ex)
211 def test_arity_exception
214 rescue Exception => ex
215 expectation = "+1:in `sub'"
216 check(expectation, ex)
219 def test_exception_from_eval
222 eval("raise RuntimeError.new")
225 +1:in `test_exception_from_eval'
226 #{__FILE__}:#{@get_exception_yield_line}:in `eval'
227 +1:in `test_exception_from_eval'
228 #{__FILE__}:#{@get_exception_yield_line}:in `get_exception'
230 check(expectation, ex)
233 def test_exception_from_block_inside_eval
236 eval("def foo; yield; end; foo { raise RuntimeError.new }")
239 +1:in `test_exception_from_block_inside_eval'
241 (eval):1:in `test_exception_from_block_inside_eval'
242 #{__FILE__}:#{@get_exception_yield_line}:in `eval'
243 +1:in `test_exception_from_block_inside_eval'
244 #{__FILE__}:#{@get_exception_yield_line}:in `get_exception'
246 check(expectation, ex)