]> Git Repo - J-u-boot.git/blob - tools/patman/test_checkpatch.py
Merge tag 'mmc-2021-7-30' of https://source.denx.de/u-boot/custodians/u-boot-mmc
[J-u-boot.git] / tools / patman / test_checkpatch.py
1 # -*- coding: utf-8 -*-
2 # SPDX-License-Identifier: GPL-2.0+
3 #
4 # Tests for U-Boot-specific checkpatch.pl features
5 #
6 # Copyright (c) 2011 The Chromium OS Authors.
7 #
8
9 import os
10 import tempfile
11 import unittest
12
13 from patman import checkpatch
14 from patman import gitutil
15 from patman import patchstream
16 from patman import series
17 from patman import commit
18
19
20 class Line:
21     def __init__(self, fname, text):
22         self.fname = fname
23         self.text = text
24
25
26 class PatchMaker:
27     def __init__(self):
28         self.lines = []
29
30     def add_line(self, fname, text):
31         self.lines.append(Line(fname, text))
32
33     def get_patch_text(self):
34         base = '''From 125b77450f4c66b8fd9654319520bbe795c9ef31 Mon Sep 17 00:00:00 2001
35 From: Simon Glass <[email protected]>
36 Date: Sun, 14 Jun 2020 09:45:14 -0600
37 Subject: [PATCH] Test commit
38
39 This is a test commit.
40
41 Signed-off-by: Simon Glass <[email protected]>
42 ---
43
44 '''
45         lines = base.splitlines()
46
47         # Create the diffstat
48         change = 0
49         insert = 0
50         for line in self.lines:
51             lines.append(' %s      | 1 +' % line.fname)
52             change += 1
53             insert += 1
54         lines.append(' %d files changed, %d insertions(+)' % (change, insert))
55         lines.append('')
56
57         # Create the patch info for each file
58         for line in self.lines:
59             lines.append('diff --git a/%s b/%s' % (line.fname, line.fname))
60             lines.append('index 7837d459f18..5ba7840f68e 100644')
61             lines.append('--- a/%s' % line.fname)
62             lines.append('+++ b/%s' % line.fname)
63             lines += ('''@@ -121,6 +121,7 @@ enum uclass_id {
64         UCLASS_W1,              /* Dallas 1-Wire bus */
65         UCLASS_W1_EEPROM,       /* one-wire EEPROMs */
66         UCLASS_WDT,             /* Watchdog Timer driver */
67 +%s
68
69         UCLASS_COUNT,
70         UCLASS_INVALID = -1,
71 ''' % line.text).splitlines()
72         lines.append('---')
73         lines.append('2.17.1')
74
75         return '\n'.join(lines)
76
77     def get_patch(self):
78         inhandle, inname = tempfile.mkstemp()
79         infd = os.fdopen(inhandle, 'w')
80         infd.write(self.get_patch_text())
81         infd.close()
82         return inname
83
84     def run_checkpatch(self):
85         return checkpatch.CheckPatch(self.get_patch(), show_types=True)
86
87
88 class TestPatch(unittest.TestCase):
89     """Test the u_boot_line() function in checkpatch.pl"""
90
91     def testBasic(self):
92         """Test basic filter operation"""
93         data='''
94
95 From 656c9a8c31fa65859d924cd21da920d6ba537fad Mon Sep 17 00:00:00 2001
96 From: Simon Glass <[email protected]>
97 Date: Thu, 28 Apr 2011 09:58:51 -0700
98 Subject: [PATCH (resend) 3/7] Tegra2: Add more clock support
99
100 This adds functions to enable/disable clocks and reset to on-chip peripherals.
101
102 cmd/pci.c:152:11: warning: format ‘%llx’ expects argument of type
103    ‘long long unsigned int’, but argument 3 has type
104    ‘u64 {aka long unsigned int}’ [-Wformat=]
105
106 BUG=chromium-os:13875
107 TEST=build U-Boot for Seaboard, boot
108
109 Change-Id: I80fe1d0c0b7dd10aa58ce5bb1d9290b6664d5413
110
111 Review URL: http://codereview.chromium.org/6900006
112
113 Signed-off-by: Simon Glass <[email protected]>
114 ---
115  arch/arm/cpu/armv7/tegra2/Makefile         |    2 +-
116  arch/arm/cpu/armv7/tegra2/ap20.c           |   57 ++----
117  arch/arm/cpu/armv7/tegra2/clock.c          |  163 +++++++++++++++++
118 '''
119         expected='''Message-Id: <19991231235959.0.I80fe1d0c0b7dd10aa58ce5bb1d9290b6664d5413@changeid>
120
121
122 From 656c9a8c31fa65859d924cd21da920d6ba537fad Mon Sep 17 00:00:00 2001
123 From: Simon Glass <[email protected]>
124 Date: Thu, 28 Apr 2011 09:58:51 -0700
125 Subject: [PATCH (resend) 3/7] Tegra2: Add more clock support
126
127 This adds functions to enable/disable clocks and reset to on-chip peripherals.
128
129 cmd/pci.c:152:11: warning: format ‘%llx’ expects argument of type
130    ‘long long unsigned int’, but argument 3 has type
131    ‘u64 {aka long unsigned int}’ [-Wformat=]
132
133 Signed-off-by: Simon Glass <[email protected]>
134 ---
135
136  arch/arm/cpu/armv7/tegra2/Makefile         |    2 +-
137  arch/arm/cpu/armv7/tegra2/ap20.c           |   57 ++----
138  arch/arm/cpu/armv7/tegra2/clock.c          |  163 +++++++++++++++++
139 '''
140         out = ''
141         inhandle, inname = tempfile.mkstemp()
142         infd = os.fdopen(inhandle, 'w', encoding='utf-8')
143         infd.write(data)
144         infd.close()
145
146         exphandle, expname = tempfile.mkstemp()
147         expfd = os.fdopen(exphandle, 'w', encoding='utf-8')
148         expfd.write(expected)
149         expfd.close()
150
151         # Normally by the time we call fix_patch we've already collected
152         # metadata.  Here, we haven't, but at least fake up something.
153         # Set the "count" to -1 which tells fix_patch to use a bogus/fixed
154         # time for generating the Message-Id.
155         com = commit.Commit('')
156         com.change_id = 'I80fe1d0c0b7dd10aa58ce5bb1d9290b6664d5413'
157         com.count = -1
158
159         patchstream.fix_patch(None, inname, series.Series(), com)
160
161         rc = os.system('diff -u %s %s' % (inname, expname))
162         self.assertEqual(rc, 0)
163
164         os.remove(inname)
165         os.remove(expname)
166
167     def GetData(self, data_type):
168         data='''From 4924887af52713cabea78420eff03badea8f0035 Mon Sep 17 00:00:00 2001
169 From: Simon Glass <[email protected]>
170 Date: Thu, 7 Apr 2011 10:14:41 -0700
171 Subject: [PATCH 1/4] Add microsecond boot time measurement
172
173 This defines the basics of a new boot time measurement feature. This allows
174 logging of very accurate time measurements as the boot proceeds, by using
175 an available microsecond counter.
176
177 %s
178 ---
179  README              |   11 ++++++++
180  MAINTAINERS         |    3 ++
181  common/bootstage.c  |   50 ++++++++++++++++++++++++++++++++++++
182  include/bootstage.h |   71 +++++++++++++++++++++++++++++++++++++++++++++++++++
183  include/common.h    |    8 ++++++
184  5 files changed, 141 insertions(+), 0 deletions(-)
185  create mode 100644 common/bootstage.c
186  create mode 100644 include/bootstage.h
187
188 diff --git a/README b/README
189 index 6f3748d..f9e4e65 100644
190 --- a/README
191 +++ b/README
192 @@ -2026,6 +2026,17 @@ The following options need to be configured:
193                 example, some LED's) on your board. At the moment,
194                 the following checkpoints are implemented:
195
196 +- Time boot progress
197 +               CONFIG_BOOTSTAGE
198 +
199 +               Define this option to enable microsecond boot stage timing
200 +               on supported platforms. For this to work your platform
201 +               needs to define a function timer_get_us() which returns the
202 +               number of microseconds since reset. This would normally
203 +               be done in your SOC or board timer.c file.
204 +
205 +               You can add calls to bootstage_mark() to set time markers.
206 +
207  - Standalone program support:
208                 CONFIG_STANDALONE_LOAD_ADDR
209
210 diff --git a/MAINTAINERS b/MAINTAINERS
211 index b167b028ec..beb7dc634f 100644
212 --- a/MAINTAINERS
213 +++ b/MAINTAINERS
214 @@ -474,3 +474,8 @@ S:  Maintained
215  T:     git git://git.denx.de/u-boot.git
216  F:     *
217  F:     */
218 +
219 +BOOTSTAGE
220 +M:     Simon Glass <[email protected]>
221 +L:     [email protected]
222 +F:     common/bootstage.c
223 diff --git a/common/bootstage.c b/common/bootstage.c
224 new file mode 100644
225 index 0000000..2234c87
226 --- /dev/null
227 +++ b/common/bootstage.c
228 @@ -0,0 +1,37 @@
229 +%s
230 +/*
231 + * Copyright (c) 2011, Google Inc. All rights reserved.
232 + *
233 + */
234 +
235 +/*
236 + * This module records the progress of boot and arbitrary commands, and
237 + * permits accurate timestamping of each. The records can optionally be
238 + * passed to kernel in the ATAGs
239 + */
240 +
241 +#include <common.h>
242 +
243 +struct bootstage_record {
244 +       u32 time_us;
245 +       const char *name;
246 +};
247 +
248 +static struct bootstage_record record[BOOTSTAGE_COUNT];
249 +
250 +u32 bootstage_mark(enum bootstage_id id, const char *name)
251 +{
252 +       struct bootstage_record *rec = &record[id];
253 +
254 +       /* Only record the first event for each */
255 +%sif (!rec->name) {
256 +               rec->time_us = (u32)timer_get_us();
257 +               rec->name = name;
258 +       }
259 +       if (!rec->name &&
260 +       %ssomething_else) {
261 +               rec->time_us = (u32)timer_get_us();
262 +               rec->name = name;
263 +       }
264 +%sreturn rec->time_us;
265 +}
266 --
267 1.7.3.1
268 '''
269         signoff = 'Signed-off-by: Simon Glass <[email protected]>\n'
270         license = '// SPDX-License-Identifier: GPL-2.0+'
271         tab = ' '
272         indent = '    '
273         if data_type == 'good':
274             pass
275         elif data_type == 'no-signoff':
276             signoff = ''
277         elif data_type == 'no-license':
278             license = ''
279         elif data_type == 'spaces':
280             tab = '   '
281         elif data_type == 'indent':
282             indent = tab
283         else:
284             print('not implemented')
285         return data % (signoff, license, tab, indent, tab)
286
287     def SetupData(self, data_type):
288         inhandle, inname = tempfile.mkstemp()
289         infd = os.fdopen(inhandle, 'w')
290         data = self.GetData(data_type)
291         infd.write(data)
292         infd.close()
293         return inname
294
295     def testGood(self):
296         """Test checkpatch operation"""
297         inf = self.SetupData('good')
298         result = checkpatch.CheckPatch(inf)
299         self.assertEqual(result.ok, True)
300         self.assertEqual(result.problems, [])
301         self.assertEqual(result.errors, 0)
302         self.assertEqual(result.warnings, 0)
303         self.assertEqual(result.checks, 0)
304         self.assertEqual(result.lines, 62)
305         os.remove(inf)
306
307     def testNoSignoff(self):
308         inf = self.SetupData('no-signoff')
309         result = checkpatch.CheckPatch(inf)
310         self.assertEqual(result.ok, False)
311         self.assertEqual(len(result.problems), 1)
312         self.assertEqual(result.errors, 1)
313         self.assertEqual(result.warnings, 0)
314         self.assertEqual(result.checks, 0)
315         self.assertEqual(result.lines, 62)
316         os.remove(inf)
317
318     def testNoLicense(self):
319         inf = self.SetupData('no-license')
320         result = checkpatch.CheckPatch(inf)
321         self.assertEqual(result.ok, False)
322         self.assertEqual(len(result.problems), 1)
323         self.assertEqual(result.errors, 0)
324         self.assertEqual(result.warnings, 1)
325         self.assertEqual(result.checks, 0)
326         self.assertEqual(result.lines, 62)
327         os.remove(inf)
328
329     def testSpaces(self):
330         inf = self.SetupData('spaces')
331         result = checkpatch.CheckPatch(inf)
332         self.assertEqual(result.ok, False)
333         self.assertEqual(len(result.problems), 3)
334         self.assertEqual(result.errors, 0)
335         self.assertEqual(result.warnings, 3)
336         self.assertEqual(result.checks, 0)
337         self.assertEqual(result.lines, 62)
338         os.remove(inf)
339
340     def testIndent(self):
341         inf = self.SetupData('indent')
342         result = checkpatch.CheckPatch(inf)
343         self.assertEqual(result.ok, False)
344         self.assertEqual(len(result.problems), 1)
345         self.assertEqual(result.errors, 0)
346         self.assertEqual(result.warnings, 0)
347         self.assertEqual(result.checks, 1)
348         self.assertEqual(result.lines, 62)
349         os.remove(inf)
350
351     def checkSingleMessage(self, pm, msg, pmtype = 'warning'):
352         """Helper function to run checkpatch and check the result
353
354         Args:
355             pm: PatchMaker object to use
356             msg: Expected message (e.g. 'LIVETREE')
357             pmtype: Type of problem ('error', 'warning')
358         """
359         result = pm.run_checkpatch()
360         if pmtype == 'warning':
361             self.assertEqual(result.warnings, 1)
362         elif pmtype == 'error':
363             self.assertEqual(result.errors, 1)
364         if len(result.problems) != 1:
365             print(result.problems)
366         self.assertEqual(len(result.problems), 1)
367         self.assertIn(msg, result.problems[0]['cptype'])
368
369     def testUclass(self):
370         """Test for possible new uclass"""
371         pm = PatchMaker()
372         pm.add_line('include/dm/uclass-id.h', 'UCLASS_WIBBLE,')
373         self.checkSingleMessage(pm, 'NEW_UCLASS')
374
375     def testLivetree(self):
376         """Test for using the livetree API"""
377         pm = PatchMaker()
378         pm.add_line('common/main.c', 'fdtdec_do_something()')
379         self.checkSingleMessage(pm, 'LIVETREE')
380
381     def testNewCommand(self):
382         """Test for adding a new command"""
383         pm = PatchMaker()
384         pm.add_line('common/main.c', 'do_wibble(struct cmd_tbl *cmd_tbl)')
385         self.checkSingleMessage(pm, 'CMD_TEST')
386
387     def testPreferIf(self):
388         """Test for using #ifdef"""
389         pm = PatchMaker()
390         pm.add_line('common/main.c', '#ifdef CONFIG_YELLOW')
391         pm.add_line('common/init.h', '#ifdef CONFIG_YELLOW')
392         pm.add_line('fred.dtsi', '#ifdef CONFIG_YELLOW')
393         self.checkSingleMessage(pm, "PREFER_IF")
394
395     def testCommandUseDefconfig(self):
396         """Test for enabling/disabling commands using preprocesor"""
397         pm = PatchMaker()
398         pm.add_line('common/main.c', '#undef CONFIG_CMD_WHICH')
399         self.checkSingleMessage(pm, 'DEFINE_CONFIG_CMD', 'error')
400
401     def testBarredIncludeInHdr(self):
402         """Test for using a barred include in a header file"""
403         pm = PatchMaker()
404         #pm.add_line('include/myfile.h', '#include <common.h>')
405         pm.add_line('include/myfile.h', '#include <dm.h>')
406         self.checkSingleMessage(pm, 'BARRED_INCLUDE_IN_HDR', 'error')
407
408     def testConfigIsEnabledConfig(self):
409         """Test for accidental CONFIG_IS_ENABLED(CONFIG_*) calls"""
410         pm = PatchMaker()
411         pm.add_line('common/main.c', 'if (CONFIG_IS_ENABLED(CONFIG_CLK))')
412         self.checkSingleMessage(pm, 'CONFIG_IS_ENABLED_CONFIG', 'error')
413
414     def check_struct(self, auto, suffix, warning):
415         """Check one of the warnings for struct naming
416
417         Args:
418             auto: Auto variable name, e.g. 'per_child_auto'
419             suffix: Suffix to expect on member, e.g. '_priv'
420             warning: Warning name, e.g. 'PRIV_AUTO'
421         """
422         pm = PatchMaker()
423         pm.add_line('common/main.c', '.%s = sizeof(struct(fred)),' % auto)
424         pm.add_line('common/main.c', '.%s = sizeof(struct(mary%s)),' %
425                     (auto, suffix))
426         self.checkSingleMessage(
427             pm, warning, "struct 'fred' should have a %s suffix" % suffix)
428
429     def testDmDriverAuto(self):
430         """Check for the correct suffix on 'struct driver' auto members"""
431         self.check_struct('priv_auto', '_priv', 'PRIV_AUTO')
432         self.check_struct('plat_auto', '_plat', 'PLAT_AUTO')
433         self.check_struct('per_child_auto', '_priv', 'CHILD_PRIV_AUTO')
434         self.check_struct('per_child_plat_auto', '_plat', 'CHILD_PLAT_AUTO')
435
436     def testDmUclassAuto(self):
437         """Check for the correct suffix on 'struct uclass' auto members"""
438         # Some of these are omitted since they match those from struct driver
439         self.check_struct('per_device_auto', '_priv', 'DEVICE_PRIV_AUTO')
440         self.check_struct('per_device_plat_auto', '_plat', 'DEVICE_PLAT_AUTO')
441
442     def check_strl(self, func):
443         """Check one of the checks for strn(cpy|cat)"""
444         pm = PatchMaker()
445         pm.add_line('common/main.c', "strn%s(foo, bar, sizeof(foo));" % func)
446         self.checkSingleMessage(pm, "STRL",
447             "strl%s is preferred over strn%s because it always produces a nul-terminated string\n"
448             % (func, func))
449
450     def testStrl(self):
451         """Check for uses of strn(cat|cpy)"""
452         self.check_strl("cat");
453         self.check_strl("cpy");
454
455 if __name__ == "__main__":
456     unittest.main()
457     gitutil.RunTests()
This page took 0.052278 seconds and 4 git commands to generate.