xref: /linux/tools/unittests/test_cmatch.py (revision 5181afcdf99527dd92a88f80fc4d0d8013e1b510)
150b87bb4SMauro Carvalho Chehab#!/usr/bin/env python3
250b87bb4SMauro Carvalho Chehab# SPDX-License-Identifier: GPL-2.0
350b87bb4SMauro Carvalho Chehab# Copyright(c) 2026: Mauro Carvalho Chehab <mchehab@kernel.org>.
450b87bb4SMauro Carvalho Chehab#
550b87bb4SMauro Carvalho Chehab# pylint: disable=C0413,R0904
650b87bb4SMauro Carvalho Chehab
750b87bb4SMauro Carvalho Chehab
850b87bb4SMauro Carvalho Chehab"""
950b87bb4SMauro Carvalho ChehabUnit tests for kernel-doc CMatch.
1050b87bb4SMauro Carvalho Chehab"""
1150b87bb4SMauro Carvalho Chehab
1250b87bb4SMauro Carvalho Chehabimport os
1350b87bb4SMauro Carvalho Chehabimport re
1450b87bb4SMauro Carvalho Chehabimport sys
1550b87bb4SMauro Carvalho Chehabimport unittest
1650b87bb4SMauro Carvalho Chehab
1750b87bb4SMauro Carvalho Chehab
1850b87bb4SMauro Carvalho Chehab# Import Python modules
1950b87bb4SMauro Carvalho Chehab
2050b87bb4SMauro Carvalho ChehabSRC_DIR = os.path.dirname(os.path.realpath(__file__))
2150b87bb4SMauro Carvalho Chehabsys.path.insert(0, os.path.join(SRC_DIR, "../lib/python"))
2250b87bb4SMauro Carvalho Chehab
2350b87bb4SMauro Carvalho Chehabfrom kdoc.c_lex import CMatch
24*c22aa12cSMauro Carvalho Chehabfrom kdoc.kdoc_re import KernRe
2550b87bb4SMauro Carvalho Chehabfrom unittest_helper import run_unittest
2650b87bb4SMauro Carvalho Chehab
2750b87bb4SMauro Carvalho Chehab#
2850b87bb4SMauro Carvalho Chehab# Override unittest.TestCase to better compare diffs ignoring whitespaces
2950b87bb4SMauro Carvalho Chehab#
3050b87bb4SMauro Carvalho Chehabclass TestCaseDiff(unittest.TestCase):
3150b87bb4SMauro Carvalho Chehab    """
3250b87bb4SMauro Carvalho Chehab    Disable maximum limit on diffs and add a method to better
3350b87bb4SMauro Carvalho Chehab    handle diffs with whitespace differences.
3450b87bb4SMauro Carvalho Chehab    """
3550b87bb4SMauro Carvalho Chehab
3650b87bb4SMauro Carvalho Chehab    @classmethod
3750b87bb4SMauro Carvalho Chehab    def setUpClass(cls):
3850b87bb4SMauro Carvalho Chehab        """Ensure that there won't be limit for diffs"""
3950b87bb4SMauro Carvalho Chehab        cls.maxDiff = None
4050b87bb4SMauro Carvalho Chehab
4150b87bb4SMauro Carvalho Chehab
4250b87bb4SMauro Carvalho Chehab#
4350b87bb4SMauro Carvalho Chehab# Tests doing with different macros
4450b87bb4SMauro Carvalho Chehab#
4550b87bb4SMauro Carvalho Chehab
4650b87bb4SMauro Carvalho Chehabclass TestSearch(TestCaseDiff):
4750b87bb4SMauro Carvalho Chehab    """
4850b87bb4SMauro Carvalho Chehab    Test search mechanism
4950b87bb4SMauro Carvalho Chehab    """
5050b87bb4SMauro Carvalho Chehab
5150b87bb4SMauro Carvalho Chehab    def test_search_acquires_simple(self):
5250b87bb4SMauro Carvalho Chehab        line = "__acquires(ctx) foo();"
5350b87bb4SMauro Carvalho Chehab        result = ", ".join(CMatch("__acquires").search(line))
5450b87bb4SMauro Carvalho Chehab        self.assertEqual(result, "__acquires(ctx)")
5550b87bb4SMauro Carvalho Chehab
5650b87bb4SMauro Carvalho Chehab    def test_search_acquires_multiple(self):
5750b87bb4SMauro Carvalho Chehab        line = "__acquires(ctx) __acquires(other) bar();"
5850b87bb4SMauro Carvalho Chehab        result = ", ".join(CMatch("__acquires").search(line))
5950b87bb4SMauro Carvalho Chehab        self.assertEqual(result, "__acquires(ctx), __acquires(other)")
6050b87bb4SMauro Carvalho Chehab
6150b87bb4SMauro Carvalho Chehab    def test_search_acquires_nested_paren(self):
6250b87bb4SMauro Carvalho Chehab        line = "__acquires((ctx1, ctx2)) baz();"
6350b87bb4SMauro Carvalho Chehab        result = ", ".join(CMatch("__acquires").search(line))
6450b87bb4SMauro Carvalho Chehab        self.assertEqual(result, "__acquires((ctx1, ctx2))")
6550b87bb4SMauro Carvalho Chehab
6650b87bb4SMauro Carvalho Chehab    def test_search_must_hold(self):
6750b87bb4SMauro Carvalho Chehab        line = "__must_hold(&lock) do_something();"
6850b87bb4SMauro Carvalho Chehab        result = ", ".join(CMatch("__must_hold").search(line))
6950b87bb4SMauro Carvalho Chehab        self.assertEqual(result, "__must_hold(&lock)")
7050b87bb4SMauro Carvalho Chehab
7150b87bb4SMauro Carvalho Chehab    def test_search_must_hold_shared(self):
7250b87bb4SMauro Carvalho Chehab        line = "__must_hold_shared(RCU) other();"
7350b87bb4SMauro Carvalho Chehab        result = ", ".join(CMatch("__must_hold_shared").search(line))
7450b87bb4SMauro Carvalho Chehab        self.assertEqual(result, "__must_hold_shared(RCU)")
7550b87bb4SMauro Carvalho Chehab
7650b87bb4SMauro Carvalho Chehab    def test_search_no_false_positive(self):
7750b87bb4SMauro Carvalho Chehab        line = "call__acquires(foo);  // should stay intact"
78*c22aa12cSMauro Carvalho Chehab        result = ", ".join(CMatch(r"__acquires").search(line))
7950b87bb4SMauro Carvalho Chehab        self.assertEqual(result, "")
8050b87bb4SMauro Carvalho Chehab
8150b87bb4SMauro Carvalho Chehab    def test_search_no_macro_remains(self):
8250b87bb4SMauro Carvalho Chehab        line = "do_something_else();"
8350b87bb4SMauro Carvalho Chehab        result = ", ".join(CMatch("__acquires").search(line))
8450b87bb4SMauro Carvalho Chehab        self.assertEqual(result, "")
8550b87bb4SMauro Carvalho Chehab
8650b87bb4SMauro Carvalho Chehab    def test_search_no_function(self):
8750b87bb4SMauro Carvalho Chehab        line = "something"
8850b87bb4SMauro Carvalho Chehab        result = ", ".join(CMatch(line).search(line))
8950b87bb4SMauro Carvalho Chehab        self.assertEqual(result, "")
9050b87bb4SMauro Carvalho Chehab
9150b87bb4SMauro Carvalho Chehab#
92*c22aa12cSMauro Carvalho Chehab# Override unittest.TestCase to better compare diffs ignoring whitespaces
93*c22aa12cSMauro Carvalho Chehab#
94*c22aa12cSMauro Carvalho Chehabclass TestCaseDiff(unittest.TestCase):
95*c22aa12cSMauro Carvalho Chehab    """
96*c22aa12cSMauro Carvalho Chehab    Disable maximum limit on diffs and add a method to better
97*c22aa12cSMauro Carvalho Chehab    handle diffs with whitespace differences.
98*c22aa12cSMauro Carvalho Chehab    """
99*c22aa12cSMauro Carvalho Chehab
100*c22aa12cSMauro Carvalho Chehab    @classmethod
101*c22aa12cSMauro Carvalho Chehab    def setUpClass(cls):
102*c22aa12cSMauro Carvalho Chehab        """Ensure that there won't be limit for diffs"""
103*c22aa12cSMauro Carvalho Chehab        cls.maxDiff = None
104*c22aa12cSMauro Carvalho Chehab
105*c22aa12cSMauro Carvalho Chehab    def assertLogicallyEqual(self, a, b):
106*c22aa12cSMauro Carvalho Chehab        """
107*c22aa12cSMauro Carvalho Chehab        Compare two results ignoring multiple whitespace differences.
108*c22aa12cSMauro Carvalho Chehab
109*c22aa12cSMauro Carvalho Chehab        This is useful to check more complex matches picked from examples.
110*c22aa12cSMauro Carvalho Chehab        On a plus side, we also don't need to use dedent.
111*c22aa12cSMauro Carvalho Chehab        Please notice that line breaks still need to match. We might
112*c22aa12cSMauro Carvalho Chehab        remove it at the regex, but this way, checking the diff is easier.
113*c22aa12cSMauro Carvalho Chehab        """
114*c22aa12cSMauro Carvalho Chehab        a = re.sub(r"[\t ]+", " ", a.strip())
115*c22aa12cSMauro Carvalho Chehab        b = re.sub(r"[\t ]+", " ", b.strip())
116*c22aa12cSMauro Carvalho Chehab
117*c22aa12cSMauro Carvalho Chehab        a = re.sub(r"\s+\n", "\n", a)
118*c22aa12cSMauro Carvalho Chehab        b = re.sub(r"\s+\n", "\n", b)
119*c22aa12cSMauro Carvalho Chehab
120*c22aa12cSMauro Carvalho Chehab        a = re.sub(" ;", ";", a)
121*c22aa12cSMauro Carvalho Chehab        b = re.sub(" ;", ";", b)
122*c22aa12cSMauro Carvalho Chehab
123*c22aa12cSMauro Carvalho Chehab        self.assertEqual(a, b)
124*c22aa12cSMauro Carvalho Chehab
125*c22aa12cSMauro Carvalho Chehab#
126*c22aa12cSMauro Carvalho Chehab# Tests doing with different macros
127*c22aa12cSMauro Carvalho Chehab#
128*c22aa12cSMauro Carvalho Chehab
129*c22aa12cSMauro Carvalho Chehabclass TestSubMultipleMacros(TestCaseDiff):
130*c22aa12cSMauro Carvalho Chehab    """
131*c22aa12cSMauro Carvalho Chehab    Tests doing with different macros.
132*c22aa12cSMauro Carvalho Chehab
133*c22aa12cSMauro Carvalho Chehab    Here, we won't use assertLogicallyEqual. Instead, we'll check if each
134*c22aa12cSMauro Carvalho Chehab    of the expected patterns are present at the answer.
135*c22aa12cSMauro Carvalho Chehab    """
136*c22aa12cSMauro Carvalho Chehab
137*c22aa12cSMauro Carvalho Chehab    def test_acquires_simple(self):
138*c22aa12cSMauro Carvalho Chehab        """Simple replacement test with __acquires"""
139*c22aa12cSMauro Carvalho Chehab        line = "__acquires(ctx) foo();"
140*c22aa12cSMauro Carvalho Chehab        result = CMatch(r"__acquires").sub("REPLACED", line)
141*c22aa12cSMauro Carvalho Chehab
142*c22aa12cSMauro Carvalho Chehab        self.assertEqual("REPLACED foo();", result)
143*c22aa12cSMauro Carvalho Chehab
144*c22aa12cSMauro Carvalho Chehab    def test_acquires_multiple(self):
145*c22aa12cSMauro Carvalho Chehab        """Multiple __acquires"""
146*c22aa12cSMauro Carvalho Chehab        line = "__acquires(ctx) __acquires(other) bar();"
147*c22aa12cSMauro Carvalho Chehab        result = CMatch(r"__acquires").sub("REPLACED", line)
148*c22aa12cSMauro Carvalho Chehab
149*c22aa12cSMauro Carvalho Chehab        self.assertEqual("REPLACED REPLACED bar();", result)
150*c22aa12cSMauro Carvalho Chehab
151*c22aa12cSMauro Carvalho Chehab    def test_acquires_nested_paren(self):
152*c22aa12cSMauro Carvalho Chehab        """__acquires with nested pattern"""
153*c22aa12cSMauro Carvalho Chehab        line = "__acquires((ctx1, ctx2)) baz();"
154*c22aa12cSMauro Carvalho Chehab        result = CMatch(r"__acquires").sub("REPLACED", line)
155*c22aa12cSMauro Carvalho Chehab
156*c22aa12cSMauro Carvalho Chehab        self.assertEqual("REPLACED baz();", result)
157*c22aa12cSMauro Carvalho Chehab
158*c22aa12cSMauro Carvalho Chehab    def test_must_hold(self):
159*c22aa12cSMauro Carvalho Chehab        """__must_hold with a pointer"""
160*c22aa12cSMauro Carvalho Chehab        line = "__must_hold(&lock) do_something();"
161*c22aa12cSMauro Carvalho Chehab        result = CMatch(r"__must_hold").sub("REPLACED", line)
162*c22aa12cSMauro Carvalho Chehab
163*c22aa12cSMauro Carvalho Chehab        self.assertNotIn("__must_hold(", result)
164*c22aa12cSMauro Carvalho Chehab        self.assertIn("do_something();", result)
165*c22aa12cSMauro Carvalho Chehab
166*c22aa12cSMauro Carvalho Chehab    def test_must_hold_shared(self):
167*c22aa12cSMauro Carvalho Chehab        """__must_hold with an upercase defined value"""
168*c22aa12cSMauro Carvalho Chehab        line = "__must_hold_shared(RCU) other();"
169*c22aa12cSMauro Carvalho Chehab        result = CMatch(r"__must_hold_shared").sub("REPLACED", line)
170*c22aa12cSMauro Carvalho Chehab
171*c22aa12cSMauro Carvalho Chehab        self.assertNotIn("__must_hold_shared(", result)
172*c22aa12cSMauro Carvalho Chehab        self.assertIn("other();", result)
173*c22aa12cSMauro Carvalho Chehab
174*c22aa12cSMauro Carvalho Chehab    def test_no_false_positive(self):
175*c22aa12cSMauro Carvalho Chehab        """
176*c22aa12cSMauro Carvalho Chehab        Ensure that unrelated text containing similar patterns is preserved
177*c22aa12cSMauro Carvalho Chehab        """
178*c22aa12cSMauro Carvalho Chehab        line = "call__acquires(foo);  // should stay intact"
179*c22aa12cSMauro Carvalho Chehab        result = CMatch(r"\b__acquires").sub("REPLACED", line)
180*c22aa12cSMauro Carvalho Chehab
181*c22aa12cSMauro Carvalho Chehab        self.assertLogicallyEqual(result, "call__acquires(foo);")
182*c22aa12cSMauro Carvalho Chehab
183*c22aa12cSMauro Carvalho Chehab    def test_mixed_macros(self):
184*c22aa12cSMauro Carvalho Chehab        """Add a mix of macros"""
185*c22aa12cSMauro Carvalho Chehab        line = "__acquires(ctx) __releases(ctx) __must_hold(&lock) foo();"
186*c22aa12cSMauro Carvalho Chehab
187*c22aa12cSMauro Carvalho Chehab        result = CMatch(r"__acquires").sub("REPLACED", line)
188*c22aa12cSMauro Carvalho Chehab        result = CMatch(r"__releases").sub("REPLACED", result)
189*c22aa12cSMauro Carvalho Chehab        result = CMatch(r"__must_hold").sub("REPLACED", result)
190*c22aa12cSMauro Carvalho Chehab
191*c22aa12cSMauro Carvalho Chehab        self.assertNotIn("__acquires(", result)
192*c22aa12cSMauro Carvalho Chehab        self.assertNotIn("__releases(", result)
193*c22aa12cSMauro Carvalho Chehab        self.assertNotIn("__must_hold(", result)
194*c22aa12cSMauro Carvalho Chehab
195*c22aa12cSMauro Carvalho Chehab        self.assertIn("foo();", result)
196*c22aa12cSMauro Carvalho Chehab
197*c22aa12cSMauro Carvalho Chehab    def test_no_macro_remains(self):
198*c22aa12cSMauro Carvalho Chehab        """Ensures that unmatched macros are untouched"""
199*c22aa12cSMauro Carvalho Chehab        line = "do_something_else();"
200*c22aa12cSMauro Carvalho Chehab        result = CMatch(r"__acquires").sub("REPLACED", line)
201*c22aa12cSMauro Carvalho Chehab
202*c22aa12cSMauro Carvalho Chehab        self.assertEqual(result, line)
203*c22aa12cSMauro Carvalho Chehab
204*c22aa12cSMauro Carvalho Chehab    def test_no_function(self):
205*c22aa12cSMauro Carvalho Chehab        """Ensures that no functions will remain untouched"""
206*c22aa12cSMauro Carvalho Chehab        line = "something"
207*c22aa12cSMauro Carvalho Chehab        result = CMatch(line).sub("REPLACED", line)
208*c22aa12cSMauro Carvalho Chehab
209*c22aa12cSMauro Carvalho Chehab        self.assertEqual(result, line)
210*c22aa12cSMauro Carvalho Chehab
211*c22aa12cSMauro Carvalho Chehab#
212*c22aa12cSMauro Carvalho Chehab# Check if the diff is logically equivalent. To simplify, the tests here
213*c22aa12cSMauro Carvalho Chehab# use a single macro name for all replacements.
214*c22aa12cSMauro Carvalho Chehab#
215*c22aa12cSMauro Carvalho Chehab
216*c22aa12cSMauro Carvalho Chehabclass TestSubSimple(TestCaseDiff):
217*c22aa12cSMauro Carvalho Chehab    """
218*c22aa12cSMauro Carvalho Chehab    Test argument replacements.
219*c22aa12cSMauro Carvalho Chehab
220*c22aa12cSMauro Carvalho Chehab    Here, the function name can be anything. So, we picked __attribute__(),
221*c22aa12cSMauro Carvalho Chehab    to mimic a macro found at the Kernel, but none of the replacements her
222*c22aa12cSMauro Carvalho Chehab    has any relationship with the Kernel usage.
223*c22aa12cSMauro Carvalho Chehab    """
224*c22aa12cSMauro Carvalho Chehab
225*c22aa12cSMauro Carvalho Chehab    MACRO = "__attribute__"
226*c22aa12cSMauro Carvalho Chehab
227*c22aa12cSMauro Carvalho Chehab    @classmethod
228*c22aa12cSMauro Carvalho Chehab    def setUpClass(cls):
229*c22aa12cSMauro Carvalho Chehab        """Define a CMatch to be used for all tests"""
230*c22aa12cSMauro Carvalho Chehab        cls.matcher = CMatch(cls.MACRO)
231*c22aa12cSMauro Carvalho Chehab
232*c22aa12cSMauro Carvalho Chehab    def test_sub_with_capture(self):
233*c22aa12cSMauro Carvalho Chehab        """Test all arguments replacement with a single arg"""
234*c22aa12cSMauro Carvalho Chehab        line = f"{self.MACRO}(&ctx)\nfoo();"
235*c22aa12cSMauro Carvalho Chehab
236*c22aa12cSMauro Carvalho Chehab        result = self.matcher.sub(r"ACQUIRED(\0)", line)
237*c22aa12cSMauro Carvalho Chehab
238*c22aa12cSMauro Carvalho Chehab        self.assertLogicallyEqual("ACQUIRED(&ctx)\nfoo();", result)
239*c22aa12cSMauro Carvalho Chehab
240*c22aa12cSMauro Carvalho Chehab    def test_sub_zero_placeholder(self):
241*c22aa12cSMauro Carvalho Chehab        """Test all arguments replacement with a multiple args"""
242*c22aa12cSMauro Carvalho Chehab        line = f"{self.MACRO}(arg1, arg2)\nbar();"
243*c22aa12cSMauro Carvalho Chehab
244*c22aa12cSMauro Carvalho Chehab        result = self.matcher.sub(r"REPLACED(\0)", line)
245*c22aa12cSMauro Carvalho Chehab
246*c22aa12cSMauro Carvalho Chehab        self.assertLogicallyEqual("REPLACED(arg1, arg2)\nbar();", result)
247*c22aa12cSMauro Carvalho Chehab
248*c22aa12cSMauro Carvalho Chehab    def test_sub_single_placeholder(self):
249*c22aa12cSMauro Carvalho Chehab        """Single replacement rule for \1"""
250*c22aa12cSMauro Carvalho Chehab        line = f"{self.MACRO}(ctx, boo)\nfoo();"
251*c22aa12cSMauro Carvalho Chehab        result = self.matcher.sub(r"ACQUIRED(\1)", line)
252*c22aa12cSMauro Carvalho Chehab
253*c22aa12cSMauro Carvalho Chehab        self.assertLogicallyEqual("ACQUIRED(ctx)\nfoo();", result)
254*c22aa12cSMauro Carvalho Chehab
255*c22aa12cSMauro Carvalho Chehab    def test_sub_multiple_placeholders(self):
256*c22aa12cSMauro Carvalho Chehab        """Replacement rule for both \1 and \2"""
257*c22aa12cSMauro Carvalho Chehab        line = f"{self.MACRO}(arg1, arg2)\nbar();"
258*c22aa12cSMauro Carvalho Chehab        result = self.matcher.sub(r"REPLACE(\1, \2)", line)
259*c22aa12cSMauro Carvalho Chehab
260*c22aa12cSMauro Carvalho Chehab        self.assertLogicallyEqual("REPLACE(arg1, arg2)\nbar();", result)
261*c22aa12cSMauro Carvalho Chehab
262*c22aa12cSMauro Carvalho Chehab    def test_sub_mixed_placeholders(self):
263*c22aa12cSMauro Carvalho Chehab        """Replacement rule for \0, \1 and additional text"""
264*c22aa12cSMauro Carvalho Chehab        line = f"{self.MACRO}(foo, bar)\nbaz();"
265*c22aa12cSMauro Carvalho Chehab        result = self.matcher.sub(r"ALL(\0) FIRST(\1)", line)
266*c22aa12cSMauro Carvalho Chehab
267*c22aa12cSMauro Carvalho Chehab        self.assertLogicallyEqual("ALL(foo, bar) FIRST(foo)\nbaz();", result)
268*c22aa12cSMauro Carvalho Chehab
269*c22aa12cSMauro Carvalho Chehab    def test_sub_no_placeholder(self):
270*c22aa12cSMauro Carvalho Chehab        """Replacement without placeholders"""
271*c22aa12cSMauro Carvalho Chehab        line = f"{self.MACRO}(arg)\nfoo();"
272*c22aa12cSMauro Carvalho Chehab        result = self.matcher.sub(r"NO_BACKREFS()", line)
273*c22aa12cSMauro Carvalho Chehab
274*c22aa12cSMauro Carvalho Chehab        self.assertLogicallyEqual("NO_BACKREFS()\nfoo();", result)
275*c22aa12cSMauro Carvalho Chehab
276*c22aa12cSMauro Carvalho Chehab    def test_sub_count_parameter(self):
277*c22aa12cSMauro Carvalho Chehab        """Verify that the algorithm stops after the requested count"""
278*c22aa12cSMauro Carvalho Chehab        line = f"{self.MACRO}(a1) x();\n{self.MACRO}(a2) y();"
279*c22aa12cSMauro Carvalho Chehab        result = self.matcher.sub(r"ONLY_FIRST(\1) ", line, count=1)
280*c22aa12cSMauro Carvalho Chehab
281*c22aa12cSMauro Carvalho Chehab        self.assertLogicallyEqual(f"ONLY_FIRST(a1) x();\n{self.MACRO}(a2) y();",
282*c22aa12cSMauro Carvalho Chehab                                  result)
283*c22aa12cSMauro Carvalho Chehab
284*c22aa12cSMauro Carvalho Chehab    def test_strip_multiple_acquires(self):
285*c22aa12cSMauro Carvalho Chehab        """Check if spaces between removed delimiters will be dropped"""
286*c22aa12cSMauro Carvalho Chehab        line = f"int {self.MACRO}(1)  {self.MACRO}(2 )   {self.MACRO}(3) foo;"
287*c22aa12cSMauro Carvalho Chehab        result = self.matcher.sub("", line)
288*c22aa12cSMauro Carvalho Chehab
289*c22aa12cSMauro Carvalho Chehab        self.assertLogicallyEqual(result, "int foo;")
290*c22aa12cSMauro Carvalho Chehab
291*c22aa12cSMauro Carvalho Chehab    def test_rise_early_greedy(self):
292*c22aa12cSMauro Carvalho Chehab        line = f"{self.MACRO}(a, b, c, d);"
293*c22aa12cSMauro Carvalho Chehab        sub = r"\1, \2+, \3"
294*c22aa12cSMauro Carvalho Chehab
295*c22aa12cSMauro Carvalho Chehab        with self.assertRaises(ValueError):
296*c22aa12cSMauro Carvalho Chehab            result = self.matcher.sub(sub, line)
297*c22aa12cSMauro Carvalho Chehab
298*c22aa12cSMauro Carvalho Chehab    def test_rise_multiple_greedy(self):
299*c22aa12cSMauro Carvalho Chehab        line = f"{self.MACRO}(a, b, c, d);"
300*c22aa12cSMauro Carvalho Chehab        sub = r"\1, \2+, \3+"
301*c22aa12cSMauro Carvalho Chehab
302*c22aa12cSMauro Carvalho Chehab        with self.assertRaises(ValueError):
303*c22aa12cSMauro Carvalho Chehab            result = self.matcher.sub(sub, line)
304*c22aa12cSMauro Carvalho Chehab
305*c22aa12cSMauro Carvalho Chehab#
306*c22aa12cSMauro Carvalho Chehab# Test replacements with slashrefs
307*c22aa12cSMauro Carvalho Chehab#
308*c22aa12cSMauro Carvalho Chehab
309*c22aa12cSMauro Carvalho Chehab
310*c22aa12cSMauro Carvalho Chehabclass TestSubWithLocalXforms(TestCaseDiff):
311*c22aa12cSMauro Carvalho Chehab    """
312*c22aa12cSMauro Carvalho Chehab    Test diferent usecase patterns found at the Kernel.
313*c22aa12cSMauro Carvalho Chehab
314*c22aa12cSMauro Carvalho Chehab    Here, replacements using both CMatch and KernRe can be tested,
315*c22aa12cSMauro Carvalho Chehab    as it will import the actual replacement rules used by kernel-doc.
316*c22aa12cSMauro Carvalho Chehab    """
317*c22aa12cSMauro Carvalho Chehab
318*c22aa12cSMauro Carvalho Chehab    struct_xforms = [
319*c22aa12cSMauro Carvalho Chehab        (CMatch("__attribute__"), ' '),
320*c22aa12cSMauro Carvalho Chehab        (CMatch('__aligned'), ' '),
321*c22aa12cSMauro Carvalho Chehab        (CMatch('__counted_by'), ' '),
322*c22aa12cSMauro Carvalho Chehab        (CMatch('__counted_by_(le|be)'), ' '),
323*c22aa12cSMauro Carvalho Chehab        (CMatch('__guarded_by'), ' '),
324*c22aa12cSMauro Carvalho Chehab        (CMatch('__pt_guarded_by'), ' '),
325*c22aa12cSMauro Carvalho Chehab
326*c22aa12cSMauro Carvalho Chehab        (CMatch('__cacheline_group_(begin|end)'), ''),
327*c22aa12cSMauro Carvalho Chehab
328*c22aa12cSMauro Carvalho Chehab        (CMatch('struct_group'), r'\2'),
329*c22aa12cSMauro Carvalho Chehab        (CMatch('struct_group_attr'), r'\3'),
330*c22aa12cSMauro Carvalho Chehab        (CMatch('struct_group_tagged'), r'struct \1 { \3+ } \2;'),
331*c22aa12cSMauro Carvalho Chehab        (CMatch('__struct_group'), r'\4'),
332*c22aa12cSMauro Carvalho Chehab
333*c22aa12cSMauro Carvalho Chehab        (CMatch('__ETHTOOL_DECLARE_LINK_MODE_MASK'), r'DECLARE_BITMAP(\1, __ETHTOOL_LINK_MODE_MASK_NBITS)'),
334*c22aa12cSMauro Carvalho Chehab        (CMatch('DECLARE_PHY_INTERFACE_MASK',), r'DECLARE_BITMAP(\1, PHY_INTERFACE_MODE_MAX)'),
335*c22aa12cSMauro Carvalho Chehab        (CMatch('DECLARE_BITMAP'), r'unsigned long \1[BITS_TO_LONGS(\2)]'),
336*c22aa12cSMauro Carvalho Chehab
337*c22aa12cSMauro Carvalho Chehab        (CMatch('DECLARE_HASHTABLE'), r'unsigned long \1[1 << ((\2) - 1)]'),
338*c22aa12cSMauro Carvalho Chehab        (CMatch('DECLARE_KFIFO'), r'\2 *\1'),
339*c22aa12cSMauro Carvalho Chehab        (CMatch('DECLARE_KFIFO_PTR'), r'\2 *\1'),
340*c22aa12cSMauro Carvalho Chehab        (CMatch('(?:__)?DECLARE_FLEX_ARRAY'), r'\1 \2[]'),
341*c22aa12cSMauro Carvalho Chehab        (CMatch('DEFINE_DMA_UNMAP_ADDR'), r'dma_addr_t \1'),
342*c22aa12cSMauro Carvalho Chehab        (CMatch('DEFINE_DMA_UNMAP_LEN'), r'__u32 \1'),
343*c22aa12cSMauro Carvalho Chehab        (CMatch('VIRTIO_DECLARE_FEATURES'), r'union { u64 \1; u64 \1_array[VIRTIO_FEATURES_U64S]; }'),
344*c22aa12cSMauro Carvalho Chehab    ]
345*c22aa12cSMauro Carvalho Chehab
346*c22aa12cSMauro Carvalho Chehab    function_xforms = [
347*c22aa12cSMauro Carvalho Chehab        (CMatch('__printf'), ""),
348*c22aa12cSMauro Carvalho Chehab        (CMatch('__(?:re)?alloc_size'), ""),
349*c22aa12cSMauro Carvalho Chehab        (CMatch("__diagnose_as"), ""),
350*c22aa12cSMauro Carvalho Chehab        (CMatch("DECL_BUCKET_PARAMS"), r"\1, \2"),
351*c22aa12cSMauro Carvalho Chehab
352*c22aa12cSMauro Carvalho Chehab        (CMatch("__cond_acquires"), ""),
353*c22aa12cSMauro Carvalho Chehab        (CMatch("__cond_releases"), ""),
354*c22aa12cSMauro Carvalho Chehab        (CMatch("__acquires"), ""),
355*c22aa12cSMauro Carvalho Chehab        (CMatch("__releases"), ""),
356*c22aa12cSMauro Carvalho Chehab        (CMatch("__must_hold"), ""),
357*c22aa12cSMauro Carvalho Chehab        (CMatch("__must_not_hold"), ""),
358*c22aa12cSMauro Carvalho Chehab        (CMatch("__must_hold_shared"), ""),
359*c22aa12cSMauro Carvalho Chehab        (CMatch("__cond_acquires_shared"), ""),
360*c22aa12cSMauro Carvalho Chehab        (CMatch("__acquires_shared"), ""),
361*c22aa12cSMauro Carvalho Chehab        (CMatch("__releases_shared"), ""),
362*c22aa12cSMauro Carvalho Chehab        (CMatch("__attribute__"), ""),
363*c22aa12cSMauro Carvalho Chehab    ]
364*c22aa12cSMauro Carvalho Chehab
365*c22aa12cSMauro Carvalho Chehab    var_xforms = [
366*c22aa12cSMauro Carvalho Chehab        (CMatch('__guarded_by'), ""),
367*c22aa12cSMauro Carvalho Chehab        (CMatch('__pt_guarded_by'), ""),
368*c22aa12cSMauro Carvalho Chehab        (CMatch("LIST_HEAD"), r"struct list_head \1"),
369*c22aa12cSMauro Carvalho Chehab    ]
370*c22aa12cSMauro Carvalho Chehab
371*c22aa12cSMauro Carvalho Chehab    #: Transforms main dictionary used at apply_transforms().
372*c22aa12cSMauro Carvalho Chehab    xforms = {
373*c22aa12cSMauro Carvalho Chehab        "struct": struct_xforms,
374*c22aa12cSMauro Carvalho Chehab        "func": function_xforms,
375*c22aa12cSMauro Carvalho Chehab        "var": var_xforms,
376*c22aa12cSMauro Carvalho Chehab    }
377*c22aa12cSMauro Carvalho Chehab
378*c22aa12cSMauro Carvalho Chehab    @classmethod
379*c22aa12cSMauro Carvalho Chehab    def apply_transforms(cls, xform_type, text):
380*c22aa12cSMauro Carvalho Chehab        """
381*c22aa12cSMauro Carvalho Chehab        Mimic the behavior of kdoc_parser.apply_transforms() method.
382*c22aa12cSMauro Carvalho Chehab
383*c22aa12cSMauro Carvalho Chehab        For each element of STRUCT_XFORMS, apply apply_transforms.
384*c22aa12cSMauro Carvalho Chehab
385*c22aa12cSMauro Carvalho Chehab        There are two parameters:
386*c22aa12cSMauro Carvalho Chehab
387*c22aa12cSMauro Carvalho Chehab        - ``xform_type``
388*c22aa12cSMauro Carvalho Chehab            Can be ``func``, ``struct`` or ``var``;
389*c22aa12cSMauro Carvalho Chehab        - ``text``
390*c22aa12cSMauro Carvalho Chehab            The text where the sub patterns from CTransforms will be applied.
391*c22aa12cSMauro Carvalho Chehab        """
392*c22aa12cSMauro Carvalho Chehab        for search, subst in cls.xforms.get(xform_type):
393*c22aa12cSMauro Carvalho Chehab            text = search.sub(subst, text)
394*c22aa12cSMauro Carvalho Chehab
395*c22aa12cSMauro Carvalho Chehab        return text.strip()
396*c22aa12cSMauro Carvalho Chehab
397*c22aa12cSMauro Carvalho Chehab        cls.matcher = CMatch(r"struct_group[\w\_]*")
398*c22aa12cSMauro Carvalho Chehab
399*c22aa12cSMauro Carvalho Chehab    def test_struct_group(self):
400*c22aa12cSMauro Carvalho Chehab        """
401*c22aa12cSMauro Carvalho Chehab        Test struct_group using a pattern from
402*c22aa12cSMauro Carvalho Chehab        drivers/net/ethernet/asix/ax88796c_main.h.
403*c22aa12cSMauro Carvalho Chehab        """
404*c22aa12cSMauro Carvalho Chehab        line = """
405*c22aa12cSMauro Carvalho Chehab            struct tx_pkt_info {
406*c22aa12cSMauro Carvalho Chehab                    struct_group(tx_overhead,
407*c22aa12cSMauro Carvalho Chehab                            struct tx_sop_header sop;
408*c22aa12cSMauro Carvalho Chehab                            struct tx_segment_header seg;
409*c22aa12cSMauro Carvalho Chehab                    );
410*c22aa12cSMauro Carvalho Chehab                    struct tx_eop_header eop;
411*c22aa12cSMauro Carvalho Chehab                    u16 pkt_len;
412*c22aa12cSMauro Carvalho Chehab                    u16 seq_num;
413*c22aa12cSMauro Carvalho Chehab            };
414*c22aa12cSMauro Carvalho Chehab        """
415*c22aa12cSMauro Carvalho Chehab        expected = """
416*c22aa12cSMauro Carvalho Chehab            struct tx_pkt_info {
417*c22aa12cSMauro Carvalho Chehab                    struct tx_sop_header sop;
418*c22aa12cSMauro Carvalho Chehab                    struct tx_segment_header seg;
419*c22aa12cSMauro Carvalho Chehab                    struct tx_eop_header eop;
420*c22aa12cSMauro Carvalho Chehab                    u16 pkt_len;
421*c22aa12cSMauro Carvalho Chehab                    u16 seq_num;
422*c22aa12cSMauro Carvalho Chehab            };
423*c22aa12cSMauro Carvalho Chehab        """
424*c22aa12cSMauro Carvalho Chehab
425*c22aa12cSMauro Carvalho Chehab        result = self.apply_transforms("struct", line)
426*c22aa12cSMauro Carvalho Chehab        self.assertLogicallyEqual(result, expected)
427*c22aa12cSMauro Carvalho Chehab
428*c22aa12cSMauro Carvalho Chehab    def test_struct_group_attr(self):
429*c22aa12cSMauro Carvalho Chehab        """
430*c22aa12cSMauro Carvalho Chehab        Test two struct_group_attr using patterns from fs/smb/client/cifspdu.h.
431*c22aa12cSMauro Carvalho Chehab        """
432*c22aa12cSMauro Carvalho Chehab        line = """
433*c22aa12cSMauro Carvalho Chehab            typedef struct smb_com_open_rsp {
434*c22aa12cSMauro Carvalho Chehab                struct smb_hdr hdr;     /* wct = 34 BB */
435*c22aa12cSMauro Carvalho Chehab                __u8 AndXCommand;
436*c22aa12cSMauro Carvalho Chehab                __u8 AndXReserved;
437*c22aa12cSMauro Carvalho Chehab                __le16 AndXOffset;
438*c22aa12cSMauro Carvalho Chehab                __u8 OplockLevel;
439*c22aa12cSMauro Carvalho Chehab                __u16 Fid;
440*c22aa12cSMauro Carvalho Chehab                __le32 CreateAction;
441*c22aa12cSMauro Carvalho Chehab                struct_group_attr(common_attributes,,
442*c22aa12cSMauro Carvalho Chehab                    __le64 CreationTime;
443*c22aa12cSMauro Carvalho Chehab                    __le64 LastAccessTime;
444*c22aa12cSMauro Carvalho Chehab                    __le64 LastWriteTime;
445*c22aa12cSMauro Carvalho Chehab                    __le64 ChangeTime;
446*c22aa12cSMauro Carvalho Chehab                    __le32 FileAttributes;
447*c22aa12cSMauro Carvalho Chehab                );
448*c22aa12cSMauro Carvalho Chehab                __le64 AllocationSize;
449*c22aa12cSMauro Carvalho Chehab                __le64 EndOfFile;
450*c22aa12cSMauro Carvalho Chehab                __le16 FileType;
451*c22aa12cSMauro Carvalho Chehab                __le16 DeviceState;
452*c22aa12cSMauro Carvalho Chehab                __u8 DirectoryFlag;
453*c22aa12cSMauro Carvalho Chehab                __u16 ByteCount;        /* bct = 0 */
454*c22aa12cSMauro Carvalho Chehab            } OPEN_RSP;
455*c22aa12cSMauro Carvalho Chehab            typedef struct {
456*c22aa12cSMauro Carvalho Chehab                struct_group_attr(common_attributes,,
457*c22aa12cSMauro Carvalho Chehab                    __le64 CreationTime;
458*c22aa12cSMauro Carvalho Chehab                    __le64 LastAccessTime;
459*c22aa12cSMauro Carvalho Chehab                    __le64 LastWriteTime;
460*c22aa12cSMauro Carvalho Chehab                    __le64 ChangeTime;
461*c22aa12cSMauro Carvalho Chehab                    __le32 Attributes;
462*c22aa12cSMauro Carvalho Chehab                );
463*c22aa12cSMauro Carvalho Chehab                __u32 Pad1;
464*c22aa12cSMauro Carvalho Chehab                __le64 AllocationSize;
465*c22aa12cSMauro Carvalho Chehab                __le64 EndOfFile;
466*c22aa12cSMauro Carvalho Chehab                __le32 NumberOfLinks;
467*c22aa12cSMauro Carvalho Chehab                __u8 DeletePending;
468*c22aa12cSMauro Carvalho Chehab                __u8 Directory;
469*c22aa12cSMauro Carvalho Chehab                __u16 Pad2;
470*c22aa12cSMauro Carvalho Chehab                __le32 EASize;
471*c22aa12cSMauro Carvalho Chehab                __le32 FileNameLength;
472*c22aa12cSMauro Carvalho Chehab                union {
473*c22aa12cSMauro Carvalho Chehab                    char __pad;
474*c22aa12cSMauro Carvalho Chehab                    DECLARE_FLEX_ARRAY(char, FileName);
475*c22aa12cSMauro Carvalho Chehab                };
476*c22aa12cSMauro Carvalho Chehab            } FILE_ALL_INFO;       /* level 0x107 QPathInfo */
477*c22aa12cSMauro Carvalho Chehab        """
478*c22aa12cSMauro Carvalho Chehab        expected = """
479*c22aa12cSMauro Carvalho Chehab            typedef struct smb_com_open_rsp {
480*c22aa12cSMauro Carvalho Chehab                struct smb_hdr hdr;
481*c22aa12cSMauro Carvalho Chehab                __u8 AndXCommand;
482*c22aa12cSMauro Carvalho Chehab                __u8 AndXReserved;
483*c22aa12cSMauro Carvalho Chehab                __le16 AndXOffset;
484*c22aa12cSMauro Carvalho Chehab                __u8 OplockLevel;
485*c22aa12cSMauro Carvalho Chehab                __u16 Fid;
486*c22aa12cSMauro Carvalho Chehab                __le32 CreateAction;
487*c22aa12cSMauro Carvalho Chehab                __le64 CreationTime;
488*c22aa12cSMauro Carvalho Chehab                __le64 LastAccessTime;
489*c22aa12cSMauro Carvalho Chehab                __le64 LastWriteTime;
490*c22aa12cSMauro Carvalho Chehab                __le64 ChangeTime;
491*c22aa12cSMauro Carvalho Chehab                __le32 FileAttributes;
492*c22aa12cSMauro Carvalho Chehab                __le64 AllocationSize;
493*c22aa12cSMauro Carvalho Chehab                __le64 EndOfFile;
494*c22aa12cSMauro Carvalho Chehab                __le16 FileType;
495*c22aa12cSMauro Carvalho Chehab                __le16 DeviceState;
496*c22aa12cSMauro Carvalho Chehab                __u8 DirectoryFlag;
497*c22aa12cSMauro Carvalho Chehab                __u16 ByteCount;
498*c22aa12cSMauro Carvalho Chehab            } OPEN_RSP;
499*c22aa12cSMauro Carvalho Chehab        typedef struct {
500*c22aa12cSMauro Carvalho Chehab            __le64 CreationTime;
501*c22aa12cSMauro Carvalho Chehab            __le64 LastAccessTime;
502*c22aa12cSMauro Carvalho Chehab            __le64 LastWriteTime;
503*c22aa12cSMauro Carvalho Chehab            __le64 ChangeTime;
504*c22aa12cSMauro Carvalho Chehab            __le32 Attributes;
505*c22aa12cSMauro Carvalho Chehab            __u32 Pad1;
506*c22aa12cSMauro Carvalho Chehab            __le64 AllocationSize;
507*c22aa12cSMauro Carvalho Chehab            __le64 EndOfFile;
508*c22aa12cSMauro Carvalho Chehab            __le32 NumberOfLinks;
509*c22aa12cSMauro Carvalho Chehab            __u8 DeletePending;
510*c22aa12cSMauro Carvalho Chehab            __u8 Directory;
511*c22aa12cSMauro Carvalho Chehab            __u16 Pad2;
512*c22aa12cSMauro Carvalho Chehab            __le32 EASize;
513*c22aa12cSMauro Carvalho Chehab            __le32 FileNameLength;
514*c22aa12cSMauro Carvalho Chehab            union {
515*c22aa12cSMauro Carvalho Chehab                char __pad;
516*c22aa12cSMauro Carvalho Chehab                char FileName[];
517*c22aa12cSMauro Carvalho Chehab            };
518*c22aa12cSMauro Carvalho Chehab        } FILE_ALL_INFO;
519*c22aa12cSMauro Carvalho Chehab        """
520*c22aa12cSMauro Carvalho Chehab
521*c22aa12cSMauro Carvalho Chehab        result = self.apply_transforms("struct", line)
522*c22aa12cSMauro Carvalho Chehab        self.assertLogicallyEqual(result, expected)
523*c22aa12cSMauro Carvalho Chehab
524*c22aa12cSMauro Carvalho Chehab    def test_raw_struct_group(self):
525*c22aa12cSMauro Carvalho Chehab        """
526*c22aa12cSMauro Carvalho Chehab        Test a __struct_group pattern from include/uapi/cxl/features.h.
527*c22aa12cSMauro Carvalho Chehab        """
528*c22aa12cSMauro Carvalho Chehab        line = """
529*c22aa12cSMauro Carvalho Chehab            struct cxl_mbox_get_sup_feats_out {
530*c22aa12cSMauro Carvalho Chehab                __struct_group(cxl_mbox_get_sup_feats_out_hdr, hdr, /* empty */,
531*c22aa12cSMauro Carvalho Chehab                    __le16 num_entries;
532*c22aa12cSMauro Carvalho Chehab                    __le16 supported_feats;
533*c22aa12cSMauro Carvalho Chehab                    __u8 reserved[4];
534*c22aa12cSMauro Carvalho Chehab                );
535*c22aa12cSMauro Carvalho Chehab                struct cxl_feat_entry ents[] __counted_by_le(num_entries);
536*c22aa12cSMauro Carvalho Chehab            } __attribute__ ((__packed__));
537*c22aa12cSMauro Carvalho Chehab        """
538*c22aa12cSMauro Carvalho Chehab        expected = """
539*c22aa12cSMauro Carvalho Chehab            struct cxl_mbox_get_sup_feats_out {
540*c22aa12cSMauro Carvalho Chehab                __le16 num_entries;
541*c22aa12cSMauro Carvalho Chehab                __le16 supported_feats;
542*c22aa12cSMauro Carvalho Chehab                __u8 reserved[4];
543*c22aa12cSMauro Carvalho Chehab                struct cxl_feat_entry ents[];
544*c22aa12cSMauro Carvalho Chehab            };
545*c22aa12cSMauro Carvalho Chehab        """
546*c22aa12cSMauro Carvalho Chehab
547*c22aa12cSMauro Carvalho Chehab        result = self.apply_transforms("struct", line)
548*c22aa12cSMauro Carvalho Chehab        self.assertLogicallyEqual(result, expected)
549*c22aa12cSMauro Carvalho Chehab
550*c22aa12cSMauro Carvalho Chehab    def test_raw_struct_group_tagged(self):
551*c22aa12cSMauro Carvalho Chehab        r"""
552*c22aa12cSMauro Carvalho Chehab        Test cxl_regs with struct_group_tagged patterns from drivers/cxl/cxl.h.
553*c22aa12cSMauro Carvalho Chehab
554*c22aa12cSMauro Carvalho Chehab        NOTE:
555*c22aa12cSMauro Carvalho Chehab
556*c22aa12cSMauro Carvalho Chehab            This one has actually a violation from what kernel-doc would
557*c22aa12cSMauro Carvalho Chehab            expect: Kernel-doc regex expects only 3 members, but this is
558*c22aa12cSMauro Carvalho Chehab            actually defined as::
559*c22aa12cSMauro Carvalho Chehab
560*c22aa12cSMauro Carvalho Chehab                #define struct_group_tagged(TAG, NAME, MEMBERS...)
561*c22aa12cSMauro Carvalho Chehab
562*c22aa12cSMauro Carvalho Chehab            The replace expression there is::
563*c22aa12cSMauro Carvalho Chehab
564*c22aa12cSMauro Carvalho Chehab                struct \1 { \3 } \2;
565*c22aa12cSMauro Carvalho Chehab
566*c22aa12cSMauro Carvalho Chehab            but it should be really something like::
567*c22aa12cSMauro Carvalho Chehab
568*c22aa12cSMauro Carvalho Chehab                struct \1 { \3 \4 \5 \6 \7 \8 ... } \2;
569*c22aa12cSMauro Carvalho Chehab
570*c22aa12cSMauro Carvalho Chehab            a later fix would be needed to address it.
571*c22aa12cSMauro Carvalho Chehab
572*c22aa12cSMauro Carvalho Chehab        """
573*c22aa12cSMauro Carvalho Chehab        line = """
574*c22aa12cSMauro Carvalho Chehab            struct cxl_regs {
575*c22aa12cSMauro Carvalho Chehab                struct_group_tagged(cxl_component_regs, component,
576*c22aa12cSMauro Carvalho Chehab                    void __iomem *hdm_decoder;
577*c22aa12cSMauro Carvalho Chehab                    void __iomem *ras;
578*c22aa12cSMauro Carvalho Chehab                );
579*c22aa12cSMauro Carvalho Chehab
580*c22aa12cSMauro Carvalho Chehab
581*c22aa12cSMauro Carvalho Chehab                /* This is actually a violation: too much commas */
582*c22aa12cSMauro Carvalho Chehab                struct_group_tagged(cxl_device_regs, device_regs,
583*c22aa12cSMauro Carvalho Chehab                    void __iomem *status, *mbox, *memdev;
584*c22aa12cSMauro Carvalho Chehab                );
585*c22aa12cSMauro Carvalho Chehab
586*c22aa12cSMauro Carvalho Chehab                struct_group_tagged(cxl_pmu_regs, pmu_regs,
587*c22aa12cSMauro Carvalho Chehab                    void __iomem *pmu;
588*c22aa12cSMauro Carvalho Chehab                );
589*c22aa12cSMauro Carvalho Chehab
590*c22aa12cSMauro Carvalho Chehab                struct_group_tagged(cxl_rch_regs, rch_regs,
591*c22aa12cSMauro Carvalho Chehab                    void __iomem *dport_aer;
592*c22aa12cSMauro Carvalho Chehab                );
593*c22aa12cSMauro Carvalho Chehab
594*c22aa12cSMauro Carvalho Chehab                struct_group_tagged(cxl_rcd_regs, rcd_regs,
595*c22aa12cSMauro Carvalho Chehab                    void __iomem *rcd_pcie_cap;
596*c22aa12cSMauro Carvalho Chehab                );
597*c22aa12cSMauro Carvalho Chehab            };
598*c22aa12cSMauro Carvalho Chehab        """
599*c22aa12cSMauro Carvalho Chehab        expected = """
600*c22aa12cSMauro Carvalho Chehab        struct cxl_regs {
601*c22aa12cSMauro Carvalho Chehab            struct cxl_component_regs {
602*c22aa12cSMauro Carvalho Chehab                void __iomem *hdm_decoder;
603*c22aa12cSMauro Carvalho Chehab                void __iomem *ras;
604*c22aa12cSMauro Carvalho Chehab            } component;
605*c22aa12cSMauro Carvalho Chehab
606*c22aa12cSMauro Carvalho Chehab            struct cxl_device_regs {
607*c22aa12cSMauro Carvalho Chehab                void __iomem *status, *mbox, *memdev;
608*c22aa12cSMauro Carvalho Chehab            } device_regs;
609*c22aa12cSMauro Carvalho Chehab
610*c22aa12cSMauro Carvalho Chehab            struct cxl_pmu_regs {
611*c22aa12cSMauro Carvalho Chehab                void __iomem *pmu;
612*c22aa12cSMauro Carvalho Chehab            } pmu_regs;
613*c22aa12cSMauro Carvalho Chehab
614*c22aa12cSMauro Carvalho Chehab            struct cxl_rch_regs {
615*c22aa12cSMauro Carvalho Chehab                void __iomem *dport_aer;
616*c22aa12cSMauro Carvalho Chehab            } rch_regs;
617*c22aa12cSMauro Carvalho Chehab
618*c22aa12cSMauro Carvalho Chehab            struct cxl_rcd_regs {
619*c22aa12cSMauro Carvalho Chehab                void __iomem *rcd_pcie_cap;
620*c22aa12cSMauro Carvalho Chehab            } rcd_regs;
621*c22aa12cSMauro Carvalho Chehab        };
622*c22aa12cSMauro Carvalho Chehab        """
623*c22aa12cSMauro Carvalho Chehab
624*c22aa12cSMauro Carvalho Chehab        result = self.apply_transforms("struct", line)
625*c22aa12cSMauro Carvalho Chehab        self.assertLogicallyEqual(result, expected)
626*c22aa12cSMauro Carvalho Chehab
627*c22aa12cSMauro Carvalho Chehab    def test_struct_group_tagged_with_private(self):
628*c22aa12cSMauro Carvalho Chehab        """
629*c22aa12cSMauro Carvalho Chehab        Replace struct_group_tagged with private, using the same regex
630*c22aa12cSMauro Carvalho Chehab        for the replacement as what happens in xforms_lists.py.
631*c22aa12cSMauro Carvalho Chehab
632*c22aa12cSMauro Carvalho Chehab        As the private removal happens outside NestedGroup class, we manually
633*c22aa12cSMauro Carvalho Chehab        dropped the remaining part of the struct, to simulate what happens
634*c22aa12cSMauro Carvalho Chehab        at kdoc_parser.
635*c22aa12cSMauro Carvalho Chehab
636*c22aa12cSMauro Carvalho Chehab        Taken from include/net/page_pool/types.h
637*c22aa12cSMauro Carvalho Chehab        """
638*c22aa12cSMauro Carvalho Chehab        line = """
639*c22aa12cSMauro Carvalho Chehab            struct page_pool_params {
640*c22aa12cSMauro Carvalho Chehab                struct_group_tagged(page_pool_params_slow, slow,
641*c22aa12cSMauro Carvalho Chehab                                    struct net_device *netdev;
642*c22aa12cSMauro Carvalho Chehab                                    unsigned int queue_idx;
643*c22aa12cSMauro Carvalho Chehab                                    unsigned int    flags;
644*c22aa12cSMauro Carvalho Chehab                                    /* private: only under "slow" struct */
645*c22aa12cSMauro Carvalho Chehab                                    unsigned int ignored;
646*c22aa12cSMauro Carvalho Chehab                );
647*c22aa12cSMauro Carvalho Chehab                /* Struct below shall not be ignored */
648*c22aa12cSMauro Carvalho Chehab                struct_group_tagged(page_pool_params_fast, fast,
649*c22aa12cSMauro Carvalho Chehab                                    unsigned int    order;
650*c22aa12cSMauro Carvalho Chehab                                    unsigned int    pool_size;
651*c22aa12cSMauro Carvalho Chehab                                    int             nid;
652*c22aa12cSMauro Carvalho Chehab                                    struct device   *dev;
653*c22aa12cSMauro Carvalho Chehab                                    struct napi_struct *napi;
654*c22aa12cSMauro Carvalho Chehab                                    enum dma_data_direction dma_dir;
655*c22aa12cSMauro Carvalho Chehab                                    unsigned int    max_len;
656*c22aa12cSMauro Carvalho Chehab                                    unsigned int    offset;
657*c22aa12cSMauro Carvalho Chehab                );
658*c22aa12cSMauro Carvalho Chehab            };
659*c22aa12cSMauro Carvalho Chehab        """
660*c22aa12cSMauro Carvalho Chehab        expected = """
661*c22aa12cSMauro Carvalho Chehab            struct page_pool_params {
662*c22aa12cSMauro Carvalho Chehab                struct page_pool_params_slow {
663*c22aa12cSMauro Carvalho Chehab                    struct net_device *netdev;
664*c22aa12cSMauro Carvalho Chehab                    unsigned int queue_idx;
665*c22aa12cSMauro Carvalho Chehab                    unsigned int    flags;
666*c22aa12cSMauro Carvalho Chehab                } slow;
667*c22aa12cSMauro Carvalho Chehab                struct page_pool_params_fast {
668*c22aa12cSMauro Carvalho Chehab                    unsigned int order;
669*c22aa12cSMauro Carvalho Chehab                    unsigned int    pool_size;
670*c22aa12cSMauro Carvalho Chehab                    int             nid;
671*c22aa12cSMauro Carvalho Chehab                    struct device   *dev;
672*c22aa12cSMauro Carvalho Chehab                    struct napi_struct *napi;
673*c22aa12cSMauro Carvalho Chehab                    enum dma_data_direction dma_dir;
674*c22aa12cSMauro Carvalho Chehab                    unsigned int    max_len;
675*c22aa12cSMauro Carvalho Chehab                    unsigned int    offset;
676*c22aa12cSMauro Carvalho Chehab                } fast;
677*c22aa12cSMauro Carvalho Chehab            };
678*c22aa12cSMauro Carvalho Chehab        """
679*c22aa12cSMauro Carvalho Chehab
680*c22aa12cSMauro Carvalho Chehab        result = self.apply_transforms("struct", line)
681*c22aa12cSMauro Carvalho Chehab        self.assertLogicallyEqual(result, expected)
682*c22aa12cSMauro Carvalho Chehab
683*c22aa12cSMauro Carvalho Chehab    def test_struct_kcov(self):
684*c22aa12cSMauro Carvalho Chehab        """
685*c22aa12cSMauro Carvalho Chehab        """
686*c22aa12cSMauro Carvalho Chehab        line = """
687*c22aa12cSMauro Carvalho Chehab            struct kcov {
688*c22aa12cSMauro Carvalho Chehab                refcount_t              refcount;
689*c22aa12cSMauro Carvalho Chehab                spinlock_t              lock;
690*c22aa12cSMauro Carvalho Chehab                enum kcov_mode          mode __guarded_by(&lock);
691*c22aa12cSMauro Carvalho Chehab                unsigned int            size __guarded_by(&lock);
692*c22aa12cSMauro Carvalho Chehab                void                    *area __guarded_by(&lock);
693*c22aa12cSMauro Carvalho Chehab                struct task_struct      *t __guarded_by(&lock);
694*c22aa12cSMauro Carvalho Chehab                bool                    remote;
695*c22aa12cSMauro Carvalho Chehab                unsigned int            remote_size;
696*c22aa12cSMauro Carvalho Chehab                int                     sequence;
697*c22aa12cSMauro Carvalho Chehab            };
698*c22aa12cSMauro Carvalho Chehab        """
699*c22aa12cSMauro Carvalho Chehab        expected = """
700*c22aa12cSMauro Carvalho Chehab        """
701*c22aa12cSMauro Carvalho Chehab
702*c22aa12cSMauro Carvalho Chehab        result = self.apply_transforms("struct", line)
703*c22aa12cSMauro Carvalho Chehab        self.assertLogicallyEqual(result, expected)
704*c22aa12cSMauro Carvalho Chehab
705*c22aa12cSMauro Carvalho Chehab
706*c22aa12cSMauro Carvalho Chehab    def test_struct_kcov(self):
707*c22aa12cSMauro Carvalho Chehab        """
708*c22aa12cSMauro Carvalho Chehab        Test a struct from kernel/kcov.c.
709*c22aa12cSMauro Carvalho Chehab        """
710*c22aa12cSMauro Carvalho Chehab        line = """
711*c22aa12cSMauro Carvalho Chehab            struct kcov {
712*c22aa12cSMauro Carvalho Chehab                refcount_t              refcount;
713*c22aa12cSMauro Carvalho Chehab                spinlock_t              lock;
714*c22aa12cSMauro Carvalho Chehab                enum kcov_mode          mode __guarded_by(&lock);
715*c22aa12cSMauro Carvalho Chehab                unsigned int            size __guarded_by(&lock);
716*c22aa12cSMauro Carvalho Chehab                void                    *area __guarded_by(&lock);
717*c22aa12cSMauro Carvalho Chehab                struct task_struct      *t __guarded_by(&lock);
718*c22aa12cSMauro Carvalho Chehab                bool                    remote;
719*c22aa12cSMauro Carvalho Chehab                unsigned int            remote_size;
720*c22aa12cSMauro Carvalho Chehab                int                     sequence;
721*c22aa12cSMauro Carvalho Chehab            };
722*c22aa12cSMauro Carvalho Chehab        """
723*c22aa12cSMauro Carvalho Chehab        expected = """
724*c22aa12cSMauro Carvalho Chehab            struct kcov {
725*c22aa12cSMauro Carvalho Chehab                refcount_t              refcount;
726*c22aa12cSMauro Carvalho Chehab                spinlock_t              lock;
727*c22aa12cSMauro Carvalho Chehab                enum kcov_mode          mode;
728*c22aa12cSMauro Carvalho Chehab                unsigned int            size;
729*c22aa12cSMauro Carvalho Chehab                void                    *area;
730*c22aa12cSMauro Carvalho Chehab                struct task_struct      *t;
731*c22aa12cSMauro Carvalho Chehab                bool                    remote;
732*c22aa12cSMauro Carvalho Chehab                unsigned int            remote_size;
733*c22aa12cSMauro Carvalho Chehab                int                     sequence;
734*c22aa12cSMauro Carvalho Chehab            };
735*c22aa12cSMauro Carvalho Chehab        """
736*c22aa12cSMauro Carvalho Chehab
737*c22aa12cSMauro Carvalho Chehab        result = self.apply_transforms("struct", line)
738*c22aa12cSMauro Carvalho Chehab        self.assertLogicallyEqual(result, expected)
739*c22aa12cSMauro Carvalho Chehab
740*c22aa12cSMauro Carvalho Chehab    def test_vars_stackdepot(self):
741*c22aa12cSMauro Carvalho Chehab        """
742*c22aa12cSMauro Carvalho Chehab        Test guarded_by on vars from lib/stackdepot.c.
743*c22aa12cSMauro Carvalho Chehab        """
744*c22aa12cSMauro Carvalho Chehab        line = """
745*c22aa12cSMauro Carvalho Chehab            size_t pool_offset __guarded_by(&pool_lock) = DEPOT_POOL_SIZE;
746*c22aa12cSMauro Carvalho Chehab            __guarded_by(&pool_lock) LIST_HEAD(free_stacks);
747*c22aa12cSMauro Carvalho Chehab            void **stack_pools __pt_guarded_by(&pool_lock);
748*c22aa12cSMauro Carvalho Chehab        """
749*c22aa12cSMauro Carvalho Chehab        expected = """
750*c22aa12cSMauro Carvalho Chehab            size_t pool_offset = DEPOT_POOL_SIZE;
751*c22aa12cSMauro Carvalho Chehab            struct list_head free_stacks;
752*c22aa12cSMauro Carvalho Chehab            void **stack_pools;
753*c22aa12cSMauro Carvalho Chehab        """
754*c22aa12cSMauro Carvalho Chehab
755*c22aa12cSMauro Carvalho Chehab        result = self.apply_transforms("var", line)
756*c22aa12cSMauro Carvalho Chehab        self.assertLogicallyEqual(result, expected)
757*c22aa12cSMauro Carvalho Chehab
758*c22aa12cSMauro Carvalho Chehab    def test_functions_with_acquires_and_releases(self):
759*c22aa12cSMauro Carvalho Chehab        """
760*c22aa12cSMauro Carvalho Chehab        Test guarded_by on vars from lib/stackdepot.c.
761*c22aa12cSMauro Carvalho Chehab        """
762*c22aa12cSMauro Carvalho Chehab        line = """
763*c22aa12cSMauro Carvalho Chehab            bool prepare_report_consumer(unsigned long *flags,
764*c22aa12cSMauro Carvalho Chehab                                         const struct access_info *ai,
765*c22aa12cSMauro Carvalho Chehab                                         struct other_info *other_info) \
766*c22aa12cSMauro Carvalho Chehab                                        __cond_acquires(true, &report_lock);
767*c22aa12cSMauro Carvalho Chehab
768*c22aa12cSMauro Carvalho Chehab            int tcp_sigpool_start(unsigned int id, struct tcp_sigpool *c) \
769*c22aa12cSMauro Carvalho Chehab                                  __cond_acquires(0, RCU_BH);
770*c22aa12cSMauro Carvalho Chehab
771*c22aa12cSMauro Carvalho Chehab            bool undo_report_consumer(unsigned long *flags,
772*c22aa12cSMauro Carvalho Chehab                                      const struct access_info *ai,
773*c22aa12cSMauro Carvalho Chehab                                      struct other_info *other_info) \
774*c22aa12cSMauro Carvalho Chehab                                     __cond_releases(true, &report_lock);
775*c22aa12cSMauro Carvalho Chehab
776*c22aa12cSMauro Carvalho Chehab            void debugfs_enter_cancellation(struct file *file,
777*c22aa12cSMauro Carvalho Chehab                                            struct debugfs_cancellation *c) \
778*c22aa12cSMauro Carvalho Chehab                                           __acquires(cancellation);
779*c22aa12cSMauro Carvalho Chehab
780*c22aa12cSMauro Carvalho Chehab            void debugfs_leave_cancellation(struct file *file,
781*c22aa12cSMauro Carvalho Chehab                                            struct debugfs_cancellation *c) \
782*c22aa12cSMauro Carvalho Chehab                                           __releases(cancellation);
783*c22aa12cSMauro Carvalho Chehab
784*c22aa12cSMauro Carvalho Chehab            acpi_cpu_flags acpi_os_acquire_lock(acpi_spinlock lockp) \
785*c22aa12cSMauro Carvalho Chehab                                               __acquires(lockp);
786*c22aa12cSMauro Carvalho Chehab
787*c22aa12cSMauro Carvalho Chehab            void acpi_os_release_lock(acpi_spinlock lockp,
788*c22aa12cSMauro Carvalho Chehab                                      acpi_cpu_flags not_used) \
789*c22aa12cSMauro Carvalho Chehab                                     __releases(lockp)
790*c22aa12cSMauro Carvalho Chehab        """
791*c22aa12cSMauro Carvalho Chehab        expected = """
792*c22aa12cSMauro Carvalho Chehab            bool prepare_report_consumer(unsigned long *flags,
793*c22aa12cSMauro Carvalho Chehab                                         const struct access_info *ai,
794*c22aa12cSMauro Carvalho Chehab                                         struct other_info *other_info);
795*c22aa12cSMauro Carvalho Chehab
796*c22aa12cSMauro Carvalho Chehab            int tcp_sigpool_start(unsigned int id, struct tcp_sigpool *c);
797*c22aa12cSMauro Carvalho Chehab
798*c22aa12cSMauro Carvalho Chehab            bool undo_report_consumer(unsigned long *flags,
799*c22aa12cSMauro Carvalho Chehab                                      const struct access_info *ai,
800*c22aa12cSMauro Carvalho Chehab                                      struct other_info *other_info);
801*c22aa12cSMauro Carvalho Chehab
802*c22aa12cSMauro Carvalho Chehab            void debugfs_enter_cancellation(struct file *file,
803*c22aa12cSMauro Carvalho Chehab                                            struct debugfs_cancellation *c);
804*c22aa12cSMauro Carvalho Chehab
805*c22aa12cSMauro Carvalho Chehab            void debugfs_leave_cancellation(struct file *file,
806*c22aa12cSMauro Carvalho Chehab                                            struct debugfs_cancellation *c);
807*c22aa12cSMauro Carvalho Chehab
808*c22aa12cSMauro Carvalho Chehab            acpi_cpu_flags acpi_os_acquire_lock(acpi_spinlock lockp);
809*c22aa12cSMauro Carvalho Chehab
810*c22aa12cSMauro Carvalho Chehab            void acpi_os_release_lock(acpi_spinlock lockp,
811*c22aa12cSMauro Carvalho Chehab                                      acpi_cpu_flags not_used)
812*c22aa12cSMauro Carvalho Chehab        """
813*c22aa12cSMauro Carvalho Chehab
814*c22aa12cSMauro Carvalho Chehab        result = self.apply_transforms("func", line)
815*c22aa12cSMauro Carvalho Chehab        self.assertLogicallyEqual(result, expected)
816*c22aa12cSMauro Carvalho Chehab
817*c22aa12cSMauro Carvalho Chehab#
81850b87bb4SMauro Carvalho Chehab# Run all tests
81950b87bb4SMauro Carvalho Chehab#
82050b87bb4SMauro Carvalho Chehabif __name__ == "__main__":
82150b87bb4SMauro Carvalho Chehab    run_unittest(__file__)
822