| #!/usr/bin/env python3 |
| |
| # Copyright 2022 The IREE Authors |
| # |
| # Licensed under the Apache License v2.0 with LLVM Exceptions. |
| # See https://llvm.org/LICENSE.txt for license information. |
| # SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception |
| """Parses a list of tests from ctest into a format for the web test runner. |
| |
| Example usage: |
| ctest --test-dir build-emscripten --show-only=json-v1 > /tmp/ctest.json |
| python3 parse_test_list.py \ |
| --ctest_dump=/tmp/ctest.json \ |
| --build_dir=build-emscripten \ |
| --output_format=html \ |
| -o /tmp/parsed.html |
| """ |
| |
| import argparse |
| import json |
| import os |
| |
| |
| def parse_arguments(): |
| """Parses command line arguments.""" |
| parser = argparse.ArgumentParser() |
| parser.add_argument("--ctest_dump", |
| type=str, |
| required=True, |
| help="Path to the output of `ctest --show-only=json-v1`") |
| parser.add_argument( |
| "--build_dir", |
| type=str, |
| required=True, |
| help="Path to the CMake build directory (absolute or relative)") |
| parser.add_argument( |
| "--output_format", |
| type=str, |
| choices=("html", "json"), |
| default="html", |
| help= |
| "Output format, either 'html' for the test runner or 'json' for a list of JSON objects", |
| ) |
| parser.add_argument("-o", |
| "--output", |
| type=str, |
| required=True, |
| help="Output file path") |
| return parser.parse_args() |
| |
| |
| def get_normalized_relative_path(absolute_path, root_directory): |
| # Strip the root directory prefix and get a relative path. |
| relative_path = os.path.relpath(absolute_path, root_directory) |
| # Replace the path separator (such as '\' on Windows) with web-style '/'. |
| normalized_path = relative_path.replace(os.sep, '/') |
| return normalized_path |
| |
| |
| def parse_ctest_dump(ctest_dump_path, build_dir): |
| parsed_tests = [] |
| |
| # Open the ctest dump JSON file and parse each test. |
| # https://cmake.org/cmake/help/latest/manual/ctest.1.html#show-as-json-object-model |
| with open(ctest_dump_path, "rt") as f: |
| data = json.load(f) |
| for test in data["tests"]: |
| parsed_test = { |
| "testName": test["name"], |
| "requiredFiles": [], |
| "args": [], |
| } |
| |
| # Parse the 'command' list into the source file and its arguments. |
| # /path/to/test_runner.js # such as iree-check-module.js or test.js |
| # arg 1 # such as --device=local-task |
| # arg 2 # such as check_vmvx_op.mlir_module.vmfb |
| test_source_absolute_path = test["command"][0] |
| parsed_test["sourceFile"] = get_normalized_relative_path( |
| test_source_absolute_path, build_dir) |
| |
| parsed_test["args"] = test["command"][1:] |
| |
| # Parse the test "properties". |
| # Note: required file paths are relative to the working directory. |
| for property in test["properties"]: |
| if property["name"] == "REQUIRED_FILES": |
| parsed_test["requiredFiles"] = property["value"] |
| elif property["name"] == "WORKING_DIRECTORY": |
| working_directory_absolute_path = property["value"] |
| parsed_test["workingDirectory"] = get_normalized_relative_path( |
| working_directory_absolute_path, build_dir) |
| |
| parsed_tests.append(parsed_test) |
| |
| print("Parsed {} tests from '{}'".format(len(parsed_tests), ctest_dump_path)) |
| return parsed_tests |
| |
| |
| def print_parsed_tests(parsed_tests, output_path, output_format): |
| with open(output_path, "wt") as f: |
| if output_format == "html": |
| print("Outputting parsed tests as HTML to '" + output_path + "'") |
| for test in parsed_tests: |
| f.write( |
| "<li><a href=\"test-runner.html?testName={testName}&sourceFile={sourceFile}&workingDirectory={workingDirectory}&requiredFiles={requiredFiles}&args={args}\" target=testRunner>{testName}</a></li>\n" |
| .format(testName=test["testName"], |
| sourceFile=test["sourceFile"], |
| workingDirectory=test["workingDirectory"], |
| requiredFiles="[" + ",".join(test["requiredFiles"]) + "]", |
| args="[" + ",".join(test["args"]) + "]")) |
| elif output_format == "json": |
| print("Outputting parsed tests as JSON to '" + output_path + "'") |
| f.write(json.dumps(parsed_tests, indent=2)) |
| else: |
| raise Exception("Unknown output format: '" + output_format + "'") |
| |
| |
| def main(args): |
| # Refine the provided build directory path to a normalized, absolute path. |
| build_dir = args.build_dir |
| if not os.path.isabs(build_dir): |
| build_dir = os.path.join(os.getcwd(), build_dir) |
| build_dir = os.path.normpath(build_dir) |
| |
| # Create the output directory as needed (relative paths are fine here). |
| output_dir = os.path.dirname(args.output) |
| if output_dir and not os.path.isdir(output_dir): |
| os.makedirs(output_dir) |
| |
| parsed_tests = parse_ctest_dump(args.ctest_dump, build_dir) |
| parsed_tests.sort(key=lambda test: test["testName"]) |
| |
| print_parsed_tests(parsed_tests, args.output, args.output_format) |
| |
| |
| if __name__ == "__main__": |
| main(parse_arguments()) |