]> git.donarmstrong.com Git - lilypond.git/blob - buildscripts/coverage.py
sort uncovered chunks by length
[lilypond.git] / buildscripts / coverage.py
1 #!/bin/sh
2 import os
3 import glob
4 import re
5 import sys
6 import optparse
7
8 #File 'accidental-engraver.cc'
9 #Lines executed:87.70% of 252
10
11 def summary (args):
12     results = []
13     for f in args:
14         str = open (f).read ()
15         m = re.search ("File '([^']+.cc)'\s*Lines executed:([0-9.]+)% of ([0-9]+)", str)
16
17         if m and '/usr/lib' in m.group (1):
18             continue
19
20         if m:
21             cov = float (m.group (2))
22             lines = int (m.group (3))
23             pain = lines * (100.0 - cov)
24             file = m.group (1)
25             tup = (pain, locals ().copy())
26
27             results.append(tup)
28
29     results.sort ()
30     results.reverse()
31
32     print 'files sorted by number of untested lines (decreasing)'
33     print
34     print '%5s (%6s): %s' % ('cov %', 'lines', 'file')
35     print '----------------------------------------------'
36
37     for (pain, d) in results:
38         print '%(cov)5.2f (%(lines)6d): %(file)s' % d
39
40 class Chunk:
41     def __init__ (self, range, all_lines, file):
42         self.range = range
43         self.all_lines = all_lines
44         self.file = file
45
46     def length (self):
47         return self.range[1] - self.range[0]
48     def text (self):
49         return ''.join ([l[0] for l in self.lines()])
50         
51     def lines (self):
52         return self.all_lines[self.range[0]:
53                               self.range[1]]
54     def widen (self):
55         self.range = (min (self.range[0] -1, 0),
56                       self.range[0] +1)
57     def write (self):
58         print 'uncovered chunk in', self.file
59         for (c, n, l) in self.lines ():
60             sys.stdout.write ('%8s:%8d:%s' % (c,n,l))
61             
62 def read_gcov (f):
63     ls = []
64
65     in_lines = [l for l in open (f).readlines ()]
66     (count_len, line_num_len) = tuple (map (len, in_lines[0].split( ':')[:2]))
67     
68     for l in in_lines:
69         c = l[:count_len].strip ()
70         l = l[count_len+1:]
71         n = int (l[:line_num_len].strip ())
72
73         if n == 0:
74             continue
75         
76         l = l[line_num_len+1:]
77
78         ls.append ((c,n,l))
79         
80     return ls
81
82 def get_chunks (ls, file):
83     chunks = []
84     chunk = []
85     for (c,n,l) in ls:
86         if '#' in c:
87             chunk.append ((n,l))
88         elif c.strip () != '-' or l == '}\n':
89             if chunk:
90                 nums = [n-1 for (n, l) in chunk]
91                 chunks.append (Chunk ((min (nums), max (nums)+1),
92                                       ls, file))
93                 chunk = []
94             
95     return chunks
96
97
98 def widen_chunk (ch, ls):
99     a -= 1
100     b += 1
101
102     return [(n, l)  for (c, n, l) in ls[a:b]]
103     
104
105 def is_exception_chunk (ch):
106     for (n,l) in ch:
107         for stat in  ('warning', 'error'):
108             if stat in l:
109                 return True
110     return False
111
112 def is_inspection_chunk (ch):
113     for (n,l) in ch:
114         for stat in  ('::print',):
115             if stat in l:
116                 return True
117     return False
118
119 def extract_uncovered (file):
120     try:
121         ls = read_gcov (file)
122     except IOError, s :
123         print s
124         return []
125         
126     cs = get_chunks (ls, file)
127     def interesting (c):
128         t = c.text()
129         for stat in  ('warning', 'error', 'print'):
130             if stat in t:
131                 return False
132         return True
133
134    
135     return [c for c in cs if interesting (c)]
136     
137
138 def main ():
139     p = optparse.OptionParser (usage="usage coverage.py [options] files",
140                                description="")
141     p.add_option ("--summary",
142                   action='store_true',
143                   default=False,
144                   dest="summary")
145     
146     p.add_option ("--uncovered",
147                   default=False,
148                   action='store_true',
149                   dest="uncovered")
150
151     
152     (options, args) = p.parse_args ()
153     
154
155     if options.summary:
156         summary (['%s.gcov-summary' % s for s in args])
157
158     if options.uncovered:
159         uncovered = []
160         for a in args:
161             uncovered += extract_uncovered ('%s.gcov' % a)
162             
163         uncovered = [(c.length (), c) for c in uncovered]
164         uncovered.sort ()
165         uncovered.reverse ()
166         for (score, c) in uncovered:
167             c.write ()
168
169             
170         
171 if __name__ == '__main__':
172     main ()