]> git.donarmstrong.com Git - lilypond.git/blob - scripts/auxiliar/coverage.py
Add '-dcrop' option to ps and svg backends
[lilypond.git] / scripts / auxiliar / coverage.py
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_score() > 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 ()