This reverts commit cb935f3456.
Discussion in D68708 advises that green dragon is being briskly
refurbished, and it's good to have this patch up testing it.
149 lines
5.3 KiB
Python
149 lines
5.3 KiB
Python
# DExTer : Debugging Experience Tester
|
|
# ~~~~~~ ~ ~~ ~ ~~
|
|
#
|
|
# Part of the LLVM Project, 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
|
|
"""Base class for subtools that do build/run tests."""
|
|
|
|
import abc
|
|
from datetime import datetime
|
|
import os
|
|
import sys
|
|
|
|
from dex.builder import add_builder_tool_arguments
|
|
from dex.builder import handle_builder_tool_options
|
|
from dex.debugger.Debuggers import add_debugger_tool_arguments
|
|
from dex.debugger.Debuggers import handle_debugger_tool_options
|
|
from dex.heuristic.Heuristic import add_heuristic_tool_arguments
|
|
from dex.tools.ToolBase import ToolBase
|
|
from dex.utils import get_root_directory, warn
|
|
from dex.utils.Exceptions import Error, ToolArgumentError
|
|
from dex.utils.ReturnCode import ReturnCode
|
|
|
|
|
|
class TestToolBase(ToolBase):
|
|
def __init__(self, *args, **kwargs):
|
|
super(TestToolBase, self).__init__(*args, **kwargs)
|
|
self.build_script: str = None
|
|
|
|
def add_tool_arguments(self, parser, defaults):
|
|
parser.description = self.__doc__
|
|
add_builder_tool_arguments(parser)
|
|
add_debugger_tool_arguments(parser, self.context, defaults)
|
|
add_heuristic_tool_arguments(parser)
|
|
|
|
parser.add_argument(
|
|
'test_path',
|
|
type=str,
|
|
metavar='<test-path>',
|
|
nargs='?',
|
|
default=os.path.abspath(
|
|
os.path.join(get_root_directory(), '..', 'tests')),
|
|
help='directory containing test(s)')
|
|
|
|
parser.add_argument(
|
|
'--results-directory',
|
|
type=str,
|
|
metavar='<directory>',
|
|
default=os.path.abspath(
|
|
os.path.join(get_root_directory(), '..', 'results',
|
|
datetime.now().strftime('%Y-%m-%d-%H%M-%S'))),
|
|
help='directory to save results')
|
|
|
|
def handle_options(self, defaults):
|
|
options = self.context.options
|
|
|
|
# We accept either or both of --binary and --builder.
|
|
if not options.binary and not options.builder:
|
|
raise Error('expected --builder or --binary')
|
|
|
|
# --binary overrides --builder
|
|
if options.binary:
|
|
if options.builder:
|
|
warn(self.context, "overriding --builder with --binary\n")
|
|
|
|
options.binary = os.path.abspath(options.binary)
|
|
if not os.path.isfile(options.binary):
|
|
raise Error('<d>could not find binary file</> <r>"{}"</>'
|
|
.format(options.binary))
|
|
else:
|
|
try:
|
|
self.build_script = handle_builder_tool_options(self.context)
|
|
except ToolArgumentError as e:
|
|
raise Error(e)
|
|
|
|
try:
|
|
handle_debugger_tool_options(self.context, defaults)
|
|
except ToolArgumentError as e:
|
|
raise Error(e)
|
|
|
|
options.test_path = os.path.abspath(options.test_path)
|
|
if not os.path.isfile(options.test_path) and not os.path.isdir(options.test_path):
|
|
raise Error(
|
|
'<d>could not find test path</> <r>"{}"</>'.format(
|
|
options.test_path))
|
|
|
|
options.results_directory = os.path.abspath(options.results_directory)
|
|
if not os.path.isdir(options.results_directory):
|
|
try:
|
|
os.makedirs(options.results_directory, exist_ok=True)
|
|
except OSError as e:
|
|
raise Error(
|
|
'<d>could not create directory</> <r>"{}"</> <y>({})</>'.
|
|
format(options.results_directory, e.strerror))
|
|
|
|
def go(self) -> ReturnCode: # noqa
|
|
options = self.context.options
|
|
|
|
options.executable = os.path.join(
|
|
self.context.working_directory.path, 'tmp.exe')
|
|
|
|
if os.path.isdir(options.test_path):
|
|
|
|
subdirs = sorted([
|
|
r for r, _, f in os.walk(options.test_path)
|
|
if 'test.cfg' in f
|
|
])
|
|
|
|
for subdir in subdirs:
|
|
|
|
# TODO: read file extensions from the test.cfg file instead so
|
|
# that this isn't just limited to C and C++.
|
|
options.source_files = [
|
|
os.path.normcase(os.path.join(subdir, f))
|
|
for f in os.listdir(subdir) if any(
|
|
f.endswith(ext) for ext in ['.c', '.cpp'])
|
|
]
|
|
|
|
self._run_test(self._get_test_name(subdir))
|
|
else:
|
|
options.source_files = [options.test_path]
|
|
self._run_test(self._get_test_name(options.test_path))
|
|
|
|
return self._handle_results()
|
|
|
|
@staticmethod
|
|
def _is_current_directory(test_directory):
|
|
return test_directory == '.'
|
|
|
|
def _get_test_name(self, test_path):
|
|
"""Get the test name from either the test file, or the sub directory
|
|
path it's stored in.
|
|
"""
|
|
# test names are distinguished by their relative path from the
|
|
# specified test path.
|
|
test_name = os.path.relpath(test_path,
|
|
self.context.options.test_path)
|
|
if self._is_current_directory(test_name):
|
|
test_name = os.path.basename(test_path)
|
|
return test_name
|
|
|
|
@abc.abstractmethod
|
|
def _run_test(self, test_dir):
|
|
pass
|
|
|
|
@abc.abstractmethod
|
|
def _handle_results(self) -> ReturnCode:
|
|
pass
|