mirror of
https://github.com/llvm/llvm-project.git
synced 2025-05-08 05:46:07 +00:00

Summary: This patch implements a unified way of cleaning the build folder of each test. This is done by completely removing the build folder before each test, in the respective setUp() method. Previously, we were using a combination of several methods, each with it's own drawbacks: - nuking the entire build tree before running dotest: the issue here is that this did not take place if you ran dotest manually - running "make clean" before the main "make" target: this relied on the clean command being correctly implemented. This was usually true, but not always. - for files which were not produced by make, each python file was responsible for ensuring their deleting, using a variety of methods. With this approach, the previous methods become redundant. I remove the first two, since they are centralized. For the other various bits of clean-up code in python files, I indend to delete it when I come across it. Reviewers: aprantl Subscribers: emaste, ki.stfu, mgorny, eraman, lldb-commits Differential Revision: https://reviews.llvm.org/D44526 llvm-svn: 327703
269 lines
9.1 KiB
Python
269 lines
9.1 KiB
Python
from __future__ import print_function
|
|
from __future__ import absolute_import
|
|
|
|
# System modules
|
|
import os
|
|
|
|
# Third-party modules
|
|
|
|
# LLDB modules
|
|
import lldb
|
|
from .lldbtest import *
|
|
from . import configuration
|
|
from . import lldbutil
|
|
from .decorators import *
|
|
|
|
|
|
def source_type(filename):
|
|
_, extension = os.path.splitext(filename)
|
|
return {
|
|
'.c': 'C_SOURCES',
|
|
'.cpp': 'CXX_SOURCES',
|
|
'.cxx': 'CXX_SOURCES',
|
|
'.cc': 'CXX_SOURCES',
|
|
'.m': 'OBJC_SOURCES',
|
|
'.mm': 'OBJCXX_SOURCES'
|
|
}.get(extension, None)
|
|
|
|
|
|
class CommandParser:
|
|
|
|
def __init__(self):
|
|
self.breakpoints = []
|
|
|
|
def parse_one_command(self, line):
|
|
parts = line.split('//%')
|
|
|
|
command = None
|
|
new_breakpoint = True
|
|
|
|
if len(parts) == 2:
|
|
command = parts[1].strip() # take off whitespace
|
|
new_breakpoint = parts[0].strip() != ""
|
|
|
|
return (command, new_breakpoint)
|
|
|
|
def parse_source_files(self, source_files):
|
|
for source_file in source_files:
|
|
file_handle = open(source_file)
|
|
lines = file_handle.readlines()
|
|
line_number = 0
|
|
# non-NULL means we're looking through whitespace to find
|
|
# additional commands
|
|
current_breakpoint = None
|
|
for line in lines:
|
|
line_number = line_number + 1 # 1-based, so we do this first
|
|
(command, new_breakpoint) = self.parse_one_command(line)
|
|
|
|
if new_breakpoint:
|
|
current_breakpoint = None
|
|
|
|
if command is not None:
|
|
if current_breakpoint is None:
|
|
current_breakpoint = {}
|
|
current_breakpoint['file_name'] = source_file
|
|
current_breakpoint['line_number'] = line_number
|
|
current_breakpoint['command'] = command
|
|
self.breakpoints.append(current_breakpoint)
|
|
else:
|
|
current_breakpoint['command'] = current_breakpoint[
|
|
'command'] + "\n" + command
|
|
|
|
def set_breakpoints(self, target):
|
|
for breakpoint in self.breakpoints:
|
|
breakpoint['breakpoint'] = target.BreakpointCreateByLocation(
|
|
breakpoint['file_name'], breakpoint['line_number'])
|
|
|
|
def handle_breakpoint(self, test, breakpoint_id):
|
|
for breakpoint in self.breakpoints:
|
|
if breakpoint['breakpoint'].GetID() == breakpoint_id:
|
|
test.execute_user_command(breakpoint['command'])
|
|
return
|
|
|
|
|
|
class InlineTest(TestBase):
|
|
# Internal implementation
|
|
|
|
def getRerunArgs(self):
|
|
# The -N option says to NOT run a if it matches the option argument, so
|
|
# if we are using dSYM we say to NOT run dwarf (-N dwarf) and vice
|
|
# versa.
|
|
if self.using_dsym is None:
|
|
# The test was skipped altogether.
|
|
return ""
|
|
elif self.using_dsym:
|
|
return "-N dwarf " + self.mydir
|
|
else:
|
|
return "-N dsym " + self.mydir
|
|
|
|
def BuildMakefile(self):
|
|
makefilePath = self.getBuildArtifact("Makefile")
|
|
if os.path.exists(makefilePath):
|
|
return
|
|
|
|
categories = {}
|
|
|
|
for f in os.listdir(self.getSourceDir()):
|
|
t = source_type(f)
|
|
if t:
|
|
if t in list(categories.keys()):
|
|
categories[t].append(f)
|
|
else:
|
|
categories[t] = [f]
|
|
|
|
makefile = open(makefilePath, 'w+')
|
|
|
|
level = os.sep.join(
|
|
[".."] * len(self.mydir.split(os.sep))) + os.sep + "make"
|
|
|
|
makefile.write("LEVEL = " + level + "\n")
|
|
|
|
for t in list(categories.keys()):
|
|
line = t + " := " + " ".join(categories[t])
|
|
makefile.write(line + "\n")
|
|
|
|
if ('OBJCXX_SOURCES' in list(categories.keys())) or (
|
|
'OBJC_SOURCES' in list(categories.keys())):
|
|
makefile.write(
|
|
"LDFLAGS = $(CFLAGS) -lobjc -framework Foundation\n")
|
|
|
|
if ('CXX_SOURCES' in list(categories.keys())):
|
|
makefile.write("CXXFLAGS += -std=c++11\n")
|
|
|
|
makefile.write("include $(LEVEL)/Makefile.rules\n")
|
|
makefile.write("\ncleanup:\n\trm -f Makefile *.d\n\n")
|
|
makefile.flush()
|
|
makefile.close()
|
|
|
|
@add_test_categories(["dsym"])
|
|
def __test_with_dsym(self):
|
|
self.using_dsym = True
|
|
self.BuildMakefile()
|
|
self.build()
|
|
self.do_test()
|
|
__test_with_dsym.debug_info = "dsym"
|
|
|
|
@add_test_categories(["dwarf"])
|
|
def __test_with_dwarf(self):
|
|
self.using_dsym = False
|
|
self.BuildMakefile()
|
|
self.build()
|
|
self.do_test()
|
|
__test_with_dwarf.debug_info = "dwarf"
|
|
|
|
@add_test_categories(["dwo"])
|
|
def __test_with_dwo(self):
|
|
self.using_dsym = False
|
|
self.BuildMakefile()
|
|
self.build()
|
|
self.do_test()
|
|
__test_with_dwo.debug_info = "dwo"
|
|
|
|
@add_test_categories(["gmodules"])
|
|
def __test_with_gmodules(self):
|
|
self.using_dsym = False
|
|
self.BuildMakefile()
|
|
self.build()
|
|
self.do_test()
|
|
__test_with_gmodules.debug_info = "gmodules"
|
|
|
|
def execute_user_command(self, __command):
|
|
exec(__command, globals(), locals())
|
|
|
|
def do_test(self):
|
|
exe = self.getBuildArtifact("a.out")
|
|
source_files = [f for f in os.listdir(self.getSourceDir())
|
|
if source_type(f)]
|
|
target = self.dbg.CreateTarget(exe)
|
|
|
|
parser = CommandParser()
|
|
parser.parse_source_files(source_files)
|
|
parser.set_breakpoints(target)
|
|
|
|
process = target.LaunchSimple(None, None, self.get_process_working_directory())
|
|
hit_breakpoints = 0
|
|
|
|
while lldbutil.get_stopped_thread(process, lldb.eStopReasonBreakpoint):
|
|
hit_breakpoints += 1
|
|
thread = lldbutil.get_stopped_thread(
|
|
process, lldb.eStopReasonBreakpoint)
|
|
breakpoint_id = thread.GetStopReasonDataAtIndex(0)
|
|
parser.handle_breakpoint(self, breakpoint_id)
|
|
process.Continue()
|
|
|
|
self.assertTrue(hit_breakpoints > 0,
|
|
"inline test did not hit a single breakpoint")
|
|
# Either the process exited or the stepping plan is complete.
|
|
self.assertTrue(process.GetState() in [lldb.eStateStopped,
|
|
lldb.eStateExited],
|
|
PROCESS_EXITED)
|
|
|
|
# Utilities for testcases
|
|
|
|
def check_expression(self, expression, expected_result, use_summary=True):
|
|
value = self.frame().EvaluateExpression(expression)
|
|
self.assertTrue(value.IsValid(), expression + "returned a valid value")
|
|
if self.TraceOn():
|
|
print(value.GetSummary())
|
|
print(value.GetValue())
|
|
if use_summary:
|
|
answer = value.GetSummary()
|
|
else:
|
|
answer = value.GetValue()
|
|
report_str = "%s expected: %s got: %s" % (
|
|
expression, expected_result, answer)
|
|
self.assertTrue(answer == expected_result, report_str)
|
|
|
|
|
|
def ApplyDecoratorsToFunction(func, decorators):
|
|
tmp = func
|
|
if isinstance(decorators, list):
|
|
for decorator in decorators:
|
|
tmp = decorator(tmp)
|
|
elif hasattr(decorators, '__call__'):
|
|
tmp = decorators(tmp)
|
|
return tmp
|
|
|
|
|
|
def MakeInlineTest(__file, __globals, decorators=None):
|
|
# Adjust the filename if it ends in .pyc. We want filenames to
|
|
# reflect the source python file, not the compiled variant.
|
|
if __file is not None and __file.endswith(".pyc"):
|
|
# Strip the trailing "c"
|
|
__file = __file[0:-1]
|
|
|
|
# Derive the test name from the current file name
|
|
file_basename = os.path.basename(__file)
|
|
InlineTest.mydir = TestBase.compute_mydir(__file)
|
|
|
|
test_name, _ = os.path.splitext(file_basename)
|
|
# Build the test case
|
|
test = type(test_name, (InlineTest,), {'using_dsym': None})
|
|
test.name = test_name
|
|
|
|
target_platform = lldb.DBG.GetSelectedPlatform().GetTriple().split('-')[2]
|
|
if test_categories.is_supported_on_platform(
|
|
"dsym", target_platform, configuration.compiler):
|
|
test.test_with_dsym = ApplyDecoratorsToFunction(
|
|
test._InlineTest__test_with_dsym, decorators)
|
|
if test_categories.is_supported_on_platform(
|
|
"dwarf", target_platform, configuration.compiler):
|
|
test.test_with_dwarf = ApplyDecoratorsToFunction(
|
|
test._InlineTest__test_with_dwarf, decorators)
|
|
if test_categories.is_supported_on_platform(
|
|
"dwo", target_platform, configuration.compiler):
|
|
test.test_with_dwo = ApplyDecoratorsToFunction(
|
|
test._InlineTest__test_with_dwo, decorators)
|
|
if test_categories.is_supported_on_platform(
|
|
"gmodules", target_platform, configuration.compiler):
|
|
test.test_with_gmodules = ApplyDecoratorsToFunction(
|
|
test._InlineTest__test_with_gmodules, decorators)
|
|
|
|
# Add the test case to the globals, and hide InlineTest
|
|
__globals.update({test_name: test})
|
|
|
|
# Keep track of the original test filename so we report it
|
|
# correctly in test results.
|
|
test.test_filename = __file
|
|
return test
|