Commit | Line | Data |
---|---|---|
920dae64 AT |
1 | import hotshot |
2 | import hotshot.log | |
3 | import os | |
4 | import pprint | |
5 | import unittest | |
6 | ||
7 | from test import test_support | |
8 | ||
9 | from hotshot.log import ENTER, EXIT, LINE | |
10 | ||
11 | ||
12 | def shortfilename(fn): | |
13 | # We use a really shortened filename since an exact match is made, | |
14 | # and the source may be either a Python source file or a | |
15 | # pre-compiled bytecode file. | |
16 | if fn: | |
17 | return os.path.splitext(os.path.basename(fn))[0] | |
18 | else: | |
19 | return fn | |
20 | ||
21 | ||
22 | class UnlinkingLogReader(hotshot.log.LogReader): | |
23 | """Extend the LogReader so the log file is unlinked when we're | |
24 | done with it.""" | |
25 | ||
26 | def __init__(self, logfn): | |
27 | self.__logfn = logfn | |
28 | hotshot.log.LogReader.__init__(self, logfn) | |
29 | ||
30 | def next(self, index=None): | |
31 | try: | |
32 | return hotshot.log.LogReader.next(self) | |
33 | except StopIteration: | |
34 | self.close() | |
35 | os.unlink(self.__logfn) | |
36 | raise | |
37 | ||
38 | ||
39 | class HotShotTestCase(unittest.TestCase): | |
40 | def new_profiler(self, lineevents=0, linetimings=1): | |
41 | self.logfn = test_support.TESTFN | |
42 | return hotshot.Profile(self.logfn, lineevents, linetimings) | |
43 | ||
44 | def get_logreader(self): | |
45 | return UnlinkingLogReader(self.logfn) | |
46 | ||
47 | def get_events_wotime(self): | |
48 | L = [] | |
49 | for event in self.get_logreader(): | |
50 | what, (filename, lineno, funcname), tdelta = event | |
51 | L.append((what, (shortfilename(filename), lineno, funcname))) | |
52 | return L | |
53 | ||
54 | def check_events(self, expected): | |
55 | events = self.get_events_wotime() | |
56 | if events != expected: | |
57 | self.fail( | |
58 | "events did not match expectation; got:\n%s\nexpected:\n%s" | |
59 | % (pprint.pformat(events), pprint.pformat(expected))) | |
60 | ||
61 | def run_test(self, callable, events, profiler=None): | |
62 | if profiler is None: | |
63 | profiler = self.new_profiler() | |
64 | self.failUnless(not profiler._prof.closed) | |
65 | profiler.runcall(callable) | |
66 | self.failUnless(not profiler._prof.closed) | |
67 | profiler.close() | |
68 | self.failUnless(profiler._prof.closed) | |
69 | self.check_events(events) | |
70 | ||
71 | def test_addinfo(self): | |
72 | def f(p): | |
73 | p.addinfo("test-key", "test-value") | |
74 | profiler = self.new_profiler() | |
75 | profiler.runcall(f, profiler) | |
76 | profiler.close() | |
77 | log = self.get_logreader() | |
78 | info = log._info | |
79 | list(log) | |
80 | self.failUnless(info["test-key"] == ["test-value"]) | |
81 | ||
82 | def test_line_numbers(self): | |
83 | def f(): | |
84 | y = 2 | |
85 | x = 1 | |
86 | def g(): | |
87 | f() | |
88 | f_lineno = f.func_code.co_firstlineno | |
89 | g_lineno = g.func_code.co_firstlineno | |
90 | events = [(ENTER, ("test_hotshot", g_lineno, "g")), | |
91 | (LINE, ("test_hotshot", g_lineno+1, "g")), | |
92 | (ENTER, ("test_hotshot", f_lineno, "f")), | |
93 | (LINE, ("test_hotshot", f_lineno+1, "f")), | |
94 | (LINE, ("test_hotshot", f_lineno+2, "f")), | |
95 | (EXIT, ("test_hotshot", f_lineno, "f")), | |
96 | (EXIT, ("test_hotshot", g_lineno, "g")), | |
97 | ] | |
98 | self.run_test(g, events, self.new_profiler(lineevents=1)) | |
99 | ||
100 | def test_start_stop(self): | |
101 | # Make sure we don't return NULL in the start() and stop() | |
102 | # methods when there isn't an error. Bug in 2.2 noted by | |
103 | # Anthony Baxter. | |
104 | profiler = self.new_profiler() | |
105 | profiler.start() | |
106 | profiler.stop() | |
107 | profiler.close() | |
108 | os.unlink(self.logfn) | |
109 | ||
110 | ||
111 | def test_main(): | |
112 | test_support.run_unittest(HotShotTestCase) | |
113 | ||
114 | ||
115 | if __name__ == "__main__": | |
116 | test_main() |