clang-tools 24.0.0git
check_alphabetical_order_test.py
Go to the documentation of this file.
1# Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
2# See https://llvm.org/LICENSE.txt for license information.
3# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
4
5# To run these tests:
6# python3 check_alphabetical_order_test.py -v
7
8import check_alphabetical_order as _mod
9from contextlib import redirect_stderr
10import io
11import os
12import tempfile
13import textwrap
14from typing import cast
15import unittest
16
17
18class TestAlphabeticalOrderCheck(unittest.TestCase):
20 input_text = textwrap.dedent(
21 """\
22 | Name | Offers fixes |
23 | --- | --- |
24 | {doc}`bugprone-virtual-near-miss <bugprone/virtual-near-miss>` | Yes |
25 | {doc}`cert-flp30-c <cert/flp30-c>` | |
26 | {doc}`abseil-cleanup-ctad <abseil/cleanup-ctad>` | Yes |
27 | A non-doc row that should stay after docs | |
28 """
29 )
30
31 expected_text = textwrap.dedent(
32 """\
33 | Name | Offers fixes |
34 | --- | --- |
35 | {doc}`abseil-cleanup-ctad <abseil/cleanup-ctad>` | Yes |
36 | {doc}`bugprone-virtual-near-miss <bugprone/virtual-near-miss>` | Yes |
37 | {doc}`cert-flp30-c <cert/flp30-c>` | |
38 | A non-doc row that should stay after docs | |
39 """
40 )
41
42 out_str = _mod.normalize_list_md(input_text)
43 self.assertEqual(out_str, expected_text)
44
45 def test_find_heading(self) -> None:
46 text = textwrap.dedent(
47 """\
48 - Deprecated the {program}`clang-tidy` `zircon` module. All checks have been
49 moved to the `fuchsia` module instead. The `zircon` module will be removed
50 in the 24th release.
51
52 #### New checks
53 - New {doc}`bugprone-derived-method-shadowing-base-method
54 <clang-tidy/checks/bugprone/derived-method-shadowing-base-method>` check.
55 """
56 )
57 lines = text.splitlines(True)
58 idx = _mod.find_heading(lines, "New checks")
59 self.assertEqual(idx, 4)
60
62 # Ensure duplicate detection works properly when sorting is incorrect.
63 text = textwrap.dedent(
64 """\
65 #### Changes in existing checks
66
67 - Improved {doc}`bugprone-easily-swappable-parameters
68 <clang-tidy/checks/bugprone/easily-swappable-parameters>` check by
69 correcting a spelling mistake on its option
70 `NamePrefixSuffixSilenceDissimilarityTreshold`.
71
72 - Improved {doc}`bugprone-exception-escape
73 <clang-tidy/checks/bugprone/exception-escape>` check's handling of lambdas:
74 exceptions from captures are now diagnosed, exceptions in the bodies of
75 lambdas that aren't actually invoked are not.
76
77 - Improved {doc}`bugprone-easily-swappable-parameters
78 <clang-tidy/checks/bugprone/easily-swappable-parameters>` check by
79 correcting a spelling mistake on its option
80 `NamePrefixSuffixSilenceDissimilarityTreshold`.
81
82 """
83 )
84 lines = text.splitlines(True)
85 report = _mod._emit_duplicate_report(lines, "Changes in existing checks")
86 self.assertIsNotNone(report)
87 report_str = cast(str, report)
88
89 expected_report = textwrap.dedent(
90 """\
91 Error: Duplicate entries in 'Changes in existing checks'.
92
93 Please merge these entries into a single bullet point.
94
95 -- Duplicate: - Improved {doc}`bugprone-easily-swappable-parameters
96
97 - At line 3:
98 - Improved {doc}`bugprone-easily-swappable-parameters
99 <clang-tidy/checks/bugprone/easily-swappable-parameters>` check by
100 correcting a spelling mistake on its option
101 `NamePrefixSuffixSilenceDissimilarityTreshold`.
102
103 - At line 13:
104 - Improved {doc}`bugprone-easily-swappable-parameters
105 <clang-tidy/checks/bugprone/easily-swappable-parameters>` check by
106 correcting a spelling mistake on its option
107 `NamePrefixSuffixSilenceDissimilarityTreshold`.
108
109 """
110 )
111 self.assertEqual(report_str, expected_report)
112
114 # When content is not normalized, the function writes normalized text and returns 0.
115 rn_text = textwrap.dedent(
116 """\
117 #### New checks
118
119 - New {doc}`readability-redundant-parentheses
120 <clang-tidy/checks/readability/redundant-parentheses>` check.
121
122 Detect redundant parentheses.
123
124 - New {doc}`bugprone-derived-method-shadowing-base-method
125 <clang-tidy/checks/bugprone/derived-method-shadowing-base-method>` check.
126
127 Finds derived class methods that shadow a (non-virtual) base class method.
128
129 """
130 )
131 with tempfile.TemporaryDirectory() as td:
132 rn_doc = os.path.join(td, "ReleaseNotes.md")
133 out_path = os.path.join(td, "out.md")
134 with open(rn_doc, "w", encoding="utf-8") as f:
135 f.write(rn_text)
136
137 buf = io.StringIO()
138 with redirect_stderr(buf):
139 rc = _mod.process_release_notes(out_path, rn_doc)
140
141 self.assertEqual(rc, 0)
142 with open(out_path, "r", encoding="utf-8") as f:
143 out = f.read()
144
145 expected_out = textwrap.dedent(
146 """\
147 #### New checks
148
149 - New {doc}`bugprone-derived-method-shadowing-base-method
150 <clang-tidy/checks/bugprone/derived-method-shadowing-base-method>` check.
151
152 Finds derived class methods that shadow a (non-virtual) base class method.
153
154 - New {doc}`readability-redundant-parentheses
155 <clang-tidy/checks/readability/redundant-parentheses>` check.
156
157 Detect redundant parentheses.
158
159 """
160 )
161
162 self.assertEqual(out, expected_out)
163 self.assertIn("not alphabetically sorted", buf.getvalue())
164
166 # Sorting is incorrect and duplicates exist, should report ordering issues first.
167 rn_text = textwrap.dedent(
168 """\
169 #### Changes in existing checks
170
171 - Improved {doc}`bugprone-easily-swappable-parameters
172 <clang-tidy/checks/bugprone/easily-swappable-parameters>` check by
173 correcting a spelling mistake on its option
174 `NamePrefixSuffixSilenceDissimilarityTreshold`.
175
176 - Improved {doc}`bugprone-exception-escape
177 <clang-tidy/checks/bugprone/exception-escape>` check's handling of lambdas:
178 exceptions from captures are now diagnosed, exceptions in the bodies of
179 lambdas that aren't actually invoked are not.
180
181 - Improved {doc}`bugprone-easily-swappable-parameters
182 <clang-tidy/checks/bugprone/easily-swappable-parameters>` check by
183 correcting a spelling mistake on its option
184 `NamePrefixSuffixSilenceDissimilarityTreshold`.
185
186 """
187 )
188 with tempfile.TemporaryDirectory() as td:
189 rn_doc = os.path.join(td, "ReleaseNotes.md")
190 out_path = os.path.join(td, "out.md")
191 with open(rn_doc, "w", encoding="utf-8") as f:
192 f.write(rn_text)
193
194 buf = io.StringIO()
195 with redirect_stderr(buf):
196 rc = _mod.process_release_notes(out_path, rn_doc)
197 self.assertEqual(rc, 0)
198 self.assertIn(
199 "Entries in 'clang-tools-extra/docs/ReleaseNotes.md' are not alphabetically sorted.",
200 buf.getvalue(),
201 )
202
203 with open(out_path, "r", encoding="utf-8") as f:
204 out = f.read()
205 expected_out = textwrap.dedent(
206 """\
207 #### Changes in existing checks
208
209 - Improved {doc}`bugprone-easily-swappable-parameters
210 <clang-tidy/checks/bugprone/easily-swappable-parameters>` check by
211 correcting a spelling mistake on its option
212 `NamePrefixSuffixSilenceDissimilarityTreshold`.
213
214 - Improved {doc}`bugprone-easily-swappable-parameters
215 <clang-tidy/checks/bugprone/easily-swappable-parameters>` check by
216 correcting a spelling mistake on its option
217 `NamePrefixSuffixSilenceDissimilarityTreshold`.
218
219 - Improved {doc}`bugprone-exception-escape
220 <clang-tidy/checks/bugprone/exception-escape>` check's handling of lambdas:
221 exceptions from captures are now diagnosed, exceptions in the bodies of
222 lambdas that aren't actually invoked are not.
223
224 """
225 )
226 self.assertEqual(out, expected_out)
227
229 # Sorting is already correct but duplicates exist, should return 3 and report.
230 rn_text = textwrap.dedent(
231 """\
232 #### Changes in existing checks
233
234 - Improved {doc}`bugprone-easily-swappable-parameters
235 <clang-tidy/checks/bugprone/easily-swappable-parameters>` check by
236 correcting a spelling mistake on its option
237 `NamePrefixSuffixSilenceDissimilarityTreshold`.
238
239 - Improved {doc}`bugprone-easily-swappable-parameters
240 <clang-tidy/checks/bugprone/easily-swappable-parameters>` check by
241 correcting a spelling mistake on its option
242 `NamePrefixSuffixSilenceDissimilarityTreshold`.
243
244 - Improved {doc}`bugprone-exception-escape
245 <clang-tidy/checks/bugprone/exception-escape>` check's handling of lambdas:
246 exceptions from captures are now diagnosed, exceptions in the bodies of
247 lambdas that aren't actually invoked are not.
248
249 """
250 )
251 with tempfile.TemporaryDirectory() as td:
252 rn_doc = os.path.join(td, "ReleaseNotes.md")
253 out_path = os.path.join(td, "out.md")
254 with open(rn_doc, "w", encoding="utf-8") as f:
255 f.write(rn_text)
256
257 buf = io.StringIO()
258 with redirect_stderr(buf):
259 rc = _mod.process_release_notes(out_path, rn_doc)
260
261 self.assertEqual(rc, 3)
262 expected_report = textwrap.dedent(
263 """\
264 Error: Duplicate entries in 'Changes in existing checks'.
265
266 Please merge these entries into a single bullet point.
267
268 -- Duplicate: - Improved {doc}`bugprone-easily-swappable-parameters
269
270 - At line 3:
271 - Improved {doc}`bugprone-easily-swappable-parameters
272 <clang-tidy/checks/bugprone/easily-swappable-parameters>` check by
273 correcting a spelling mistake on its option
274 `NamePrefixSuffixSilenceDissimilarityTreshold`.
275
276 - At line 8:
277 - Improved {doc}`bugprone-easily-swappable-parameters
278 <clang-tidy/checks/bugprone/easily-swappable-parameters>` check by
279 correcting a spelling mistake on its option
280 `NamePrefixSuffixSilenceDissimilarityTreshold`.
281
282 """
283 )
284 self.assertEqual(buf.getvalue(), expected_report)
285
286 with open(out_path, "r", encoding="utf-8") as f:
287 out = f.read()
288 self.assertEqual(out, rn_text)
289
291 rn_text = textwrap.dedent(
292 """\
293 #### Changes in existing checks
294
295 - Improved {doc}`bugprone-easily-swappable-parameters
296 <clang-tidy/checks/bugprone/easily-swappable-parameters>` check by
297 correcting a spelling mistake on its option
298 `NamePrefixSuffixSilenceDissimilarityTreshold`.
299
300 - Improved {doc}`llvm-prefer-isa-or-dyn-cast-in-conditionals
301 <clang-tidy/checks/llvm/prefer-isa-or-dyn-cast-in-conditionals>` check:
302
303 - Fix-it handles callees with nested-name-specifier correctly.
304
305 - `if` statements with init-statement (`if (auto X = ...; ...)`) are
306 handled correctly.
307
308 - `for` loops are supported.
309
310 - Improved {doc}`bugprone-exception-escape
311 <clang-tidy/checks/bugprone/exception-escape>` check's handling of lambdas:
312 exceptions from captures are now diagnosed, exceptions in the bodies of
313 lambdas that aren't actually invoked are not.
314
315 """
316 )
317
318 out = _mod.normalize_release_notes(rn_text.splitlines(True))
319
320 expected_out = textwrap.dedent(
321 """\
322 #### Changes in existing checks
323
324 - Improved {doc}`bugprone-easily-swappable-parameters
325 <clang-tidy/checks/bugprone/easily-swappable-parameters>` check by
326 correcting a spelling mistake on its option
327 `NamePrefixSuffixSilenceDissimilarityTreshold`.
328
329 - Improved {doc}`bugprone-exception-escape
330 <clang-tidy/checks/bugprone/exception-escape>` check's handling of lambdas:
331 exceptions from captures are now diagnosed, exceptions in the bodies of
332 lambdas that aren't actually invoked are not.
333
334 - Improved {doc}`llvm-prefer-isa-or-dyn-cast-in-conditionals
335 <clang-tidy/checks/llvm/prefer-isa-or-dyn-cast-in-conditionals>` check:
336
337 - Fix-it handles callees with nested-name-specifier correctly.
338
339 - `if` statements with init-statement (`if (auto X = ...; ...)`) are
340 handled correctly.
341
342 - `for` loops are supported.
343
344 """
345 )
346 self.assertEqual(out, expected_out)
347
349 rn_text = textwrap.dedent(
350 """\
351 #### Changes in existing checks
352
353 - Renamed {doc}`performance-faster-string-find
354 <clang-tidy/checks/performance/faster-string-find>` to
355 {doc}`performance-faster-string-operation
356 <clang-tidy/checks/performance/faster-string-operation>`.
357 The `performance-faster-string-find` name is kept as an alias.
358
359 - Renamed {doc}`google-explicit-constructor
360 <clang-tidy/checks/google/explicit-constructor>`
361 to {doc}`misc-explicit-constructor
362 <clang-tidy/checks/misc/explicit-constructor>`. The
363 `google-explicit-constructor`
364 name is kept as an alias.
365
366 """
367 )
368
369 out = _mod.normalize_release_notes(rn_text.splitlines(True))
370
371 expected_out = textwrap.dedent(
372 """\
373 #### Changes in existing checks
374
375 - Renamed {doc}`google-explicit-constructor
376 <clang-tidy/checks/google/explicit-constructor>`
377 to {doc}`misc-explicit-constructor
378 <clang-tidy/checks/misc/explicit-constructor>`. The
379 `google-explicit-constructor`
380 name is kept as an alias.
381
382 - Renamed {doc}`performance-faster-string-find
383 <clang-tidy/checks/performance/faster-string-find>` to
384 {doc}`performance-faster-string-operation
385 <clang-tidy/checks/performance/faster-string-operation>`.
386 The `performance-faster-string-find` name is kept as an alias.
387
388 """
389 )
390 self.assertEqual(out, expected_out)
391
393 list_text = textwrap.dedent(
394 """\
395 | Name | Redirect | Offers fixes |
396 | --- | --- | --- |
397 | {doc}`cert-dcl16-c <cert/dcl16-c>` | {doc}`readability-uppercase-literal-suffix <readability/uppercase-literal-suffix>` | Yes |
398 | {doc}`cert-con36-c <cert/con36-c>` | {doc}`bugprone-spuriously-wake-up-functions <bugprone/spuriously-wake-up-functions>` | |
399 | {doc}`cert-dcl37-c <cert/dcl37-c>` | {doc}`bugprone-reserved-identifier <bugprone/reserved-identifier>` | Yes |
400 | {doc}`cert-arr39-c <cert/arr39-c>` | {doc}`bugprone-sizeof-expression <bugprone/sizeof-expression>` | |
401 """
402 )
403 with tempfile.TemporaryDirectory() as td:
404 in_doc = os.path.join(td, "list.md")
405 out_doc = os.path.join(td, "out.md")
406 with open(in_doc, "w", encoding="utf-8") as f:
407 f.write(list_text)
408 buf = io.StringIO()
409 with redirect_stderr(buf):
410 rc = _mod.process_checks_list(out_doc, in_doc)
411 self.assertEqual(rc, 0)
412 self.assertIn(
413 "Checks in 'clang-tools-extra/docs/clang-tidy/checks/list.md' tables are not alphabetically sorted.",
414 buf.getvalue(),
415 )
416 self.assertEqual(rc, 0)
417 with open(out_doc, "r", encoding="utf-8") as f:
418 out = f.read()
419
420 expected_out = textwrap.dedent(
421 """\
422 | Name | Redirect | Offers fixes |
423 | --- | --- | --- |
424 | {doc}`cert-arr39-c <cert/arr39-c>` | {doc}`bugprone-sizeof-expression <bugprone/sizeof-expression>` | |
425 | {doc}`cert-con36-c <cert/con36-c>` | {doc}`bugprone-spuriously-wake-up-functions <bugprone/spuriously-wake-up-functions>` | |
426 | {doc}`cert-dcl16-c <cert/dcl16-c>` | {doc}`readability-uppercase-literal-suffix <readability/uppercase-literal-suffix>` | Yes |
427 | {doc}`cert-dcl37-c <cert/dcl37-c>` | {doc}`bugprone-reserved-identifier <bugprone/reserved-identifier>` | Yes |
428 """
429 )
430 self.assertEqual(out, expected_out)
431
432
433if __name__ == "__main__":
434 unittest.main()