| #!/usr/bin/env python3 | |
| # Copyright (c) 2017, the R8 project authors. Please see the AUTHORS file | |
| # for details. All rights reserved. Use of this source code is governed by a | |
| # BSD-style license that can be found in the LICENSE file. | |
| # Compare multiple CTS test_result.xml files | |
| from __future__ import print_function | |
| from os.path import basename | |
| import argparse | |
| import sys | |
| import utils | |
| class Module: | |
| def __init__(self): | |
| self.test_cases = {} | |
| self.bf_covered_in_file = 0 # bitfield, one bit per file | |
| def get_test_case_maybe_create(self, test_case_name): | |
| return self.test_cases.setdefault(test_case_name, TestCase()) | |
| def set_file_index_present(self, file_idx): | |
| self.bf_covered_in_file |= (1 << file_idx) | |
| def report(self, module_name, files, diff_only): | |
| bf_all_files = self.bf_covered_in_file | |
| for test_case_name, test_case in self.test_cases.iteritems(): | |
| if test_case.bf_covered_in_file != bf_all_files: | |
| report_missing_thing('test_case', | |
| module_name + '/' + test_case_name, | |
| test_case.bf_covered_in_file, files) | |
| for test_case_name, test_case in self.test_cases.iteritems(): | |
| test_case.report(module_name, test_case_name, files, diff_only) | |
| class TestCase: | |
| def __init__(self): | |
| self.tests = {} | |
| self.bf_covered_in_file = 0 # bitfield, one bit per file | |
| def get_test_maybe_create(self, test_name): | |
| return self.tests.setdefault(test_name, Test()) | |
| def set_file_index_present(self, file_idx): | |
| self.bf_covered_in_file |= (1 << file_idx) | |
| def report(self, module_name, test_case_name, files, diff_only): | |
| bf_all_files = self.bf_covered_in_file | |
| for test_name, test in self.tests.iteritems(): | |
| do_report = test.bf_passing_in_file != bf_all_files | |
| if diff_only: | |
| do_report = do_report and test.bf_failing_in_file != bf_all_files | |
| if do_report: | |
| test.report(module_name, test_case_name, test_name, files) | |
| class Test: | |
| def __init__(self): | |
| self.bf_failing_in_file = 0 # bitfields, one bit per file | |
| self.bf_passing_in_file = 0 | |
| def set_file_index_outcome(self, outcome_is_passed, file_idx): | |
| bf_value = (1 << file_idx) | |
| if outcome_is_passed: | |
| self.bf_passing_in_file |= bf_value | |
| else: | |
| self.bf_failing_in_file |= bf_value | |
| # Report test's status in all files: pass/fail/missing | |
| def report(self, module_name, test_case_name, test_name, files): | |
| print('Test: {}/{}/{}:'.format(module_name, test_case_name, test_name)) | |
| for file_idx, f in enumerate(files): | |
| bf_value = 1 << file_idx | |
| print('\t- {:20}'.format(basename(f)), end='') | |
| if self.bf_passing_in_file & bf_value: | |
| print('PASS') | |
| elif self.bf_failing_in_file & bf_value: | |
| print(' FAIL') | |
| else: | |
| print(' -- -- (missing)') | |
| def parse_arguments(): | |
| parser = argparse.ArgumentParser( | |
| description='Compare multiple Android CTS test_result.xml files.') | |
| parser.add_argument('files', | |
| nargs='+', | |
| help='List of (possibly renamed) test_result.xml files') | |
| parser.add_argument( | |
| '--diff-only', | |
| action='store_true', | |
| help="Don't list tests that consistently fail in all result files," | |
| " list only differences.") | |
| return parser.parse_args() | |
| # Read CTS test_result.xml from file and merge into result_tree | |
| def add_to_result_tree(result_tree, file_xml, file_idx): | |
| module = None | |
| test_case = None | |
| for x in utils.read_cts_test_result(file_xml): | |
| if type(x) is utils.CtsModule: | |
| module = result_tree.setdefault(x.name, Module()) | |
| module.set_file_index_present(file_idx) | |
| elif type(x) is utils.CtsTestCase: | |
| test_case = module.get_test_case_maybe_create(x.name) | |
| test_case.set_file_index_present(file_idx) | |
| else: | |
| assert (type(x) is utils.CtsTest) | |
| v = test_case.get_test_maybe_create(x.name) | |
| v.set_file_index_outcome(x.outcome, file_idx) | |
| # main tree_report function | |
| def tree_report(result_tree, files, diff_only): | |
| bf_all_files = (1 << len(files)) - 1 | |
| for module_name, module in result_tree.iteritems(): | |
| if module.bf_covered_in_file != bf_all_files: | |
| report_missing_thing('module', module_name, | |
| module.bf_covered_in_file, files) | |
| for module_name, module in result_tree.iteritems(): | |
| module.report(module_name, files, diff_only) | |
| def report_missing_thing(thing_type, thing_name, bf_covered_in_file, files): | |
| print('Missing {}: {}, from:'.format(thing_type, thing_name)) | |
| for file_idx, f in enumerate(files): | |
| if not (bf_covered_in_file & (1 << file_idx)): | |
| print('\t- ' + f) | |
| def Main(): | |
| m = Module() | |
| m.get_test_case_maybe_create('qwe') | |
| args = parse_arguments() | |
| result_tree = {} | |
| for file_idx, f in enumerate(args.files): | |
| add_to_result_tree(result_tree, f, file_idx) | |
| tree_report(result_tree, args.files, args.diff_only) | |
| return 0 | |
| if __name__ == '__main__': | |
| sys.exit(Main()) |