1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219
|
# Testing the line trace facility.
import test_support
import unittest
import sys
import difflib
if not __debug__:
raise test_support.TestSkipped, "tracing not supported under -O"
# A very basic example. If this fails, we're in deep trouble.
def basic():
return 1
basic.events = [(0, 'call'),
(0, 'line'),
(1, 'line'),
(1, 'return')]
# Armin Rigo's failing example:
def arigo_example():
x = 1
del x
while 0:
pass
x = 1
arigo_example.events = [(0, 'call'),
(0, 'line'),
(1, 'line'),
(2, 'line'),
(3, 'line'),
(3, 'line'),
(5, 'line'),
(5, 'return')]
# check that lines consisting of just one instruction get traced:
def one_instr_line():
x = 1
del x
x = 1
one_instr_line.events = [(0, 'call'),
(0, 'line'),
(1, 'line'),
(2, 'line'),
(3, 'line'),
(3, 'return')]
def no_pop_tops(): # 0
x = 1 # 1
for a in range(2): # 2
if a: # 3
x = 1 # 4
else: # 5
x = 1 # 6
no_pop_tops.events = [(0, 'call'),
(0, 'line'),
(1, 'line'),
(2, 'line'),
(2, 'line'),
(3, 'line'),
(6, 'line'),
(2, 'line'),
(3, 'line'),
(4, 'line'),
(2, 'line'),
(2, 'return')]
def no_pop_blocks():
while 0:
bla
x = 1
no_pop_blocks.events = [(0, 'call'),
(0, 'line'),
(1, 'line'),
(1, 'line'),
(3, 'line'),
(3, 'return')]
def called(): # line -3
x = 1
def call(): # line 0
called()
call.events = [(0, 'call'),
(0, 'line'),
(1, 'line'),
(-3, 'call'),
(-3, 'line'),
(-2, 'line'),
(-2, 'return'),
(1, 'return')]
def raises():
raise Exception
def test_raise():
try:
raises()
except Exception, exc:
x = 1
test_raise.events = [(0, 'call'),
(0, 'line'),
(1, 'line'),
(2, 'line'),
(-3, 'call'),
(-3, 'line'),
(-2, 'line'),
(-2, 'exception'),
(2, 'exception'),
(3, 'line'),
(4, 'line'),
(4, 'return')]
def _settrace_and_return(tracefunc):
sys.settrace(tracefunc)
sys._getframe().f_back.f_trace = tracefunc
def settrace_and_return(tracefunc):
_settrace_and_return(tracefunc)
settrace_and_return.events = [(1, 'return')]
def _settrace_and_raise(tracefunc):
sys.settrace(tracefunc)
sys._getframe().f_back.f_trace = tracefunc
raise RuntimeError
def settrace_and_raise(tracefunc):
try:
_settrace_and_raise(tracefunc)
except RuntimeError, exc:
pass
settrace_and_raise.events = [(2, 'exception'),
(3, 'line'),
(4, 'line'),
(4, 'return')]
class Tracer:
def __init__(self):
self.events = []
def trace(self, frame, event, arg):
self.events.append((frame.f_lineno, event))
return self.trace
class TraceTestCase(unittest.TestCase):
def compare_events(self, line_offset, events, expected_events):
events = [(l - line_offset, e) for (l, e) in events]
if events != expected_events:
self.fail(
"events did not match expectation:\n" +
"\n".join(difflib.ndiff(map(str, expected_events),
map(str, events))))
def run_test(self, func):
tracer = Tracer()
sys.settrace(tracer.trace)
func()
sys.settrace(None)
self.compare_events(func.func_code.co_firstlineno,
tracer.events, func.events)
def run_test2(self, func):
tracer = Tracer()
func(tracer.trace)
sys.settrace(None)
self.compare_events(func.func_code.co_firstlineno,
tracer.events, func.events)
def test_1_basic(self):
self.run_test(basic)
def test_2_arigo(self):
self.run_test(arigo_example)
def test_3_one_instr(self):
self.run_test(one_instr_line)
def test_4_no_pop_blocks(self):
self.run_test(no_pop_blocks)
def test_5_no_pop_tops(self):
self.run_test(no_pop_tops)
def test_6_call(self):
self.run_test(call)
def test_7_raise(self):
self.run_test(test_raise)
def test_8_settrace_and_return(self):
self.run_test2(settrace_and_return)
def test_9_settrace_and_raise(self):
self.run_test2(settrace_and_raise)
class RaisingTraceFuncTestCase(unittest.TestCase):
def test_it(self):
def tr(frame, event, arg):
raise ValueError # just something that isn't RuntimeError
def f():
return 1
try:
for i in xrange(sys.getrecursionlimit() + 1):
sys.settrace(tr)
try:
f()
except ValueError:
pass
else:
self.fail("exception not thrown!")
except RuntimeError:
self.fail("recursion counter not reset")
def test_main():
test_support.run_unittest(TraceTestCase)
test_support.run_unittest(RaisingTraceFuncTestCase)
if __name__ == "__main__":
test_main()
|