Files
clang-p2996/lldb/test/API/tools/lldb-dap/stackTrace/TestDAP_stackTrace.py
John Harrison 0e0b501bf5 [lldb-dap] Take two at refactoring the startup sequence. (#140331)
This is more straight forward refactor of the startup sequence that
reverts parts of ba29e60f9a. Unlike my
previous attempt, I ended up removing the pending request queue and not
including an `AsyncReqeustHandler` because I don't think we actually
need that at the moment.

The key is that during the startup flow there are 2 parallel operations
happening in the DAP that have different triggers.

* The `initialize` request is sent and once the response is received the
`launch` or `attach` is sent.
* When the `initialized` event is recieved the `setBreakpionts` and
other config requests are made followed by the `configurationDone`
event.

I moved the `initialized` event back to happen in the `PostRun` of the
`launch` or `attach` request handlers. This ensures that we have a valid
target by the time the configuration calls are made. I added also added
a few extra validations that to the `configurationeDone` handler to
ensure we're in an expected state.

I've also fixed up the tests to match the new flow. With the other
additional test fixes in 087a5d2ec7 I
think we've narrowed down the main source of test instability that
motivated the startup sequence change.
2025-05-16 19:28:34 -07:00

245 lines
8.9 KiB
Python

"""
Test lldb-dap stackTrace request
"""
import os
import lldbdap_testcase
from lldbsuite.test.decorators import *
from lldbsuite.test.lldbtest import *
class TestDAP_stackTrace(lldbdap_testcase.DAPTestCaseBase):
name_key_path = ["name"]
source_key_path = ["source", "path"]
line_key_path = ["line"]
# stackTrace additioanl frames for paginated traces
page_size = 20
def verify_stackFrames(self, start_idx, stackFrames):
frame_idx = start_idx
for stackFrame in stackFrames:
# Don't care about frame above main
if frame_idx > 40:
return
self.verify_stackFrame(frame_idx, stackFrame)
frame_idx += 1
def verify_stackFrame(self, frame_idx, stackFrame):
frame_name = self.get_dict_value(stackFrame, self.name_key_path)
frame_source = self.get_dict_value(stackFrame, self.source_key_path)
frame_line = self.get_dict_value(stackFrame, self.line_key_path)
if frame_idx == 0:
expected_line = self.recurse_end
expected_name = "recurse"
elif frame_idx < 40:
expected_line = self.recurse_call
expected_name = "recurse"
else:
expected_line = self.recurse_invocation
expected_name = "main"
self.assertEqual(
frame_name,
expected_name,
'frame #%i name "%s" == "%s"' % (frame_idx, frame_name, expected_name),
)
self.assertEqual(
frame_source,
self.source_path,
'frame #%i source "%s" == "%s"'
% (frame_idx, frame_source, self.source_path),
)
self.assertEqual(
frame_line,
expected_line,
"frame #%i line %i == %i" % (frame_idx, frame_line, expected_line),
)
def test_stackTrace(self):
"""
Tests the 'stackTrace' packet and all its variants.
"""
program = self.getBuildArtifact("a.out")
self.build_and_launch(program)
source = "main.c"
self.source_path = os.path.join(os.getcwd(), source)
self.recurse_end = line_number(source, "recurse end")
self.recurse_call = line_number(source, "recurse call")
self.recurse_invocation = line_number(source, "recurse invocation")
lines = [self.recurse_end]
# Set breakpoint at a point of deepest recuusion
breakpoint_ids = self.set_source_breakpoints(source, lines)
self.assertEqual(
len(breakpoint_ids), len(lines), "expect correct number of breakpoints"
)
self.continue_to_breakpoints(breakpoint_ids)
startFrame = 0
# Verify we get all stack frames with no arguments
(stackFrames, totalFrames) = self.get_stackFrames_and_totalFramesCount()
frameCount = len(stackFrames)
self.assertGreaterEqual(
frameCount, 40, "verify we get at least 40 frames for all frames"
)
self.assertEqual(
totalFrames,
frameCount,
"verify total frames returns a speculative page size",
)
self.verify_stackFrames(startFrame, stackFrames)
# Verify totalFrames contains a speculative page size of additional frames with startFrame = 0 and levels = 0
(stackFrames, totalFrames) = self.get_stackFrames_and_totalFramesCount(
startFrame=0, levels=10
)
self.assertEqual(len(stackFrames), 10, "verify we get levels=10 frames")
self.assertEqual(
totalFrames,
len(stackFrames) + self.page_size,
"verify total frames returns a speculative page size",
)
self.verify_stackFrames(startFrame, stackFrames)
# Verify all stack frames by specifying startFrame = 0 and levels not
# specified
stackFrames = self.get_stackFrames(startFrame=startFrame)
self.assertEqual(
frameCount,
len(stackFrames),
("verify same number of frames with startFrame=%i") % (startFrame),
)
self.verify_stackFrames(startFrame, stackFrames)
# Verify all stack frames by specifying startFrame = 0 and levels = 0
levels = 0
stackFrames = self.get_stackFrames(startFrame=startFrame, levels=levels)
self.assertEqual(
frameCount,
len(stackFrames),
("verify same number of frames with startFrame=%i and" " levels=%i")
% (startFrame, levels),
)
self.verify_stackFrames(startFrame, stackFrames)
# Get only the first stack frame by sepcifying startFrame = 0 and
# levels = 1
levels = 1
stackFrames = self.get_stackFrames(startFrame=startFrame, levels=levels)
self.assertEqual(
levels,
len(stackFrames),
("verify one frame with startFrame=%i and" " levels=%i")
% (startFrame, levels),
)
self.verify_stackFrames(startFrame, stackFrames)
# Get only the first 3 stack frames by sepcifying startFrame = 0 and
# levels = 3
levels = 3
stackFrames = self.get_stackFrames(startFrame=startFrame, levels=levels)
self.assertEqual(
levels,
len(stackFrames),
("verify %i frames with startFrame=%i and" " levels=%i")
% (levels, startFrame, levels),
)
self.verify_stackFrames(startFrame, stackFrames)
# Get only the first 15 stack frames by sepcifying startFrame = 5 and
# levels = 16
startFrame = 5
levels = 16
stackFrames = self.get_stackFrames(startFrame=startFrame, levels=levels)
self.assertEqual(
levels,
len(stackFrames),
("verify %i frames with startFrame=%i and" " levels=%i")
% (levels, startFrame, levels),
)
self.verify_stackFrames(startFrame, stackFrames)
# Verify we cap things correctly when we ask for too many frames
startFrame = 5
levels = 1000
(stackFrames, totalFrames) = self.get_stackFrames_and_totalFramesCount(
startFrame=startFrame, levels=levels
)
self.assertEqual(
len(stackFrames),
frameCount - startFrame,
("verify less than 1000 frames with startFrame=%i and" " levels=%i")
% (startFrame, levels),
)
self.assertEqual(
totalFrames,
frameCount,
"verify we get correct value for totalFrames count "
"when requested frames not from 0 index",
)
self.verify_stackFrames(startFrame, stackFrames)
# Verify level=0 works with non-zerp start frame
startFrame = 5
levels = 0
stackFrames = self.get_stackFrames(startFrame=startFrame, levels=levels)
self.assertEqual(
len(stackFrames),
frameCount - startFrame,
("verify less than 1000 frames with startFrame=%i and" " levels=%i")
% (startFrame, levels),
)
self.verify_stackFrames(startFrame, stackFrames)
# Verify we get not frames when startFrame is too high
startFrame = 1000
levels = 1
stackFrames = self.get_stackFrames(startFrame=startFrame, levels=levels)
self.assertEqual(
0, len(stackFrames), "verify zero frames with startFrame out of bounds"
)
@skipIfWindows
def test_functionNameWithArgs(self):
"""
Test that the stack frame without a function name is given its pc in the response.
"""
program = self.getBuildArtifact("a.out")
self.build_and_launch(program, customFrameFormat="${function.name-with-args}")
source = "main.c"
self.set_source_breakpoints(source, [line_number(source, "recurse end")])
self.continue_to_next_stop()
frame = self.get_stackFrames()[0]
self.assertEqual(frame["name"], "recurse(x=1)")
@skipIfWindows
def test_StackFrameFormat(self):
"""
Test the StackFrameFormat.
"""
program = self.getBuildArtifact("a.out")
self.build_and_launch(program)
source = "main.c"
self.set_source_breakpoints(source, [line_number(source, "recurse end")])
self.continue_to_next_stop()
frame = self.get_stackFrames(format={"parameters": True})[0]
self.assertEqual(frame["name"], "recurse(x=1)")
frame = self.get_stackFrames(format={"parameterNames": True})[0]
self.assertEqual(frame["name"], "recurse(x=1)")
frame = self.get_stackFrames(format={"parameterValues": True})[0]
self.assertEqual(frame["name"], "recurse(x=1)")
frame = self.get_stackFrames(format={"parameters": False, "line": True})[0]
self.assertEqual(frame["name"], "main.c:5:5 recurse")
frame = self.get_stackFrames(format={"parameters": False, "module": True})[0]
self.assertEqual(frame["name"], "a.out recurse")