Skip to content

[lldb] Support ordered patterns in lldbtest.expect #131475

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Conversation

kastiglione
Copy link
Contributor

@kastiglione kastiglione commented Mar 15, 2025

Change lldbtest.expect to require the regexes in patterns be found in order – when the
ordered parameter is true. This matches the behavior of substrs.

The ordered parameter is true by default, so this change also fixes tests by either
tweaking the patterns to work in order, or by setting ordered=False.

I have often wanted to test with patterns and also verify the order. This change
allows that.

Change `lldbtest.expect` to search the given `patterns` in order, if the `ordered`
parameter is true.

The `ordered` parameter is true by default, so this change also fixes tests by either
tweaking the patterns to work in order, or by setting `ordered=False`.

I have often wanted to test with `patterns` and also verify the order. This change
allows that.
@llvmbot
Copy link
Member

llvmbot commented Mar 15, 2025

@llvm/pr-subscribers-lldb

Author: Dave Lee (kastiglione)

Changes

Change lldbtest.expect to search the given patterns in order, if the ordered
parameter is true.

The ordered parameter is true by default, so this change also fixes tests by either
tweaking the patterns to work in order, or by setting ordered=False.

I have often wanted to test with patterns and also verify the order. This change
allows that.


Full diff: https://github.com/llvm/llvm-project/pull/131475.diff

9 Files Affected:

  • (modified) lldb/packages/Python/lldbsuite/test/lldbtest.py (+9-8)
  • (modified) lldb/test/API/functionalities/alias/TestBtAliasRepeat.py (+1-1)
  • (modified) lldb/test/API/functionalities/data-formatter/data-formatter-objc/TestDataFormatterObjCNSContainer.py (+2)
  • (modified) lldb/test/API/functionalities/data-formatter/data-formatter-stl/generic/unordered/TestDataFormatterGenericUnordered.py (+2-2)
  • (modified) lldb/test/API/functionalities/data-formatter/data-formatter-stl/libcxx/span/TestDataFormatterLibcxxSpan.py (+1-1)
  • (modified) lldb/test/API/functionalities/data-formatter/root-reference-children/TestRootReferenceChildren.py (+2-2)
  • (modified) lldb/test/API/lang/cpp/signed_types/TestSignedTypes.py (+1-1)
  • (modified) lldb/test/API/lang/objc/foundation/TestObjCMethods.py (+1-1)
  • (modified) lldb/test/API/source-manager/TestSourceManager.py (+1)
diff --git a/lldb/packages/Python/lldbsuite/test/lldbtest.py b/lldb/packages/Python/lldbsuite/test/lldbtest.py
index 590024ef77119..fa9105b701dcd 100644
--- a/lldb/packages/Python/lldbsuite/test/lldbtest.py
+++ b/lldb/packages/Python/lldbsuite/test/lldbtest.py
@@ -2460,9 +2460,9 @@ def found_str(matched):
         if substrs and matched == matching:
             start = 0
             for substr in substrs:
-                index = output[start:].find(substr)
-                start = start + index + len(substr) if ordered and matching else 0
+                index = output.find(substr, start)
                 matched = index != -1
+                start = index + len(substr) if ordered and matched else 0
                 log_lines.append(
                     '{} sub string: "{}" ({})'.format(
                         expecting_str, substr, found_str(matched)
@@ -2473,20 +2473,21 @@ def found_str(matched):
                     break
 
         if patterns and matched == matching:
+            start = 0
             for pattern in patterns:
-                matched = re.search(pattern, output)
+                pat = re.compile(pattern)
+                match = pat.search(output, start)
+                matched = bool(match)
+                start = match.end() if ordered and matched else 0
 
                 pattern_line = '{} regex pattern: "{}" ({}'.format(
                     expecting_str, pattern, found_str(matched)
                 )
-                if matched:
-                    pattern_line += ', matched "{}"'.format(matched.group(0))
+                if match:
+                    pattern_line += ', matched "{}"'.format(match.group(0))
                 pattern_line += ")"
                 log_lines.append(pattern_line)
 
-                # Convert to bool because match objects
-                # are True-ish but is not True itself
-                matched = bool(matched)
                 if matched != matching:
                     break
 
diff --git a/lldb/test/API/functionalities/alias/TestBtAliasRepeat.py b/lldb/test/API/functionalities/alias/TestBtAliasRepeat.py
index 42b5accddc0ba..60c0dd0a233bf 100644
--- a/lldb/test/API/functionalities/alias/TestBtAliasRepeat.py
+++ b/lldb/test/API/functionalities/alias/TestBtAliasRepeat.py
@@ -9,7 +9,7 @@ def test(self):
         lldbutil.run_to_source_breakpoint(self, "return", lldb.SBFileSpec("main.c"))
 
         # Expect "frame #0" but not "frame #1".
-        self.expect("bt 1", inHistory=True, patterns=["frame #0", "^(?!.*frame #1)"])
+        self.expect("bt 1", inHistory=True, patterns=["frame #0", "(?!.*frame #1)"])
 
         # Run an empty command to run the repeat command for `bt`.
         # The repeat command for `bt N` lists the subsequent N frames.
diff --git a/lldb/test/API/functionalities/data-formatter/data-formatter-objc/TestDataFormatterObjCNSContainer.py b/lldb/test/API/functionalities/data-formatter/data-formatter-objc/TestDataFormatterObjCNSContainer.py
index c90a5c61d9c0b..e6fb549945666 100644
--- a/lldb/test/API/functionalities/data-formatter/data-formatter-objc/TestDataFormatterObjCNSContainer.py
+++ b/lldb/test/API/functionalities/data-formatter/data-formatter-objc/TestDataFormatterObjCNSContainer.py
@@ -52,6 +52,7 @@ def nscontainers_data_formatter_commands(self):
 
         self.expect(
             "frame variable -d run-target *nscfDictionary",
+            ordered=False,
             patterns=[
                 r"\(__NSCFDictionary\) \*nscfDictionary =",
                 'key = 0x.* @"foo"',
@@ -67,6 +68,7 @@ def nscontainers_data_formatter_commands(self):
 
         self.expect(
             "frame variable -d run-target *cfDictionaryRef",
+            ordered=False,
             patterns=[
                 r"\(const __CFDictionary\) \*cfDictionaryRef =",
                 'key = 0x.* @"foo"',
diff --git a/lldb/test/API/functionalities/data-formatter/data-formatter-stl/generic/unordered/TestDataFormatterGenericUnordered.py b/lldb/test/API/functionalities/data-formatter/data-formatter-stl/generic/unordered/TestDataFormatterGenericUnordered.py
index 50dfbbf6b90a5..71cd12f3a3d56 100644
--- a/lldb/test/API/functionalities/data-formatter/data-formatter-stl/generic/unordered/TestDataFormatterGenericUnordered.py
+++ b/lldb/test/API/functionalities/data-formatter/data-formatter-stl/generic/unordered/TestDataFormatterGenericUnordered.py
@@ -122,8 +122,8 @@ def cleanup():
         )
 
     def look_for_content_and_continue(self, var_name, patterns):
-        self.expect(("frame variable %s" % var_name), patterns=patterns)
-        self.expect(("frame variable %s" % var_name), patterns=patterns)
+        self.expect(("frame variable %s" % var_name), ordered=False, patterns=patterns)
+        self.expect(("frame variable %s" % var_name), ordered=False, patterns=patterns)
         self.runCmd("continue")
 
     @add_test_categories(["libstdcxx"])
diff --git a/lldb/test/API/functionalities/data-formatter/data-formatter-stl/libcxx/span/TestDataFormatterLibcxxSpan.py b/lldb/test/API/functionalities/data-formatter/data-formatter-stl/libcxx/span/TestDataFormatterLibcxxSpan.py
index 4df4fa1acc8e7..42efe415b6acf 100644
--- a/lldb/test/API/functionalities/data-formatter/data-formatter-stl/libcxx/span/TestDataFormatterLibcxxSpan.py
+++ b/lldb/test/API/functionalities/data-formatter/data-formatter-stl/libcxx/span/TestDataFormatterLibcxxSpan.py
@@ -172,4 +172,4 @@ def test_ref_and_ptr(self):
 
         # The pointer should just show the right number of elements:
 
-        self.expect("frame variable ptr", patterns=["ptr = 0x.*", " size=5"])
+        self.expect("frame variable ptr", patterns=["ptr = 0x[0-9a-f]+ size=5"])
diff --git a/lldb/test/API/functionalities/data-formatter/root-reference-children/TestRootReferenceChildren.py b/lldb/test/API/functionalities/data-formatter/root-reference-children/TestRootReferenceChildren.py
index 5de66177e7cad..7c366445b1c6e 100644
--- a/lldb/test/API/functionalities/data-formatter/root-reference-children/TestRootReferenceChildren.py
+++ b/lldb/test/API/functionalities/data-formatter/root-reference-children/TestRootReferenceChildren.py
@@ -20,8 +20,8 @@ def test(self):
             "v summary_and_children_ref", substrs=["some summary", "child = 30"]
         )
         self.expect(
-            "v summary_only_ref", patterns=["some summary", "(?s)^(?!.*child = )"]
+            "v summary_only_ref", patterns=["some summary", "(?s)(?!.*child = )"]
         )
         self.expect(
-            "v children_only_ref", patterns=["(?s)^(?!.*some summary)", "child = 30"]
+            "v children_only_ref", patterns=["(?s)(?!.*some summary)", "child = 30"]
         )
diff --git a/lldb/test/API/lang/cpp/signed_types/TestSignedTypes.py b/lldb/test/API/lang/cpp/signed_types/TestSignedTypes.py
index b8c2c23613868..2a5c9bb1bd766 100644
--- a/lldb/test/API/lang/cpp/signed_types/TestSignedTypes.py
+++ b/lldb/test/API/lang/cpp/signed_types/TestSignedTypes.py
@@ -57,8 +57,8 @@ def test(self):
             "frame variable --show-types --no-args",
             VARIABLES_DISPLAYED_CORRECTLY,
             patterns=[
-                r"\((short int|short)\) the_signed_short = 99",
                 r"\((signed char|char)\) the_signed_char = 'c'",
+                r"\((short int|short)\) the_signed_short = 99",
             ],
             substrs=[
                 "(int) the_signed_int = 99",
diff --git a/lldb/test/API/lang/objc/foundation/TestObjCMethods.py b/lldb/test/API/lang/objc/foundation/TestObjCMethods.py
index 5fa3f280d33bf..e82cb2f308602 100644
--- a/lldb/test/API/lang/objc/foundation/TestObjCMethods.py
+++ b/lldb/test/API/lang/objc/foundation/TestObjCMethods.py
@@ -166,7 +166,7 @@ def test_data_type_and_expr(self):
             "frame variable --show-types --scope",
             VARIABLES_DISPLAYED_CORRECTLY,
             substrs=["ARG: (MyString *) self"],
-            patterns=[r"ARG: \(.*\) _cmd", "(objc_selector *)|(SEL)"],
+            patterns=[r"ARG: \(SEL|objc_selector \*\) _cmd"],
         )
 
         # rdar://problem/8651752
diff --git a/lldb/test/API/source-manager/TestSourceManager.py b/lldb/test/API/source-manager/TestSourceManager.py
index 1283c73e152a9..eca0dd5e6159f 100644
--- a/lldb/test/API/source-manager/TestSourceManager.py
+++ b/lldb/test/API/source-manager/TestSourceManager.py
@@ -129,6 +129,7 @@ def do_display_source_python_api(
             stream.GetData(),
             "Source code displayed correctly:\n" + stream.GetData(),
             exe=False,
+            ordered=False,
             patterns=["=>", "%d.*Hello world" % self.line, needle_regex],
         )
 

Copy link
Collaborator

@jimingham jimingham left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM. I wondered for a second whether there now should be separate flags for substrings & patterns, but I can't think of a reason why you would want to provide both substrings and patterns and for one to be ordered and the other not.

@kastiglione kastiglione merged commit 6d2b828 into llvm:main Mar 17, 2025
10 checks passed
@kastiglione kastiglione deleted the lldb-Support-ordered-patterns-in-lldbtest.expect branch March 17, 2025 21:30
@luporl
Copy link
Contributor

luporl commented Mar 18, 2025

This change broke https://lab.llvm.org/buildbot/#/builders/141/builds/7116.

functionalities/breakpoint/breakpoint_locations/TestBreakpointLocations.py passes when I revert this change.
Can you please take a look?

@kastiglione
Copy link
Contributor Author

@luporl I have a fix, I'll share the link soon.

@kastiglione
Copy link
Contributor Author

@luporl #131890

kastiglione added a commit to swiftlang/llvm-project that referenced this pull request Mar 20, 2025
Change `lldbtest.expect` to require the regexes in `patterns` be found in order – when the
`ordered` parameter is true. This matches the behavior of `substrs`.

The `ordered` parameter is true by default, so this change also fixes tests by either
tweaking the patterns to work in order, or by setting `ordered=False`.

I have often wanted to test with `patterns` and also verify the order. This change
allows that.

(cherry picked from commit 6d2b828)
kastiglione added a commit to swiftlang/llvm-project that referenced this pull request Mar 21, 2025
Change `lldbtest.expect` to require the regexes in `patterns` be found in order – when the
`ordered` parameter is true. This matches the behavior of `substrs`.

The `ordered` parameter is true by default, so this change also fixes tests by either
tweaking the patterns to work in order, or by setting `ordered=False`.

I have often wanted to test with `patterns` and also verify the order. This change
allows that.

(cherry picked from commit 6d2b828)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants