1require 'test/unit'
2require 'thread'
3
4class TestBacktrace < Test::Unit::TestCase
5  def test_exception
6    bt = Fiber.new{
7      begin
8        raise
9      rescue => e
10        e.backtrace
11      end
12    }.resume
13    assert_equal(1, bt.size)
14    assert_match(/.+:\d+:.+/, bt[0])
15  end
16
17  def test_caller_lev
18    cs = []
19    Fiber.new{
20      Proc.new{
21        cs << caller(0)
22        cs << caller(1)
23        cs << caller(2)
24        cs << caller(3)
25        cs << caller(4)
26        cs << caller(5)
27      }.call
28    }.resume
29    assert_equal(3, cs[0].size)
30    assert_equal(2, cs[1].size)
31    assert_equal(1, cs[2].size)
32    assert_equal(0, cs[3].size)
33    assert_equal(nil, cs[4])
34
35    #
36    max = 7
37    rec = lambda{|n|
38      if n > 0
39        1.times{
40          rec[n-1]
41        }
42      else
43        (max*3).times{|i|
44          total_size = caller(0).size
45          c = caller(i)
46          if c
47            assert_equal(total_size - i, caller(i).size, "[ruby-dev:45673]")
48          end
49        }
50      end
51    }
52    bt = Fiber.new{
53      rec[max]
54    }.resume
55  end
56
57  def test_caller_lev_and_n
58    m = 10
59    rec = lambda{|n|
60      if n < 0
61        (m*6).times{|lev|
62          (m*6).times{|n|
63            t = caller(0).size
64            r = caller(lev, n)
65            r = r.size if r.respond_to? :size
66
67            # STDERR.puts [t, lev, n, r].inspect
68            if n == 0
69              assert_equal(0, r, [t, lev, n, r].inspect)
70            elsif t < lev
71              assert_equal(nil, r, [t, lev, n, r].inspect)
72            else
73              if t - lev > n
74                assert_equal(n, r, [t, lev, n, r].inspect)
75              else
76                assert_equal(t - lev, r, [t, lev, n, r].inspect)
77              end
78            end
79          }
80        }
81      else
82        rec[n-1]
83      end
84    }
85    rec[m]
86  end
87
88  def test_caller_with_nil_length
89    assert_equal caller(0), caller(0, nil)
90  end
91
92  def test_caller_locations
93    cs = caller(0); locs = caller_locations(0).map{|loc|
94      loc.to_s
95    }
96    assert_equal(cs, locs)
97  end
98
99  def test_caller_locations_with_range
100    cs = caller(0,2); locs = caller_locations(0..1).map { |loc|
101      loc.to_s
102    }
103    assert_equal(cs, locs)
104  end
105
106  def test_caller_locations_to_s_inspect
107    cs = caller(0); locs = caller_locations(0)
108    cs.zip(locs){|str, loc|
109      assert_equal(str, loc.to_s)
110      assert_equal(str.inspect, loc.inspect)
111    }
112  end
113
114  def th_rec q, n=10
115    if n > 1
116      th_rec q, n-1
117    else
118      q.pop
119    end
120  end
121
122  def test_thread_backtrace
123    begin
124      q = Queue.new
125      th = Thread.new{
126        th_rec q
127      }
128      sleep 0.5
129      th_backtrace = th.backtrace
130      th_locations = th.backtrace_locations
131
132      assert_equal(10, th_backtrace.count{|e| e =~ /th_rec/})
133      assert_equal(th_backtrace, th_locations.map{|e| e.to_s})
134      assert_equal(th_backtrace, th.backtrace(0))
135      assert_equal(th_locations.map{|e| e.to_s},
136                   th.backtrace_locations(0).map{|e| e.to_s})
137      th_backtrace.size.times{|n|
138        assert_equal(n, th.backtrace(0, n).size)
139        assert_equal(n, th.backtrace_locations(0, n).size)
140      }
141      n = th_backtrace.size
142      assert_equal(n, th.backtrace(0, n + 1).size)
143      assert_equal(n, th.backtrace_locations(0, n + 1).size)
144    ensure
145      q << true
146    end
147  end
148
149  def test_thread_backtrace_locations_with_range
150    begin
151      q = Queue.new
152      th = Thread.new{
153        th_rec q
154      }
155      sleep 0.5
156      bt = th.backtrace(0,2)
157      locs = th.backtrace_locations(0..1).map { |loc|
158        loc.to_s
159      }
160      assert_equal(bt, locs)
161    ensure
162      q << true
163    end
164  end
165end
166