summaryrefslogtreecommitdiff
path: root/tools/dtoc/test_src_scan.py
diff options
context:
space:
mode:
authorTom Rini <trini@konsulko.com>2021-04-05 11:29:57 -0400
committerTom Rini <trini@konsulko.com>2021-04-05 11:29:57 -0400
commit90eba245a66aa20589404ba537215faf2012c1a3 (patch)
treec581cd1f00dd162aeac4262bb4e74c2a9fea98c9 /tools/dtoc/test_src_scan.py
parentb46dd116ce03e235f2a7d4843c6278e1da44b5e1 (diff)
parentdb8b46120aed6554d1ff405260ea6d2cc2439fcc (diff)
Merge branch 'next'
Diffstat (limited to 'tools/dtoc/test_src_scan.py')
-rw-r--r--tools/dtoc/test_src_scan.py397
1 files changed, 391 insertions, 6 deletions
diff --git a/tools/dtoc/test_src_scan.py b/tools/dtoc/test_src_scan.py
index 7d686530d68..0af86dcf0c3 100644
--- a/tools/dtoc/test_src_scan.py
+++ b/tools/dtoc/test_src_scan.py
@@ -7,6 +7,7 @@
This includes unit tests for scanning of the source code
"""
+import copy
import os
import shutil
import tempfile
@@ -17,6 +18,20 @@ from dtoc import src_scan
from patman import test_util
from patman import tools
+OUR_PATH = os.path.dirname(os.path.realpath(__file__))
+
+class FakeNode:
+ """Fake Node object for testing"""
+ def __init__(self):
+ self.name = None
+ self.props = {}
+
+class FakeProp:
+ """Fake Prop object for testing"""
+ def __init__(self):
+ self.name = None
+ self.value = None
+
# This is a test so is allowed to access private things in the module it is
# testing
# pylint: disable=W0212
@@ -44,7 +59,8 @@ class TestSrcScan(unittest.TestCase):
def test_additional(self):
"""Test with additional drivers to scan"""
scan = src_scan.Scanner(
- None, True, [None, '', 'tools/dtoc/dtoc_test_scan_drivers.cxx'])
+ None, True,
+ [None, '', 'tools/dtoc/test/dtoc_test_scan_drivers.cxx'])
scan.scan_drivers()
self.assertIn('sandbox_gpio_alias2', scan._driver_aliases)
self.assertEqual('sandbox_gpio',
@@ -69,10 +85,22 @@ class TestSrcScan(unittest.TestCase):
def test_driver(self):
"""Test the Driver class"""
- drv1 = src_scan.Driver('fred')
- drv2 = src_scan.Driver('mary')
- drv3 = src_scan.Driver('fred')
- self.assertEqual("Driver(name='fred')", str(drv1))
+ i2c = 'I2C_UCLASS'
+ compat = {'rockchip,rk3288-grf': 'ROCKCHIP_SYSCON_GRF',
+ 'rockchip,rk3288-srf': None}
+ drv1 = src_scan.Driver('fred', 'fred.c')
+ drv2 = src_scan.Driver('mary', 'mary.c')
+ drv3 = src_scan.Driver('fred', 'fred.c')
+ drv1.uclass_id = i2c
+ drv1.compat = compat
+ drv2.uclass_id = i2c
+ drv2.compat = compat
+ drv3.uclass_id = i2c
+ drv3.compat = compat
+ self.assertEqual(
+ "Driver(name='fred', used=False, uclass_id='I2C_UCLASS', "
+ "compat={'rockchip,rk3288-grf': 'ROCKCHIP_SYSCON_GRF', "
+ "'rockchip,rk3288-srf': None}, priv=)", str(drv1))
self.assertEqual(drv1, drv3)
self.assertNotEqual(drv1, drv2)
self.assertNotEqual(drv2, drv3)
@@ -91,7 +119,9 @@ class TestSrcScan(unittest.TestCase):
fname_list = []
add_file('fname.c')
+ add_file('.git/ignoreme.c')
add_file('dir/fname2.c')
+ add_file('build-sandbox/ignoreme2.c')
# Mock out scan_driver and check that it is called with the
# expected files
@@ -101,7 +131,362 @@ class TestSrcScan(unittest.TestCase):
self.assertEqual(2, len(mocked.mock_calls))
self.assertEqual(mock.call(fname_list[0]),
mocked.mock_calls[0])
- self.assertEqual(mock.call(fname_list[1]),
+ # .git file should be ignored
+ self.assertEqual(mock.call(fname_list[2]),
mocked.mock_calls[1])
finally:
shutil.rmtree(indir)
+
+ def test_scan(self):
+ """Test scanning of a driver"""
+ fname = os.path.join(OUR_PATH, '..', '..', 'drivers/i2c/tegra_i2c.c')
+ buff = tools.ReadFile(fname, False)
+ scan = src_scan.Scanner(None, False, None)
+ scan._parse_driver(fname, buff)
+ self.assertIn('i2c_tegra', scan._drivers)
+ drv = scan._drivers['i2c_tegra']
+ self.assertEqual('i2c_tegra', drv.name)
+ self.assertEqual('UCLASS_I2C', drv.uclass_id)
+ self.assertEqual(
+ {'nvidia,tegra114-i2c': 'TYPE_114',
+ 'nvidia,tegra20-i2c': 'TYPE_STD',
+ 'nvidia,tegra20-i2c-dvc': 'TYPE_DVC'}, drv.compat)
+ self.assertEqual('i2c_bus', drv.priv)
+ self.assertEqual(1, len(scan._drivers))
+
+ def test_normalized_name(self):
+ """Test operation of get_normalized_compat_name()"""
+ prop = FakeProp()
+ prop.name = 'compatible'
+ prop.value = 'rockchip,rk3288-grf'
+ node = FakeNode()
+ node.props = {'compatible': prop}
+
+ # get_normalized_compat_name() uses this to check for root node
+ node.parent = FakeNode()
+
+ scan = src_scan.Scanner(None, False, None)
+ with test_util.capture_sys_output() as (stdout, _):
+ name, aliases = scan.get_normalized_compat_name(node)
+ self.assertEqual('rockchip_rk3288_grf', name)
+ self.assertEqual([], aliases)
+ self.assertEqual(
+ 'WARNING: the driver rockchip_rk3288_grf was not found in the driver list',
+ stdout.getvalue().strip())
+
+ i2c = 'I2C_UCLASS'
+ compat = {'rockchip,rk3288-grf': 'ROCKCHIP_SYSCON_GRF',
+ 'rockchip,rk3288-srf': None}
+ drv = src_scan.Driver('fred', 'fred.c')
+ drv.uclass_id = i2c
+ drv.compat = compat
+ scan._drivers['rockchip_rk3288_grf'] = drv
+
+ scan._driver_aliases['rockchip_rk3288_srf'] = 'rockchip_rk3288_grf'
+
+ with test_util.capture_sys_output() as (stdout, _):
+ name, aliases = scan.get_normalized_compat_name(node)
+ self.assertEqual('', stdout.getvalue().strip())
+ self.assertEqual('rockchip_rk3288_grf', name)
+ self.assertEqual([], aliases)
+
+ prop.value = 'rockchip,rk3288-srf'
+ with test_util.capture_sys_output() as (stdout, _):
+ name, aliases = scan.get_normalized_compat_name(node)
+ self.assertEqual('', stdout.getvalue().strip())
+ self.assertEqual('rockchip_rk3288_grf', name)
+ self.assertEqual(['rockchip_rk3288_srf'], aliases)
+
+ def test_scan_errors(self):
+ """Test detection of scanning errors"""
+ buff = '''
+static const struct udevice_id tegra_i2c_ids2[] = {
+ { .compatible = "nvidia,tegra114-i2c", .data = TYPE_114 },
+ { }
+};
+
+U_BOOT_DRIVER(i2c_tegra) = {
+ .name = "i2c_tegra",
+ .id = UCLASS_I2C,
+ .of_match = tegra_i2c_ids,
+};
+'''
+ scan = src_scan.Scanner(None, False, None)
+ with self.assertRaises(ValueError) as exc:
+ scan._parse_driver('file.c', buff)
+ self.assertIn(
+ "file.c: Unknown compatible var 'tegra_i2c_ids' (found: tegra_i2c_ids2)",
+ str(exc.exception))
+
+ def test_of_match(self):
+ """Test detection of of_match_ptr() member"""
+ buff = '''
+static const struct udevice_id tegra_i2c_ids[] = {
+ { .compatible = "nvidia,tegra114-i2c", .data = TYPE_114 },
+ { }
+};
+
+U_BOOT_DRIVER(i2c_tegra) = {
+ .name = "i2c_tegra",
+ .id = UCLASS_I2C,
+ .of_match = of_match_ptr(tegra_i2c_ids),
+};
+'''
+ scan = src_scan.Scanner(None, False, None)
+ scan._parse_driver('file.c', buff)
+ self.assertIn('i2c_tegra', scan._drivers)
+ drv = scan._drivers['i2c_tegra']
+ self.assertEqual('i2c_tegra', drv.name)
+ self.assertEqual('', drv.phase)
+ self.assertEqual([], drv.headers)
+
+ def test_priv(self):
+ """Test collection of struct info from drivers"""
+ buff = '''
+static const struct udevice_id test_ids[] = {
+ { .compatible = "nvidia,tegra114-i2c", .data = TYPE_114 },
+ { }
+};
+
+U_BOOT_DRIVER(testing) = {
+ .name = "testing",
+ .id = UCLASS_I2C,
+ .of_match = test_ids,
+ .priv_auto = sizeof(struct some_priv),
+ .plat_auto = sizeof(struct some_plat),
+ .per_child_auto = sizeof(struct some_cpriv),
+ .per_child_plat_auto = sizeof(struct some_cplat),
+ DM_PHASE(tpl)
+ DM_HEADER(<i2c.h>)
+ DM_HEADER(<asm/clk.h>)
+};
+'''
+ scan = src_scan.Scanner(None, False, None)
+ scan._parse_driver('file.c', buff)
+ self.assertIn('testing', scan._drivers)
+ drv = scan._drivers['testing']
+ self.assertEqual('testing', drv.name)
+ self.assertEqual('UCLASS_I2C', drv.uclass_id)
+ self.assertEqual(
+ {'nvidia,tegra114-i2c': 'TYPE_114'}, drv.compat)
+ self.assertEqual('some_priv', drv.priv)
+ self.assertEqual('some_plat', drv.plat)
+ self.assertEqual('some_cpriv', drv.child_priv)
+ self.assertEqual('some_cplat', drv.child_plat)
+ self.assertEqual('tpl', drv.phase)
+ self.assertEqual(['<i2c.h>', '<asm/clk.h>'], drv.headers)
+ self.assertEqual(1, len(scan._drivers))
+
+ def test_uclass_scan(self):
+ """Test collection of uclass-driver info"""
+ buff = '''
+UCLASS_DRIVER(i2c) = {
+ .id = UCLASS_I2C,
+ .name = "i2c",
+ .flags = DM_UC_FLAG_SEQ_ALIAS,
+ .priv_auto = sizeof(struct some_priv),
+ .per_device_auto = sizeof(struct per_dev_priv),
+ .per_device_plat_auto = sizeof(struct per_dev_plat),
+ .per_child_auto = sizeof(struct per_child_priv),
+ .per_child_plat_auto = sizeof(struct per_child_plat),
+ .child_post_bind = i2c_child_post_bind,
+};
+
+'''
+ scan = src_scan.Scanner(None, False, None)
+ scan._parse_uclass_driver('file.c', buff)
+ self.assertIn('UCLASS_I2C', scan._uclass)
+ drv = scan._uclass['UCLASS_I2C']
+ self.assertEqual('i2c', drv.name)
+ self.assertEqual('UCLASS_I2C', drv.uclass_id)
+ self.assertEqual('some_priv', drv.priv)
+ self.assertEqual('per_dev_priv', drv.per_dev_priv)
+ self.assertEqual('per_dev_plat', drv.per_dev_plat)
+ self.assertEqual('per_child_priv', drv.per_child_priv)
+ self.assertEqual('per_child_plat', drv.per_child_plat)
+ self.assertEqual(1, len(scan._uclass))
+
+ drv2 = copy.deepcopy(drv)
+ self.assertEqual(drv, drv2)
+ drv2.priv = 'other_priv'
+ self.assertNotEqual(drv, drv2)
+
+ # The hashes only depend on the uclass ID, so should be equal
+ self.assertEqual(drv.__hash__(), drv2.__hash__())
+
+ self.assertEqual("UclassDriver(name='i2c', uclass_id='UCLASS_I2C')",
+ str(drv))
+
+ def test_uclass_scan_errors(self):
+ """Test detection of uclass scanning errors"""
+ buff = '''
+UCLASS_DRIVER(i2c) = {
+ .name = "i2c",
+};
+
+'''
+ scan = src_scan.Scanner(None, False, None)
+ with self.assertRaises(ValueError) as exc:
+ scan._parse_uclass_driver('file.c', buff)
+ self.assertIn("file.c: Cannot parse uclass ID in driver 'i2c'",
+ str(exc.exception))
+
+ def test_struct_scan(self):
+ """Test collection of struct info"""
+ buff = '''
+/* some comment */
+struct some_struct1 {
+ struct i2c_msg *msgs;
+ uint nmsgs;
+};
+'''
+ scan = src_scan.Scanner(None, False, None)
+ scan._basedir = os.path.join(OUR_PATH, '..', '..')
+ scan._parse_structs('arch/arm/include/asm/file.h', buff)
+ self.assertIn('some_struct1', scan._structs)
+ struc = scan._structs['some_struct1']
+ self.assertEqual('some_struct1', struc.name)
+ self.assertEqual('asm/file.h', struc.fname)
+
+ buff = '''
+/* another comment */
+struct another_struct {
+ int speed_hz;
+ int max_transaction_bytes;
+};
+'''
+ scan._parse_structs('include/file2.h', buff)
+ self.assertIn('another_struct', scan._structs)
+ struc = scan._structs['another_struct']
+ self.assertEqual('another_struct', struc.name)
+ self.assertEqual('file2.h', struc.fname)
+
+ self.assertEqual(2, len(scan._structs))
+
+ self.assertEqual("Struct(name='another_struct', fname='file2.h')",
+ str(struc))
+
+ def test_struct_scan_errors(self):
+ """Test scanning a header file with an invalid unicode file"""
+ output = tools.GetOutputFilename('output.h')
+ tools.WriteFile(output, b'struct this is a test \x81 of bad unicode')
+
+ scan = src_scan.Scanner(None, False, None)
+ with test_util.capture_sys_output() as (stdout, _):
+ scan.scan_header(output)
+ self.assertIn('due to unicode error', stdout.getvalue())
+
+ def setup_dup_drivers(self, name, phase=''):
+ """Set up for a duplcate test
+
+ Returns:
+ tuple:
+ Scanner to use
+ Driver record for first driver
+ Text of second driver declaration
+ Node for driver 1
+ """
+ driver1 = '''
+static const struct udevice_id test_ids[] = {
+ { .compatible = "nvidia,tegra114-i2c", .data = TYPE_114 },
+ { }
+};
+
+U_BOOT_DRIVER(%s) = {
+ .name = "testing",
+ .id = UCLASS_I2C,
+ .of_match = test_ids,
+ %s
+};
+''' % (name, 'DM_PHASE(%s)' % phase if phase else '')
+ driver2 = '''
+static const struct udevice_id test_ids[] = {
+ { .compatible = "nvidia,tegra114-dvc" },
+ { }
+};
+
+U_BOOT_DRIVER(%s) = {
+ .name = "testing",
+ .id = UCLASS_RAM,
+ .of_match = test_ids,
+};
+''' % name
+ scan = src_scan.Scanner(None, False, None, phase)
+ scan._parse_driver('file1.c', driver1)
+ self.assertIn(name, scan._drivers)
+ drv1 = scan._drivers[name]
+
+ prop = FakeProp()
+ prop.name = 'compatible'
+ prop.value = 'nvidia,tegra114-i2c'
+ node = FakeNode()
+ node.name = 'testing'
+ node.props = {'compatible': prop}
+
+ # get_normalized_compat_name() uses this to check for root node
+ node.parent = FakeNode()
+
+ return scan, drv1, driver2, node
+
+ def test_dup_drivers(self):
+ """Test handling of duplicate drivers"""
+ name = 'nvidia_tegra114_i2c'
+ scan, drv1, driver2, node = self.setup_dup_drivers(name)
+ self.assertEqual('', drv1.phase)
+
+ # The driver should not have a duplicate yet
+ self.assertEqual([], drv1.dups)
+
+ scan._parse_driver('file2.c', driver2)
+
+ # The first driver should now be a duplicate of the second
+ drv2 = scan._drivers[name]
+ self.assertEqual('', drv2.phase)
+ self.assertEqual(1, len(drv2.dups))
+ self.assertEqual([drv1], drv2.dups)
+
+ # There is no way to distinguish them, so we should expect a warning
+ self.assertTrue(drv2.warn_dups)
+
+ # We should see a warning
+ with test_util.capture_sys_output() as (stdout, _):
+ scan.mark_used([node])
+ self.assertEqual(
+ "Warning: Duplicate driver name 'nvidia_tegra114_i2c' (orig=file2.c, dups=file1.c)",
+ stdout.getvalue().strip())
+
+ def test_dup_drivers_phase(self):
+ """Test handling of duplicate drivers but with different phases"""
+ name = 'nvidia_tegra114_i2c'
+ scan, drv1, driver2, node = self.setup_dup_drivers(name, 'spl')
+ scan._parse_driver('file2.c', driver2)
+ self.assertEqual('spl', drv1.phase)
+
+ # The second driver should now be a duplicate of the second
+ self.assertEqual(1, len(drv1.dups))
+ drv2 = drv1.dups[0]
+
+ # The phase is different, so we should not warn of dups
+ self.assertFalse(drv1.warn_dups)
+
+ # We should not see a warning
+ with test_util.capture_sys_output() as (stdout, _):
+ scan.mark_used([node])
+ self.assertEqual('', stdout.getvalue().strip())
+
+ def test_sequence(self):
+ """Test assignment of sequence numnbers"""
+ scan = src_scan.Scanner(None, False, None, '')
+ node = FakeNode()
+ uc = src_scan.UclassDriver('UCLASS_I2C')
+ node.uclass = uc
+ node.driver = True
+ node.seq = -1
+ node.path = 'mypath'
+ uc.alias_num_to_node[2] = node
+
+ # This should assign 3 (after the 2 that exists)
+ seq = scan.assign_seq(node)
+ self.assertEqual(3, seq)
+ self.assertEqual({'mypath': 3}, uc.alias_path_to_num)
+ self.assertEqual({2: node, 3: node}, uc.alias_num_to_node)