xref: /linux/tools/lib/python/kdoc/kdoc_yaml_file.py (revision b37b3cbbb1f1a99bc8b95d9f00fcf887c27f4770)
1*b37b3cbbSMauro Carvalho Chehab#!/usr/bin/env python3
2*b37b3cbbSMauro Carvalho Chehab# SPDX-License-Identifier: GPL-2.0
3*b37b3cbbSMauro Carvalho Chehab# Copyright(c) 2026: Mauro Carvalho Chehab <mchehab@kernel.org>.
4*b37b3cbbSMauro Carvalho Chehab
5*b37b3cbbSMauro Carvalho Chehabimport os
6*b37b3cbbSMauro Carvalho Chehab
7*b37b3cbbSMauro Carvalho Chehabfrom kdoc.kdoc_output import ManFormat, RestFormat
8*b37b3cbbSMauro Carvalho Chehab
9*b37b3cbbSMauro Carvalho Chehab
10*b37b3cbbSMauro Carvalho Chehabclass KDocTestFile():
11*b37b3cbbSMauro Carvalho Chehab    """
12*b37b3cbbSMauro Carvalho Chehab    Handles the logic needed to store kernel‑doc output inside a YAML file.
13*b37b3cbbSMauro Carvalho Chehab     Useful for unit tests and regression tests.
14*b37b3cbbSMauro Carvalho Chehab    """
15*b37b3cbbSMauro Carvalho Chehab
16*b37b3cbbSMauro Carvalho Chehab    def __init__(self, config, yaml_file, yaml_content):
17*b37b3cbbSMauro Carvalho Chehab        #
18*b37b3cbbSMauro Carvalho Chehab        # Bail out early if yaml is not available
19*b37b3cbbSMauro Carvalho Chehab        #
20*b37b3cbbSMauro Carvalho Chehab        try:
21*b37b3cbbSMauro Carvalho Chehab            import yaml
22*b37b3cbbSMauro Carvalho Chehab        except ImportError:
23*b37b3cbbSMauro Carvalho Chehab            sys.exit("Warning: yaml package not available. Aborting it.")
24*b37b3cbbSMauro Carvalho Chehab
25*b37b3cbbSMauro Carvalho Chehab        self.config = config
26*b37b3cbbSMauro Carvalho Chehab        self.test_file = os.path.expanduser(yaml_file)
27*b37b3cbbSMauro Carvalho Chehab        self.yaml_content = yaml_content
28*b37b3cbbSMauro Carvalho Chehab
29*b37b3cbbSMauro Carvalho Chehab        self.tests = []
30*b37b3cbbSMauro Carvalho Chehab
31*b37b3cbbSMauro Carvalho Chehab        out_dir = os.path.dirname(self.test_file)
32*b37b3cbbSMauro Carvalho Chehab        if out_dir and not os.path.isdir(out_dir):
33*b37b3cbbSMauro Carvalho Chehab            sys.exit(f"Directory {out_dir} doesn't exist.")
34*b37b3cbbSMauro Carvalho Chehab
35*b37b3cbbSMauro Carvalho Chehab        self.out_style = []
36*b37b3cbbSMauro Carvalho Chehab
37*b37b3cbbSMauro Carvalho Chehab        if "man" in self.yaml_content:
38*b37b3cbbSMauro Carvalho Chehab            out_style = ManFormat()
39*b37b3cbbSMauro Carvalho Chehab            out_style.set_config(self.config)
40*b37b3cbbSMauro Carvalho Chehab
41*b37b3cbbSMauro Carvalho Chehab            self.out_style.append(out_style)
42*b37b3cbbSMauro Carvalho Chehab
43*b37b3cbbSMauro Carvalho Chehab        if "rst" in self.yaml_content:
44*b37b3cbbSMauro Carvalho Chehab            out_style = RestFormat()
45*b37b3cbbSMauro Carvalho Chehab            out_style.set_config(self.config)
46*b37b3cbbSMauro Carvalho Chehab
47*b37b3cbbSMauro Carvalho Chehab            self.out_style.append(out_style)
48*b37b3cbbSMauro Carvalho Chehab
49*b37b3cbbSMauro Carvalho Chehab    def set_filter(self, export, internal, symbol, nosymbol,
50*b37b3cbbSMauro Carvalho Chehab                   function_table, enable_lineno, no_doc_sections):
51*b37b3cbbSMauro Carvalho Chehab        """
52*b37b3cbbSMauro Carvalho Chehab        Set filters at the output classes.
53*b37b3cbbSMauro Carvalho Chehab        """
54*b37b3cbbSMauro Carvalho Chehab        for out_style in self.out_style:
55*b37b3cbbSMauro Carvalho Chehab            out_style.set_filter(export, internal, symbol,
56*b37b3cbbSMauro Carvalho Chehab                                 nosymbol, function_table,
57*b37b3cbbSMauro Carvalho Chehab                                 enable_lineno, no_doc_sections)
58*b37b3cbbSMauro Carvalho Chehab
59*b37b3cbbSMauro Carvalho Chehab    @staticmethod
60*b37b3cbbSMauro Carvalho Chehab    def get_kdoc_item(arg, start_line=1):
61*b37b3cbbSMauro Carvalho Chehab
62*b37b3cbbSMauro Carvalho Chehab        d = vars(arg)
63*b37b3cbbSMauro Carvalho Chehab
64*b37b3cbbSMauro Carvalho Chehab        declaration_start_line = d.get("declaration_start_line")
65*b37b3cbbSMauro Carvalho Chehab        if not declaration_start_line:
66*b37b3cbbSMauro Carvalho Chehab            return d
67*b37b3cbbSMauro Carvalho Chehab
68*b37b3cbbSMauro Carvalho Chehab        d["declaration_start_line"] = start_line
69*b37b3cbbSMauro Carvalho Chehab
70*b37b3cbbSMauro Carvalho Chehab        parameterdesc_start_lines = d.get("parameterdesc_start_lines")
71*b37b3cbbSMauro Carvalho Chehab        if parameterdesc_start_lines:
72*b37b3cbbSMauro Carvalho Chehab            for key in parameterdesc_start_lines:
73*b37b3cbbSMauro Carvalho Chehab                ln = parameterdesc_start_lines[key]
74*b37b3cbbSMauro Carvalho Chehab                ln += start_line - declaration_start_line
75*b37b3cbbSMauro Carvalho Chehab
76*b37b3cbbSMauro Carvalho Chehab                parameterdesc_start_lines[key] = ln
77*b37b3cbbSMauro Carvalho Chehab
78*b37b3cbbSMauro Carvalho Chehab        sections_start_lines = d.get("sections_start_lines")
79*b37b3cbbSMauro Carvalho Chehab        if sections_start_lines:
80*b37b3cbbSMauro Carvalho Chehab            for key in sections_start_lines:
81*b37b3cbbSMauro Carvalho Chehab                ln = sections_start_lines[key]
82*b37b3cbbSMauro Carvalho Chehab                ln += start_line - declaration_start_line
83*b37b3cbbSMauro Carvalho Chehab
84*b37b3cbbSMauro Carvalho Chehab                sections_start_lines[key] = ln
85*b37b3cbbSMauro Carvalho Chehab
86*b37b3cbbSMauro Carvalho Chehab        return d
87*b37b3cbbSMauro Carvalho Chehab
88*b37b3cbbSMauro Carvalho Chehab    def output_symbols(self, fname, symbols, source):
89*b37b3cbbSMauro Carvalho Chehab        """
90*b37b3cbbSMauro Carvalho Chehab        Store source, symbols and output strings at self.tests.
91*b37b3cbbSMauro Carvalho Chehab        """
92*b37b3cbbSMauro Carvalho Chehab
93*b37b3cbbSMauro Carvalho Chehab        #
94*b37b3cbbSMauro Carvalho Chehab        # KdocItem needs to be converted into dicts
95*b37b3cbbSMauro Carvalho Chehab        #
96*b37b3cbbSMauro Carvalho Chehab        kdoc_item = []
97*b37b3cbbSMauro Carvalho Chehab        expected = []
98*b37b3cbbSMauro Carvalho Chehab
99*b37b3cbbSMauro Carvalho Chehab        if not symbols and not source:
100*b37b3cbbSMauro Carvalho Chehab            return
101*b37b3cbbSMauro Carvalho Chehab
102*b37b3cbbSMauro Carvalho Chehab        if not source or len(symbols) != len(source):
103*b37b3cbbSMauro Carvalho Chehab            print(f"Warning: lengths are different. Ignoring {fname}")
104*b37b3cbbSMauro Carvalho Chehab
105*b37b3cbbSMauro Carvalho Chehab            # Folding without line numbers is too hard.
106*b37b3cbbSMauro Carvalho Chehab            # The right thing to do here to proceed would be to delete
107*b37b3cbbSMauro Carvalho Chehab            # not-handled source blocks, as len(source) should be bigger
108*b37b3cbbSMauro Carvalho Chehab            # than len(symbols)
109*b37b3cbbSMauro Carvalho Chehab            return
110*b37b3cbbSMauro Carvalho Chehab
111*b37b3cbbSMauro Carvalho Chehab        base_name = "test_" + fname.replace(".", "_").replace("/", "_")
112*b37b3cbbSMauro Carvalho Chehab        expected_dict = {}
113*b37b3cbbSMauro Carvalho Chehab        start_line=1
114*b37b3cbbSMauro Carvalho Chehab
115*b37b3cbbSMauro Carvalho Chehab        for i in range(0, len(symbols)):
116*b37b3cbbSMauro Carvalho Chehab            arg = symbols[i]
117*b37b3cbbSMauro Carvalho Chehab
118*b37b3cbbSMauro Carvalho Chehab            if "KdocItem" in self.yaml_content:
119*b37b3cbbSMauro Carvalho Chehab                msg = self.get_kdoc_item(arg)
120*b37b3cbbSMauro Carvalho Chehab
121*b37b3cbbSMauro Carvalho Chehab                expected_dict["kdoc_item"] = msg
122*b37b3cbbSMauro Carvalho Chehab
123*b37b3cbbSMauro Carvalho Chehab            for out_style in self.out_style:
124*b37b3cbbSMauro Carvalho Chehab                if isinstance(out_style, ManFormat):
125*b37b3cbbSMauro Carvalho Chehab                    key = "man"
126*b37b3cbbSMauro Carvalho Chehab                else:
127*b37b3cbbSMauro Carvalho Chehab                    key = "rst"
128*b37b3cbbSMauro Carvalho Chehab
129*b37b3cbbSMauro Carvalho Chehab                expected_dict[key]= out_style.output_symbols(fname, [arg])
130*b37b3cbbSMauro Carvalho Chehab
131*b37b3cbbSMauro Carvalho Chehab            name = f"{base_name}_{i:03d}"
132*b37b3cbbSMauro Carvalho Chehab
133*b37b3cbbSMauro Carvalho Chehab            test = {
134*b37b3cbbSMauro Carvalho Chehab                "name": name,
135*b37b3cbbSMauro Carvalho Chehab                "description": f"{fname} line {source[i]["ln"]}",
136*b37b3cbbSMauro Carvalho Chehab                "fname": fname,
137*b37b3cbbSMauro Carvalho Chehab                "source": source[i]["data"],
138*b37b3cbbSMauro Carvalho Chehab                "expected": [expected_dict]
139*b37b3cbbSMauro Carvalho Chehab            }
140*b37b3cbbSMauro Carvalho Chehab
141*b37b3cbbSMauro Carvalho Chehab            self.tests.append(test)
142*b37b3cbbSMauro Carvalho Chehab
143*b37b3cbbSMauro Carvalho Chehab            expected_dict = {}
144*b37b3cbbSMauro Carvalho Chehab
145*b37b3cbbSMauro Carvalho Chehab    def write(self):
146*b37b3cbbSMauro Carvalho Chehab        """
147*b37b3cbbSMauro Carvalho Chehab        Output the content of self.tests to self.test_file.
148*b37b3cbbSMauro Carvalho Chehab        """
149*b37b3cbbSMauro Carvalho Chehab        import yaml
150*b37b3cbbSMauro Carvalho Chehab
151*b37b3cbbSMauro Carvalho Chehab        data = {"tests": self.tests}
152*b37b3cbbSMauro Carvalho Chehab
153*b37b3cbbSMauro Carvalho Chehab        with open(self.test_file, "w", encoding="utf-8") as fp:
154*b37b3cbbSMauro Carvalho Chehab            yaml.safe_dump(data, fp, sort_keys=False, default_style="|",
155*b37b3cbbSMauro Carvalho Chehab                           default_flow_style=False, allow_unicode=True)
156