Restruct the structure of outcome file presentation

Signed-off-by: Pengyu Lv <pengyu.lv@arm.com>
This commit is contained in:
Pengyu Lv 2023-11-22 19:02:15 +08:00
parent a6cf5d67c5
commit a442858878

View file

@ -40,25 +40,6 @@ class Results:
def _print_line(fmt, *args, **kwargs): def _print_line(fmt, *args, **kwargs):
sys.stderr.write((fmt + '\n').format(*args, **kwargs)) sys.stderr.write((fmt + '\n').format(*args, **kwargs))
class TestCaseOutcomes:
"""The outcomes of one test case across many configurations."""
# pylint: disable=too-few-public-methods
def __init__(self):
# Collect a list of witnesses of the test case succeeding or failing.
# Currently we don't do anything with witnesses except count them.
# The format of a witness is determined by the read_outcome_file
# function; it's the platform and configuration joined by ';'.
self.successes = []
self.failures = []
def hits(self):
"""Return the number of times a test case has been run.
This includes passes and failures, but not skips.
"""
return len(self.successes) + len(self.failures)
def execute_reference_driver_tests(results: Results, ref_component, driver_component, \ def execute_reference_driver_tests(results: Results, ref_component, driver_component, \
outcome_file): outcome_file):
"""Run the tests specified in ref_component and driver_component. Results """Run the tests specified in ref_component and driver_component. Results
@ -82,7 +63,12 @@ def analyze_coverage(results, outcomes, allow_list, full_coverage):
"""Check that all available test cases are executed at least once.""" """Check that all available test cases are executed at least once."""
available = check_test_cases.collect_available_test_cases() available = check_test_cases.collect_available_test_cases()
for key in available: for key in available:
hits = outcomes[key].hits() if key in outcomes else 0 hits = 0
for _comp, comp_outcomes in outcomes.items():
if key in comp_outcomes["successes"] or \
key in comp_outcomes["failures"]:
hits += 1
if hits == 0 and key not in allow_list: if hits == 0 and key not in allow_list:
if full_coverage: if full_coverage:
results.error('Test case not executed: {}', key) results.error('Test case not executed: {}', key)
@ -117,8 +103,14 @@ def analyze_driver_vs_reference(results: Results, outcomes,
- only some specific test inside a test suite, for which the corresponding - only some specific test inside a test suite, for which the corresponding
output string is provided output string is provided
""" """
seen_reference_passing = False ref_outcomes = outcomes.get("component_" + component_ref)
for key in outcomes: driver_outcomes = outcomes.get("component_" + component_driver)
if ref_outcomes is None or not ref_outcomes['successes']:
results.error("no passing test in reference component: bad outcome file?")
return
for key in ref_outcomes["successes"]:
# key is like "test_suite_foo.bar;Description of test case" # key is like "test_suite_foo.bar;Description of test case"
(full_test_suite, test_string) = key.split(';') (full_test_suite, test_string) = key.split(';')
test_suite = full_test_suite.split('.')[0] # retrieve main part of test suite name test_suite = full_test_suite.split('.')[0] # retrieve main part of test suite name
@ -136,23 +128,11 @@ def analyze_driver_vs_reference(results: Results, outcomes,
if name_matches_pattern(test_string, str_or_re): if name_matches_pattern(test_string, str_or_re):
ignored = True ignored = True
# Search for tests that run in reference component and not in driver component if not ignored and not key in driver_outcomes['successes']:
driver_test_passed = False
reference_test_passed = False
for entry in outcomes[key].successes:
if component_driver in entry:
driver_test_passed = True
if component_ref in entry:
reference_test_passed = True
seen_reference_passing = True
if reference_test_passed and not driver_test_passed and not ignored:
results.error("PASS -> SKIP/FAIL: {}", key) results.error("PASS -> SKIP/FAIL: {}", key)
if ignored and driver_test_passed: if ignored and key in driver_outcomes['successes']:
results.error("uselessly ignored: {}", key) results.error("uselessly ignored: {}", key)
if not seen_reference_passing:
results.error("no passing test in reference component: bad outcome file?")
def analyze_outcomes(results: Results, outcomes, args): def analyze_outcomes(results: Results, outcomes, args):
"""Run all analyses on the given outcome collection.""" """Run all analyses on the given outcome collection."""
analyze_coverage(results, outcomes, args['allow_list'], analyze_coverage(results, outcomes, args['allow_list'],
@ -168,15 +148,19 @@ by a semicolon.
outcomes = {} outcomes = {}
with open(outcome_file, 'r', encoding='utf-8') as input_file: with open(outcome_file, 'r', encoding='utf-8') as input_file:
for line in input_file: for line in input_file:
(platform, config, suite, case, result, _cause) = line.split(';') (_platform, config, suite, case, result, _cause) = line.split(';')
key = ';'.join([suite, case]) key = ';'.join([suite, case])
setup = ';'.join([platform, config]) if config not in outcomes:
if key not in outcomes: outcomes[config] = {"successes":[], "failures":[]}
outcomes[key] = TestCaseOutcomes()
if result == 'PASS': if result == 'PASS':
outcomes[key].successes.append(setup) outcomes[config]['successes'].append(key)
elif result == 'FAIL': elif result == 'FAIL':
outcomes[key].failures.append(setup) outcomes[config]['failures'].append(key)
for config in outcomes:
outcomes[config]['successes'] = frozenset(outcomes[config]['successes'])
outcomes[config]['failures'] = frozenset(outcomes[config]['failures'])
return outcomes return outcomes
def do_analyze_coverage(results: Results, outcomes_or_file, args): def do_analyze_coverage(results: Results, outcomes_or_file, args):