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