mirror of
https://github.com/uutils/coreutils.git
synced 2025-07-07 13:35:00 +00:00
185 lines
6.1 KiB
Python
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()
|