Author: Raphael Isemann
Date: 2026-06-16T11:48:01+01:00
New Revision: 74ac7c93cb93c7faf1723d53193a948db26a7424

URL: 
https://github.com/llvm/llvm-project/commit/74ac7c93cb93c7faf1723d53193a948db26a7424
DIFF: 
https://github.com/llvm/llvm-project/commit/74ac7c93cb93c7faf1723d53193a948db26a7424.diff

LOG: [lldb][test] Introduce build_and_run test utility (#194386)

We currently have several hundred tests require a running process in a
given state, and therefore perform the same three tasks:

* compile a test executable
* set a breakpoint by finding a source regex
* then launch the test process to hit that breakpoint.

A large chunk of these tests do this exact same setup with various
versions of copied boilerplate code. The different versions we have all
have different conventions of naming the breakpoint comment, the main
file (and whether it should be resolved), and different generated error
messages if things go wrong.

We already have a standardized and much shorter way of doing this in
LLDB (see below), but this still encourages test writers to specify
non-standard file names and non-standard breakpoint comment names.

```
    self.build()
    lldbutil.run_to_source_breakpoint(
        self, "break here", lldb.SBFileSpec("main.cpp")
    )
```

This patch introduces a simple `build_and_run` wrapper that takes care
of all of these things in one go. It also forces the standard naming
scheme that most tests have adoped with a breakpoint comment called
`break here` and a `main.*` file.

I already adapted a few tests to this new format so that all added code
in this patch is tested. I'll do the updating of the other tests in a
several follow up PRs so that downstream folks can easily temporarily
revert it if it causes issues.

Added: 
    

Modified: 
    lldb/packages/Python/lldbsuite/test/lldbtest.py
    
lldb/test/API/commands/expression/anonymous-struct/TestCallUserAnonTypedef.py
    lldb/test/API/commands/expression/dollar-in-variable/TestDollarInVariable.py
    lldb/test/API/lang/objc/bitfield_ivars/TestBitfieldIvars.py
    
lldb/test/API/lang/objcxx/conflicting-names-class-update-utility-expr/TestObjCConflictingNamesForClassUpdateExpr.py

Removed: 
    


################################################################################
diff  --git a/lldb/packages/Python/lldbsuite/test/lldbtest.py 
b/lldb/packages/Python/lldbsuite/test/lldbtest.py
index b01dce6a9759a..6fb3045cbbe45 100644
--- a/lldb/packages/Python/lldbsuite/test/lldbtest.py
+++ b/lldb/packages/Python/lldbsuite/test/lldbtest.py
@@ -47,7 +47,7 @@
 import time
 import datetime
 import traceback
-from typing import Optional, Union
+from typing import Optional, Tuple, Union
 
 # Third-party modules
 import unittest
@@ -1617,6 +1617,38 @@ def build(
 
         self.runBuildCommand(command)
 
+    def build_and_run(
+        self,
+        build_dictionary: dict[str, str] | None = None,
+        file_name: str = "",
+        comment: str = "// break here",
+    ) -> Tuple[lldb.SBTarget, lldb.SBProcess, lldb.SBThread, 
lldb.SBBreakpoint]:
+        """
+        Builds the target binary, launches it and runs to the breakpoint
+        location specified by the '// break here' comment.
+
+        Returns the target/process/thread/breakpoint returned from
+        lldbutil.run_to_name_breakpoint
+        """
+        self.build(dictionary=build_dictionary)
+
+        if file_name:
+            main_candidates = [file_name]
+        else:
+            main_candidates = ["main.c", "main.cpp", "main.m", "main.mm"]
+
+        for candidate in main_candidates:
+            if os.path.exists(candidate):
+                return lldbutil.run_to_source_breakpoint(
+                    self, comment, lldb.SBFileSpec(candidate, False)
+                )
+
+        self.fail(
+            f"Could not find any main file in {self.mydir}."
+            + "Searched: "
+            + ", ".join(main_candidates)
+        )
+
     def runBuildCommand(self, command):
         self.trace(shlex.join(command))
         try:

diff  --git 
a/lldb/test/API/commands/expression/anonymous-struct/TestCallUserAnonTypedef.py 
b/lldb/test/API/commands/expression/anonymous-struct/TestCallUserAnonTypedef.py
index 4d11a2b8c8b05..fd2c1c50a08d9 100644
--- 
a/lldb/test/API/commands/expression/anonymous-struct/TestCallUserAnonTypedef.py
+++ 
b/lldb/test/API/commands/expression/anonymous-struct/TestCallUserAnonTypedef.py
@@ -17,8 +17,5 @@
 class TestExprLookupAnonStructTypedef(TestBase):
     def test(self):
         """Test typedeffed untagged struct arguments for function call 
expressions"""
-        self.build()
-        lldbutil.run_to_source_breakpoint(
-            self, "// break here", lldb.SBFileSpec("main.cpp")
-        )
+        self.build_and_run()
         self.expect_expr("multiply(&s)", result_type="double", 
result_value="1")

diff  --git 
a/lldb/test/API/commands/expression/dollar-in-variable/TestDollarInVariable.py 
b/lldb/test/API/commands/expression/dollar-in-variable/TestDollarInVariable.py
index 1b18cd137751b..4e3be3f49de32 100644
--- 
a/lldb/test/API/commands/expression/dollar-in-variable/TestDollarInVariable.py
+++ 
b/lldb/test/API/commands/expression/dollar-in-variable/TestDollarInVariable.py
@@ -6,10 +6,7 @@
 
 class TestCase(TestBase):
     def test(self):
-        self.build()
-        lldbutil.run_to_source_breakpoint(
-            self, "// break here", lldb.SBFileSpec("main.c")
-        )
+        self.build_and_run()
 
         self.expect_expr("$__lldb_expr_result", result_type="int", 
result_value="11")
         self.expect_expr("$foo", result_type="int", result_value="12")

diff  --git a/lldb/test/API/lang/objc/bitfield_ivars/TestBitfieldIvars.py 
b/lldb/test/API/lang/objc/bitfield_ivars/TestBitfieldIvars.py
index d9f95aeee0cbd..294c6fb18a4c2 100644
--- a/lldb/test/API/lang/objc/bitfield_ivars/TestBitfieldIvars.py
+++ b/lldb/test/API/lang/objc/bitfield_ivars/TestBitfieldIvars.py
@@ -6,10 +6,7 @@
 
 class TestBitfieldIvars(TestBase):
     def test(self):
-        self.build()
-        lldbutil.run_to_source_breakpoint(
-            self, "// break here", lldb.SBFileSpec("main.m")
-        )
+        self.build_and_run()
 
         self.expect_expr(
             "chb->hb->field1", result_type="unsigned int", result_value="0"

diff  --git 
a/lldb/test/API/lang/objcxx/conflicting-names-class-update-utility-expr/TestObjCConflictingNamesForClassUpdateExpr.py
 
b/lldb/test/API/lang/objcxx/conflicting-names-class-update-utility-expr/TestObjCConflictingNamesForClassUpdateExpr.py
index ad58bd33c7307..c3fc4b7c0ba41 100644
--- 
a/lldb/test/API/lang/objcxx/conflicting-names-class-update-utility-expr/TestObjCConflictingNamesForClassUpdateExpr.py
+++ 
b/lldb/test/API/lang/objcxx/conflicting-names-class-update-utility-expr/TestObjCConflictingNamesForClassUpdateExpr.py
@@ -17,10 +17,7 @@ class list works even when user-code contains functions with 
apparently
         function.
         """
 
-        self.build()
-        lldbutil.run_to_source_breakpoint(
-            self, "// break here", lldb.SBFileSpec("main.mm")
-        )
+        self.build_and_run()
 
         # First check our side effect variable is in its initial state.
         self.expect_expr("called_function", result_summary='"none"')


        
_______________________________________________
lldb-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits

Reply via email to