Linux kernel mirror (for testing)
git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel
os
linux
1#!/usr/bin/env python3
2# SPDX-License-Identifier: GPL-2.0
3# Copyright(c) 2026: Mauro Carvalho Chehab <mchehab@kernel.org>.
4
5import os
6
7from kdoc.kdoc_output import ManFormat, RestFormat
8
9
10class KDocTestFile():
11 """
12 Handles the logic needed to store kernel‑doc output inside a YAML file.
13 Useful for unit tests and regression tests.
14 """
15
16 def __init__(self, config, yaml_file, yaml_content):
17 #
18 # Bail out early if yaml is not available
19 #
20 try:
21 import yaml
22 except ImportError:
23 sys.exit("Warning: yaml package not available. Aborting it.")
24
25 self.config = config
26 self.test_file = os.path.expanduser(yaml_file)
27 self.yaml_content = yaml_content
28 self.test_names = set()
29
30 self.tests = []
31
32 out_dir = os.path.dirname(self.test_file)
33 if out_dir and not os.path.isdir(out_dir):
34 sys.exit(f"Directory {out_dir} doesn't exist.")
35
36 self.out_style = []
37
38 if "man" in self.yaml_content:
39 out_style = ManFormat()
40 out_style.set_config(self.config)
41
42 self.out_style.append(out_style)
43
44 if "rst" in self.yaml_content:
45 out_style = RestFormat()
46 out_style.set_config(self.config)
47
48 self.out_style.append(out_style)
49
50 def set_filter(self, export, internal, symbol, nosymbol,
51 function_table, enable_lineno, no_doc_sections):
52 """
53 Set filters at the output classes.
54 """
55 for out_style in self.out_style:
56 out_style.set_filter(export, internal, symbol,
57 nosymbol, function_table,
58 enable_lineno, no_doc_sections)
59
60 @staticmethod
61 def get_kdoc_item(arg, start_line=1):
62
63 d = vars(arg)
64
65 declaration_start_line = d.get("declaration_start_line")
66 if not declaration_start_line:
67 return d
68
69 d["declaration_start_line"] = start_line
70
71 parameterdesc_start_lines = d.get("parameterdesc_start_lines")
72 if parameterdesc_start_lines:
73 for key in parameterdesc_start_lines:
74 ln = parameterdesc_start_lines[key]
75 ln += start_line - declaration_start_line
76
77 parameterdesc_start_lines[key] = ln
78
79 sections_start_lines = d.get("sections_start_lines")
80 if sections_start_lines:
81 for key in sections_start_lines:
82 ln = sections_start_lines[key]
83 ln += start_line - declaration_start_line
84
85 sections_start_lines[key] = ln
86
87 return d
88
89 def output_symbols(self, fname, symbols):
90 """
91 Store source, symbols and output strings at self.tests.
92 """
93
94 #
95 # KdocItem needs to be converted into dicts
96 #
97 kdoc_item = []
98 expected = []
99
100 #
101 # Source code didn't produce any symbol
102 #
103 if not symbols:
104 return
105
106 expected_dict = {}
107 start_line=1
108
109 for arg in symbols:
110 source = arg.get("source", "")
111
112 if arg and "KdocItem" in self.yaml_content:
113 msg = self.get_kdoc_item(arg)
114
115 other_stuff = msg.get("other_stuff", {})
116 if "source" in other_stuff:
117 del other_stuff["source"]
118
119 expected_dict["kdoc_item"] = msg
120
121 base_name = arg.name
122 if not base_name:
123 base_name = fname
124 base_name = base_name.lower().replace(".", "_").replace("/", "_")
125
126
127 # Don't add duplicated names
128 i = 0
129 name = base_name
130 while name in self.test_names:
131 i += 1
132 name = f"{base_name}_{i:03d}"
133
134 self.test_names.add(name)
135
136 for out_style in self.out_style:
137 if isinstance(out_style, ManFormat):
138 key = "man"
139 else:
140 key = "rst"
141
142 expected_dict[key]= out_style.output_symbols(fname, [arg]).strip()
143
144 test = {
145 "name": name,
146 "description": f"{fname} line {arg.declaration_start_line}",
147 "fname": fname,
148 "source": source,
149 "expected": [expected_dict]
150 }
151
152 self.tests.append(test)
153
154 expected_dict = {}
155
156 def write(self):
157 """
158 Output the content of self.tests to self.test_file.
159 """
160 import yaml
161
162 # Helper function to better handle multilines
163 def str_presenter(dumper, data):
164 if "\n" in data:
165 return dumper.represent_scalar("tag:yaml.org,2002:str", data, style="|")
166
167 return dumper.represent_scalar("tag:yaml.org,2002:str", data)
168
169 # Register the representer
170 yaml.add_representer(str, str_presenter)
171
172 data = {"tests": self.tests}
173
174 with open(self.test_file, "w", encoding="utf-8") as fp:
175 yaml.dump(data, fp,
176 sort_keys=False, width=120, indent=2,
177 default_flow_style=False, allow_unicode=True,
178 explicit_start=False, explicit_end=False)