1#!/usr/bin/env python
2"""
3Summarize the information in the given coverage files.
4
5Emits the number of rules covered or the percentage of rules covered depending
6on whether --num-rules has been used to specify the total number of rules.
7"""
8from __future__ import print_function
9
10import argparse
11import struct
12
13class FileFormatError(Exception):
14  pass
15
16def backend_int_pair(s):
17  backend, sep, value = s.partition('=')
18  if sep is None:
19    raise argparse.ArgumentTypeError("'=' missing, expected name=value")
20  if not backend:
21    raise argparse.ArgumentTypeError("Expected name=value")
22  if not value:
23    raise argparse.ArgumentTypeError("Expected name=value")
24  return backend, int(value)
25
26def main():
27  parser = argparse.ArgumentParser(description=__doc__)
28  parser.add_argument('input', nargs='+')
29  parser.add_argument('--num-rules', type=backend_int_pair, action='append',
30                      metavar='BACKEND=NUM',
31                      help='Specify the number of rules for a backend')
32  args = parser.parse_args()
33
34  covered_rules = {}
35
36  for input_filename in args.input:
37    with open(input_filename, 'rb') as input_fh:
38      data = input_fh.read()
39      pos = 0
40      while data:
41        backend, _, data = data.partition('\0')
42        pos += len(backend)
43        pos += 1
44
45        if len(backend) == 0:
46          raise FileFormatError()
47        backend, = struct.unpack("%ds" % len(backend), backend)
48
49        while data:
50          if len(data) < 8:
51            raise FileFormatError()
52          rule_id, = struct.unpack("Q", data[:8])
53          pos += 8
54          data = data[8:]
55          if rule_id == (2 ** 64) - 1:
56            break
57          covered_rules[backend] = covered_rules.get(backend, {})
58          covered_rules[backend][rule_id] = covered_rules[backend].get(rule_id, 0) + 1
59
60  num_rules = dict(args.num_rules)
61  for backend, rules_for_backend in covered_rules.items():
62    if backend in num_rules:
63      print("%s: %3.2f%% of rules covered" % (backend, float(len(rules_for_backend)) / num_rules[backend]) * 100)
64    else:
65      print("%s: %d rules covered" % (backend, len(rules_for_backend)))
66
67if __name__ == '__main__':
68  main()
69