1import pytest
2from unittest.mock import Mock
3from unittest.mock import call
4from checksymbolslib.test_util import assert_db_calls
5import checksymbolslib.makefile as m
6
7
8handle_eval = [
9    ('generic',
10     'package/foo/foo.mk',
11     5,
12     '$(eval $(generic-package))',
13     {'add_symbol_usage': [call('BR2_PACKAGE_FOO', 'package/foo/foo.mk', 5)]}),
14    ('ignore trailing whitespace',
15     'package/foo/foo.mk',
16     5,
17     '$(eval $(generic-package)) ',
18     {'add_symbol_usage': [call('BR2_PACKAGE_FOO', 'package/foo/foo.mk', 5)]}),
19    ('ignore indent',
20     'package/foo/foo.mk',
21     5,
22     '\t$(eval $(generic-package))',
23     {'add_symbol_usage': [call('BR2_PACKAGE_FOO', 'package/foo/foo.mk', 5)]}),
24    ('rootfs',
25     'fs/foo/foo.mk',
26     5,
27     '$(eval $(rootfs))',
28     {'add_symbol_usage': [
29         call('BR2_TARGET_ROOTFS_FOO', 'fs/foo/foo.mk', 5),
30         call('BR2_TARGET_ROOTFS_FOO_BZIP2', 'fs/foo/foo.mk', 5),
31         call('BR2_TARGET_ROOTFS_FOO_GZIP', 'fs/foo/foo.mk', 5),
32         call('BR2_TARGET_ROOTFS_FOO_LZ4', 'fs/foo/foo.mk', 5),
33         call('BR2_TARGET_ROOTFS_FOO_LZMA', 'fs/foo/foo.mk', 5),
34         call('BR2_TARGET_ROOTFS_FOO_LZO', 'fs/foo/foo.mk', 5),
35         call('BR2_TARGET_ROOTFS_FOO_XZ', 'fs/foo/foo.mk', 5),
36         call('BR2_TARGET_ROOTFS_FOO_ZSTD', 'fs/foo/foo.mk', 5)]}),
37    ('kernel module',
38     'package/foo/foo.mk',
39     6,
40     '$(eval $(kernel-module))',
41     {'add_symbol_usage': [call('BR2_PACKAGE_FOO', 'package/foo/foo.mk', 6)]}),
42    ('not an eval for package infra',
43     'docs/manual/manual.mk',
44     10,
45     '$(eval $(call asciidoc-document))',
46     {}),
47    ('linux',
48     'linux/linux.mk',
49     617,
50     '$(eval $(kconfig-package))',
51     {'add_symbol_usage': [call('BR2_LINUX_KERNEL', 'linux/linux.mk', 617)]}),
52    ('virtual toolchain',
53     'toolchain/toolchain-external/toolchain-external.mk',
54     18,
55     '$(eval $(virtual-package))',
56     {'add_symbol_usage': [
57         call('BR2_PACKAGE_PROVIDES_TOOLCHAIN_EXTERNAL', 'toolchain/toolchain-external/toolchain-external.mk', 18),
58         call('BR2_PACKAGE_HAS_TOOLCHAIN_EXTERNAL', 'toolchain/toolchain-external/toolchain-external.mk', 18),
59         call('BR2_TOOLCHAIN_EXTERNAL', 'toolchain/toolchain-external/toolchain-external.mk', 18)],
60      'add_symbol_virtual': [call('BR2_TOOLCHAIN_EXTERNAL', 'toolchain/toolchain-external/toolchain-external.mk', 18)]}),
61    ('virtual package',
62     'package/foo/foo.mk',
63     18,
64     '$(eval $(virtual-package))',
65     {'add_symbol_usage': [
66         call('BR2_PACKAGE_PROVIDES_FOO', 'package/foo/foo.mk', 18),
67         call('BR2_PACKAGE_HAS_FOO', 'package/foo/foo.mk', 18),
68         call('BR2_PACKAGE_FOO', 'package/foo/foo.mk', 18)],
69      'add_symbol_virtual': [call('BR2_PACKAGE_FOO', 'package/foo/foo.mk', 18)]}),
70    ('host virtual package',
71     'package/foo/foo.mk',
72     18,
73     '$(eval $(host-virtual-package))',
74     {'add_symbol_usage': [
75         call('BR2_PACKAGE_PROVIDES_HOST_FOO', 'package/foo/foo.mk', 18),
76         call('BR2_PACKAGE_HAS_HOST_FOO', 'package/foo/foo.mk', 18),
77         call('BR2_PACKAGE_HOST_FOO', 'package/foo/foo.mk', 18)]}),
78    ('host generic package',
79     'package/foo/foo.mk',
80     18,
81     '$(eval $(host-package))',
82     {'add_symbol_usage': [call('BR2_PACKAGE_HOST_FOO', 'package/foo/foo.mk', 18)]}),
83    ('boot package',
84     'boot/foo/foo.mk',
85     18,
86     '$(eval $(generic-package))',
87     {'add_symbol_usage': [call('BR2_TARGET_FOO', 'boot/foo/foo.mk', 18)]}),
88    ('toolchain package',
89     'toolchain/foo/foo.mk',
90     18,
91     '$(eval $(generic-package))',
92     {'add_symbol_usage': [call('BR2_FOO', 'toolchain/foo/foo.mk', 18)]}),
93    ('generic package',
94     'package/foo/foo.mk',
95     18,
96     '$(eval $(generic-package))',
97     {'add_symbol_usage': [call('BR2_PACKAGE_FOO', 'package/foo/foo.mk', 18)]}),
98    ('cmake package',
99     'package/foo/foo.mk',
100     18,
101     '$(eval $(cmake-package))',
102     {'add_symbol_usage': [call('BR2_PACKAGE_FOO', 'package/foo/foo.mk', 18)]}),
103    ]
104
105
106@pytest.mark.parametrize('testname,filename,lineno,line,expected_calls', handle_eval)
107def test_handle_eval(testname, filename, lineno, line, expected_calls):
108    db = Mock()
109    m.handle_eval(db, filename, lineno, line)
110    assert_db_calls(db, expected_calls)
111
112
113handle_definition = [
114    ('legacy attribution',
115     'Makefile.legacy',
116     9,
117     'BR2_LEGACY_FOO := foo',
118     True,
119     {'add_symbol_legacy_definition': [call('BR2_LEGACY_FOO', 'Makefile.legacy', 9)]}),
120    ('attribution 1',
121     'Makefile',
122     9,
123     'BR2_FOO ?= foo',
124     False,
125     {'add_symbol_definition': [call('BR2_FOO', 'Makefile', 9)]}),
126    ('attribution 2',
127     'Makefile',
128     9,
129     'BR2_FOO = $(BR2_BAR)',
130     False,
131     {'add_symbol_definition': [call('BR2_FOO', 'Makefile', 9)]}),
132    ('attribution 3',
133     'Makefile',
134     9,
135     'BR2_FOO := foo',
136     False,
137     {'add_symbol_definition': [call('BR2_FOO', 'Makefile', 9)]}),
138    ('normal export',
139     'Makefile',
140     90,
141     'export BR2_FOO',
142     False,
143     {'add_symbol_definition': [call('BR2_FOO', 'Makefile', 90)]}),
144    ('legacy export',
145     'Makefile.legacy',
146     90,
147     'export BR2_FOO',
148     True,
149     {'add_symbol_legacy_definition': [call('BR2_FOO', 'Makefile.legacy', 90)]}),
150    ]
151
152
153@pytest.mark.parametrize('testname,filename,lineno,line,legacy,expected_calls', handle_definition)
154def test_handle_definition(testname, filename, lineno, line, legacy, expected_calls):
155    db = Mock()
156    m.handle_definition(db, filename, lineno, line, legacy)
157    assert_db_calls(db, expected_calls)
158
159
160handle_usage = [
161    ('legacy',
162     'Makefile.legacy',
163     8,
164     'ifeq ($(BR2_LEGACY),y)',
165     True,
166     {'add_symbol_usage_in_legacy': [call('BR2_LEGACY', 'Makefile.legacy', 8)]}),
167    ('attribution',
168     'Makefile',
169     9,
170     'BR2_FOO = $(BR2_BAR)',
171     False,
172     {'add_symbol_usage': [call('BR2_BAR', 'Makefile', 9)]}),
173    ('host virtual package',
174     'package/foo/foo.mk',
175     18,
176     '$(eval $(host-virtual-package))',
177     False,
178     {'add_symbol_usage': [
179         call('BR2_PACKAGE_PROVIDES_HOST_FOO', 'package/foo/foo.mk', 18),
180         call('BR2_PACKAGE_HAS_HOST_FOO', 'package/foo/foo.mk', 18),
181         call('BR2_PACKAGE_HOST_FOO', 'package/foo/foo.mk', 18)]}),
182    ]
183
184
185@pytest.mark.parametrize('testname,filename,lineno,line,legacy,expected_calls', handle_usage)
186def test_handle_usage(testname, filename, lineno, line, legacy, expected_calls):
187    db = Mock()
188    m.handle_usage(db, filename, lineno, line, legacy)
189    assert_db_calls(db, expected_calls)
190
191
192populate_db = [
193    ('legacy',
194     'Makefile.legacy',
195     [[8, 'ifeq ($(BR2_LEGACY),y)'],
196      [9, 'BR2_LEGACY_FOO := foo'],
197      [34, 'ifneq ($(BUILDROOT_CONFIG),$(BR2_CONFIG))']],
198     {'add_symbol_usage_in_legacy': [
199         call('BR2_LEGACY', 'Makefile.legacy', 8),
200         call('BR2_CONFIG', 'Makefile.legacy', 34)],
201      'add_symbol_legacy_definition': [call('BR2_LEGACY_FOO', 'Makefile.legacy', 9)]}),
202    ('attribution',
203     'Makefile',
204     [[9, 'BR2_FOO = $(BR2_BAR)']],
205     {'add_symbol_definition': [call('BR2_FOO', 'Makefile', 9)],
206      'add_symbol_usage': [call('BR2_BAR', 'Makefile', 9)]}),
207    ('legacy attribution',
208     'Makefile.legacy',
209     [[9, 'BR2_FOO = $(BR2_BAR)']],
210     {'add_symbol_legacy_definition': [call('BR2_FOO', 'Makefile.legacy', 9)],
211      'add_symbol_usage_in_legacy': [call('BR2_BAR', 'Makefile.legacy', 9)]}),
212    ('generic',
213     'package/foo/foo.mk',
214     [[3, 'ifeq ($(BR2_PACKAGE_FOO_BAR):$(BR2_BAR),y:)'],
215      [4, 'export BR2_PACKAGE_FOO_BAZ'],
216      [5, '$(eval $(generic-package))']],
217     {'add_symbol_usage': [
218         call('BR2_PACKAGE_FOO_BAR', 'package/foo/foo.mk', 3),
219         call('BR2_BAR', 'package/foo/foo.mk', 3),
220         call('BR2_PACKAGE_FOO', 'package/foo/foo.mk', 5)],
221      'add_symbol_definition': [call('BR2_PACKAGE_FOO_BAZ', 'package/foo/foo.mk', 4)]}),
222    ('rootfs',
223     'fs/foo/foo.mk',
224     [[4, 'ifeq ($(BR2_TARGET_ROOTFS_FOO_LZ4),y)'],
225      [5, '$(eval $(rootfs))']],
226     {'add_symbol_usage': [
227         call('BR2_TARGET_ROOTFS_FOO', 'fs/foo/foo.mk', 5),
228         call('BR2_TARGET_ROOTFS_FOO_BZIP2', 'fs/foo/foo.mk', 5),
229         call('BR2_TARGET_ROOTFS_FOO_GZIP', 'fs/foo/foo.mk', 5),
230         call('BR2_TARGET_ROOTFS_FOO_LZ4', 'fs/foo/foo.mk', 4),
231         call('BR2_TARGET_ROOTFS_FOO_LZ4', 'fs/foo/foo.mk', 5),
232         call('BR2_TARGET_ROOTFS_FOO_LZMA', 'fs/foo/foo.mk', 5),
233         call('BR2_TARGET_ROOTFS_FOO_LZO', 'fs/foo/foo.mk', 5),
234         call('BR2_TARGET_ROOTFS_FOO_XZ', 'fs/foo/foo.mk', 5),
235         call('BR2_TARGET_ROOTFS_FOO_ZSTD', 'fs/foo/foo.mk', 5)]}),
236    ]
237
238
239@pytest.mark.parametrize('testname,filename,file_content,expected_calls', populate_db)
240def test_populate_db(testname, filename, file_content, expected_calls):
241    db = Mock()
242    m.populate_db(db, filename, file_content)
243    assert_db_calls(db, expected_calls)
244
245
246check_filename = [
247    ('arch/arch.mk.riscv',
248     'arch/arch.mk.riscv',
249     True),
250    ('fs/cramfs/cramfs.mk',
251     'fs/cramfs/cramfs.mk',
252     True),
253    ('linux/linux-ext-fbtft.mk',
254     'linux/linux-ext-fbtft.mk',
255     True),
256    ('package/ace/ace.mk',
257     'package/ace/ace.mk',
258     True),
259    ('package/linux-tools/linux-tool-hv.mk.in',
260     'package/linux-tools/linux-tool-hv.mk.in',
261     True),
262    ('package/pkg-generic.mk',
263     'package/pkg-generic.mk',
264     True),
265    ('package/x11r7/xlib_libXt/xlib_libXt.mk',
266     'package/x11r7/xlib_libXt/xlib_libXt.mk',
267     True),
268    ('support/dependencies/check-host-make.mk',
269     'support/dependencies/check-host-make.mk',
270     True),
271    ('toolchain/toolchain-external/toolchain-external-arm-aarch64-be/toolchain-external-arm-aarch64-be.mk',
272     'toolchain/toolchain-external/toolchain-external-arm-aarch64-be/toolchain-external-arm-aarch64-be.mk',
273     True),
274    ('Makefile.legacy',
275     'Makefile.legacy',
276     True),
277    ('boot/common.mk',
278     'boot/common.mk',
279     True),
280    ('fs/common.mk',
281     'fs/common.mk',
282     True),
283    ('Makefile',
284     'Makefile',
285     True),
286    ('package/Makefile.in',
287     'package/Makefile.in',
288     True),
289    ('Config.in',
290     'Config.in',
291     False),
292    ('package/foo/0001-Makefile.patch',
293     'package/foo/0001-Makefile.patch',
294     False),
295    ]
296
297
298@pytest.mark.parametrize('testname,filename,expected', check_filename)
299def test_check_filename(testname, filename, expected):
300    symbols = m.check_filename(filename)
301    assert symbols == expected
302