[Lldb-commits] [lldb] [lldb][test] Cleanup and modernize TestHiddenIvars.py (PR #202023)
Raphael Isemann via lldb-commits
lldb-commits at lists.llvm.org
Sat Jun 6 02:48:36 PDT 2026
https://github.com/Teemperor created https://github.com/llvm/llvm-project/pull/202023
This is simple rewrite of the test. The patch improves three things:
* It replaces old expect tests with the new expect_* variants that no longer rely on substring matching.
* It unifies the strip/non-stripped checks as we actually produce identical SBValues in both cases (by fetching data from the Objective-C runtime).
* It builds this test with a shared build directory. Our stripping logic generates a new stripped binary in a subdirectory and doesn't touch the shared build files. This also halves the test runtime to 6s.
>From ca3b03338fb702bd9b55f31dddf685957b663232 Mon Sep 17 00:00:00 2001
From: Raphael Isemann <rise at apple.com>
Date: Thu, 4 Jun 2026 19:09:26 +0100
Subject: [PATCH] [lldb][test] Cleanup and modernize TestHiddenIvars.py
This is simple rewrite of the test. The patch improves three things:
* It replaces old expect tests with the new expect_* variants that no
longer rely on substring matching.
* It unifies the strip/non-stripped checks as we actually produce
identical SBValues in both cases (by fetching data from the Objective-C
runtime).
* It builds this test with a shared build directory. Our stripping
logic generates a new stripped binary in a subdirectory and doesn't
touch the shared build files. This also halves the test runtime to 6s.
---
.../lang/objc/hidden-ivars/TestHiddenIvars.py | 268 ++++++------------
1 file changed, 80 insertions(+), 188 deletions(-)
diff --git a/lldb/test/API/lang/objc/hidden-ivars/TestHiddenIvars.py b/lldb/test/API/lang/objc/hidden-ivars/TestHiddenIvars.py
index d21b427c54ffc..d2ed2f1130437 100644
--- a/lldb/test/API/lang/objc/hidden-ivars/TestHiddenIvars.py
+++ b/lldb/test/API/lang/objc/hidden-ivars/TestHiddenIvars.py
@@ -1,8 +1,7 @@
"""Test that hidden ivars in a shared library are visible from the main executable."""
-import subprocess
-
import unittest
+
import lldb
from lldbsuite.test.decorators import *
from lldbsuite.test.lldbtest import *
@@ -10,224 +9,117 @@
@skipIfTargetDoesNotSupportSharedLibraries()
+ at skipIf(archs=["i386"]) # requires modern objc runtime
class HiddenIvarsTestCase(TestBase):
- SHARED_BUILD_TESTCASE = False
-
- def setUp(self):
- # Call super's setUp().
- TestBase.setUp(self)
- # Find the line number to break inside main().
- self.source = "main.m"
- self.line = line_number(self.source, "// breakpoint1")
- # The makefile names of the shared libraries as they appear in DYLIB_NAME.
- # The names should have no loading "lib" or extension as they will be
- # localized
- self.shlib_names = ["InternalDefiner"]
+ SHARED_BUILD_TESTCASE = True
+
+ def common_setup(self, strip):
+ exe_name = "stripped/a.out" if strip else "a.out"
+ return lldbutil.run_to_source_breakpoint(
+ self,
+ "// breakpoint1",
+ lldb.SBFileSpec("main.m"),
+ exe_name=exe_name,
+ extra_images=["InternalDefiner"],
+ )
@skipIf(
debug_info=no_match("dsym"),
bugnumber="This test requires a stripped binary and a dSYM",
)
def test_expr_stripped(self):
- if self.getArchitecture() == "i386":
- self.skipTest("requires modern objc runtime")
- else:
- self.build()
- self.expr(True)
+ self.build()
+ self.expr(strip=True)
def test_expr(self):
- if self.getArchitecture() == "i386":
- self.skipTest("requires modern objc runtime")
- else:
- self.build()
- self.expr(False)
+ self.build()
+ self.expr(strip=False)
@skipIf(
debug_info=no_match("dsym"),
bugnumber="This test requires a stripped binary and a dSYM",
)
def test_frame_variable_stripped(self):
- if self.getArchitecture() == "i386":
- self.skipTest("requires modern objc runtime")
- else:
- self.build()
- self.frame_var(True)
+ self.build()
+ self.frame_var(strip=True)
def test_frame_variable(self):
- if self.getArchitecture() == "i386":
- self.skipTest("requires modern objc runtime")
- else:
- self.build()
- self.frame_var(False)
+ self.build()
+ self.frame_var(strip=False)
@unittest.expectedFailure # rdar://18683637
def test_frame_variable_across_modules(self):
- if self.getArchitecture() == "i386":
- self.skipTest("requires modern objc runtime")
- else:
- self.build()
- self.common_setup(False)
- self.expect(
- "frame variable k->bar", VARIABLES_DISPLAYED_CORRECTLY, substrs=["= 3"]
- )
-
- def common_setup(self, strip):
- if strip:
- exe = self.getBuildArtifact("stripped/a.out")
- else:
- exe = self.getBuildArtifact("a.out")
- # Create a target by the debugger.
- target = self.dbg.CreateTarget(exe)
- self.assertTrue(target, VALID_TARGET)
-
- # Create the breakpoint inside function 'main'.
- breakpoint = target.BreakpointCreateByLocation(self.source, self.line)
- self.assertTrue(breakpoint, VALID_BREAKPOINT)
-
- # Register our shared libraries for remote targets so they get
- # automatically uploaded
- environment = self.registerSharedLibrariesWithTarget(target, self.shlib_names)
-
- # Now launch the process, and do not stop at entry point.
- process = target.LaunchSimple(
- None, environment, self.get_process_working_directory()
- )
- self.assertTrue(process, PROCESS_IS_VALID)
-
- self.runCmd("file " + exe, CURRENT_EXECUTABLE_SET)
-
- # Break inside the foo function which takes a bar_ptr argument.
- lldbutil.run_break_set_by_file_and_line(
- self, "main.m", self.line, num_expected_locations=1, loc_exact=True
- )
-
- self.runCmd("run", RUN_SUCCEEDED)
-
- # The stop reason of the thread should be breakpoint.
- self.expect(
- "thread list",
- STOPPED_DUE_TO_BREAKPOINT,
- substrs=["stopped", "stop reason = breakpoint"],
- )
-
- # The breakpoint should have a hit count of 1.
- lldbutil.check_breakpoint(self, bpno=1, expected_hit_count=1)
+ self.build()
+ self.common_setup(False)
+ self.expect_var_path("k->bar", value="3")
def expr(self, strip):
self.common_setup(strip)
- # This should display correctly.
- self.expect(
- "expression (j->_definer->foo)",
- VARIABLES_DISPLAYED_CORRECTLY,
- substrs=["= 4"],
- )
-
- self.expect(
- "expression (j->_definer->bar)",
- VARIABLES_DISPLAYED_CORRECTLY,
- substrs=["= 5"],
- )
-
- if strip:
- self.expect(
- "expression *(j->_definer)",
- VARIABLES_DISPLAYED_CORRECTLY,
- substrs=["foo = 4"],
- )
- else:
- self.expect(
- "expression *(j->_definer)",
- VARIABLES_DISPLAYED_CORRECTLY,
- substrs=["foo = 4", "bar = 5"],
- )
-
- self.expect(
- "expression (k->foo)", VARIABLES_DISPLAYED_CORRECTLY, substrs=["= 2"]
- )
-
- self.expect(
- "expression (k->bar)", VARIABLES_DISPLAYED_CORRECTLY, substrs=["= 3"]
+ self.expect_expr("j->_definer->foo", result_value="4")
+ self.expect_expr("j->_definer->bar", result_value="5")
+
+ self.expect_expr(
+ "*(j->_definer)",
+ result_type="InternalDefiner",
+ result_children=[
+ ValueCheck(name="NSObject"),
+ ValueCheck(name="foo", value="4"),
+ ValueCheck(name="bar", value="5"),
+ ],
)
- self.expect(
- "expression k.filteredDataSource",
- VARIABLES_DISPLAYED_CORRECTLY,
- substrs=[" = 0x", '"2 elements"'],
+ self.expect_expr("k->foo", result_value="2")
+ self.expect_expr("k->bar", result_value="3")
+
+ self.expect_expr("k.filteredDataSource", result_summary='@"2 elements"')
+
+ self.expect_expr(
+ "*k",
+ result_type="InheritContainer",
+ result_children=[
+ ValueCheck(
+ name="InternalDefiner",
+ children=[
+ ValueCheck(name="NSObject"),
+ ValueCheck(name="foo", value="2"),
+ ValueCheck(name="bar", value="3"),
+ ],
+ ),
+ ValueCheck(name="_filteredDataSource", summary='@"2 elements"'),
+ ],
)
- if strip:
- self.expect(
- "expression *(k)",
- VARIABLES_DISPLAYED_CORRECTLY,
- substrs=["foo = 2", " = 0x", '"2 elements"'],
- )
- else:
- self.expect(
- "expression *(k)",
- VARIABLES_DISPLAYED_CORRECTLY,
- substrs=[
- "foo = 2",
- "bar = 3",
- "_filteredDataSource = 0x",
- '"2 elements"',
- ],
- )
-
def frame_var(self, strip):
self.common_setup(strip)
- # This should display correctly.
- self.expect(
- "frame variable j->_definer->foo",
- VARIABLES_DISPLAYED_CORRECTLY,
- substrs=["= 4"],
- )
+ self.expect_var_path("j->_definer->foo", value="4")
+ self.expect_var_path("j->_definer->bar", value="5")
- if not strip:
- self.expect(
- "frame variable j->_definer->bar",
- VARIABLES_DISPLAYED_CORRECTLY,
- substrs=["= 5"],
- )
-
- if strip:
- self.expect(
- "frame variable *j->_definer",
- VARIABLES_DISPLAYED_CORRECTLY,
- substrs=["foo = 4"],
- )
- else:
- self.expect(
- "frame variable *j->_definer",
- VARIABLES_DISPLAYED_CORRECTLY,
- substrs=["foo = 4", "bar = 5"],
- )
-
- self.expect(
- "frame variable k->foo", VARIABLES_DISPLAYED_CORRECTLY, substrs=["= 2"]
+ self.expect_var_path(
+ "*j->_definer",
+ children=[
+ ValueCheck(name="NSObject"),
+ ValueCheck(name="foo", value="4"),
+ ValueCheck(name="bar", value="5"),
+ ],
)
- self.expect(
- "frame variable k->_filteredDataSource",
- VARIABLES_DISPLAYED_CORRECTLY,
- substrs=[" = 0x", '"2 elements"'],
+ self.expect_var_path("k->foo", value="2")
+ self.expect_var_path("k->_filteredDataSource", summary='@"2 elements"')
+
+ self.expect_var_path(
+ "*k",
+ type="InheritContainer",
+ children=[
+ ValueCheck(
+ name="InternalDefiner",
+ children=[
+ ValueCheck(name="NSObject"),
+ ValueCheck(name="foo", value="2"),
+ ValueCheck(name="bar", value="3"),
+ ],
+ ),
+ ValueCheck(name="_filteredDataSource", summary='@"2 elements"'),
+ ],
)
-
- if strip:
- self.expect(
- "frame variable *k",
- VARIABLES_DISPLAYED_CORRECTLY,
- substrs=["foo = 2", "_filteredDataSource = 0x", '"2 elements"'],
- )
- else:
- self.expect(
- "frame variable *k",
- VARIABLES_DISPLAYED_CORRECTLY,
- substrs=[
- "foo = 2",
- "bar = 3",
- "_filteredDataSource = 0x",
- '"2 elements"',
- ],
- )
More information about the lldb-commits
mailing list