mirror of
https://gitflic.ru/project/openide/openide.git
synced 2025-12-16 22:51:17 +07:00
Fix Log/Condition breakpoints for debugger plugins. Fix Step Into, Step Over commands for debugger plugins Co-authored-by: Andrey Lisin <andrey.lisin@jetbrains.com> Merge-request: IJ-MR-132334 Merged-by: Egor Eliseev <Egor.Eliseev@jetbrains.com> GitOrigin-RevId: b495a41fe37f61e4271d3438bab37846e0013006
286 lines
9.4 KiB
Python
286 lines
9.4 KiB
Python
import sys, os
|
|
import importlib.util
|
|
|
|
helpers_dir = os.getenv("PYCHARM_HELPERS_DIR", sys.path[0])
|
|
if sys.path[0] != helpers_dir:
|
|
sys.path.insert(0, helpers_dir)
|
|
|
|
from tcunittest import TeamcityTestResult
|
|
|
|
from pycharm_run_utils import import_system_module
|
|
from pycharm_run_utils import adjust_sys_path
|
|
from pycharm_run_utils import debug, getModuleName
|
|
|
|
adjust_sys_path()
|
|
|
|
re = import_system_module("re")
|
|
inspect = import_system_module("inspect")
|
|
|
|
try:
|
|
from attest.reporters import AbstractReporter
|
|
from attest.collectors import Tests
|
|
from attest import TestBase
|
|
except:
|
|
raise NameError("Please, install attests")
|
|
|
|
|
|
class TeamCityReporter(AbstractReporter, TeamcityTestResult):
|
|
"""Teamcity reporter for attests."""
|
|
|
|
def __init__(self, prefix):
|
|
TeamcityTestResult.__init__(self)
|
|
self.prefix = prefix
|
|
|
|
def begin(self, tests):
|
|
"""initialize suite stack and count tests"""
|
|
self.total = len(tests)
|
|
self.suite_stack = []
|
|
self.messages.testCount(self.total)
|
|
|
|
def success(self, result):
|
|
"""called when test finished successfully"""
|
|
suite = self.get_suite_name(result.test)
|
|
self.start_suite(suite)
|
|
name = self.get_test_name(result)
|
|
self.start_test(result, name)
|
|
self.messages.testFinished(name)
|
|
|
|
def failure(self, result):
|
|
"""called when test failed"""
|
|
suite = self.get_suite_name(result.test)
|
|
self.start_suite(suite)
|
|
name = self.get_test_name(result)
|
|
self.start_test(result, name)
|
|
exctype, value, tb = result.exc_info
|
|
error_value = self.find_error_value(tb)
|
|
if (error_value.startswith("'") or error_value.startswith('"')) and \
|
|
(error_value.endswith("'") or error_value.endswith('"')):
|
|
first = self._unescape(self.find_first(error_value))
|
|
second = self._unescape(self.find_second(error_value))
|
|
else:
|
|
first = second = ""
|
|
|
|
err = self.formatErr(result.exc_info)
|
|
if isinstance(result.error, AssertionError):
|
|
self.messages.testFailed(name, message='Failure',
|
|
details=err,
|
|
expected=first, actual=second)
|
|
else:
|
|
self.messages.testError(name, message='Error',
|
|
details=err)
|
|
|
|
def finished(self):
|
|
"""called when all tests finished"""
|
|
self.end_last_suite()
|
|
for suite in self.suite_stack[::-1]:
|
|
self.messages.testSuiteFinished(suite)
|
|
|
|
def get_test_name(self, result):
|
|
name = result.test_name
|
|
ind = name.find("%") # remove unique module prefix
|
|
if ind != -1:
|
|
name = name[:ind] + name[name.find(".", ind):]
|
|
return name
|
|
|
|
def end_last_suite(self):
|
|
if self.current_suite:
|
|
self.messages.testSuiteFinished(self.current_suite)
|
|
self.current_suite = None
|
|
|
|
def get_suite_name(self, test):
|
|
module = inspect.getmodule(test)
|
|
klass = getattr(test, "im_class", None)
|
|
file = module.__file__
|
|
if file.endswith("pyc"):
|
|
file = file[:-1]
|
|
|
|
suite = module.__name__
|
|
if self.prefix:
|
|
tmp = file[:-3]
|
|
ind = tmp.split(self.prefix)[1]
|
|
suite = ind.replace("/", ".")
|
|
if klass:
|
|
suite += "." + klass.__name__
|
|
lineno = inspect.getsourcelines(klass)
|
|
else:
|
|
lineno = ("", 1)
|
|
|
|
return (suite, file + ":" + str(lineno[1]))
|
|
|
|
def start_suite(self, suite_info):
|
|
"""finish previous suite and put current suite
|
|
to stack"""
|
|
suite, file = suite_info
|
|
if suite != self.current_suite:
|
|
if self.current_suite:
|
|
if suite.startswith(self.current_suite + "."):
|
|
self.suite_stack.append(self.current_suite)
|
|
else:
|
|
self.messages.testSuiteFinished(self.current_suite)
|
|
for s in self.suite_stack:
|
|
if not suite.startswith(s + "."):
|
|
self.current_suite = s
|
|
self.messages.testSuiteFinished(self.current_suite)
|
|
else:
|
|
break
|
|
self.current_suite = suite
|
|
self.messages.testSuiteStarted(self.current_suite,
|
|
location="file://" + file)
|
|
|
|
def start_test(self, result, name):
|
|
"""trying to find test location """
|
|
real_func = result.test.func_closure[0].cell_contents
|
|
lineno = inspect.getsourcelines(real_func)
|
|
file = inspect.getsourcefile(real_func)
|
|
self.messages.testStarted(name, "file://" + file + ":" + str(lineno[1]))
|
|
|
|
|
|
def get_subclasses(module, base_class=TestBase):
|
|
test_classes = []
|
|
for name in dir(module):
|
|
obj = getattr(module, name)
|
|
try:
|
|
if issubclass(obj, base_class):
|
|
test_classes.append(obj)
|
|
except TypeError: # If 'obj' is not a class
|
|
pass
|
|
return test_classes
|
|
|
|
|
|
def load_source(module_name, file_path):
|
|
spec = importlib.util.spec_from_file_location(module_name, file_path)
|
|
module = importlib.util.module_from_spec(spec)
|
|
spec.loader.exec_module(module)
|
|
return module
|
|
|
|
|
|
def get_module(file_name):
|
|
baseName = os.path.splitext(os.path.basename(file_name))[0]
|
|
return load_source(baseName, file_name)
|
|
|
|
|
|
modules = {}
|
|
|
|
|
|
def getModuleName(prefix, cnt):
|
|
""" adds unique number to prevent name collisions"""
|
|
return prefix + "%" + str(cnt)
|
|
|
|
|
|
def loadSource(fileName):
|
|
baseName = os.path.basename(fileName)
|
|
moduleName = os.path.splitext(baseName)[0]
|
|
|
|
if moduleName in modules:
|
|
cnt = 2
|
|
prefix = moduleName
|
|
while getModuleName(prefix, cnt) in modules:
|
|
cnt += 1
|
|
moduleName = getModuleName(prefix, cnt)
|
|
debug("/ Loading " + fileName + " as " + moduleName)
|
|
module = load_source(moduleName, fileName)
|
|
modules[moduleName] = module
|
|
return module
|
|
|
|
|
|
def register_tests_from_module(module, tests):
|
|
"""add tests from module to main test suite"""
|
|
tests_to_register = []
|
|
|
|
for i in dir(module):
|
|
obj = getattr(module, i)
|
|
if isinstance(obj, Tests):
|
|
tests_to_register.append(i)
|
|
|
|
for i in tests_to_register:
|
|
baseName = module.__name__ + "." + i
|
|
tests.register(baseName)
|
|
test_subclasses = get_subclasses(module)
|
|
if test_subclasses:
|
|
for subclass in test_subclasses:
|
|
tests.register(subclass())
|
|
|
|
|
|
def register_tests_from_folder(tests, folder, pattern=None):
|
|
"""add tests from folder to main test suite"""
|
|
listing = os.listdir(folder)
|
|
files = listing
|
|
if pattern: # get files matched given pattern
|
|
prog_list = [re.compile(pat.strip()) for pat in pattern.split(',')]
|
|
files = []
|
|
for fileName in listing:
|
|
if os.path.isdir(folder + fileName):
|
|
files.append(fileName)
|
|
for prog in prog_list:
|
|
if prog.match(fileName):
|
|
files.append(fileName)
|
|
|
|
if not folder.endswith("/"):
|
|
folder += "/"
|
|
for fileName in files:
|
|
if os.path.isdir(folder + fileName):
|
|
register_tests_from_folder(tests, folder + fileName, pattern)
|
|
if not fileName.endswith("py"):
|
|
continue
|
|
|
|
module = loadSource(folder + fileName)
|
|
register_tests_from_module(module, tests)
|
|
|
|
|
|
def process_args():
|
|
tests = Tests()
|
|
prefix = ""
|
|
if not sys.argv:
|
|
return
|
|
|
|
arg = sys.argv[1].strip()
|
|
if not len(arg):
|
|
return
|
|
|
|
argument_list = arg.split("::")
|
|
if len(argument_list) == 1:
|
|
# From module or folder
|
|
a_splitted = argument_list[0].split(";")
|
|
if len(a_splitted) != 1:
|
|
# means we have pattern to match against
|
|
if a_splitted[0].endswith("/"):
|
|
debug("/ from folder " + a_splitted[0] + ". Use pattern: " + a_splitted[
|
|
1])
|
|
prefix = a_splitted[0]
|
|
register_tests_from_folder(tests, a_splitted[0], a_splitted[1])
|
|
else:
|
|
if argument_list[0].endswith("/"):
|
|
debug("/ from folder " + argument_list[0])
|
|
prefix = a_splitted[0]
|
|
register_tests_from_folder(tests, argument_list[0])
|
|
else:
|
|
debug("/ from file " + argument_list[0])
|
|
module = get_module(argument_list[0])
|
|
register_tests_from_module(module, tests)
|
|
|
|
elif len(argument_list) == 2:
|
|
# From testcase
|
|
debug("/ from test class " + argument_list[1] + " in " + argument_list[0])
|
|
module = get_module(argument_list[0])
|
|
klass = getattr(module, argument_list[1])
|
|
tests.register(klass())
|
|
else:
|
|
# From method in class or from function
|
|
module = get_module(argument_list[0])
|
|
if argument_list[1] == "":
|
|
debug("/ from function " + argument_list[2] + " in " + argument_list[0])
|
|
# test function, not method
|
|
test = getattr(module, argument_list[2])
|
|
else:
|
|
debug("/ from method " + argument_list[2] + " in class " + argument_list[
|
|
1] + " in " + argument_list[0])
|
|
klass = getattr(module, argument_list[1])
|
|
test = getattr(klass(), argument_list[2])
|
|
tests.register([test])
|
|
|
|
tests.run(reporter=TeamCityReporter(prefix))
|
|
|
|
|
|
if __name__ == "__main__":
|
|
process_args()
|