OLD | NEW |
| (Empty) |
1 #!/usr/bin/env python | |
2 | |
3 import os | |
4 import glob | |
5 import re | |
6 import sys | |
7 import optparse | |
8 | |
9 #File 'accidental-engraver.cc' | |
10 #Lines executed:87.70% of 252 | |
11 | |
12 def summary (args): | |
13 results = [] | |
14 for f in args: | |
15 str = open (f).read () | |
16 m = re.search ("File '([^']+.cc)'\s*Lines executed:([0-9.]+)% of ([0-9]+
)", str) | |
17 | |
18 if m and '/usr/lib' in m.group (1): | |
19 continue | |
20 | |
21 if m: | |
22 cov = float (m.group (2)) | |
23 lines = int (m.group (3)) | |
24 pain = lines * (100.0 - cov) | |
25 file = m.group (1) | |
26 tup = (pain, locals ().copy()) | |
27 | |
28 results.append(tup) | |
29 | |
30 results.sort () | |
31 results.reverse() | |
32 | |
33 print 'files sorted by number of untested lines (decreasing)' | |
34 print | |
35 print '%5s (%6s): %s' % ('cov %', 'lines', 'file') | |
36 print '----------------------------------------------' | |
37 | |
38 for (pain, d) in results: | |
39 print '%(cov)5.2f (%(lines)6d): %(file)s' % d | |
40 | |
41 class Chunk: | |
42 def __init__ (self, range, coverage_count, all_lines, file): | |
43 assert coverage_count >= 0 | |
44 assert type (range) == type (()) | |
45 ········ | |
46 self.coverage_count = coverage_count | |
47 self.range = range | |
48 self.all_lines = all_lines | |
49 self.file = file | |
50 | |
51 def length (self): | |
52 return self.range[1] - self.range[0] | |
53 | |
54 def text (self): | |
55 return ''.join ([l[2] for l in self.lines()]) | |
56 ········ | |
57 def lines (self): | |
58 return self.all_lines[self.range[0]: | |
59 self.range[1]] | |
60 def widen (self): | |
61 self.range = (min (self.range[0] -1, 0), | |
62 self.range[0] +1) | |
63 def write (self): | |
64 print 'chunk in', self.file | |
65 for (c, n, l) in self.lines (): | |
66 cov = '%d' % c | |
67 if c == 0: | |
68 cov = '#######' | |
69 elif c < 0: | |
70 cov = '' | |
71 sys.stdout.write ('%8s:%8d:%s' % (cov, n, l)) | |
72 ············ | |
73 def uncovered_score (self): | |
74 return self.length () | |
75 ···· | |
76 class SchemeChunk (Chunk): | |
77 def uncovered_score (self): | |
78 text = self.text () | |
79 if (text.startswith ('(define ') | |
80 and not text.startswith ('(define (')): | |
81 return 0 | |
82 | |
83 if text.startswith ('(use-modules '): | |
84 return 0 | |
85 | |
86 if (text.startswith ('(define-public ') | |
87 and not text.startswith ('(define-public (')): | |
88 return 0 | |
89 | |
90 return len ([l for (c,n,l) in self.lines() if (c == 0)])· | |
91 | |
92 def read_gcov (f): | |
93 ls = [] | |
94 | |
95 in_lines = [l for l in open (f).readlines ()] | |
96 (count_len, line_num_len) = tuple (map (len, in_lines[0].split (':')[:2])) | |
97 ···· | |
98 for l in in_lines: | |
99 c = l[:count_len].strip () | |
100 l = l[count_len+1:] | |
101 n = int (l[:line_num_len].strip ()) | |
102 | |
103 if n == 0: | |
104 continue | |
105 | |
106 if '#' in c: | |
107 c = 0 | |
108 elif c == '-': | |
109 c = -1 | |
110 else: | |
111 c = int (c) | |
112 ········ | |
113 l = l[line_num_len+1:] | |
114 | |
115 ls.append ((c,n,l)) | |
116 ········ | |
117 return ls | |
118 | |
119 def get_c_chunks (ls, file): | |
120 chunks = [] | |
121 chunk = [] | |
122 | |
123 last_c = -1 | |
124 for (c, n, l) in ls: | |
125 if not (c == last_c or c < 0 and l != '}\n'): | |
126 if chunk and last_c >= 0: | |
127 nums = [n-1 for (n, l) in chunk] | |
128 chunks.append (Chunk ((min (nums), max (nums)+1), | |
129 last_c, ls, file)) | |
130 chunk = [] | |
131 | |
132 chunk.append ((n,l)) | |
133 if c >= 0: | |
134 last_c = c | |
135 ············ | |
136 return chunks | |
137 | |
138 def get_scm_chunks (ls, file): | |
139 chunks = [] | |
140 chunk = [] | |
141 | |
142 def new_chunk (): | |
143 if chunk: | |
144 nums = [n-1 for (n, l) in chunk] | |
145 chunks.append (SchemeChunk ((min (nums), max (nums)+1), | |
146 max (last_c, 0), ls, file)) | |
147 chunk[:] = [] | |
148 ········ | |
149 last_c = -1 | |
150 for (cov_count, line_number, line) in ls: | |
151 if line.startswith ('('): | |
152 new_chunk () | |
153 last_c = -1 | |
154 ········ | |
155 chunk.append ((line_number, line)) | |
156 if cov_count >= 0: | |
157 last_c = cov_count | |
158 | |
159 return chunks | |
160 | |
161 def widen_chunk (ch, ls): | |
162 a -= 1 | |
163 b += 1 | |
164 | |
165 return [(n, l) for (c, n, l) in ls[a:b]] | |
166 ···· | |
167 | |
168 def extract_chunks (file): | |
169 try: | |
170 ls = read_gcov (file) | |
171 except IOError, s : | |
172 print s | |
173 return [] | |
174 ········ | |
175 cs = [] | |
176 if 'scm' in file: | |
177 cs = get_scm_chunks (ls, file) | |
178 else: | |
179 cs = get_c_chunks (ls, file) | |
180 return cs | |
181 | |
182 | |
183 def filter_uncovered (chunks): | |
184 def interesting (c): | |
185 if c.coverage_count > 0: | |
186 return False | |
187 ········ | |
188 t = c.text() | |
189 for stat in ('warning', 'error', 'print', 'scm_gc_mark'): | |
190 if stat in t: | |
191 return False | |
192 return True | |
193 ··· | |
194 return [c for c in chunks if interesting (c)] | |
195 ···· | |
196 | |
197 def main (): | |
198 p = optparse.OptionParser (usage="usage coverage.py [options] files", | |
199 description="") | |
200 p.add_option ("--summary", | |
201 action='store_true', | |
202 default=False, | |
203 dest="summary") | |
204 ···· | |
205 p.add_option ("--hotspots", | |
206 default=False, | |
207 action='store_true', | |
208 dest="hotspots") | |
209 ···· | |
210 p.add_option ("--uncovered", | |
211 default=False, | |
212 action='store_true', | |
213 dest="uncovered") | |
214 | |
215 ···· | |
216 (options, args) = p.parse_args () | |
217 ···· | |
218 | |
219 if options.summary: | |
220 summary (['%s.gcov-summary' % s for s in args]) | |
221 | |
222 if options.uncovered or options.hotspots: | |
223 chunks = [] | |
224 for a in args: | |
225 name = a | |
226 if name.endswith ('scm'): | |
227 name += '.cov' | |
228 else: | |
229 name += '.gcov' | |
230 ············ | |
231 chunks += extract_chunks (name) | |
232 | |
233 if options.uncovered: | |
234 chunks = filter_uncovered (chunks) | |
235 chunks = [(c.uncovered_score (), c) for c in chunks if c.uncovered_s
core() > 0] | |
236 elif options.hotspots: | |
237 chunks = [((c.coverage_count, -c.length()), c) for c in chunks] | |
238 ············ | |
239 ············ | |
240 chunks.sort () | |
241 chunks.reverse () | |
242 for (score, c) in chunks: | |
243 c.write () | |
244 | |
245 ············ | |
246 ········ | |
247 if __name__ == '__main__': | |
248 main () | |
OLD | NEW |