llvm-project/lldb/packages/Python/lldbsuite/test/lldbinline.py

Ignoring revisions in .git-blame-ignore-revs. Click here to bypass and see the normal blame view.

208 lines
6.9 KiB
Python
Raw Normal View History

from __future__ import print_function
from __future__ import absolute_import
# System modules
import os
# Third-party modules
import io
# 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 = io.open(source_file, encoding='utf-8')
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 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+')
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 Makefile.rules\n")
makefile.write("\ncleanup:\n\trm -f Makefile *.d\n\n")
makefile.flush()
makefile.close()
def _test(self):
self.BuildMakefile()
self.build()
self.do_test()
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)
test_name, _ = os.path.splitext(file_basename)
test_func = ApplyDecoratorsToFunction(InlineTest._test, decorators)
# Build the test case
test_class = type(test_name, (InlineTest,), dict(test=test_func, name=test_name))
# Add the test case to the globals, and hide InlineTest
__globals.update({test_name: test_class})
# Keep track of the original test filename so we report it
# correctly in test results.
test_class.test_filename = __file
[lldbinline] Set directory attribute on test-specific classes Set the "mydir" attribute of an inline test on the test-specific class, instead of on the base InlineTest class. This makes it possible to run dotest.py on a directory containing inline tests. This wasn't really possible prior to this patch, because what would happen is that one test would just run over and over again, even though the test infrastructure would claim that different tests were being run. Example: The test infrastructure claimed that all of these different tests were passing, which couldn't be true -- $ ./bin/lldb-dotest /Users/vsk/src/tailcall/lldb/test/testcases/functionalities/tail_call_frames/ -G dwarf -t 2>&1 | grep PASS PASS: LLDB (/Users/vsk/src/builds/tailcall-RA/bin/clang-8-x86_64) :: test_dwarf (lldbsuite.test.lldbtest.TestDisambiguateTailCallSeq) PASS: LLDB (/Users/vsk/src/builds/tailcall-RA/bin/clang-8-x86_64) :: test_dwarf (lldbsuite.test.lldbtest.TestArtificialFrameStepOutMessage) PASS: LLDB (/Users/vsk/src/builds/tailcall-RA/bin/clang-8-x86_64) :: test_dwarf (lldbsuite.test.lldbtest.TestAmbiguousTailCallSeq1) PASS: LLDB (/Users/vsk/src/builds/tailcall-RA/bin/clang-8-x86_64) :: test_dwarf (lldbsuite.test.lldbtest.TestDisambiguatePathsToCommonSink) PASS: LLDB (/Users/vsk/src/builds/tailcall-RA/bin/clang-8-x86_64) :: test_dwarf (lldbsuite.test.lldbtest.TestDisambiguateCallSite) PASS: LLDB (/Users/vsk/src/builds/tailcall-RA/bin/clang-8-x86_64) :: test_dwarf (lldbsuite.test.lldbtest.TestUnambiguousTailCalls) PASS: LLDB (/Users/vsk/src/builds/tailcall-RA/bin/clang-8-x86_64) :: test_dwarf (lldbsuite.test.lldbtest.TestAmbiguousTailCallSeq2) RESULT: PASSED (7 passes, 0 failures, 0 errors, 24 skipped, 0 expected failures, 0 unexpected successes) ... because it wasn't even looking at some of these tests: $ ./bin/lldb-dotest /Users/vsk/src/tailcall/lldb/test/testcases/functionalities/tail_call_frames/ -G dwarf -t 2>&1 | grep "Change dir" Change dir to: /Users/vsk/src/tailcall/lldb/packages/Python/lldbsuite/test/functionalities/tail_call_frames/ambiguous_tail_call_seq2 Change dir to: /Users/vsk/src/tailcall/lldb/packages/Python/lldbsuite/test/functionalities/tail_call_frames/ambiguous_tail_call_seq2 Change dir to: /Users/vsk/src/tailcall/lldb/packages/Python/lldbsuite/test/functionalities/tail_call_frames/ambiguous_tail_call_seq2 Change dir to: /Users/vsk/src/tailcall/lldb/packages/Python/lldbsuite/test/functionalities/tail_call_frames/sbapi_support Change dir to: /Users/vsk/src/tailcall/lldb/packages/Python/lldbsuite/test/functionalities/tail_call_frames/ambiguous_tail_call_seq2 Change dir to: /Users/vsk/src/tailcall/lldb/packages/Python/lldbsuite/test/functionalities/tail_call_frames/thread_step_out_or_return Change dir to: /Users/vsk/src/tailcall/lldb/packages/Python/lldbsuite/test/functionalities/tail_call_frames/ambiguous_tail_call_seq2 Change dir to: /Users/vsk/src/tailcall/lldb/packages/Python/lldbsuite/test/functionalities/tail_call_frames/ambiguous_tail_call_seq2 Change dir to: /Users/vsk/src/tailcall/lldb/packages/Python/lldbsuite/test/functionalities/tail_call_frames/ambiguous_tail_call_seq2 E.g it was only building one of them: $ ls lldb-test-build.noindex/functionalities/tail_call_frames/                         ambiguous_tail_call_seq2 Differential Revision: https://reviews.llvm.org/D52516 llvm-svn: 343023
2018-09-26 04:20:13 +08:00
test_class.mydir = TestBase.compute_mydir(__file)
return test_class