| """ | |
| Test SBFrameList API. | |
| """ | |
| import lldb | |
| from lldbsuite.test.decorators import * | |
| from lldbsuite.test.lldbtest import * | |
| from lldbsuite.test import lldbutil | |
| class FrameListAPITestCase(TestBase): | |
| def test_frame_list_api(self): | |
| """Test SBThread.GetFrames() returns a valid SBFrameList.""" | |
| self.build() | |
| self.frame_list_api() | |
| def test_frame_list_iterator(self): | |
| """Test SBFrameList iterator functionality.""" | |
| self.build() | |
| self.frame_list_iterator() | |
| def test_frame_list_indexing(self): | |
| """Test SBFrameList indexing and length.""" | |
| self.build() | |
| self.frame_list_indexing() | |
| def test_frame_list_get_thread(self): | |
| """Test SBFrameList.GetThread() returns correct thread.""" | |
| self.build() | |
| self.frame_list_get_thread() | |
| def setUp(self): | |
| TestBase.setUp(self) | |
| self.main_source = "main.cpp" | |
| def frame_list_api(self): | |
| """Test SBThread.GetFrames() returns a valid SBFrameList.""" | |
| exe = self.getBuildArtifact("a.out") | |
| target, process, thread, bkpt = lldbutil.run_to_source_breakpoint( | |
| self, "Set break point at this line", lldb.SBFileSpec(self.main_source) | |
| ) | |
| self.assertTrue( | |
| thread.IsValid(), "There should be a thread stopped due to breakpoint" | |
| ) | |
| # Test GetFrames() returns a valid SBFrameList | |
| frame_list = thread.GetFrames() | |
| self.assertTrue(frame_list.IsValid(), "Frame list should be valid") | |
| self.assertGreater( | |
| frame_list.GetSize(), 0, "Frame list should have at least one frame" | |
| ) | |
| # Verify frame list size matches thread frame count | |
| self.assertEqual( | |
| frame_list.GetSize(), | |
| thread.GetNumFrames(), | |
| "Frame list size should match thread frame count", | |
| ) | |
| # Verify frames are the same | |
| for i in range(frame_list.GetSize()): | |
| frame_from_list = frame_list.GetFrameAtIndex(i) | |
| frame_from_thread = thread.GetFrameAtIndex(i) | |
| self.assertTrue( | |
| frame_from_list.IsValid(), f"Frame {i} from list should be valid" | |
| ) | |
| self.assertEqual( | |
| frame_from_list.GetPC(), | |
| frame_from_thread.GetPC(), | |
| f"Frame {i} PC should match", | |
| ) | |
| def frame_list_iterator(self): | |
| """Test SBFrameList iterator functionality.""" | |
| exe = self.getBuildArtifact("a.out") | |
| target, process, thread, bkpt = lldbutil.run_to_source_breakpoint( | |
| self, "Set break point at this line", lldb.SBFileSpec(self.main_source) | |
| ) | |
| self.assertTrue( | |
| thread.IsValid(), "There should be a thread stopped due to breakpoint" | |
| ) | |
| frame_list = thread.GetFrames() | |
| # Test iteration | |
| frame_count = 0 | |
| for frame in frame_list: | |
| self.assertTrue(frame.IsValid(), "Each frame should be valid") | |
| frame_count += 1 | |
| self.assertEqual( | |
| frame_count, | |
| frame_list.GetSize(), | |
| "Iterator should visit all frames", | |
| ) | |
| # Test that we can iterate multiple times | |
| second_count = 0 | |
| for frame in frame_list: | |
| second_count += 1 | |
| self.assertEqual( | |
| frame_count, second_count, "Should be able to iterate multiple times" | |
| ) | |
| def frame_list_indexing(self): | |
| """Test SBFrameList indexing and length.""" | |
| exe = self.getBuildArtifact("a.out") | |
| target, process, thread, bkpt = lldbutil.run_to_source_breakpoint( | |
| self, "Set break point at this line", lldb.SBFileSpec(self.main_source) | |
| ) | |
| self.assertTrue( | |
| thread.IsValid(), "There should be a thread stopped due to breakpoint" | |
| ) | |
| frame_list = thread.GetFrames() | |
| # Test len() | |
| self.assertEqual( | |
| len(frame_list), frame_list.GetSize(), "len() should return frame count" | |
| ) | |
| # Test positive indexing | |
| first_frame = frame_list[0] | |
| self.assertTrue(first_frame.IsValid(), "First frame should be valid") | |
| self.assertEqual( | |
| first_frame.GetPC(), | |
| thread.GetFrameAtIndex(0).GetPC(), | |
| "Indexed frame should match", | |
| ) | |
| # Test negative indexing | |
| if len(frame_list) > 0: | |
| last_frame = frame_list[-1] | |
| self.assertTrue(last_frame.IsValid(), "Last frame should be valid") | |
| self.assertEqual( | |
| last_frame.GetPC(), | |
| thread.GetFrameAtIndex(len(frame_list) - 1).GetPC(), | |
| "Negative indexing should work", | |
| ) | |
| # Test out of bounds returns None | |
| out_of_bounds = frame_list[10000] | |
| self.assertIsNone(out_of_bounds, "Out of bounds index should return None") | |
| # Test bool conversion | |
| self.assertTrue(bool(frame_list), "Non-empty frame list should be truthy") | |
| # Test Clear() | |
| frame_list.Clear() | |
| # Note: Clear() clears the underlying StackFrameList cache, | |
| # but the frame list object itself should still be valid | |
| self.assertTrue( | |
| frame_list.IsValid(), "Frame list should still be valid after Clear()" | |
| ) | |
| def frame_list_get_thread(self): | |
| """Test SBFrameList.GetThread() returns correct thread.""" | |
| exe = self.getBuildArtifact("a.out") | |
| target, process, thread, bkpt = lldbutil.run_to_source_breakpoint( | |
| self, "Set break point at this line", lldb.SBFileSpec(self.main_source) | |
| ) | |
| self.assertTrue( | |
| thread.IsValid(), "There should be a thread stopped due to breakpoint" | |
| ) | |
| frame_list = thread.GetFrames() | |
| self.assertTrue(frame_list.IsValid(), "Frame list should be valid") | |
| # Test GetThread() returns the correct thread | |
| thread_from_list = frame_list.GetThread() | |
| self.assertTrue( | |
| thread_from_list.IsValid(), "Thread from frame list should be valid" | |
| ) | |
| self.assertEqual( | |
| thread_from_list.GetThreadID(), | |
| thread.GetThreadID(), | |
| "Frame list should return the correct thread", | |
| ) | |
| # Verify it's the same thread object | |
| self.assertEqual( | |
| thread_from_list.GetProcess().GetProcessID(), | |
| thread.GetProcess().GetProcessID(), | |
| "Thread should belong to same process", | |
| ) |