0c5472ace2
This script checks for inconsistencies on symbols declared in Config.in and used in .mk files. Currently it checks only symbols following the pattern BR2_\w+ . The script first gets the list of all files in the repository (using git ls-files like 'make check-flake8' already do). Then it parses all relevant files, searching for symbol definitions and usages, and add entries into a database. At the end, the database is searched for inconsistencies: - symbol that is part of "choice" and is referenced with "select"; - legacy symbol being referenced in packages; - legacy symbol being redefined in packages; - symbol referenced but not defined; - symbol defined but not referenced; - legacy symbol that has a Note stating it is referenced by a package (for legacy handling) but is referenced in the package without a comment "# legacy"; - legacy symbol that has a Note stating it is referenced by a package but it is not actually referenced. There is also a debug parameter --search that dumps any filename or symbol entries from the database that matches a regexp. Sample usages: $ utils/check-symbols $ utils/docker-run utils/check-symbols $ utils/check-symbols --search 'GETTEXT\b|\/openssl' At same time the script is created: - add unit tests for it, they can be run using: utils/docker-run python3 -m pytest -v utils/checksymbolslib/ - add two more GitLab CI jobs: check-symbols (to check current tree using the script) and check-check-symbols (to check the script against its unit tests) Cc: Thomas Petazzoni <thomas.petazzoni@bootlin.com> Signed-off-by: Ricardo Martincoski <ricardo.martincoski@gmail.com> [Peter: print warnings to stderr, rename change_current_dir() to change_to_top_dir()] Signed-off-by: Peter Korsgaard <peter@korsgaard.com>
153 lines
3.8 KiB
Python
153 lines
3.8 KiB
Python
import os
|
|
import pytest
|
|
import tempfile
|
|
import checksymbolslib.file as m
|
|
|
|
|
|
def test_get_list_of_files_in_the_repo():
|
|
all_files = m.get_list_of_files_in_the_repo()
|
|
assert 'Makefile' in all_files
|
|
assert 'package/Config.in' in all_files
|
|
assert len(all_files) > 1000
|
|
|
|
|
|
get_list_of_files_to_process = [
|
|
('unknown file type',
|
|
['a/file/Config.in',
|
|
'another/file.mk',
|
|
'unknown/file/type'],
|
|
['a/file/Config.in',
|
|
'another/file.mk']),
|
|
('runtime test infra fixtures',
|
|
['a/file/Config.in',
|
|
'support/testing/a/broken/Config.in',
|
|
'another/file.mk'],
|
|
['a/file/Config.in',
|
|
'another/file.mk']),
|
|
]
|
|
|
|
|
|
@pytest.mark.parametrize('testname,all_files,expected', get_list_of_files_to_process)
|
|
def test_get_list_of_files_to_process(testname, all_files, expected):
|
|
files_to_process = m.get_list_of_files_to_process(all_files)
|
|
assert files_to_process == expected
|
|
|
|
|
|
get_list_of_filenames_with_pattern = [
|
|
('ignored directories',
|
|
['a/file/Config.in',
|
|
'support/testing/a/broken/file/Config.in',
|
|
'not/found.mk',
|
|
'another/file.mk'],
|
|
['a/file/Config.in',
|
|
'not/found.mk',
|
|
'another/file.mk'],
|
|
'file',
|
|
['support/testing/a/broken/file/Config.in']),
|
|
('processed files',
|
|
['a/file/Config.in',
|
|
'not/found.mk',
|
|
'another/file.mk'],
|
|
[],
|
|
'file',
|
|
['a/file/Config.in',
|
|
'another/file.mk']),
|
|
('case sensitive',
|
|
['a/file/Config.in',
|
|
'not/found.mk',
|
|
'another/file.mk'],
|
|
[],
|
|
'FILE',
|
|
[]),
|
|
('or',
|
|
['a/file/Config.in',
|
|
'not/found.mk',
|
|
'another/file.mk'],
|
|
[],
|
|
'file|FILE',
|
|
['a/file/Config.in',
|
|
'another/file.mk']),
|
|
('complex regexp',
|
|
['a/file/Config.in',
|
|
'not/found.mk',
|
|
'another/file.mk'],
|
|
[],
|
|
'^n[oO]+t.*mk$',
|
|
['not/found.mk']),
|
|
]
|
|
|
|
|
|
@pytest.mark.parametrize('testname,all_files,files_to_process,pattern,expected', get_list_of_filenames_with_pattern)
|
|
def test_get_list_of_filenames_with_pattern(testname, all_files, files_to_process, pattern, expected):
|
|
files_to_process = m.get_list_of_filenames_with_pattern(all_files, files_to_process, pattern)
|
|
assert files_to_process == expected
|
|
|
|
|
|
read_file = [
|
|
('indent',
|
|
'file1',
|
|
' content1\n'
|
|
'\t# comment1',
|
|
[[1, ' content1\n'],
|
|
[2, '\t# comment1']]),
|
|
('trailing space',
|
|
'file2',
|
|
'content2 \n'
|
|
'# comment2\t\n',
|
|
[[1, 'content2 \n'],
|
|
[2, '# comment2\t\n']]),
|
|
('empty line',
|
|
'file3',
|
|
'\n'
|
|
'\n',
|
|
[[1, '\n'],
|
|
[2, '\n']]),
|
|
('missing newline at EOF',
|
|
'file4',
|
|
'\n'
|
|
' text\t',
|
|
[[1, '\n'],
|
|
[2, ' text\t']]),
|
|
]
|
|
|
|
|
|
@pytest.mark.parametrize('testname,filename,content,,expected', read_file)
|
|
def test_read_file(testname, filename, content, expected):
|
|
with tempfile.TemporaryDirectory(suffix='-checksymbolslib-test-file') as workdir:
|
|
full_filename = os.path.join(workdir, filename)
|
|
with open(full_filename, 'wb') as f:
|
|
f.write(content.encode())
|
|
read_file_content = m.read_file(full_filename)
|
|
assert read_file_content == expected
|
|
|
|
|
|
cleanup_file_content = [
|
|
('empty file',
|
|
[],
|
|
[]),
|
|
('empty line',
|
|
[[5, '\n']],
|
|
[[5, '']]),
|
|
('trailing space',
|
|
[[3, ' \n']],
|
|
[[3, ' ']]),
|
|
('trailing tab',
|
|
[[3, '\t\n']],
|
|
[[3, '\t']]),
|
|
('1 continuation',
|
|
[[1, 'foo \\\n'],
|
|
[2, 'bar\n']],
|
|
[[1, 'foo bar']]),
|
|
('2 continuations',
|
|
[[1, 'foo \\\n'],
|
|
[2, 'bar \\\n'],
|
|
[3, 'baz\n']],
|
|
[[1, 'foo bar baz']]),
|
|
]
|
|
|
|
|
|
@pytest.mark.parametrize('testname,file_content_raw,expected', cleanup_file_content)
|
|
def test_cleanup_file_content(testname, file_content_raw, expected):
|
|
cleaned_up_content = m.cleanup_file_content(file_content_raw)
|
|
assert cleaned_up_content == expected
|