blob: 95e29d13eed437b3853a5fd9c47389d73160f632 [file] [log] [blame]
Tamas Kenez507481b2017-06-06 15:01:33 +02001#!/usr/bin/env python
2# Copyright (c) 2017, the R8 project authors. Please see the AUTHORS file
3# for details. All rights reserved. Use of this source code is governed by a
4# BSD-style license that can be found in the LICENSE file.
5
6# Compare multiple CTS test_result.xml files
7
8from __future__ import print_function
9from os.path import basename
10import argparse
11import os
12import re
13import sys
14
15class Module:
16 def __init__(self):
17 self.test_cases = {}
18 self.bf_covered_in_file = 0 # bitfield, one bit per file
19
20 def get_test_case_maybe_create(self, test_case_name):
21 return self.test_cases.setdefault(test_case_name, TestCase())
22
23 def set_file_index_present(self, file_idx):
24 self.bf_covered_in_file |= (1 << file_idx)
25
26 def report(self, module_name, files, diff_only):
27 bf_all_files = self.bf_covered_in_file
28 for test_case_name, test_case in self.test_cases.iteritems():
29 if test_case.bf_covered_in_file != bf_all_files:
30 report_missing_thing('test_case', module_name + '/' + test_case_name,
31 test_case.bf_covered_in_file, files)
32 for test_case_name, test_case in self.test_cases.iteritems():
33 test_case.report(module_name, test_case_name, files, diff_only)
34
35class TestCase:
36 def __init__(self):
37 self.tests = {}
38 self.bf_covered_in_file = 0 # bitfield, one bit per file
39
40 def get_test_maybe_create(self, test_name):
41 return self.tests.setdefault(test_name, Test())
42
43 def set_file_index_present(self, file_idx):
44 self.bf_covered_in_file |= (1 << file_idx)
45
46 def report(self, module_name, test_case_name, files, diff_only):
47 bf_all_files = self.bf_covered_in_file
48 for test_name, test in self.tests.iteritems():
49 do_report = test.bf_passing_in_file != bf_all_files
50 if diff_only:
51 do_report = do_report and test.bf_failing_in_file != bf_all_files
52 if do_report:
53 test.report(module_name, test_case_name, test_name, files)
54
55class Test:
56 def __init__(self):
57 self.bf_failing_in_file = 0 # bitfields, one bit per file
58 self.bf_passing_in_file = 0
59
60 def set_file_index_outcome(self, outcome_is_passed, file_idx):
61 bf_value = (1 << file_idx)
62 if outcome_is_passed:
63 self.bf_passing_in_file |= bf_value
64 else:
65 self.bf_failing_in_file |= bf_value
66
67 # Report test's status in all files: pass/fail/missing
68 def report(self, module_name, test_case_name, test_name, files):
69 print('Test: {}/{}/{}:'.format(module_name, test_case_name, test_name))
70 for file_idx, f in enumerate(files):
71 bf_value = 1 << file_idx
72 print('\t- {:20}'.format(basename(f)), end = '')
73 if self.bf_passing_in_file & bf_value:
74 print('PASS')
75 elif self.bf_failing_in_file & bf_value:
76 print(' FAIL')
77 else:
78 print(' -- -- (missing)')
79
80def parse_arguments():
81 parser = argparse.ArgumentParser(
82 description = 'Compare multiple Android CTS test_result.xml files.')
83 parser.add_argument('files', nargs = '+',
84 help = 'List of (possibly renamed) test_result.xml files')
85 parser.add_argument('--diff-only',
86 action = 'store_true',
87 help = "Don't list tests that consistently fail in all result files,"
88 " list only differences.")
89 return parser.parse_args()
90
91# Read CTS test_result.xml from file and merge into result_tree
92def add_to_result_tree(result_tree, file_xml, file_idx):
93 re_module = re.compile('<Module name="([^"]*)"')
94 re_test_case = re.compile('<TestCase name="([^"]*)"')
95 re_test = re.compile('<Test result="(pass|fail)" name="([^"]*)"')
96 module = None
97 test_case = None
98 with open(file_xml) as f:
99 for line in f:
100 m = re_module.search(line)
101 if m:
102 module_name = m.groups()[0]
103 module = result_tree.setdefault(module_name, Module())
104 module.set_file_index_present(file_idx)
105 continue
106
107 m = re_test_case.search(line)
108 if m:
109 test_case_name = m.groups()[0]
110 test_case = module.get_test_case_maybe_create(test_case_name)
111 test_case.set_file_index_present(file_idx)
112 continue
113
114 m = re_test.search(line)
115 if m:
116 outcome = m.groups()[0]
117 test_name = m.groups()[1]
118 assert outcome in ["fail", "pass"]
119
120 v = test_case.get_test_maybe_create(test_name)
121 v.set_file_index_outcome(outcome == 'pass', file_idx)
122
123# main tree_report function
124def tree_report(result_tree, files, diff_only):
125 bf_all_files = (1 << len(files)) - 1
126 for module_name, module in result_tree.iteritems():
127 if module.bf_covered_in_file != bf_all_files:
128 report_missing_thing('module', module_name, module.bf_covered_in_file,
129 files)
130 for module_name, module in result_tree.iteritems():
131 module.report(module_name, files, diff_only)
132
133def report_missing_thing(thing_type, thing_name, bf_covered_in_file, files):
134 print('Missing {}: {}, from:'.format(thing_type, thing_name))
135 for file_idx, f in enumerate(files):
136 if not (bf_covered_in_file & (1 << file_idx)):
137 print('\t- ' + f)
138
139def Main():
140 m = Module()
141 m.get_test_case_maybe_create('qwe')
142
143 args = parse_arguments()
144
145 result_tree = {}
146 for file_idx, f in enumerate(args.files):
147 add_to_result_tree(result_tree, f, file_idx)
148
149 tree_report(result_tree, args.files, args.diff_only)
150
151 return 0
152
153if __name__ == '__main__':
154 sys.exit(Main())