coreutils/util/analyze-gnu-results.py
2025-03-18 20:52:46 +01:00

185 lines
6.1 KiB
Python

#!/usr/bin/env python3
"""
GNU Test Results Analyzer and Aggregator
This script analyzes and aggregates test results from the GNU test suite.
It parses JSON files containing test results (PASS/FAIL/SKIP/ERROR) and:
1. Counts the number of tests in each result category
2. Can aggregate results from multiple JSON files with priority ordering
3. Outputs shell export statements for use in GitHub Actions workflows
Priority order for aggregation (highest to lowest):
- PASS: Takes precedence over all other results (best outcome)
- FAIL: Takes precedence over ERROR and SKIP
- ERROR: Takes precedence over SKIP
- SKIP: Lowest priority
Usage:
- Single file:
python analyze-gnu-results.py test-results.json
- Multiple files (with aggregation):
python analyze-gnu-results.py file1.json file2.json
- With output file for aggregated results:
python analyze-gnu-results.py -o=output.json file1.json file2.json
Output:
Prints shell export statements for TOTAL, PASS, FAIL, SKIP, XPASS, and ERROR
that can be evaluated in a shell environment.
"""
import json
import sys
from collections import defaultdict
def get_priority(result):
"""Return a priority value for result status (lower is higher priority)"""
priorities = {
"PASS": 0, # PASS is highest priority (best result)
"FAIL": 1, # FAIL is second priority
"ERROR": 2, # ERROR is third priority
"SKIP": 3, # SKIP is lowest priority
}
return priorities.get(result, 4) # Unknown states have lowest priority
def aggregate_results(json_files):
"""
Aggregate test results from multiple JSON files.
Prioritizes results in the order: SKIP > ERROR > FAIL > PASS
"""
# Combined results dictionary
combined_results = defaultdict(dict)
# Process each JSON file
for json_file in json_files:
try:
with open(json_file, "r") as f:
data = json.load(f)
# For each utility and its tests
for utility, tests in data.items():
for test_name, result in tests.items():
# If this test hasn't been seen yet, add it
if test_name not in combined_results[utility]:
combined_results[utility][test_name] = result
else:
# If it has been seen, apply priority rules
current_priority = get_priority(
combined_results[utility][test_name]
)
new_priority = get_priority(result)
# Lower priority value means higher precedence
if new_priority < current_priority:
combined_results[utility][test_name] = result
except FileNotFoundError:
print(f"Warning: File '{json_file}' not found.", file=sys.stderr)
continue
except json.JSONDecodeError:
print(f"Warning: '{json_file}' is not a valid JSON file.", file=sys.stderr)
continue
return combined_results
def analyze_test_results(json_data):
"""
Analyze test results from GNU test suite JSON data.
Counts PASS, FAIL, SKIP results for all tests.
"""
# Counters for test results
total_tests = 0
pass_count = 0
fail_count = 0
skip_count = 0
xpass_count = 0 # Not in JSON data but included for compatibility
error_count = 0 # Not in JSON data but included for compatibility
# Analyze each utility's tests
for utility, tests in json_data.items():
for test_name, result in tests.items():
total_tests += 1
match result:
case "PASS":
pass_count += 1
case "FAIL":
fail_count += 1
case "SKIP":
skip_count += 1
case "ERROR":
error_count += 1
case "XPASS":
xpass_count += 1
# Return the statistics
return {
"TOTAL": total_tests,
"PASS": pass_count,
"FAIL": fail_count,
"SKIP": skip_count,
"XPASS": xpass_count,
"ERROR": error_count,
}
def main():
"""
Main function to process JSON files and export variables.
Supports both single file analysis and multi-file aggregation.
"""
# Check if file arguments were provided
if len(sys.argv) < 2:
print("Usage: python analyze-gnu-results.py <json> [json ...]")
print(" For multiple files, results will be aggregated")
print(" Priority SKIP > ERROR > FAIL > PASS")
sys.exit(1)
json_files = sys.argv[1:]
output_file = None
# Check if the first argument is an output file (starts with -)
if json_files[0].startswith("-o="):
output_file = json_files[0][3:]
json_files = json_files[1:]
# Process the files
if len(json_files) == 1:
# Single file analysis
try:
with open(json_files[0], "r") as file:
json_data = json.load(file)
results = analyze_test_results(json_data)
except FileNotFoundError:
print(f"Error: File '{json_files[0]}' not found.", file=sys.stderr)
sys.exit(1)
except json.JSONDecodeError:
print(
f"Error: '{json_files[0]}' is not a valid JSON file.", file=sys.stderr
)
sys.exit(1)
else:
# Multiple files - aggregate them
json_data = aggregate_results(json_files)
results = analyze_test_results(json_data)
# Save aggregated data if output file is specified
if output_file:
with open(output_file, "w") as f:
json.dump(json_data, f, indent=2)
# Print export statements for shell evaluation
print(f"export TOTAL={results['TOTAL']}")
print(f"export PASS={results['PASS']}")
print(f"export SKIP={results['SKIP']}")
print(f"export FAIL={results['FAIL']}")
print(f"export XPASS={results['XPASS']}")
print(f"export ERROR={results['ERROR']}")
if __name__ == "__main__":
main()