Merge tag 'u-boot-stm32-20220617' of https://source.denx.de/u-boot/custodians/u-boot-stm
[platform/kernel/u-boot.git] / tools / dtoc / test_src_scan.py
1 # SPDX-License-Identifier: GPL-2.0+
2 # Copyright 2020 Google LLC
3 #
4
5 """Tests for the src_scan module
6
7 This includes unit tests for scanning of the source code
8 """
9
10 import copy
11 import os
12 import shutil
13 import tempfile
14 import unittest
15 from unittest import mock
16
17 from dtoc import src_scan
18 from patman import test_util
19 from patman import tools
20
21 OUR_PATH = os.path.dirname(os.path.realpath(__file__))
22
23 EXPECT_WARN = {'rockchip_rk3288_grf':
24                    {'WARNING: the driver rockchip_rk3288_grf was not found in the driver list'}}
25
26 class FakeNode:
27     """Fake Node object for testing"""
28     def __init__(self):
29         self.name = None
30         self.props = {}
31
32 class FakeProp:
33     """Fake Prop object for testing"""
34     def __init__(self):
35         self.name = None
36         self.value = None
37
38 # This is a test so is allowed to access private things in the module it is
39 # testing
40 # pylint: disable=W0212
41
42 class TestSrcScan(unittest.TestCase):
43     """Tests for src_scan"""
44     @classmethod
45     def setUpClass(cls):
46         tools.prepare_output_dir(None)
47
48     @classmethod
49     def tearDownClass(cls):
50         tools.finalise_output_dir()
51
52     def test_simple(self):
53         """Simple test of scanning drivers"""
54         scan = src_scan.Scanner(None, None)
55         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"""
64         scan = src_scan.Scanner(
65             None, [None, '', 'tools/dtoc/test/dtoc_test_scan_drivers.cxx'])
66         scan.scan_drivers()
67         self.assertIn('sandbox_gpio_alias2', scan._driver_aliases)
68         self.assertEqual('sandbox_gpio',
69                          scan._driver_aliases['sandbox_gpio_alias2'])
70
71     def test_unicode_error(self):
72         """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
82         scan = src_scan.Scanner(None, [driver_fn])
83         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*")
87
88     def test_driver(self):
89         """Test the Driver class"""
90         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(
103             "Driver(name='fred', used=False, uclass_id='I2C_UCLASS', "
104             "compat={'rockchip,rk3288-grf': 'ROCKCHIP_SYSCON_GRF', "
105             "'rockchip,rk3288-srf': None}, priv=)", str(drv1))
106         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)
116             tools.write_file(pathname, '', binary=False)
117             fname_list.append(pathname)
118
119         try:
120             indir = tempfile.mkdtemp(prefix='dtoc.')
121
122             fname_list = []
123             add_file('fname.c')
124             add_file('.git/ignoreme.c')
125             add_file('dir/fname2.c')
126             add_file('build-sandbox/ignoreme2.c')
127
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:
131                 scan = src_scan.Scanner(indir, None)
132                 scan.scan_drivers()
133             self.assertEqual(2, len(mocked.mock_calls))
134             self.assertEqual(mock.call(fname_list[0]),
135                              mocked.mock_calls[0])
136             # .git file should be ignored
137             self.assertEqual(mock.call(fname_list[2]),
138                              mocked.mock_calls[1])
139         finally:
140             shutil.rmtree(indir)
141
142     def test_scan(self):
143         """Test scanning of a driver"""
144         fname = os.path.join(OUR_PATH, '..', '..', 'drivers/i2c/tegra_i2c.c')
145         buff = tools.read_file(fname, False)
146         scan = src_scan.Scanner(None, None)
147         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',
154              'nvidia,tegra124-i2c': 'TYPE_114',
155              '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))
159         self.assertEqual({}, scan._warnings)
160
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}
168
169         # get_normalized_compat_name() uses this to check for root node
170         node.parent = FakeNode()
171
172         scan = src_scan.Scanner(None, None)
173         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)
177         self.assertEqual(1, len(scan._missing_drivers))
178         self.assertEqual({'rockchip_rk3288_grf'}, scan._missing_drivers)
179         self.assertEqual('', stdout.getvalue().strip())
180         self.assertEqual(EXPECT_WARN, scan._warnings)
181
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)
197         self.assertEqual(EXPECT_WARN, scan._warnings)
198
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)
205         self.assertEqual(EXPECT_WARN, scan._warnings)
206
207     def test_scan_errors(self):
208         """Test detection of scanning errors"""
209         buff = '''
210 static const struct udevice_id tegra_i2c_ids2[] = {
211         { .compatible = "nvidia,tegra114-i2c", .data = TYPE_114 },
212         { }
213 };
214
215 U_BOOT_DRIVER(i2c_tegra) = {
216         .name   = "i2c_tegra",
217         .id     = UCLASS_I2C,
218         .of_match = tegra_i2c_ids,
219 };
220 '''
221         scan = src_scan.Scanner(None, None)
222         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 = '''
231 static const struct udevice_id tegra_i2c_ids[] = {
232         { .compatible = "nvidia,tegra114-i2c", .data = TYPE_114 },
233         { }
234 };
235
236 U_BOOT_DRIVER(i2c_tegra) = {
237         .name   = "i2c_tegra",
238         .id     = UCLASS_I2C,
239         .of_match = of_match_ptr(tegra_i2c_ids),
240 };
241 '''
242         scan = src_scan.Scanner(None, None)
243         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)
247         self.assertEqual('', drv.phase)
248         self.assertEqual([], drv.headers)
249
250     def test_priv(self):
251         """Test collection of struct info from drivers"""
252         buff = '''
253 static const struct udevice_id test_ids[] = {
254         { .compatible = "nvidia,tegra114-i2c", .data = TYPE_114 },
255         { }
256 };
257
258 U_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),
266         DM_PHASE(tpl)
267         DM_HEADER(<i2c.h>)
268         DM_HEADER(<asm/clk.h>)
269 };
270 '''
271         scan = src_scan.Scanner(None, None)
272         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)
283         self.assertEqual('tpl', drv.phase)
284         self.assertEqual(['<i2c.h>', '<asm/clk.h>'], drv.headers)
285         self.assertEqual(1, len(scan._drivers))
286
287     def test_uclass_scan(self):
288         """Test collection of uclass-driver info"""
289         buff = '''
290 UCLASS_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 '''
303         scan = src_scan.Scanner(None, None)
304         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 = '''
330 UCLASS_DRIVER(i2c) = {
331         .name           = "i2c",
332 };
333
334 '''
335         scan = src_scan.Scanner(None, None)
336         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))
340
341     def test_struct_scan(self):
342         """Test collection of struct info"""
343         buff = '''
344 /* some comment */
345 struct some_struct1 {
346         struct i2c_msg *msgs;
347         uint nmsgs;
348 };
349 '''
350         scan = src_scan.Scanner(None, None)
351         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 */
360 struct 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"""
378         output = tools.get_output_filename('output.h')
379         tools.write_file(output, b'struct this is a test \x81 of bad unicode')
380
381         scan = src_scan.Scanner(None, None)
382         with test_util.capture_sys_output() as (stdout, _):
383             scan.scan_header(output)
384         self.assertIn('due to unicode error', stdout.getvalue())
385
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 = '''
397 static const struct udevice_id test_ids[] = {
398         { .compatible = "nvidia,tegra114-i2c", .data = TYPE_114 },
399         { }
400 };
401
402 U_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 = '''
410 static const struct udevice_id test_ids[] = {
411         { .compatible = "nvidia,tegra114-dvc" },
412         { }
413 };
414
415 U_BOOT_DRIVER(%s) = {
416         .name   = "testing",
417         .id     = UCLASS_RAM,
418         .of_match = test_ids,
419 };
420 ''' % name
421         scan = src_scan.Scanner(None, None, phase)
422         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
433         # get_normalized_compat_name() uses this to check for root node
434         node.parent = FakeNode()
435
436         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())
483
484     def test_sequence(self):
485         """Test assignment of sequence numnbers"""
486         scan = src_scan.Scanner(None, None, '')
487         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)
500
501     def test_scan_warnings(self):
502         """Test detection of scanning warnings"""
503         buff = '''
504 static const struct udevice_id tegra_i2c_ids[] = {
505         { .compatible = "nvidia,tegra114-i2c", .data = TYPE_114 },
506         { }
507 };
508
509 U_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
580 rockchip_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())
585
586     def scan_uclass_warning(self):
587         """Test a missing .uclass in the driver"""
588         buff = '''
589 static const struct udevice_id tegra_i2c_ids[] = {
590         { .compatible = "nvidia,tegra114-i2c", .data = TYPE_114 },
591         { }
592 };
593
594 U_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 = '''
608 static const struct udevice_id tegra_i2c_ids[] = {
609         { .compatible = "nvidia,tegra114-i2c", .data = TYPE_114 },
610         { }
611 };
612
613 U_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)