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 9import os 10import tempfile 11import unittest 12 13from patman import checkpatch 14from patman import gitutil 15from patman import patchstream 16from patman import series 17from patman import commit 18 19 20class Line: 21 def __init__(self, fname, text): 22 self.fname = fname 23 self.text = text 24 25 26class 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 35From: Simon Glass <sjg@chromium.org> 36Date: Sun, 14 Jun 2020 09:45:14 -0600 37Subject: [PATCH] Test commit 38 39This is a test commit. 40 41Signed-off-by: Simon Glass <sjg@chromium.org> 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 88class 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 95From 656c9a8c31fa65859d924cd21da920d6ba537fad Mon Sep 17 00:00:00 2001 96From: Simon Glass <sjg@chromium.org> 97Date: Thu, 28 Apr 2011 09:58:51 -0700 98Subject: [PATCH (resend) 3/7] Tegra2: Add more clock support 99 100This adds functions to enable/disable clocks and reset to on-chip peripherals. 101 102cmd/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 106BUG=chromium-os:13875 107TEST=build U-Boot for Seaboard, boot 108 109Change-Id: I80fe1d0c0b7dd10aa58ce5bb1d9290b6664d5413 110 111Review URL: http://codereview.chromium.org/6900006 112 113Signed-off-by: Simon Glass <sjg@chromium.org> 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 122From 656c9a8c31fa65859d924cd21da920d6ba537fad Mon Sep 17 00:00:00 2001 123From: Simon Glass <sjg@chromium.org> 124Date: Thu, 28 Apr 2011 09:58:51 -0700 125Subject: [PATCH (resend) 3/7] Tegra2: Add more clock support 126 127This adds functions to enable/disable clocks and reset to on-chip peripherals. 128 129cmd/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 133Signed-off-by: Simon Glass <sjg@chromium.org> 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 169From: Simon Glass <sjg@chromium.org> 170Date: Thu, 7 Apr 2011 10:14:41 -0700 171Subject: [PATCH 1/4] Add microsecond boot time measurement 172 173This defines the basics of a new boot time measurement feature. This allows 174logging of very accurate time measurements as the boot proceeds, by using 175an 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 188diff --git a/README b/README 189index 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 210diff --git a/MAINTAINERS b/MAINTAINERS 211index 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 <sjg@chromium.org> 221+L: u-boot@lists.denx.de 222+F: common/bootstage.c 223diff --git a/common/bootstage.c b/common/bootstage.c 224new file mode 100644 225index 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-- 2671.7.3.1 268''' 269 signoff = 'Signed-off-by: Simon Glass <sjg@chromium.org>\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 443if __name__ == "__main__": 444 unittest.main() 445 gitutil.RunTests() 446