xref: /linux/tools/unittests/test_tokenizer.py (revision fe79f85fc85691b64db1997a3b1a2df5d6d378ae)
1#!/usr/bin/env python3
2
3"""
4Unit tests for struct/union member extractor class.
5"""
6
7
8import os
9import re
10import unittest
11import sys
12
13from unittest.mock import MagicMock
14
15SRC_DIR = os.path.dirname(os.path.realpath(__file__))
16sys.path.insert(0, os.path.join(SRC_DIR, "../lib/python"))
17
18from kdoc.c_lex import CTokenizer
19from unittest_helper import run_unittest
20
21
22#
23# List of tests.
24#
25# The code will dynamically generate one test for each key on this dictionary.
26#
27
28def make_private_test(name, data):
29    """
30    Create a test named ``name`` using parameters given by ``data`` dict.
31    """
32
33    def test(self):
34        """In-lined lambda-like function to run the test"""
35        tokens = CTokenizer(data["source"])
36        result = str(tokens)
37
38        #
39        # Avoid whitespace false positives
40        #
41        result = re.sub(r"\s++", " ", result).strip()
42        expected = re.sub(r"\s++", " ", data["trimmed"]).strip()
43
44        msg = f"failed when parsing this source:\n{data['source']}"
45        self.assertEqual(result, expected, msg=msg)
46
47    return test
48
49#: Tests to check if CTokenizer is handling properly public/private comments.
50TESTS_PRIVATE = {
51    #
52    # Simplest case: no private. Ensure that trimming won't affect struct
53    #
54    "__run__": make_private_test,
55    "no private": {
56        "source": """
57            struct foo {
58                int a;
59                int b;
60                int c;
61            };
62        """,
63        "trimmed": """
64            struct foo {
65                int a;
66                int b;
67                int c;
68            };
69        """,
70    },
71
72    #
73    # Play "by the books" by always having a public in place
74    #
75
76    "balanced_private": {
77        "source": """
78            struct foo {
79                int a;
80                /* private: */
81                int b;
82                /* public: */
83                int c;
84            };
85        """,
86        "trimmed": """
87            struct foo {
88                int a;
89                int c;
90            };
91        """,
92    },
93
94    "balanced_non_greddy_private": {
95        "source": """
96            struct foo {
97                int a;
98                /* private: */
99                int b;
100                /* public: */
101                int c;
102                /* private: */
103                int d;
104                /* public: */
105                int e;
106
107            };
108        """,
109        "trimmed": """
110            struct foo {
111                int a;
112                int c;
113                int e;
114            };
115        """,
116    },
117
118    "balanced_inner_private": {
119        "source": """
120            struct foo {
121                struct {
122                    int a;
123                    /* private: ignore below */
124                    int b;
125                /* public: but this should not be ignored */
126                };
127                int b;
128            };
129        """,
130        "trimmed": """
131            struct foo {
132                struct {
133                    int a;
134                };
135                int b;
136            };
137        """,
138    },
139
140    #
141    # Test what happens if there's no public after private place
142    #
143
144    "unbalanced_private": {
145        "source": """
146            struct foo {
147                int a;
148                /* private: */
149                int b;
150                int c;
151            };
152        """,
153        "trimmed": """
154            struct foo {
155                int a;
156            };
157        """,
158    },
159
160    "unbalanced_inner_private": {
161        "source": """
162            struct foo {
163                struct {
164                    int a;
165                    /* private: ignore below */
166                    int b;
167                /* but this should not be ignored */
168                };
169                int b;
170            };
171        """,
172        "trimmed": """
173            struct foo {
174                struct {
175                    int a;
176                };
177                int b;
178            };
179        """,
180    },
181
182    "unbalanced_struct_group_tagged_with_private": {
183        "source": """
184            struct page_pool_params {
185                struct_group_tagged(page_pool_params_fast, fast,
186                        unsigned int    order;
187                        unsigned int    pool_size;
188                        int             nid;
189                        struct device   *dev;
190                        struct napi_struct *napi;
191                        enum dma_data_direction dma_dir;
192                        unsigned int    max_len;
193                        unsigned int    offset;
194                };
195                struct_group_tagged(page_pool_params_slow, slow,
196                        struct net_device *netdev;
197                        unsigned int queue_idx;
198                        unsigned int    flags;
199                        /* private: used by test code only */
200                        void (*init_callback)(netmem_ref netmem, void *arg);
201                        void *init_arg;
202                };
203            };
204        """,
205        "trimmed": """
206            struct page_pool_params {
207                struct_group_tagged(page_pool_params_fast, fast,
208                        unsigned int    order;
209                        unsigned int    pool_size;
210                        int             nid;
211                        struct device   *dev;
212                        struct napi_struct *napi;
213                        enum dma_data_direction dma_dir;
214                        unsigned int    max_len;
215                        unsigned int    offset;
216                };
217                struct_group_tagged(page_pool_params_slow, slow,
218                        struct net_device *netdev;
219                        unsigned int queue_idx;
220                        unsigned int    flags;
221                };
222            };
223        """,
224    },
225
226    "unbalanced_two_struct_group_tagged_first_with_private": {
227        "source": """
228            struct page_pool_params {
229                struct_group_tagged(page_pool_params_slow, slow,
230                        struct net_device *netdev;
231                        unsigned int queue_idx;
232                        unsigned int    flags;
233                        /* private: used by test code only */
234                        void (*init_callback)(netmem_ref netmem, void *arg);
235                        void *init_arg;
236                };
237                struct_group_tagged(page_pool_params_fast, fast,
238                        unsigned int    order;
239                        unsigned int    pool_size;
240                        int             nid;
241                        struct device   *dev;
242                        struct napi_struct *napi;
243                        enum dma_data_direction dma_dir;
244                        unsigned int    max_len;
245                        unsigned int    offset;
246                };
247            };
248        """,
249        "trimmed": """
250            struct page_pool_params {
251                struct_group_tagged(page_pool_params_slow, slow,
252                        struct net_device *netdev;
253                        unsigned int queue_idx;
254                        unsigned int    flags;
255                };
256                struct_group_tagged(page_pool_params_fast, fast,
257                        unsigned int    order;
258                        unsigned int    pool_size;
259                        int             nid;
260                        struct device   *dev;
261                        struct napi_struct *napi;
262                        enum dma_data_direction dma_dir;
263                        unsigned int    max_len;
264                        unsigned int    offset;
265                };
266            };
267        """,
268    },
269    "unbalanced_without_end_of_line": {
270        "source": """ \
271            struct page_pool_params { \
272                struct_group_tagged(page_pool_params_slow, slow, \
273                        struct net_device *netdev; \
274                        unsigned int queue_idx; \
275                        unsigned int    flags;
276                        /* private: used by test code only */
277                        void (*init_callback)(netmem_ref netmem, void *arg); \
278                        void *init_arg; \
279                }; \
280                struct_group_tagged(page_pool_params_fast, fast, \
281                        unsigned int    order; \
282                        unsigned int    pool_size; \
283                        int             nid; \
284                        struct device   *dev; \
285                        struct napi_struct *napi; \
286                        enum dma_data_direction dma_dir; \
287                        unsigned int    max_len; \
288                        unsigned int    offset; \
289                }; \
290            };
291        """,
292        "trimmed": """
293            struct page_pool_params {
294                struct_group_tagged(page_pool_params_slow, slow,
295                        struct net_device *netdev;
296                        unsigned int queue_idx;
297                        unsigned int    flags;
298                };
299                struct_group_tagged(page_pool_params_fast, fast,
300                        unsigned int    order;
301                        unsigned int    pool_size;
302                        int             nid;
303                        struct device   *dev;
304                        struct napi_struct *napi;
305                        enum dma_data_direction dma_dir;
306                        unsigned int    max_len;
307                        unsigned int    offset;
308                };
309            };
310        """,
311    },
312}
313
314#: Dict containing all test groups fror CTokenizer
315TESTS = {
316    "TestPublicPrivate": TESTS_PRIVATE,
317}
318
319def setUp(self):
320    self.maxDiff = None
321
322def build_test_class(group_name, table):
323    """
324    Dynamically creates a class instance using type() as a generator
325    for a new class derivated from unittest.TestCase.
326
327    We're opting to do it inside a function to avoid the risk of
328    changing the globals() dictionary.
329    """
330
331    class_dict = {
332        "setUp": setUp
333    }
334
335    run = table["__run__"]
336
337    for test_name, data in table.items():
338        if test_name == "__run__":
339            continue
340
341        class_dict[f"test_{test_name}"] = run(test_name, data)
342
343    cls = type(group_name, (unittest.TestCase,), class_dict)
344
345    return cls.__name__, cls
346
347#
348# Create classes and add them to the global dictionary
349#
350for group, table in TESTS.items():
351    t = build_test_class(group, table)
352    globals()[t[0]] = t[1]
353
354#
355# main
356#
357if __name__ == "__main__":
358    run_unittest(__file__)
359