brintos

brintos / llvm-project-archived public Read only

0
0
Text · 5.4 KiB · ecfc8eb Raw
154 lines · python
1# DExTer : Debugging Experience Tester2# ~~~~~~   ~         ~~         ~   ~~3#4# Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.5# See https://llvm.org/LICENSE.txt for license information.6# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception7"""Base class for subtools that run tests."""8 9import abc10from datetime import datetime11import os12import sys13 14from dex.debugger.Debuggers import add_debugger_tool_arguments15from dex.debugger.Debuggers import handle_debugger_tool_options16from dex.heuristic.Heuristic import add_heuristic_tool_arguments17from dex.tools.ToolBase import ToolBase18from dex.utils import get_root_directory19from dex.utils.Exceptions import Error, ToolArgumentError20from dex.utils.ReturnCode import ReturnCode21 22 23def add_executable_arguments(parser):24    executable_group = parser.add_mutually_exclusive_group(required=True)25    executable_group.add_argument(26        "--binary", metavar="<file>", help="provide binary file to debug"27    )28    executable_group.add_argument(29        "--vs-solution",30        metavar="<file>",31        help="provide a path to an already existing visual studio solution.",32    )33 34 35class TestToolBase(ToolBase):36    def __init__(self, *args, **kwargs):37        super(TestToolBase, self).__init__(*args, **kwargs)38 39    def add_tool_arguments(self, parser, defaults):40        parser.description = self.__doc__41        add_debugger_tool_arguments(parser, self.context, defaults)42        add_executable_arguments(parser)43        add_heuristic_tool_arguments(parser)44 45        parser.add_argument(46            "test_path",47            type=str,48            metavar="<test-path>",49            nargs="?",50            default=os.path.abspath(os.path.join(get_root_directory(), "..", "tests")),51            help="directory containing test(s)",52        )53 54        parser.add_argument(55            "--results-directory",56            type=str,57            metavar="<directory>",58            default=None,59            help="directory to save results (default: none)",60        )61        parser.add_argument(62            "--test-root-dir",63            type=str,64            metavar="<directory>",65            default=None,66            help="if passed, result names will include relative path from this directory",67        )68 69    def handle_options(self, defaults):70        options = self.context.options71 72        if options.vs_solution:73            options.vs_solution = os.path.abspath(options.vs_solution)74            if not os.path.isfile(options.vs_solution):75                raise Error(76                    '<d>could not find VS solution file</> <r>"{}"</>'.format(77                        options.vs_solution78                    )79                )80        elif options.binary:81            options.binary = os.path.abspath(options.binary)82            if not os.path.isfile(options.binary):83                raise Error(84                    '<d>could not find binary file</> <r>"{}"</>'.format(options.binary)85                )86 87        try:88            handle_debugger_tool_options(self.context, defaults)89        except ToolArgumentError as e:90            raise Error(e)91 92        options.test_path = os.path.abspath(options.test_path)93        options.test_path = os.path.normcase(options.test_path)94        if not os.path.isfile(options.test_path) and not os.path.isdir(95            options.test_path96        ):97            raise Error(98                '<d>could not find test path</> <r>"{}"</>'.format(options.test_path)99            )100 101        if options.results_directory:102            options.results_directory = os.path.abspath(options.results_directory)103            if not os.path.isdir(options.results_directory):104                try:105                    os.makedirs(options.results_directory, exist_ok=True)106                except OSError as e:107                    raise Error(108                        '<d>could not create directory</> <r>"{}"</> <y>({})</>'.format(109                            options.results_directory, e.strerror110                        )111                    )112 113    def go(self) -> ReturnCode:  # noqa114        options = self.context.options115 116        options.executable = os.path.join(117            self.context.working_directory.path, "tmp.exe"118        )119 120        # Test files contain dexter commands.121        options.test_files = [options.test_path]122        # Source files are the files that the program was built from, and are123        # used to determine whether a breakpoint is external to the program124        # (e.g. into a system header) or not.125        options.source_files = []126        if not options.test_path.endswith(".dex"):127            options.source_files = [options.test_path]128        self._run_test(self._get_test_name(options.test_path))129 130        return self._handle_results()131 132    @staticmethod133    def _is_current_directory(test_directory):134        return test_directory == "."135 136    def _get_test_name(self, test_path):137        """Get the test name from either the test file, or the sub directory138        path it's stored in.139        """140        # Test names are either relative to an explicitly given test root directory, or else we just use the base name.141        if self.context.options.test_root_dir is not None:142            test_name = os.path.relpath(test_path, self.context.options.test_root_dir)143        else:144            test_name = os.path.basename(test_path)145        return test_name146 147    @abc.abstractmethod148    def _run_test(self, test_dir):149        pass150 151    @abc.abstractmethod152    def _handle_results(self) -> ReturnCode:153        pass154