#!/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())