blob: 64b740841ca0feb7fecec998264e4e06146f55b6 [file] [log] [blame]
Simon Glass10ea9c02020-12-28 20:35:07 -07001# SPDX-License-Identifier: GPL-2.0+
2# Copyright 2020 Google LLC
3#
4
5"""Tests for the src_scan module
6
7This includes unit tests for scanning of the source code
8"""
9
Simon Glass1a8b4b92021-02-03 06:00:54 -070010import copy
Simon Glass10ea9c02020-12-28 20:35:07 -070011import os
12import shutil
13import tempfile
14import unittest
15from unittest import mock
16
17from dtoc import src_scan
Simon Glass4583c002023-02-23 18:18:04 -070018from u_boot_pylib import test_util
19from u_boot_pylib import tools
Simon Glass10ea9c02020-12-28 20:35:07 -070020
Simon Glassc58662f2021-02-03 06:00:50 -070021OUR_PATH = os.path.dirname(os.path.realpath(__file__))
22
Simon Glass86ff01e2021-07-04 12:19:48 -060023EXPECT_WARN = {'rockchip_rk3288_grf':
24 {'WARNING: the driver rockchip_rk3288_grf was not found in the driver list'}}
25
Simon Glassc58662f2021-02-03 06:00:50 -070026class FakeNode:
27 """Fake Node object for testing"""
28 def __init__(self):
29 self.name = None
30 self.props = {}
31
32class FakeProp:
33 """Fake Prop object for testing"""
34 def __init__(self):
35 self.name = None
36 self.value = None
37
Simon Glass10ea9c02020-12-28 20:35:07 -070038# This is a test so is allowed to access private things in the module it is
39# testing
40# pylint: disable=W0212
41
42class TestSrcScan(unittest.TestCase):
43 """Tests for src_scan"""
44 @classmethod
45 def setUpClass(cls):
Simon Glassc1aa66e2022-01-29 14:14:04 -070046 tools.prepare_output_dir(None)
Simon Glass10ea9c02020-12-28 20:35:07 -070047
48 @classmethod
49 def tearDownClass(cls):
Simon Glassc1aa66e2022-01-29 14:14:04 -070050 tools.finalise_output_dir()
Simon Glass10ea9c02020-12-28 20:35:07 -070051
Simon Glass970349a2020-12-28 20:35:08 -070052 def test_simple(self):
53 """Simple test of scanning drivers"""
Simon Glass0c59ace2021-03-26 16:17:25 +130054 scan = src_scan.Scanner(None, None)
Simon Glass970349a2020-12-28 20:35:08 -070055 scan.scan_drivers()
56 self.assertIn('sandbox_gpio', scan._drivers)
57 self.assertIn('sandbox_gpio_alias', scan._driver_aliases)
58 self.assertEqual('sandbox_gpio',
59 scan._driver_aliases['sandbox_gpio_alias'])
60 self.assertNotIn('sandbox_gpio_alias2', scan._driver_aliases)
61
62 def test_additional(self):
63 """Test with additional drivers to scan"""
Simon Glass10ea9c02020-12-28 20:35:07 -070064 scan = src_scan.Scanner(
Simon Glass0c59ace2021-03-26 16:17:25 +130065 None, [None, '', 'tools/dtoc/test/dtoc_test_scan_drivers.cxx'])
Simon Glass10ea9c02020-12-28 20:35:07 -070066 scan.scan_drivers()
Simon Glass970349a2020-12-28 20:35:08 -070067 self.assertIn('sandbox_gpio_alias2', scan._driver_aliases)
68 self.assertEqual('sandbox_gpio',
69 scan._driver_aliases['sandbox_gpio_alias2'])
Simon Glass10ea9c02020-12-28 20:35:07 -070070
Simon Glass970349a2020-12-28 20:35:08 -070071 def test_unicode_error(self):
Simon Glass10ea9c02020-12-28 20:35:07 -070072 """Test running dtoc with an invalid unicode file
73
74 To be able to perform this test without adding a weird text file which
75 would produce issues when using checkpatch.pl or patman, generate the
76 file at runtime and then process it.
77 """
78 driver_fn = '/tmp/' + next(tempfile._get_candidate_names())
79 with open(driver_fn, 'wb+') as fout:
80 fout.write(b'\x81')
81
Simon Glass0c59ace2021-03-26 16:17:25 +130082 scan = src_scan.Scanner(None, [driver_fn])
Simon Glass970349a2020-12-28 20:35:08 -070083 with test_util.capture_sys_output() as (stdout, _):
84 scan.scan_drivers()
85 self.assertRegex(stdout.getvalue(),
86 r"Skipping file '.*' due to unicode error\s*")
Simon Glass10ea9c02020-12-28 20:35:07 -070087
88 def test_driver(self):
89 """Test the Driver class"""
Simon Glassc58662f2021-02-03 06:00:50 -070090 i2c = 'I2C_UCLASS'
91 compat = {'rockchip,rk3288-grf': 'ROCKCHIP_SYSCON_GRF',
92 'rockchip,rk3288-srf': None}
93 drv1 = src_scan.Driver('fred', 'fred.c')
94 drv2 = src_scan.Driver('mary', 'mary.c')
95 drv3 = src_scan.Driver('fred', 'fred.c')
96 drv1.uclass_id = i2c
97 drv1.compat = compat
98 drv2.uclass_id = i2c
99 drv2.compat = compat
100 drv3.uclass_id = i2c
101 drv3.compat = compat
102 self.assertEqual(
Simon Glassb9319c42021-02-03 06:01:01 -0700103 "Driver(name='fred', used=False, uclass_id='I2C_UCLASS', "
Simon Glassc58662f2021-02-03 06:00:50 -0700104 "compat={'rockchip,rk3288-grf': 'ROCKCHIP_SYSCON_GRF', "
105 "'rockchip,rk3288-srf': None}, priv=)", str(drv1))
Simon Glass10ea9c02020-12-28 20:35:07 -0700106 self.assertEqual(drv1, drv3)
107 self.assertNotEqual(drv1, drv2)
108 self.assertNotEqual(drv2, drv3)
109
110 def test_scan_dirs(self):
111 """Test scanning of source directories"""
112 def add_file(fname):
113 pathname = os.path.join(indir, fname)
114 dirname = os.path.dirname(pathname)
115 os.makedirs(dirname, exist_ok=True)
Simon Glassc1aa66e2022-01-29 14:14:04 -0700116 tools.write_file(pathname, '', binary=False)
Simon Glass10ea9c02020-12-28 20:35:07 -0700117 fname_list.append(pathname)
118
119 try:
120 indir = tempfile.mkdtemp(prefix='dtoc.')
121
122 fname_list = []
123 add_file('fname.c')
Simon Glass36b22202021-02-03 06:00:52 -0700124 add_file('.git/ignoreme.c')
Simon Glass10ea9c02020-12-28 20:35:07 -0700125 add_file('dir/fname2.c')
Simon Glass36b22202021-02-03 06:00:52 -0700126 add_file('build-sandbox/ignoreme2.c')
Simon Glass10ea9c02020-12-28 20:35:07 -0700127
128 # Mock out scan_driver and check that it is called with the
129 # expected files
130 with mock.patch.object(src_scan.Scanner, "scan_driver") as mocked:
Simon Glass0c59ace2021-03-26 16:17:25 +1300131 scan = src_scan.Scanner(indir, None)
Simon Glass10ea9c02020-12-28 20:35:07 -0700132 scan.scan_drivers()
133 self.assertEqual(2, len(mocked.mock_calls))
134 self.assertEqual(mock.call(fname_list[0]),
135 mocked.mock_calls[0])
Simon Glass36b22202021-02-03 06:00:52 -0700136 # .git file should be ignored
137 self.assertEqual(mock.call(fname_list[2]),
Simon Glass10ea9c02020-12-28 20:35:07 -0700138 mocked.mock_calls[1])
139 finally:
140 shutil.rmtree(indir)
Simon Glassc58662f2021-02-03 06:00:50 -0700141
142 def test_scan(self):
143 """Test scanning of a driver"""
144 fname = os.path.join(OUR_PATH, '..', '..', 'drivers/i2c/tegra_i2c.c')
Simon Glassc1aa66e2022-01-29 14:14:04 -0700145 buff = tools.read_file(fname, False)
Simon Glass0c59ace2021-03-26 16:17:25 +1300146 scan = src_scan.Scanner(None, None)
Simon Glassc58662f2021-02-03 06:00:50 -0700147 scan._parse_driver(fname, buff)
148 self.assertIn('i2c_tegra', scan._drivers)
149 drv = scan._drivers['i2c_tegra']
150 self.assertEqual('i2c_tegra', drv.name)
151 self.assertEqual('UCLASS_I2C', drv.uclass_id)
152 self.assertEqual(
153 {'nvidia,tegra114-i2c': 'TYPE_114',
Tom Rinic18e5fb2022-06-14 13:59:23 -0400154 'nvidia,tegra124-i2c': 'TYPE_114',
Simon Glassc58662f2021-02-03 06:00:50 -0700155 'nvidia,tegra20-i2c': 'TYPE_STD',
156 'nvidia,tegra20-i2c-dvc': 'TYPE_DVC'}, drv.compat)
157 self.assertEqual('i2c_bus', drv.priv)
158 self.assertEqual(1, len(scan._drivers))
Simon Glass86ff01e2021-07-04 12:19:48 -0600159 self.assertEqual({}, scan._warnings)
Simon Glassc58662f2021-02-03 06:00:50 -0700160
161 def test_normalized_name(self):
162 """Test operation of get_normalized_compat_name()"""
163 prop = FakeProp()
164 prop.name = 'compatible'
165 prop.value = 'rockchip,rk3288-grf'
166 node = FakeNode()
167 node.props = {'compatible': prop}
Simon Glass50aae3e2021-02-03 06:01:11 -0700168
169 # get_normalized_compat_name() uses this to check for root node
170 node.parent = FakeNode()
171
Simon Glass0c59ace2021-03-26 16:17:25 +1300172 scan = src_scan.Scanner(None, None)
Simon Glassc58662f2021-02-03 06:00:50 -0700173 with test_util.capture_sys_output() as (stdout, _):
174 name, aliases = scan.get_normalized_compat_name(node)
175 self.assertEqual('rockchip_rk3288_grf', name)
176 self.assertEqual([], aliases)
Simon Glass0c59ace2021-03-26 16:17:25 +1300177 self.assertEqual(1, len(scan._missing_drivers))
178 self.assertEqual({'rockchip_rk3288_grf'}, scan._missing_drivers)
Simon Glass4f1727a2021-07-04 12:19:47 -0600179 self.assertEqual('', stdout.getvalue().strip())
Simon Glass86ff01e2021-07-04 12:19:48 -0600180 self.assertEqual(EXPECT_WARN, scan._warnings)
Simon Glassc58662f2021-02-03 06:00:50 -0700181
182 i2c = 'I2C_UCLASS'
183 compat = {'rockchip,rk3288-grf': 'ROCKCHIP_SYSCON_GRF',
184 'rockchip,rk3288-srf': None}
185 drv = src_scan.Driver('fred', 'fred.c')
186 drv.uclass_id = i2c
187 drv.compat = compat
188 scan._drivers['rockchip_rk3288_grf'] = drv
189
190 scan._driver_aliases['rockchip_rk3288_srf'] = 'rockchip_rk3288_grf'
191
192 with test_util.capture_sys_output() as (stdout, _):
193 name, aliases = scan.get_normalized_compat_name(node)
194 self.assertEqual('', stdout.getvalue().strip())
195 self.assertEqual('rockchip_rk3288_grf', name)
196 self.assertEqual([], aliases)
Simon Glass86ff01e2021-07-04 12:19:48 -0600197 self.assertEqual(EXPECT_WARN, scan._warnings)
Simon Glassc58662f2021-02-03 06:00:50 -0700198
199 prop.value = 'rockchip,rk3288-srf'
200 with test_util.capture_sys_output() as (stdout, _):
201 name, aliases = scan.get_normalized_compat_name(node)
202 self.assertEqual('', stdout.getvalue().strip())
203 self.assertEqual('rockchip_rk3288_grf', name)
204 self.assertEqual(['rockchip_rk3288_srf'], aliases)
Simon Glass86ff01e2021-07-04 12:19:48 -0600205 self.assertEqual(EXPECT_WARN, scan._warnings)
Simon Glassc58662f2021-02-03 06:00:50 -0700206
207 def test_scan_errors(self):
208 """Test detection of scanning errors"""
209 buff = '''
210static const struct udevice_id tegra_i2c_ids2[] = {
211 { .compatible = "nvidia,tegra114-i2c", .data = TYPE_114 },
212 { }
213};
214
215U_BOOT_DRIVER(i2c_tegra) = {
216 .name = "i2c_tegra",
217 .id = UCLASS_I2C,
218 .of_match = tegra_i2c_ids,
219};
220'''
Simon Glass0c59ace2021-03-26 16:17:25 +1300221 scan = src_scan.Scanner(None, None)
Simon Glassc58662f2021-02-03 06:00:50 -0700222 with self.assertRaises(ValueError) as exc:
223 scan._parse_driver('file.c', buff)
224 self.assertIn(
225 "file.c: Unknown compatible var 'tegra_i2c_ids' (found: tegra_i2c_ids2)",
226 str(exc.exception))
227
228 def test_of_match(self):
229 """Test detection of of_match_ptr() member"""
230 buff = '''
231static const struct udevice_id tegra_i2c_ids[] = {
232 { .compatible = "nvidia,tegra114-i2c", .data = TYPE_114 },
233 { }
234};
235
236U_BOOT_DRIVER(i2c_tegra) = {
237 .name = "i2c_tegra",
238 .id = UCLASS_I2C,
239 .of_match = of_match_ptr(tegra_i2c_ids),
240};
241'''
Simon Glass0c59ace2021-03-26 16:17:25 +1300242 scan = src_scan.Scanner(None, None)
Simon Glassc58662f2021-02-03 06:00:50 -0700243 scan._parse_driver('file.c', buff)
244 self.assertIn('i2c_tegra', scan._drivers)
245 drv = scan._drivers['i2c_tegra']
246 self.assertEqual('i2c_tegra', drv.name)
Simon Glassb00f0062021-02-03 06:01:02 -0700247 self.assertEqual('', drv.phase)
Simon Glass735ddfc2021-02-03 06:01:04 -0700248 self.assertEqual([], drv.headers)
Simon Glassc8b19b02021-02-03 06:00:53 -0700249
250 def test_priv(self):
251 """Test collection of struct info from drivers"""
252 buff = '''
253static const struct udevice_id test_ids[] = {
254 { .compatible = "nvidia,tegra114-i2c", .data = TYPE_114 },
255 { }
256};
257
258U_BOOT_DRIVER(testing) = {
259 .name = "testing",
260 .id = UCLASS_I2C,
261 .of_match = test_ids,
262 .priv_auto = sizeof(struct some_priv),
263 .plat_auto = sizeof(struct some_plat),
264 .per_child_auto = sizeof(struct some_cpriv),
265 .per_child_plat_auto = sizeof(struct some_cplat),
Simon Glassb00f0062021-02-03 06:01:02 -0700266 DM_PHASE(tpl)
Simon Glass735ddfc2021-02-03 06:01:04 -0700267 DM_HEADER(<i2c.h>)
268 DM_HEADER(<asm/clk.h>)
Simon Glassc8b19b02021-02-03 06:00:53 -0700269};
270'''
Simon Glass0c59ace2021-03-26 16:17:25 +1300271 scan = src_scan.Scanner(None, None)
Simon Glassc8b19b02021-02-03 06:00:53 -0700272 scan._parse_driver('file.c', buff)
273 self.assertIn('testing', scan._drivers)
274 drv = scan._drivers['testing']
275 self.assertEqual('testing', drv.name)
276 self.assertEqual('UCLASS_I2C', drv.uclass_id)
277 self.assertEqual(
278 {'nvidia,tegra114-i2c': 'TYPE_114'}, drv.compat)
279 self.assertEqual('some_priv', drv.priv)
280 self.assertEqual('some_plat', drv.plat)
281 self.assertEqual('some_cpriv', drv.child_priv)
282 self.assertEqual('some_cplat', drv.child_plat)
Simon Glassb00f0062021-02-03 06:01:02 -0700283 self.assertEqual('tpl', drv.phase)
Simon Glass735ddfc2021-02-03 06:01:04 -0700284 self.assertEqual(['<i2c.h>', '<asm/clk.h>'], drv.headers)
Simon Glassc8b19b02021-02-03 06:00:53 -0700285 self.assertEqual(1, len(scan._drivers))
Simon Glass1a8b4b92021-02-03 06:00:54 -0700286
287 def test_uclass_scan(self):
288 """Test collection of uclass-driver info"""
289 buff = '''
290UCLASS_DRIVER(i2c) = {
291 .id = UCLASS_I2C,
292 .name = "i2c",
293 .flags = DM_UC_FLAG_SEQ_ALIAS,
294 .priv_auto = sizeof(struct some_priv),
295 .per_device_auto = sizeof(struct per_dev_priv),
296 .per_device_plat_auto = sizeof(struct per_dev_plat),
297 .per_child_auto = sizeof(struct per_child_priv),
298 .per_child_plat_auto = sizeof(struct per_child_plat),
299 .child_post_bind = i2c_child_post_bind,
300};
301
302'''
Simon Glass0c59ace2021-03-26 16:17:25 +1300303 scan = src_scan.Scanner(None, None)
Simon Glass1a8b4b92021-02-03 06:00:54 -0700304 scan._parse_uclass_driver('file.c', buff)
305 self.assertIn('UCLASS_I2C', scan._uclass)
306 drv = scan._uclass['UCLASS_I2C']
307 self.assertEqual('i2c', drv.name)
308 self.assertEqual('UCLASS_I2C', drv.uclass_id)
309 self.assertEqual('some_priv', drv.priv)
310 self.assertEqual('per_dev_priv', drv.per_dev_priv)
311 self.assertEqual('per_dev_plat', drv.per_dev_plat)
312 self.assertEqual('per_child_priv', drv.per_child_priv)
313 self.assertEqual('per_child_plat', drv.per_child_plat)
314 self.assertEqual(1, len(scan._uclass))
315
316 drv2 = copy.deepcopy(drv)
317 self.assertEqual(drv, drv2)
318 drv2.priv = 'other_priv'
319 self.assertNotEqual(drv, drv2)
320
321 # The hashes only depend on the uclass ID, so should be equal
322 self.assertEqual(drv.__hash__(), drv2.__hash__())
323
324 self.assertEqual("UclassDriver(name='i2c', uclass_id='UCLASS_I2C')",
325 str(drv))
326
327 def test_uclass_scan_errors(self):
328 """Test detection of uclass scanning errors"""
329 buff = '''
330UCLASS_DRIVER(i2c) = {
331 .name = "i2c",
332};
333
334'''
Simon Glass0c59ace2021-03-26 16:17:25 +1300335 scan = src_scan.Scanner(None, None)
Simon Glass1a8b4b92021-02-03 06:00:54 -0700336 with self.assertRaises(ValueError) as exc:
337 scan._parse_uclass_driver('file.c', buff)
338 self.assertIn("file.c: Cannot parse uclass ID in driver 'i2c'",
339 str(exc.exception))
Simon Glassacf5cb82021-02-03 06:00:55 -0700340
341 def test_struct_scan(self):
342 """Test collection of struct info"""
343 buff = '''
344/* some comment */
345struct some_struct1 {
346 struct i2c_msg *msgs;
347 uint nmsgs;
348};
349'''
Simon Glass0c59ace2021-03-26 16:17:25 +1300350 scan = src_scan.Scanner(None, None)
Simon Glassacf5cb82021-02-03 06:00:55 -0700351 scan._basedir = os.path.join(OUR_PATH, '..', '..')
352 scan._parse_structs('arch/arm/include/asm/file.h', buff)
353 self.assertIn('some_struct1', scan._structs)
354 struc = scan._structs['some_struct1']
355 self.assertEqual('some_struct1', struc.name)
356 self.assertEqual('asm/file.h', struc.fname)
357
358 buff = '''
359/* another comment */
360struct another_struct {
361 int speed_hz;
362 int max_transaction_bytes;
363};
364'''
365 scan._parse_structs('include/file2.h', buff)
366 self.assertIn('another_struct', scan._structs)
367 struc = scan._structs['another_struct']
368 self.assertEqual('another_struct', struc.name)
369 self.assertEqual('file2.h', struc.fname)
370
371 self.assertEqual(2, len(scan._structs))
372
373 self.assertEqual("Struct(name='another_struct', fname='file2.h')",
374 str(struc))
375
376 def test_struct_scan_errors(self):
377 """Test scanning a header file with an invalid unicode file"""
Simon Glassc1aa66e2022-01-29 14:14:04 -0700378 output = tools.get_output_filename('output.h')
379 tools.write_file(output, b'struct this is a test \x81 of bad unicode')
Simon Glassacf5cb82021-02-03 06:00:55 -0700380
Simon Glass0c59ace2021-03-26 16:17:25 +1300381 scan = src_scan.Scanner(None, None)
Simon Glassacf5cb82021-02-03 06:00:55 -0700382 with test_util.capture_sys_output() as (stdout, _):
383 scan.scan_header(output)
384 self.assertIn('due to unicode error', stdout.getvalue())
Simon Glass1d972692021-02-03 06:01:06 -0700385
386 def setup_dup_drivers(self, name, phase=''):
387 """Set up for a duplcate test
388
389 Returns:
390 tuple:
391 Scanner to use
392 Driver record for first driver
393 Text of second driver declaration
394 Node for driver 1
395 """
396 driver1 = '''
397static const struct udevice_id test_ids[] = {
398 { .compatible = "nvidia,tegra114-i2c", .data = TYPE_114 },
399 { }
400};
401
402U_BOOT_DRIVER(%s) = {
403 .name = "testing",
404 .id = UCLASS_I2C,
405 .of_match = test_ids,
406 %s
407};
408''' % (name, 'DM_PHASE(%s)' % phase if phase else '')
409 driver2 = '''
410static const struct udevice_id test_ids[] = {
411 { .compatible = "nvidia,tegra114-dvc" },
412 { }
413};
414
415U_BOOT_DRIVER(%s) = {
416 .name = "testing",
417 .id = UCLASS_RAM,
418 .of_match = test_ids,
419};
420''' % name
Simon Glass0c59ace2021-03-26 16:17:25 +1300421 scan = src_scan.Scanner(None, None, phase)
Simon Glass1d972692021-02-03 06:01:06 -0700422 scan._parse_driver('file1.c', driver1)
423 self.assertIn(name, scan._drivers)
424 drv1 = scan._drivers[name]
425
426 prop = FakeProp()
427 prop.name = 'compatible'
428 prop.value = 'nvidia,tegra114-i2c'
429 node = FakeNode()
430 node.name = 'testing'
431 node.props = {'compatible': prop}
432
Simon Glass50aae3e2021-02-03 06:01:11 -0700433 # get_normalized_compat_name() uses this to check for root node
434 node.parent = FakeNode()
435
Simon Glass1d972692021-02-03 06:01:06 -0700436 return scan, drv1, driver2, node
437
438 def test_dup_drivers(self):
439 """Test handling of duplicate drivers"""
440 name = 'nvidia_tegra114_i2c'
441 scan, drv1, driver2, node = self.setup_dup_drivers(name)
442 self.assertEqual('', drv1.phase)
443
444 # The driver should not have a duplicate yet
445 self.assertEqual([], drv1.dups)
446
447 scan._parse_driver('file2.c', driver2)
448
449 # The first driver should now be a duplicate of the second
450 drv2 = scan._drivers[name]
451 self.assertEqual('', drv2.phase)
452 self.assertEqual(1, len(drv2.dups))
453 self.assertEqual([drv1], drv2.dups)
454
455 # There is no way to distinguish them, so we should expect a warning
456 self.assertTrue(drv2.warn_dups)
457
458 # We should see a warning
459 with test_util.capture_sys_output() as (stdout, _):
460 scan.mark_used([node])
461 self.assertEqual(
462 "Warning: Duplicate driver name 'nvidia_tegra114_i2c' (orig=file2.c, dups=file1.c)",
463 stdout.getvalue().strip())
464
465 def test_dup_drivers_phase(self):
466 """Test handling of duplicate drivers but with different phases"""
467 name = 'nvidia_tegra114_i2c'
468 scan, drv1, driver2, node = self.setup_dup_drivers(name, 'spl')
469 scan._parse_driver('file2.c', driver2)
470 self.assertEqual('spl', drv1.phase)
471
472 # The second driver should now be a duplicate of the second
473 self.assertEqual(1, len(drv1.dups))
474 drv2 = drv1.dups[0]
475
476 # The phase is different, so we should not warn of dups
477 self.assertFalse(drv1.warn_dups)
478
479 # We should not see a warning
480 with test_util.capture_sys_output() as (stdout, _):
481 scan.mark_used([node])
482 self.assertEqual('', stdout.getvalue().strip())
Simon Glass337d6972021-02-03 06:01:10 -0700483
484 def test_sequence(self):
485 """Test assignment of sequence numnbers"""
Simon Glass0c59ace2021-03-26 16:17:25 +1300486 scan = src_scan.Scanner(None, None, '')
Simon Glass337d6972021-02-03 06:01:10 -0700487 node = FakeNode()
488 uc = src_scan.UclassDriver('UCLASS_I2C')
489 node.uclass = uc
490 node.driver = True
491 node.seq = -1
492 node.path = 'mypath'
493 uc.alias_num_to_node[2] = node
494
495 # This should assign 3 (after the 2 that exists)
496 seq = scan.assign_seq(node)
497 self.assertEqual(3, seq)
498 self.assertEqual({'mypath': 3}, uc.alias_path_to_num)
499 self.assertEqual({2: node, 3: node}, uc.alias_num_to_node)
Simon Glass86ff01e2021-07-04 12:19:48 -0600500
501 def test_scan_warnings(self):
502 """Test detection of scanning warnings"""
503 buff = '''
504static const struct udevice_id tegra_i2c_ids[] = {
505 { .compatible = "nvidia,tegra114-i2c", .data = TYPE_114 },
506 { }
507};
508
509U_BOOT_DRIVER(i2c_tegra) = {
510 .name = "i2c_tegra",
511 .id = UCLASS_I2C,
512 .of_match = tegra_i2c_ids + 1,
513};
514'''
515 # The '+ 1' above should generate a warning
516
517 prop = FakeProp()
518 prop.name = 'compatible'
519 prop.value = 'rockchip,rk3288-grf'
520 node = FakeNode()
521 node.props = {'compatible': prop}
522
523 # get_normalized_compat_name() uses this to check for root node
524 node.parent = FakeNode()
525
526 scan = src_scan.Scanner(None, None)
527 scan._parse_driver('file.c', buff)
528 self.assertEqual(
529 {'i2c_tegra':
530 {"file.c: Warning: unexpected suffix ' + 1' on .of_match line for compat 'tegra_i2c_ids'"}},
531 scan._warnings)
532
533 tprop = FakeProp()
534 tprop.name = 'compatible'
535 tprop.value = 'nvidia,tegra114-i2c'
536 tnode = FakeNode()
537 tnode.props = {'compatible': tprop}
538
539 # get_normalized_compat_name() uses this to check for root node
540 tnode.parent = FakeNode()
541
542 with test_util.capture_sys_output() as (stdout, _):
543 scan.get_normalized_compat_name(node)
544 scan.get_normalized_compat_name(tnode)
545 self.assertEqual('', stdout.getvalue().strip())
546
547 self.assertEqual(2, len(scan._missing_drivers))
548 self.assertEqual({'rockchip_rk3288_grf', 'nvidia_tegra114_i2c'},
549 scan._missing_drivers)
550 with test_util.capture_sys_output() as (stdout, _):
551 scan.show_warnings()
552 self.assertIn('rockchip_rk3288_grf', stdout.getvalue())
553
554 # This should show just the rockchip warning, since the tegra driver
555 # is not in self._missing_drivers
556 scan._missing_drivers.remove('nvidia_tegra114_i2c')
557 with test_util.capture_sys_output() as (stdout, _):
558 scan.show_warnings()
559 self.assertIn('rockchip_rk3288_grf', stdout.getvalue())
560 self.assertNotIn('tegra_i2c_ids', stdout.getvalue())
561
562 # Do a similar thing with used drivers. By marking the tegra driver as
563 # used, the warning related to that driver will be shown
564 drv = scan._drivers['i2c_tegra']
565 drv.used = True
566 with test_util.capture_sys_output() as (stdout, _):
567 scan.show_warnings()
568 self.assertIn('rockchip_rk3288_grf', stdout.getvalue())
569 self.assertIn('tegra_i2c_ids', stdout.getvalue())
570
571 # Add a warning to make sure multiple warnings are shown
572 scan._warnings['i2c_tegra'].update(
573 scan._warnings['nvidia_tegra114_i2c'])
574 del scan._warnings['nvidia_tegra114_i2c']
575 with test_util.capture_sys_output() as (stdout, _):
576 scan.show_warnings()
577 self.assertEqual('''i2c_tegra: WARNING: the driver nvidia_tegra114_i2c was not found in the driver list
578 : file.c: Warning: unexpected suffix ' + 1' on .of_match line for compat 'tegra_i2c_ids'
579
580rockchip_rk3288_grf: WARNING: the driver rockchip_rk3288_grf was not found in the driver list
581
582''',
583 stdout.getvalue())
584 self.assertIn('tegra_i2c_ids', stdout.getvalue())
Simon Glass43ba4922021-07-04 12:19:49 -0600585
586 def scan_uclass_warning(self):
587 """Test a missing .uclass in the driver"""
588 buff = '''
589static const struct udevice_id tegra_i2c_ids[] = {
590 { .compatible = "nvidia,tegra114-i2c", .data = TYPE_114 },
591 { }
592};
593
594U_BOOT_DRIVER(i2c_tegra) = {
595 .name = "i2c_tegra",
596 .of_match = tegra_i2c_ids,
597};
598'''
599 scan = src_scan.Scanner(None, None)
600 scan._parse_driver('file.c', buff)
601 self.assertEqual(
602 {'i2c_tegra': {'Missing .uclass in file.c'}},
603 scan._warnings)
604
605 def scan_compat_warning(self):
606 """Test a missing .compatible in the driver"""
607 buff = '''
608static const struct udevice_id tegra_i2c_ids[] = {
609 { .compatible = "nvidia,tegra114-i2c", .data = TYPE_114 },
610 { }
611};
612
613U_BOOT_DRIVER(i2c_tegra) = {
614 .name = "i2c_tegra",
615 .id = UCLASS_I2C,
616};
617'''
618 scan = src_scan.Scanner(None, None)
619 scan._parse_driver('file.c', buff)
620 self.assertEqual(
621 {'i2c_tegra': {'Missing .compatible in file.c'}},
622 scan._warnings)