#!/usr/bin/env python3 # pylint:disable=line-too-long,consider-using-dict-items """ On Android the `--output' switch to `npm run test', which produces xunit reports, doesn't work (https://github.com/brave/brave-browser/issues/15595). This script reads json on stdin (`--json-results-file') and prints xunit xml on stdout. This is a temporary hack until `--output' on Android is fixed. Only one global test iteration is supported (it seems only one is used anyway). In per-test iterations, only one is reported - a successful one, if it exists, otherwise a failed one. """ import collections import re import sys import json from operator import add from string import printable from functools import reduce def pick_iteration(test_case, iterations): """Pick the test iteration that provides the most relevant feedback""" def score(iteration): score = 1000000 if iteration['status'] == 'SUCCESS' else 0 score += len(iteration['output_snippet']) started_this_test = re.compile( r'\[ RUN \] [\w/#\.]*' + re.escape(test_case) + '\\n') score += 7500 if started_this_test.match( iteration['output_snippet']) else 0 for string in ['Stack Trace:', 'Expected:', 'Actual:']: score += 2500 if string in iteration['output_snippet'] else 0 return score return sorted(iterations, key=score, reverse=True)[0] def transform(input_json): """Read json input and return a dictionary with information necessary to produce the xunit output""" output = collections.defaultdict( lambda: {'xml': '', 'test_count': 0, 'failure_count': 0}) test_results = input_json['per_iteration_data'][0] for test_fullname, iterations in test_results.items(): delim = '#' if '#' in test_fullname else '/' if '/' in test_fullname else '.' test_suite, test_case = test_fullname.rsplit(delim, maxsplit=1) iteration = pick_iteration(test_case, iterations) output[test_suite]['test_count'] += 1 output[test_suite][ 'xml'] += f'' if iteration['status'] == 'SUCCESS': if iteration['output_snippet']: sanitized_output = ''.join( filter(lambda x: x in printable, iteration['output_snippet'])) output[test_suite]['xml'] += f"" else: output[test_suite]['failure_count'] += 1 sanitized_output = ''.join( filter(lambda x: x in printable, iteration['output_snippet'])) output[test_suite][ 'xml'] += f'' output[test_suite]['xml'] += "" return output def main(): """Read json on stdin and print xunit on stdout""" output = transform(json.load(sys.stdin)) test_count = reduce(add, (ts['test_count'] for ts in output.values()), 0) failure_count = reduce(add, (ts['failure_count'] for ts in output.values()), 0) print(f"""\n""", end='') for test_suite in output.keys(): print(f'{output[test_suite]["xml"]}', end='') print('', end='') if __name__ == "__main__": main()