| #!/usr/bin/env python |
| # 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 os |
| 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()) |