mirror of
https://git.busybox.net/buildroot.git
synced 2024-11-26 15:03:27 +08:00
utils/check-symbols: new script
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>
This commit is contained in:
parent
b95f7591bd
commit
0c5472ace2
@ -2523,7 +2523,9 @@ F: support/testing/run-tests
|
||||
F: support/testing/tests/package/test_atop.py
|
||||
F: support/testing/tests/utils/test_check_package.py
|
||||
F: utils/check-package
|
||||
F: utils/check-symbols
|
||||
F: utils/checkpackagelib/
|
||||
F: utils/checksymbolslib/
|
||||
F: utils/docker-run
|
||||
|
||||
N: Richard Braun <rbraun@sceen.net>
|
||||
|
@ -2,6 +2,10 @@
|
||||
script:
|
||||
- python3 -m pytest -v utils/checkpackagelib/
|
||||
|
||||
.check-check-symbol_base:
|
||||
script:
|
||||
- python3 -m pytest -v utils/checksymbolslib/
|
||||
|
||||
.check-DEVELOPERS_base:
|
||||
script:
|
||||
- utils/get-developers -v
|
||||
@ -14,6 +18,10 @@
|
||||
script:
|
||||
- make check-package
|
||||
|
||||
.check-symbol_base:
|
||||
script:
|
||||
- utils/check-symbols
|
||||
|
||||
.defconfig_check:
|
||||
before_script:
|
||||
- DEFCONFIG_NAME=$(echo ${CI_JOB_NAME} | sed -e 's,_check$,,g')
|
||||
|
@ -26,7 +26,7 @@ gen_tests() {
|
||||
local do_basics do_defconfigs do_runtime do_testpkg
|
||||
local defconfigs_ext cfg tst
|
||||
|
||||
basics=( check-package DEVELOPERS flake8 package )
|
||||
basics=( check-package check-symbol DEVELOPERS flake8 package symbol )
|
||||
|
||||
defconfigs=( $(cd configs; LC_ALL=C ls -1 *_defconfig) )
|
||||
|
||||
|
78
utils/check-symbols
Executable file
78
utils/check-symbols
Executable file
@ -0,0 +1,78 @@
|
||||
#!/usr/bin/env python3
|
||||
|
||||
import argparse
|
||||
import os
|
||||
import sys
|
||||
|
||||
import checksymbolslib.file as file
|
||||
from checksymbolslib.db import DB
|
||||
|
||||
|
||||
def parse_args():
|
||||
parser = argparse.ArgumentParser()
|
||||
parser.add_argument('--search', action='store', default=None,
|
||||
help='print all symbols matching a given regular expression')
|
||||
return parser.parse_args()
|
||||
|
||||
|
||||
def change_to_top_dir():
|
||||
base_dir = os.path.dirname(os.path.dirname(os.path.realpath(__file__)))
|
||||
os.chdir(base_dir)
|
||||
|
||||
|
||||
def get_full_db(files_to_process):
|
||||
db = DB()
|
||||
for f in files_to_process:
|
||||
file.populate_db_from_file(db, f)
|
||||
return db
|
||||
|
||||
|
||||
def print_filenames_with_pattern(all_files, files_to_process, pattern):
|
||||
ignored_filenames = file.get_list_of_filenames_with_pattern(all_files, files_to_process, pattern)
|
||||
processed_filenames = file.get_list_of_filenames_with_pattern(files_to_process, [], pattern)
|
||||
print('========== filenames found with pattern "{}": {}'.format(pattern, len(processed_filenames)))
|
||||
for f in processed_filenames:
|
||||
print(f)
|
||||
print('========== ignored filenames with pattern "{}": {}'.format(pattern, len(ignored_filenames)))
|
||||
for f in ignored_filenames:
|
||||
print(f)
|
||||
|
||||
|
||||
def print_symbols_with_pattern(db, pattern):
|
||||
symbols = db.get_symbols_with_pattern(pattern)
|
||||
print('========== symbols with pattern "{}": {}'.format(pattern, len(symbols)))
|
||||
for s in symbols:
|
||||
print(s, str(symbols[s]))
|
||||
|
||||
|
||||
def __main__():
|
||||
flags = parse_args()
|
||||
|
||||
change_to_top_dir()
|
||||
all_files = file.get_list_of_files_in_the_repo()
|
||||
files_to_process = file.get_list_of_files_to_process(all_files)
|
||||
db = get_full_db(files_to_process)
|
||||
|
||||
if flags.search:
|
||||
print_filenames_with_pattern(all_files, files_to_process, flags.search)
|
||||
print_symbols_with_pattern(db, flags.search)
|
||||
print('========== warnings:')
|
||||
|
||||
warnings = []
|
||||
warnings += db.get_warnings_for_choices_selected()
|
||||
warnings += db.get_warnings_for_legacy_symbols_being_defined()
|
||||
warnings += db.get_warnings_for_legacy_symbols_being_used()
|
||||
warnings += db.get_warnings_for_symbols_with_legacy_note_and_no_comment_on_usage()
|
||||
warnings += db.get_warnings_for_symbols_with_legacy_note_and_no_usage()
|
||||
warnings += db.get_warnings_for_symbols_without_definition()
|
||||
warnings += db.get_warnings_for_symbols_without_usage()
|
||||
|
||||
for filename, lineno, msg in sorted(warnings):
|
||||
print('{}:{}: {}'.format(filename, lineno, msg), file=sys.stderr)
|
||||
|
||||
if len(warnings) > 0:
|
||||
sys.exit(1)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
__main__()
|
0
utils/checksymbolslib/__init__.py
Normal file
0
utils/checksymbolslib/__init__.py
Normal file
140
utils/checksymbolslib/br.py
Normal file
140
utils/checksymbolslib/br.py
Normal file
@ -0,0 +1,140 @@
|
||||
import os
|
||||
import re
|
||||
|
||||
|
||||
ignored_directories = [
|
||||
'support/testing/',
|
||||
]
|
||||
# Makefile
|
||||
symbols_used_only_in_source_code = [
|
||||
'BR2_USE_CCACHE',
|
||||
]
|
||||
# package/skeleton/Config.in
|
||||
symbols_used_only_for_host_variant = [
|
||||
'BR2_PACKAGE_SKELETON',
|
||||
]
|
||||
# Makefile
|
||||
# package/pkg-generic.mk
|
||||
symbols_defined_only_at_command_line = [
|
||||
'BR2_GRAPH_ALT',
|
||||
'BR2_GRAPH_DEPS_OPTS',
|
||||
'BR2_GRAPH_DOT_OPTS',
|
||||
'BR2_GRAPH_OUT',
|
||||
'BR2_GRAPH_SIZE_OPTS',
|
||||
'BR2_INSTRUMENTATION_SCRIPTS',
|
||||
]
|
||||
# Makefile
|
||||
symbols_defined_only_when_using_br2_external = [
|
||||
'BR2_EXTERNAL',
|
||||
'BR2_EXTERNAL_DIRS',
|
||||
'BR2_EXTERNAL_MKS',
|
||||
'BR2_EXTERNAL_NAMES',
|
||||
]
|
||||
# boot/barebox/barebox.mk
|
||||
symbols_defined_only_for_barebox_variant = [
|
||||
'BR2_TARGET_BAREBOX_AUX_BAREBOXENV',
|
||||
]
|
||||
# toolchain/toolchain/toolchain.mk
|
||||
# toolchain/toolchain-buildroot/toolchain-buildroot.mk
|
||||
symbols_not_defined_for_fake_virtual_packages = [
|
||||
'BR2_PACKAGE_HAS_TOOLCHAIN',
|
||||
'BR2_PACKAGE_HAS_TOOLCHAIN_BUILDROOT',
|
||||
'BR2_PACKAGE_PROVIDES_TOOLCHAIN',
|
||||
'BR2_PACKAGE_PROVIDES_TOOLCHAIN_BUILDROOT',
|
||||
]
|
||||
# fs/common.mk
|
||||
suffixes_not_defined_for_all_rootfs_types = [
|
||||
'_BZIP2',
|
||||
'_GZIP',
|
||||
'_LZ4',
|
||||
'_LZMA',
|
||||
'_LZO',
|
||||
'_XZ',
|
||||
'_ZSTD',
|
||||
]
|
||||
# fs/common.mk
|
||||
rootfs_prefix = 'BR2_TARGET_ROOTFS_'
|
||||
# package/pkg-generic.mk
|
||||
package_prefix = 'BR2_PACKAGE_'
|
||||
# package/pkg-generic.mk
|
||||
boot_prefix = 'BR2_TARGET_'
|
||||
# package/pkg-generic.mk
|
||||
toolchain_prefix = 'BR2_'
|
||||
# boot/barebox/barebox.mk
|
||||
barebox_infra_suffixes = [
|
||||
'',
|
||||
'_BAREBOXENV',
|
||||
'_BOARD_DEFCONFIG',
|
||||
'_CONFIG_FRAGMENT_FILES',
|
||||
'_CUSTOM_CONFIG_FILE',
|
||||
'_CUSTOM_EMBEDDED_ENV_PATH',
|
||||
'_CUSTOM_ENV',
|
||||
'_CUSTOM_ENV_PATH',
|
||||
'_IMAGE_FILE',
|
||||
'_USE_CUSTOM_CONFIG',
|
||||
'_USE_DEFCONFIG',
|
||||
]
|
||||
re_kconfig_symbol = re.compile(r'\b(BR2_\w+)\b')
|
||||
# Example lines to be handled:
|
||||
# config BR2_TOOLCHAIN_EXTERNAL_PREFIX
|
||||
# menuconfig BR2_PACKAGE_GST1_PLUGINS_BASE
|
||||
re_kconfig_config = re.compile(r'^\s*(menu|)config\s+(BR2_\w+)')
|
||||
# Example lines to be handled:
|
||||
# default "uclibc" if BR2_TOOLCHAIN_BUILDROOT_UCLIBC
|
||||
# default BR2_TARGET_GRUB2_BUILTIN_MODULES if BR2_TARGET_GRUB2_BUILTIN_MODULES != ""
|
||||
# default y if BR2_HOSTARCH = "powerpc"
|
||||
re_kconfig_default = re.compile(r'^\s*default\s')
|
||||
re_kconfig_default_before_conditional = re.compile(r'^.*\bif\b')
|
||||
re_kconfig_default_legacy_comment = re.compile(r'#\s*legacy')
|
||||
# Example lines to be handled:
|
||||
# depends on !(BR2_TOOLCHAIN_USES_GLIBC && BR2_TOOLCHAIN_USES_MUSL)
|
||||
# depends on BR2_HOSTARCH = "x86_64" || BR2_HOSTARCH = "x86"
|
||||
re_kconfig_depends = re.compile(r'^\s*depends on\s')
|
||||
# Example lines to be handled:
|
||||
# select BR2_PACKAGE_HOST_NODEJS if BR2_PACKAGE_NODEJS_MODULES_ADDITIONAL != ""
|
||||
# select BR2_PACKAGE_LIBDRM if !(BR2_arm && BR2_PACKAGE_IMX_GPU_VIV_OUTPUT_FB)
|
||||
# select BR2_PACKAGE_OPENSSL if !(BR2_PACKAGE_GNUTLS || BR2_PACKAGE_MBEDTLS)
|
||||
re_kconfig_select = re.compile(r'^\s*select\s')
|
||||
re_kconfig_select_conditional = re.compile(r'\bif\s.*')
|
||||
# Example lines to be handled:
|
||||
# if !BR2_SKIP_LEGACY
|
||||
# if (BR2_PACKAGE_FREESCALE_IMX_PLATFORM_IMX51 || BR2_PACKAGE_FREESCALE_IMX_PLATFORM_IMX53)
|
||||
# if BR2_PACKAGE_HAS_LUAINTERPRETER && !BR2_STATIC_LIBS
|
||||
# if BR2_PACKAGE_QEMU_CUSTOM_TARGETS = ""
|
||||
re_kconfig_if = re.compile(r'^\s*if\s')
|
||||
# Example lines to be handled:
|
||||
# source "$BR2_BASE_DIR/.br2-external.in.jpeg"
|
||||
re_kconfig_source = re.compile(r'^\s*source\b')
|
||||
|
||||
re_kconfig_choice = re.compile(r'^\s*choice\b')
|
||||
re_kconfig_endchoice = re.compile(r'^\s*endchoice\b')
|
||||
re_makefile_eval = re.compile(r'^\s*\$\(eval\b')
|
||||
re_menu = re.compile(r'^\s*menu\b')
|
||||
re_endmenu = re.compile(r'^\s*endmenu\b')
|
||||
re_comments = re.compile(r'#.*$')
|
||||
re_legacy_special_comment = re.compile(r'#.*(BR2_\w+)\s.*still referenced')
|
||||
re_host_symbol = re.compile(r'(BR2_PACKAGE_HOST_\w+|BR2_PACKAGE_HAS_HOST_\w+)')
|
||||
re_makefile_symbol_usage = re.compile(r'\$\((BR2_\w+)\)')
|
||||
re_makefile_symbol_export = re.compile(r'export\s*(BR2_\w+)')
|
||||
re_makefile_symbol_attribution = re.compile(r'^\s*(BR2_\w+)\s*[?:=]')
|
||||
|
||||
|
||||
def get_package_from_filename(filename):
|
||||
package = os.path.basename(filename)[:-3].upper().replace('-', '_')
|
||||
return package
|
||||
|
||||
|
||||
def is_an_optional_symbol_for_a_roofts(symbol):
|
||||
if not symbol.startswith(rootfs_prefix):
|
||||
return False
|
||||
for sufix in suffixes_not_defined_for_all_rootfs_types:
|
||||
if symbol.endswith(sufix):
|
||||
return True
|
||||
return False
|
||||
|
||||
|
||||
def file_belongs_to_an_ignored_diretory(filename):
|
||||
for d in ignored_directories:
|
||||
if filename.startswith(d):
|
||||
return True
|
||||
return False
|
205
utils/checksymbolslib/db.py
Normal file
205
utils/checksymbolslib/db.py
Normal file
@ -0,0 +1,205 @@
|
||||
import re
|
||||
|
||||
import checksymbolslib.br as br
|
||||
|
||||
|
||||
choice = 'part of a choice'
|
||||
definition = 'definition'
|
||||
helper = 'possible config helper'
|
||||
legacy_definition = 'legacy definition'
|
||||
legacy_note = 'legacy note'
|
||||
legacy_usage = 'legacy usage'
|
||||
select = 'selected'
|
||||
usage = 'normal usage'
|
||||
usage_in_legacy = 'usage inside legacy'
|
||||
virtual = 'virtual'
|
||||
|
||||
|
||||
class DB:
|
||||
def __init__(self):
|
||||
self.all_symbols = {}
|
||||
|
||||
def __str__(self):
|
||||
return str(self.all_symbols)
|
||||
|
||||
def add_symbol_entry(self, symbol, filename, lineno, entry_type):
|
||||
if symbol not in self.all_symbols:
|
||||
self.all_symbols[symbol] = {}
|
||||
if entry_type not in self.all_symbols[symbol]:
|
||||
self.all_symbols[symbol][entry_type] = {}
|
||||
if filename not in self.all_symbols[symbol][entry_type]:
|
||||
self.all_symbols[symbol][entry_type][filename] = []
|
||||
self.all_symbols[symbol][entry_type][filename].append(lineno)
|
||||
|
||||
def add_symbol_choice(self, symbol, filename, lineno):
|
||||
self.add_symbol_entry(symbol, filename, lineno, choice)
|
||||
|
||||
def add_symbol_definition(self, symbol, filename, lineno):
|
||||
self.add_symbol_entry(symbol, filename, lineno, definition)
|
||||
|
||||
def add_symbol_helper(self, symbol, filename, lineno):
|
||||
self.add_symbol_entry(symbol, filename, lineno, helper)
|
||||
|
||||
def add_symbol_legacy_definition(self, symbol, filename, lineno):
|
||||
self.add_symbol_entry(symbol, filename, lineno, legacy_definition)
|
||||
|
||||
def add_symbol_legacy_note(self, symbol, filename, lineno):
|
||||
self.add_symbol_entry(symbol, filename, lineno, legacy_note)
|
||||
|
||||
def add_symbol_legacy_usage(self, symbol, filename, lineno):
|
||||
self.add_symbol_entry(symbol, filename, lineno, legacy_usage)
|
||||
|
||||
def add_symbol_select(self, symbol, filename, lineno):
|
||||
self.add_symbol_entry(symbol, filename, lineno, select)
|
||||
|
||||
def add_symbol_usage(self, symbol, filename, lineno):
|
||||
self.add_symbol_entry(symbol, filename, lineno, usage)
|
||||
|
||||
def add_symbol_usage_in_legacy(self, symbol, filename, lineno):
|
||||
self.add_symbol_entry(symbol, filename, lineno, usage_in_legacy)
|
||||
|
||||
def add_symbol_virtual(self, symbol, filename, lineno):
|
||||
self.add_symbol_entry(symbol, filename, lineno, virtual)
|
||||
|
||||
def get_symbols_with_pattern(self, pattern):
|
||||
re_pattern = re.compile(r'{}'.format(pattern))
|
||||
found_symbols = {}
|
||||
for symbol, entries in self.all_symbols.items():
|
||||
if not re_pattern.search(symbol):
|
||||
continue
|
||||
found_symbols[symbol] = entries
|
||||
return found_symbols
|
||||
|
||||
def get_warnings_for_choices_selected(self):
|
||||
warnings = []
|
||||
for symbol, entries in self.all_symbols.items():
|
||||
if choice not in entries:
|
||||
continue
|
||||
if select not in entries:
|
||||
continue
|
||||
all_items = []
|
||||
all_items += entries.get(select, {}).items()
|
||||
for filename, linenos in all_items:
|
||||
for lineno in linenos:
|
||||
msg = '{} is part of a "choice" and should not be "select"ed'.format(symbol)
|
||||
warnings.append((filename, lineno, msg))
|
||||
return warnings
|
||||
|
||||
def get_warnings_for_legacy_symbols_being_used(self):
|
||||
warnings = []
|
||||
for symbol, entries in self.all_symbols.items():
|
||||
if legacy_definition not in entries:
|
||||
continue
|
||||
if usage not in entries:
|
||||
continue
|
||||
all_items = []
|
||||
all_items += entries.get(usage, {}).items()
|
||||
for filename, linenos in all_items:
|
||||
for lineno in linenos:
|
||||
msg = '{} is a legacy symbol and should not be referenced'.format(symbol)
|
||||
warnings.append((filename, lineno, msg))
|
||||
return warnings
|
||||
|
||||
def get_warnings_for_legacy_symbols_being_defined(self):
|
||||
warnings = []
|
||||
for symbol, entries in self.all_symbols.items():
|
||||
if legacy_definition not in entries:
|
||||
continue
|
||||
if definition not in entries:
|
||||
continue
|
||||
all_items = []
|
||||
all_items += entries.get(definition, {}).items()
|
||||
for filename, linenos in all_items:
|
||||
for lineno in linenos:
|
||||
msg = '{} is a legacy symbol and should not be redefined'.format(symbol)
|
||||
warnings.append((filename, lineno, msg))
|
||||
return warnings
|
||||
|
||||
def get_warnings_for_symbols_without_definition(self):
|
||||
warnings = []
|
||||
for symbol, entries in self.all_symbols.items():
|
||||
if definition in entries:
|
||||
continue
|
||||
if legacy_definition in entries:
|
||||
continue
|
||||
if br.re_host_symbol.search(symbol):
|
||||
continue
|
||||
if br.is_an_optional_symbol_for_a_roofts(symbol):
|
||||
continue
|
||||
if symbol in br.symbols_defined_only_at_command_line:
|
||||
continue
|
||||
if symbol in br.symbols_defined_only_when_using_br2_external:
|
||||
continue
|
||||
if symbol in br.symbols_defined_only_for_barebox_variant:
|
||||
continue
|
||||
if symbol in br.symbols_not_defined_for_fake_virtual_packages:
|
||||
continue
|
||||
if virtual in entries:
|
||||
continue
|
||||
all_items = []
|
||||
all_items += entries.get(usage, {}).items()
|
||||
all_items += entries.get(legacy_usage, {}).items()
|
||||
all_items += entries.get(usage_in_legacy, {}).items()
|
||||
for filename, linenos in all_items:
|
||||
for lineno in linenos:
|
||||
msg = '{} referenced but not defined'.format(symbol)
|
||||
warnings.append((filename, lineno, msg))
|
||||
return warnings
|
||||
|
||||
def get_warnings_for_symbols_without_usage(self):
|
||||
warnings = []
|
||||
for symbol, entries in self.all_symbols.items():
|
||||
if usage in entries:
|
||||
continue
|
||||
if usage_in_legacy in entries:
|
||||
continue
|
||||
if legacy_usage in entries:
|
||||
continue
|
||||
if symbol in br.symbols_used_only_in_source_code:
|
||||
continue
|
||||
if symbol in br.symbols_used_only_for_host_variant:
|
||||
continue
|
||||
if helper in entries:
|
||||
continue
|
||||
if choice in entries:
|
||||
continue
|
||||
all_items = []
|
||||
all_items += entries.get(definition, {}).items()
|
||||
all_items += entries.get(legacy_definition, {}).items()
|
||||
for filename, linenos in all_items:
|
||||
for lineno in linenos:
|
||||
msg = '{} defined but not referenced'.format(symbol)
|
||||
warnings.append((filename, lineno, msg))
|
||||
return warnings
|
||||
|
||||
def get_warnings_for_symbols_with_legacy_note_and_no_comment_on_usage(self):
|
||||
warnings = []
|
||||
for symbol, entries in self.all_symbols.items():
|
||||
if legacy_note not in entries:
|
||||
continue
|
||||
if legacy_usage in entries:
|
||||
continue
|
||||
all_items = []
|
||||
all_items += entries.get(usage, {}).items()
|
||||
for filename, linenos in all_items:
|
||||
for lineno in linenos:
|
||||
msg = '{} missing "# legacy"'.format(symbol)
|
||||
warnings.append((filename, lineno, msg))
|
||||
return warnings
|
||||
|
||||
def get_warnings_for_symbols_with_legacy_note_and_no_usage(self):
|
||||
warnings = []
|
||||
for symbol, entries in self.all_symbols.items():
|
||||
if legacy_note not in entries:
|
||||
continue
|
||||
if legacy_usage in entries:
|
||||
continue
|
||||
if usage in entries:
|
||||
continue
|
||||
all_items = []
|
||||
all_items += entries.get(legacy_note, {}).items()
|
||||
for filename, linenos in all_items:
|
||||
for lineno in linenos:
|
||||
msg = '{} not referenced but has a comment stating it is'.format(symbol)
|
||||
warnings.append((filename, lineno, msg))
|
||||
return warnings
|
83
utils/checksymbolslib/file.py
Normal file
83
utils/checksymbolslib/file.py
Normal file
@ -0,0 +1,83 @@
|
||||
import re
|
||||
import subprocess
|
||||
|
||||
import checksymbolslib.br as br
|
||||
import checksymbolslib.kconfig as kconfig
|
||||
import checksymbolslib.makefile as makefile
|
||||
|
||||
|
||||
file_types = [
|
||||
kconfig,
|
||||
makefile,
|
||||
]
|
||||
|
||||
|
||||
def get_list_of_files_in_the_repo():
|
||||
cmd = ['git', 'ls-files']
|
||||
p = subprocess.Popen(cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
|
||||
stdout = p.communicate()[0]
|
||||
processed_output = [str(line.decode().rstrip()) for line in stdout.splitlines() if line]
|
||||
return processed_output
|
||||
|
||||
|
||||
def get_list_of_files_to_process(all_files):
|
||||
files_to_process = []
|
||||
for f in all_files:
|
||||
if br.file_belongs_to_an_ignored_diretory(f):
|
||||
continue
|
||||
for t in file_types:
|
||||
if t.check_filename(f):
|
||||
files_to_process.append(f)
|
||||
break
|
||||
return files_to_process
|
||||
|
||||
|
||||
def get_list_of_filenames_with_pattern(all_files, exclude_list, pattern):
|
||||
re_pattern = re.compile(r'{}'.format(pattern))
|
||||
matching_filenames = []
|
||||
for filename in all_files:
|
||||
if re_pattern.search(filename):
|
||||
if filename not in exclude_list:
|
||||
matching_filenames.append(filename)
|
||||
return matching_filenames
|
||||
|
||||
|
||||
def read_file(filename):
|
||||
file_content_raw = []
|
||||
with open(filename, 'r', errors='surrogateescape') as f:
|
||||
for lineno, text in enumerate(f.readlines()):
|
||||
file_content_raw.append([lineno + 1, text])
|
||||
return file_content_raw
|
||||
|
||||
|
||||
def cleanup_file_content(file_content_raw):
|
||||
cleaned_up_content = []
|
||||
continuation = False
|
||||
last_line = None
|
||||
first_lineno = None
|
||||
for cur_lineno, cur_line in file_content_raw:
|
||||
if continuation:
|
||||
line = last_line + cur_line
|
||||
lineno = first_lineno
|
||||
else:
|
||||
line = cur_line
|
||||
lineno = cur_lineno
|
||||
continuation = False
|
||||
last_line = None
|
||||
first_lineno = None
|
||||
clean_line = line.rstrip('\n')
|
||||
if clean_line.endswith('\\'):
|
||||
continuation = True
|
||||
last_line = clean_line.rstrip('\\')
|
||||
first_lineno = lineno
|
||||
continue
|
||||
cleaned_up_content.append([lineno, clean_line])
|
||||
return cleaned_up_content
|
||||
|
||||
|
||||
def populate_db_from_file(db, filename):
|
||||
file_content_raw = read_file(filename)
|
||||
file_content_to_process = cleanup_file_content(file_content_raw)
|
||||
for t in file_types:
|
||||
if t.check_filename(filename):
|
||||
t.populate_db(db, filename, file_content_to_process)
|
139
utils/checksymbolslib/kconfig.py
Normal file
139
utils/checksymbolslib/kconfig.py
Normal file
@ -0,0 +1,139 @@
|
||||
import os
|
||||
|
||||
import checksymbolslib.br as br
|
||||
|
||||
|
||||
def all_symbols_from(line):
|
||||
clean_line = br.re_comments.sub('', line)
|
||||
symbols = br.re_kconfig_symbol.findall(clean_line)
|
||||
return symbols
|
||||
|
||||
|
||||
def handle_definition(db, filename, lineno, line, legacy):
|
||||
for symbol in all_symbols_from(line):
|
||||
if legacy:
|
||||
db.add_symbol_legacy_definition(symbol, filename, lineno)
|
||||
else:
|
||||
db.add_symbol_definition(symbol, filename, lineno)
|
||||
|
||||
|
||||
def handle_usage(db, filename, lineno, line, legacy):
|
||||
for symbol in all_symbols_from(line):
|
||||
if legacy:
|
||||
db.add_symbol_usage_in_legacy(symbol, filename, lineno)
|
||||
else:
|
||||
db.add_symbol_usage(symbol, filename, lineno)
|
||||
|
||||
|
||||
def handle_default(db, filename, lineno, line, legacy):
|
||||
if legacy:
|
||||
handle_usage(db, filename, lineno, line, legacy)
|
||||
return
|
||||
if not br.re_kconfig_default_legacy_comment.search(line):
|
||||
handle_usage(db, filename, lineno, line, legacy)
|
||||
return
|
||||
after = br.re_kconfig_default_before_conditional.sub('', line)
|
||||
for symbol in all_symbols_from(after):
|
||||
db.add_symbol_legacy_usage(symbol, filename, lineno)
|
||||
|
||||
|
||||
def handle_select(db, filename, lineno, line, legacy):
|
||||
handle_usage(db, filename, lineno, line, legacy)
|
||||
before = br.re_kconfig_select_conditional.sub('', line)
|
||||
for symbol in all_symbols_from(before):
|
||||
db.add_symbol_select(symbol, filename, lineno)
|
||||
|
||||
|
||||
line_type_handlers = {
|
||||
br.re_kconfig_config: handle_definition,
|
||||
br.re_kconfig_default: handle_default,
|
||||
br.re_kconfig_depends: handle_usage,
|
||||
br.re_kconfig_if: handle_usage,
|
||||
br.re_kconfig_select: handle_select,
|
||||
br.re_kconfig_source: handle_usage,
|
||||
}
|
||||
|
||||
|
||||
def handle_line(db, filename, lineno, line, legacy):
|
||||
if not br.re_kconfig_symbol.search(line):
|
||||
return
|
||||
|
||||
for regexp, line_type_handler in line_type_handlers.items():
|
||||
if regexp.search(line):
|
||||
line_type_handler(db, filename, lineno, line, legacy)
|
||||
|
||||
|
||||
def handle_config_helper(db, filename, file_content):
|
||||
symbol = None
|
||||
lineno = None
|
||||
state = 'none'
|
||||
for cur_lineno, line in file_content:
|
||||
if state == 'none':
|
||||
m = br.re_kconfig_config.search(line)
|
||||
if m is not None:
|
||||
symbol = m.group(2)
|
||||
lineno = cur_lineno
|
||||
state = 'config'
|
||||
continue
|
||||
if state == 'config':
|
||||
if br.re_kconfig_select.search(line):
|
||||
db.add_symbol_helper(symbol, filename, lineno)
|
||||
state = 'none'
|
||||
continue
|
||||
m = br.re_kconfig_config.search(line)
|
||||
if m is not None:
|
||||
symbol = m.group(2)
|
||||
lineno = cur_lineno
|
||||
continue
|
||||
|
||||
|
||||
def handle_config_choice(db, filename, file_content):
|
||||
state = 'none'
|
||||
for lineno, line in file_content:
|
||||
if state == 'none':
|
||||
if br.re_kconfig_choice.search(line):
|
||||
state = 'choice'
|
||||
continue
|
||||
if state == 'choice':
|
||||
if br.re_kconfig_endchoice.search(line):
|
||||
state = 'none'
|
||||
continue
|
||||
m = br.re_kconfig_config.search(line)
|
||||
if m is not None:
|
||||
symbol = m.group(2)
|
||||
db.add_symbol_choice(symbol, filename, lineno)
|
||||
continue
|
||||
|
||||
|
||||
def handle_note(db, filename, file_content):
|
||||
state = 'none'
|
||||
for lineno, line in file_content:
|
||||
if state == 'none':
|
||||
if br.re_menu.search(line):
|
||||
state = 'menu'
|
||||
continue
|
||||
if state == 'menu':
|
||||
if br.re_endmenu.search(line):
|
||||
state = 'none'
|
||||
continue
|
||||
m = br.re_legacy_special_comment.search(line)
|
||||
if m is not None:
|
||||
symbol = m.group(1)
|
||||
db.add_symbol_legacy_note(symbol, filename, lineno)
|
||||
continue
|
||||
|
||||
|
||||
def populate_db(db, filename, file_content):
|
||||
legacy = filename.endswith('.legacy')
|
||||
for lineno, line in file_content:
|
||||
handle_line(db, filename, lineno, line, legacy)
|
||||
handle_config_helper(db, filename, file_content)
|
||||
handle_config_choice(db, filename, file_content)
|
||||
if legacy:
|
||||
handle_note(db, filename, file_content)
|
||||
|
||||
|
||||
def check_filename(filename):
|
||||
if os.path.basename(filename).startswith('Config.'):
|
||||
return True
|
||||
return False
|
100
utils/checksymbolslib/makefile.py
Normal file
100
utils/checksymbolslib/makefile.py
Normal file
@ -0,0 +1,100 @@
|
||||
import checksymbolslib.br as br
|
||||
|
||||
|
||||
def handle_eval(db, filename, lineno, line):
|
||||
def add_multiple_symbol_usages(package, prefixes=None, suffixes=None):
|
||||
for prefix in prefixes or ['']:
|
||||
for sufix in suffixes or ['']:
|
||||
symbol = prefix + package + sufix
|
||||
db.add_symbol_usage(symbol, filename, lineno)
|
||||
|
||||
package = br.get_package_from_filename(filename)
|
||||
if '$(rootfs)' in line:
|
||||
suffixes = [''] + br.suffixes_not_defined_for_all_rootfs_types
|
||||
add_multiple_symbol_usages(package, prefixes=[br.rootfs_prefix], suffixes=suffixes)
|
||||
return
|
||||
if '$(kernel-module)' in line:
|
||||
add_multiple_symbol_usages(package, prefixes=[br.package_prefix])
|
||||
return
|
||||
if '$(barebox-package)' in line:
|
||||
add_multiple_symbol_usages(package, prefixes=[br.boot_prefix], suffixes=br.barebox_infra_suffixes)
|
||||
return
|
||||
|
||||
if '-package)' not in line:
|
||||
return
|
||||
if package == 'LINUX':
|
||||
# very special case at package/pkg-generic.mk
|
||||
add_multiple_symbol_usages('BR2_LINUX_KERNEL')
|
||||
return
|
||||
|
||||
# mimic package/pkg-generic.mk and package/pkg-virtual.mk
|
||||
if '$(virtual-' in line:
|
||||
prefixes = ['BR2_PACKAGE_PROVIDES_', 'BR2_PACKAGE_HAS_']
|
||||
if filename.startswith('toolchain/'):
|
||||
prefix = br.toolchain_prefix
|
||||
else:
|
||||
prefix = br.package_prefix
|
||||
symbol = prefix + package
|
||||
db.add_symbol_virtual(symbol, filename, lineno)
|
||||
prefixes.append(prefix)
|
||||
elif '$(host-virtual-' in line:
|
||||
prefixes = ['BR2_PACKAGE_HOST_', 'BR2_PACKAGE_PROVIDES_HOST_', 'BR2_PACKAGE_HAS_HOST_']
|
||||
elif '$(host-' in line:
|
||||
prefixes = ['BR2_PACKAGE_HOST_']
|
||||
elif filename.startswith('boot/'):
|
||||
prefixes = [br.boot_prefix]
|
||||
elif filename.startswith('toolchain/'):
|
||||
prefixes = [br.toolchain_prefix]
|
||||
elif '$(toolchain-' in line:
|
||||
prefixes = [br.toolchain_prefix]
|
||||
else:
|
||||
prefixes = [br.package_prefix]
|
||||
|
||||
add_multiple_symbol_usages(package, prefixes=prefixes)
|
||||
|
||||
|
||||
def handle_definition(db, filename, lineno, line, legacy):
|
||||
symbols = br.re_makefile_symbol_attribution.findall(line)
|
||||
symbols += br.re_makefile_symbol_export.findall(line)
|
||||
for symbol in symbols:
|
||||
if legacy:
|
||||
db.add_symbol_legacy_definition(symbol, filename, lineno)
|
||||
else:
|
||||
db.add_symbol_definition(symbol, filename, lineno)
|
||||
|
||||
|
||||
def handle_usage(db, filename, lineno, line, legacy):
|
||||
if br.re_makefile_eval.search(line):
|
||||
handle_eval(db, filename, lineno, line)
|
||||
return
|
||||
|
||||
symbols = br.re_makefile_symbol_usage.findall(line)
|
||||
for symbol in symbols:
|
||||
if legacy:
|
||||
db.add_symbol_usage_in_legacy(symbol, filename, lineno)
|
||||
else:
|
||||
db.add_symbol_usage(symbol, filename, lineno)
|
||||
|
||||
|
||||
def populate_db(db, filename, file_content):
|
||||
legacy = filename.endswith('.legacy')
|
||||
for lineno, raw_line in file_content:
|
||||
line = br.re_comments.sub('', raw_line)
|
||||
handle_definition(db, filename, lineno, line, legacy)
|
||||
handle_usage(db, filename, lineno, line, legacy)
|
||||
|
||||
|
||||
def check_filename(filename):
|
||||
if filename.endswith('.mk'):
|
||||
return True
|
||||
if filename.endswith('.mk.in'):
|
||||
return True
|
||||
if filename.startswith('arch/arch.mk.'):
|
||||
return True
|
||||
if filename in [
|
||||
'Makefile',
|
||||
'Makefile.legacy',
|
||||
'package/Makefile.in'
|
||||
]:
|
||||
return True
|
||||
return False
|
286
utils/checksymbolslib/test_db.py
Normal file
286
utils/checksymbolslib/test_db.py
Normal file
@ -0,0 +1,286 @@
|
||||
import checksymbolslib.db as m
|
||||
|
||||
|
||||
def test_empty_db():
|
||||
db = m.DB()
|
||||
assert str(db) == '{}'
|
||||
|
||||
|
||||
def test_one_definition():
|
||||
db = m.DB()
|
||||
db.add_symbol_definition('BR2_foo', 'foo/Config.in', 7)
|
||||
assert str(db) == str({
|
||||
'BR2_foo': {'definition': {'foo/Config.in': [7]}},
|
||||
})
|
||||
|
||||
|
||||
def test_three_definitions():
|
||||
db = m.DB()
|
||||
db.add_symbol_definition('BR2_foo', 'foo/Config.in', 7)
|
||||
db.add_symbol_definition('BR2_foo', 'foo/Config.in', 9)
|
||||
db.add_symbol_definition('BR2_bar', 'bar/Config.in', 5)
|
||||
assert str(db) == str({
|
||||
'BR2_foo': {'definition': {'foo/Config.in': [7, 9]}},
|
||||
'BR2_bar': {'definition': {'bar/Config.in': [5]}},
|
||||
})
|
||||
|
||||
|
||||
def test_definition_and_usage():
|
||||
db = m.DB()
|
||||
db.add_symbol_definition('BR2_foo', 'foo/Config.in', 7)
|
||||
db.add_symbol_usage('BR2_foo', 'foo/Config.in', 9)
|
||||
assert str(db) == str({
|
||||
'BR2_foo': {'definition': {'foo/Config.in': [7]}, 'normal usage': {'foo/Config.in': [9]}},
|
||||
})
|
||||
|
||||
|
||||
def test_all_entry_types():
|
||||
db = m.DB()
|
||||
db.add_symbol_choice('BR2_foo', 'foo/Config.in', 7)
|
||||
db.add_symbol_definition('BR2_foo', 'foo/Config.in', 7)
|
||||
db.add_symbol_definition('BR2_bar', 'bar/Config.in', 700)
|
||||
db.add_symbol_helper('BR2_bar', 'bar/Config.in', 700)
|
||||
db.add_symbol_legacy_definition('BR2_baz', 'Config.in.legacy', 7000)
|
||||
db.add_symbol_legacy_note('BR2_baz', 'Config.in.legacy', 7001)
|
||||
db.add_symbol_legacy_usage('BR2_bar', 'Config.in.legacy', 7001)
|
||||
db.add_symbol_select('BR2_bar', 'Config.in.legacy', 7001)
|
||||
db.add_symbol_usage('BR2_foo', 'foo/Config.in', 9)
|
||||
db.add_symbol_usage_in_legacy('BR2_bar', 'Config.in.legacy', 9)
|
||||
db.add_symbol_virtual('BR2_foo', 'foo/Config.in', 7)
|
||||
assert str(db) == str({
|
||||
'BR2_foo': {
|
||||
'part of a choice': {'foo/Config.in': [7]},
|
||||
'definition': {'foo/Config.in': [7]},
|
||||
'normal usage': {'foo/Config.in': [9]},
|
||||
'virtual': {'foo/Config.in': [7]}},
|
||||
'BR2_bar': {
|
||||
'definition': {'bar/Config.in': [700]},
|
||||
'possible config helper': {'bar/Config.in': [700]},
|
||||
'legacy usage': {'Config.in.legacy': [7001]},
|
||||
'selected': {'Config.in.legacy': [7001]},
|
||||
'usage inside legacy': {'Config.in.legacy': [9]}},
|
||||
'BR2_baz': {
|
||||
'legacy definition': {'Config.in.legacy': [7000]},
|
||||
'legacy note': {'Config.in.legacy': [7001]}},
|
||||
})
|
||||
|
||||
|
||||
def test_get_symbols_with_pattern():
|
||||
db = m.DB()
|
||||
db.add_symbol_definition('BR2_foo', 'foo/Config.in', 7)
|
||||
db.add_symbol_usage('BR2_foo', 'foo/Config.in', 9)
|
||||
db.add_symbol_definition('BR2_bar', 'bar/Config.in', 5)
|
||||
assert str(db) == str({
|
||||
'BR2_foo': {'definition': {'foo/Config.in': [7]}, 'normal usage': {'foo/Config.in': [9]}},
|
||||
'BR2_bar': {'definition': {'bar/Config.in': [5]}},
|
||||
})
|
||||
symbols = db.get_symbols_with_pattern('foo')
|
||||
assert str(symbols) == str({
|
||||
'BR2_foo': {'definition': {'foo/Config.in': [7]}, 'normal usage': {'foo/Config.in': [9]}},
|
||||
})
|
||||
symbols = db.get_symbols_with_pattern('FOO')
|
||||
assert str(symbols) == str({
|
||||
})
|
||||
symbols = db.get_symbols_with_pattern('foo|FOO')
|
||||
assert str(symbols) == str({
|
||||
'BR2_foo': {'definition': {'foo/Config.in': [7]}, 'normal usage': {'foo/Config.in': [9]}},
|
||||
})
|
||||
symbols = db.get_symbols_with_pattern('^foo')
|
||||
assert str(symbols) == str({
|
||||
})
|
||||
symbols = db.get_symbols_with_pattern('foo|bar')
|
||||
assert str(symbols) == str({
|
||||
'BR2_foo': {'definition': {'foo/Config.in': [7]}, 'normal usage': {'foo/Config.in': [9]}},
|
||||
'BR2_bar': {'definition': {'bar/Config.in': [5]}},
|
||||
})
|
||||
|
||||
|
||||
def test_get_warnings_for_choices_selected():
|
||||
db = m.DB()
|
||||
db.add_symbol_choice('BR2_foo', 'foo/Config.in', 1)
|
||||
db.add_symbol_choice('BR2_bar', 'bar/Config.in', 1)
|
||||
db.add_symbol_select('BR2_foo', 'bar/Config.in', 2)
|
||||
assert str(db) == str({
|
||||
'BR2_foo': {'part of a choice': {'foo/Config.in': [1]}, 'selected': {'bar/Config.in': [2]}},
|
||||
'BR2_bar': {'part of a choice': {'bar/Config.in': [1]}},
|
||||
})
|
||||
warnings = db.get_warnings_for_choices_selected()
|
||||
assert warnings == [
|
||||
('bar/Config.in', 2, 'BR2_foo is part of a "choice" and should not be "select"ed'),
|
||||
]
|
||||
|
||||
|
||||
def test_get_warnings_for_legacy_symbols_being_used():
|
||||
db = m.DB()
|
||||
db.add_symbol_legacy_definition('BR2_foo', 'Config.in.legacy', 1)
|
||||
db.add_symbol_usage('BR2_foo', 'bar/Config.in', 2)
|
||||
db.add_symbol_legacy_definition('BR2_bar', 'Config.in.legacy', 10)
|
||||
db.add_symbol_usage_in_legacy('BR2_bar', 'Config.in.legacy', 11)
|
||||
assert str(db) == str({
|
||||
'BR2_foo': {'legacy definition': {'Config.in.legacy': [1]}, 'normal usage': {'bar/Config.in': [2]}},
|
||||
'BR2_bar': {'legacy definition': {'Config.in.legacy': [10]}, 'usage inside legacy': {'Config.in.legacy': [11]}},
|
||||
})
|
||||
warnings = db.get_warnings_for_legacy_symbols_being_used()
|
||||
assert warnings == [
|
||||
('bar/Config.in', 2, 'BR2_foo is a legacy symbol and should not be referenced'),
|
||||
]
|
||||
|
||||
|
||||
def test_get_warnings_for_legacy_symbols_being_defined():
|
||||
db = m.DB()
|
||||
db.add_symbol_legacy_definition('BR2_foo', 'Config.in.legacy', 1)
|
||||
db.add_symbol_legacy_definition('BR2_bar', 'Config.in.legacy', 10)
|
||||
db.add_symbol_definition('BR2_foo', 'foo/Config.in', 7)
|
||||
db.add_symbol_definition('BR2_foo', 'foo/Config.in', 8)
|
||||
assert str(db) == str({
|
||||
'BR2_foo': {'legacy definition': {'Config.in.legacy': [1]}, 'definition': {'foo/Config.in': [7, 8]}},
|
||||
'BR2_bar': {'legacy definition': {'Config.in.legacy': [10]}},
|
||||
})
|
||||
warnings = db.get_warnings_for_legacy_symbols_being_defined()
|
||||
assert warnings == [
|
||||
('foo/Config.in', 7, 'BR2_foo is a legacy symbol and should not be redefined'),
|
||||
('foo/Config.in', 8, 'BR2_foo is a legacy symbol and should not be redefined'),
|
||||
]
|
||||
|
||||
|
||||
def test_get_warnings_for_symbols_without_definition():
|
||||
db = m.DB()
|
||||
db.add_symbol_definition('BR2_foo', 'foo/Config.in', 7)
|
||||
db.add_symbol_legacy_definition('BR2_bar', 'Config.in.legacy', 10)
|
||||
db.add_symbol_virtual('BR2_baz', 'baz/Config.in', 7)
|
||||
db.add_symbol_usage('BR2_foo', 'file', 1)
|
||||
db.add_symbol_usage('BR2_bar', 'file', 1)
|
||||
db.add_symbol_usage('BR2_baz', 'file', 1)
|
||||
db.add_symbol_usage('BR2_undef1', 'file', 1)
|
||||
db.add_symbol_legacy_usage('BR2_undef2', 'file', 2)
|
||||
db.add_symbol_usage_in_legacy('BR2_undef3', 'file', 3)
|
||||
db.add_symbol_usage('BR2_undef3', 'another', 1)
|
||||
db.add_symbol_legacy_usage('BR2_undef3', 'another', 2)
|
||||
db.add_symbol_usage('BR2_PACKAGE_HOST_undef', 'file', 1)
|
||||
db.add_symbol_usage('BR2_PACKAGE_HAS_HOST_undef', 'file', 1)
|
||||
db.add_symbol_usage('BR2_TARGET_ROOTFS_undef_XZ', 'file', 1)
|
||||
db.add_symbol_usage('BR2_GRAPH_ALT', 'file', 1)
|
||||
db.add_symbol_usage('BR2_EXTERNAL', 'file', 1)
|
||||
db.add_symbol_usage('BR2_TARGET_BAREBOX_AUX_BAREBOXENV', 'file', 1)
|
||||
db.add_symbol_usage('BR2_PACKAGE_HAS_TOOLCHAIN_BUILDROOT', 'file', 1)
|
||||
assert str(db) == str({
|
||||
'BR2_foo': {'definition': {'foo/Config.in': [7]}, 'normal usage': {'file': [1]}},
|
||||
'BR2_bar': {'legacy definition': {'Config.in.legacy': [10]}, 'normal usage': {'file': [1]}},
|
||||
'BR2_baz': {'virtual': {'baz/Config.in': [7]}, 'normal usage': {'file': [1]}},
|
||||
'BR2_undef1': {'normal usage': {'file': [1]}},
|
||||
'BR2_undef2': {'legacy usage': {'file': [2]}},
|
||||
'BR2_undef3': {'usage inside legacy': {'file': [3]}, 'normal usage': {'another': [1]}, 'legacy usage': {'another': [2]}},
|
||||
'BR2_PACKAGE_HOST_undef': {'normal usage': {'file': [1]}},
|
||||
'BR2_PACKAGE_HAS_HOST_undef': {'normal usage': {'file': [1]}},
|
||||
'BR2_TARGET_ROOTFS_undef_XZ': {'normal usage': {'file': [1]}},
|
||||
'BR2_GRAPH_ALT': {'normal usage': {'file': [1]}},
|
||||
'BR2_EXTERNAL': {'normal usage': {'file': [1]}},
|
||||
'BR2_TARGET_BAREBOX_AUX_BAREBOXENV': {'normal usage': {'file': [1]}},
|
||||
'BR2_PACKAGE_HAS_TOOLCHAIN_BUILDROOT': {'normal usage': {'file': [1]}},
|
||||
})
|
||||
warnings = db.get_warnings_for_symbols_without_definition()
|
||||
assert warnings == [
|
||||
('file', 1, 'BR2_undef1 referenced but not defined'),
|
||||
('file', 2, 'BR2_undef2 referenced but not defined'),
|
||||
('another', 1, 'BR2_undef3 referenced but not defined'),
|
||||
('another', 2, 'BR2_undef3 referenced but not defined'),
|
||||
('file', 3, 'BR2_undef3 referenced but not defined'),
|
||||
]
|
||||
|
||||
|
||||
def test_get_warnings_for_symbols_without_usage():
|
||||
db = m.DB()
|
||||
db.add_symbol_definition('BR2_a', 'a/Config.in', 1)
|
||||
db.add_symbol_definition('BR2_a', 'a/Config.in', 2)
|
||||
db.add_symbol_usage('BR2_a', 'file', 1)
|
||||
db.add_symbol_usage('BR2_a', 'file', 2)
|
||||
db.add_symbol_definition('BR2_b', 'b/Config.in', 2)
|
||||
db.add_symbol_usage_in_legacy('BR2_b', 'file', 1)
|
||||
db.add_symbol_definition('BR2_c', 'c/Config.in', 2)
|
||||
db.add_symbol_legacy_usage('BR2_c', 'file', 1)
|
||||
db.add_symbol_definition('BR2_USE_CCACHE', 'file', 1)
|
||||
db.add_symbol_definition('BR2_PACKAGE_SKELETON', 'file', 1)
|
||||
db.add_symbol_definition('BR2_d', 'd/Config.in', 2)
|
||||
db.add_symbol_helper('BR2_d', 'd/Config.in', 2)
|
||||
db.add_symbol_definition('BR2_e', 'e/Config.in', 2)
|
||||
db.add_symbol_choice('BR2_e', 'e/Config.in', 2)
|
||||
db.add_symbol_definition('BR2_f', 'f/Config.in', 2)
|
||||
db.add_symbol_definition('BR2_g', 'g/Config.in', 2)
|
||||
db.add_symbol_definition('BR2_g', 'g/Config.in', 3)
|
||||
db.add_symbol_legacy_definition('BR2_h', 'Config.in.legacy', 1)
|
||||
db.add_symbol_usage('BR2_h', 'file', 2)
|
||||
db.add_symbol_usage('BR2_h', 'file', 3)
|
||||
db.add_symbol_legacy_definition('BR2_i', 'Config.in.legacy', 2)
|
||||
db.add_symbol_usage_in_legacy('BR2_i', 'file', 2)
|
||||
db.add_symbol_legacy_definition('BR2_j', 'Config.in.legacy', 2)
|
||||
db.add_symbol_legacy_usage('BR2_j', 'file', 2)
|
||||
db.add_symbol_legacy_definition('BR2_k', 'Config.in.legacy', 2)
|
||||
db.add_symbol_usage('BR2_k', 'file', 5)
|
||||
db.add_symbol_usage_in_legacy('BR2_k', 'file', 6)
|
||||
db.add_symbol_legacy_usage('BR2_k', 'file', 7)
|
||||
db.add_symbol_legacy_definition('BR2_l', 'Config.in.legacy', 2)
|
||||
assert str(db) == str({
|
||||
'BR2_a': {'definition': {'a/Config.in': [1, 2]}, 'normal usage': {'file': [1, 2]}},
|
||||
'BR2_b': {'definition': {'b/Config.in': [2]}, 'usage inside legacy': {'file': [1]}},
|
||||
'BR2_c': {'definition': {'c/Config.in': [2]}, 'legacy usage': {'file': [1]}},
|
||||
'BR2_USE_CCACHE': {'definition': {'file': [1]}},
|
||||
'BR2_PACKAGE_SKELETON': {'definition': {'file': [1]}},
|
||||
'BR2_d': {'definition': {'d/Config.in': [2]}, 'possible config helper': {'d/Config.in': [2]}},
|
||||
'BR2_e': {'definition': {'e/Config.in': [2]}, 'part of a choice': {'e/Config.in': [2]}},
|
||||
'BR2_f': {'definition': {'f/Config.in': [2]}},
|
||||
'BR2_g': {'definition': {'g/Config.in': [2, 3]}},
|
||||
'BR2_h': {'legacy definition': {'Config.in.legacy': [1]}, 'normal usage': {'file': [2, 3]}},
|
||||
'BR2_i': {'legacy definition': {'Config.in.legacy': [2]}, 'usage inside legacy': {'file': [2]}},
|
||||
'BR2_j': {'legacy definition': {'Config.in.legacy': [2]}, 'legacy usage': {'file': [2]}},
|
||||
'BR2_k': {
|
||||
'legacy definition': {'Config.in.legacy': [2]},
|
||||
'normal usage': {'file': [5]},
|
||||
'usage inside legacy': {'file': [6]},
|
||||
'legacy usage': {'file': [7]}},
|
||||
'BR2_l': {'legacy definition': {'Config.in.legacy': [2]}},
|
||||
})
|
||||
warnings = db.get_warnings_for_symbols_without_usage()
|
||||
assert warnings == [
|
||||
('f/Config.in', 2, 'BR2_f defined but not referenced'),
|
||||
('g/Config.in', 2, 'BR2_g defined but not referenced'),
|
||||
('g/Config.in', 3, 'BR2_g defined but not referenced'),
|
||||
('Config.in.legacy', 2, 'BR2_l defined but not referenced'),
|
||||
]
|
||||
|
||||
|
||||
def test_get_warnings_for_symbols_with_legacy_note_and_no_comment_on_usage():
|
||||
db = m.DB()
|
||||
db.add_symbol_legacy_note('BR2_foo', 'Config.in.legacy', 1)
|
||||
db.add_symbol_legacy_usage('BR2_foo', 'package/bar/Config.in', 2)
|
||||
db.add_symbol_legacy_note('BR2_baz', 'Config.in.legacy', 7001)
|
||||
db.add_symbol_usage('BR2_baz', 'package/foo/Config.in', 1)
|
||||
assert str(db) == str({
|
||||
'BR2_foo': {'legacy note': {'Config.in.legacy': [1]}, 'legacy usage': {'package/bar/Config.in': [2]}},
|
||||
'BR2_baz': {'legacy note': {'Config.in.legacy': [7001]}, 'normal usage': {'package/foo/Config.in': [1]}},
|
||||
})
|
||||
warnings = db.get_warnings_for_symbols_with_legacy_note_and_no_comment_on_usage()
|
||||
assert warnings == [
|
||||
('package/foo/Config.in', 1, 'BR2_baz missing "# legacy"'),
|
||||
]
|
||||
|
||||
|
||||
def test_get_warnings_for_symbols_with_legacy_note_and_no_usage():
|
||||
db = m.DB()
|
||||
db.add_symbol_legacy_note('BR2_foo', 'Config.in.legacy', 1)
|
||||
db.add_symbol_legacy_usage('BR2_foo', 'package/bar/Config.in', 2)
|
||||
db.add_symbol_legacy_note('BR2_bar', 'Config.in.legacy', 1)
|
||||
db.add_symbol_usage_in_legacy('BR2_bar', 'Config.in.legacy', 7001)
|
||||
db.add_symbol_legacy_note('BR2_baz', 'Config.in.legacy', 7001)
|
||||
db.add_symbol_legacy_note('BR2_no_comment', 'Config.in.legacy', 1)
|
||||
db.add_symbol_usage('BR2_no_comment', 'package/bar/Config.in', 2)
|
||||
assert str(db) == str({
|
||||
'BR2_foo': {'legacy note': {'Config.in.legacy': [1]}, 'legacy usage': {'package/bar/Config.in': [2]}},
|
||||
'BR2_bar': {'legacy note': {'Config.in.legacy': [1]}, 'usage inside legacy': {'Config.in.legacy': [7001]}},
|
||||
'BR2_baz': {'legacy note': {'Config.in.legacy': [7001]}},
|
||||
'BR2_no_comment': {'legacy note': {'Config.in.legacy': [1]}, 'normal usage': {'package/bar/Config.in': [2]}},
|
||||
})
|
||||
warnings = db.get_warnings_for_symbols_with_legacy_note_and_no_usage()
|
||||
assert warnings == [
|
||||
('Config.in.legacy', 1, 'BR2_bar not referenced but has a comment stating it is'),
|
||||
('Config.in.legacy', 7001, 'BR2_baz not referenced but has a comment stating it is'),
|
||||
]
|
152
utils/checksymbolslib/test_file.py
Normal file
152
utils/checksymbolslib/test_file.py
Normal file
@ -0,0 +1,152 @@
|
||||
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
|
438
utils/checksymbolslib/test_kconfig.py
Normal file
438
utils/checksymbolslib/test_kconfig.py
Normal file
@ -0,0 +1,438 @@
|
||||
import pytest
|
||||
from unittest.mock import Mock
|
||||
from unittest.mock import call
|
||||
from checksymbolslib.test_util import assert_db_calls
|
||||
import checksymbolslib.kconfig as m
|
||||
|
||||
|
||||
all_symbols_from = [
|
||||
('no prefix',
|
||||
'config PACKAGE_FOO',
|
||||
[]),
|
||||
('simple',
|
||||
'config BR2_PACKAGE_FOO',
|
||||
['BR2_PACKAGE_FOO']),
|
||||
('ignore comment',
|
||||
'config BR2_PACKAGE_FOO # BR2_PACKAGE_BAR',
|
||||
['BR2_PACKAGE_FOO']),
|
||||
('ignore whitespace',
|
||||
'\tconfig BR2_PACKAGE_FOO\t # BR2_PACKAGE_BAR',
|
||||
['BR2_PACKAGE_FOO']),
|
||||
('2 occurrences',
|
||||
'\tdefault BR2_PACKAGE_FOO_BAR if BR2_PACKAGE_FOO_BAR != ""',
|
||||
['BR2_PACKAGE_FOO_BAR', 'BR2_PACKAGE_FOO_BAR']),
|
||||
]
|
||||
|
||||
|
||||
@pytest.mark.parametrize('testname,line,expected', all_symbols_from)
|
||||
def test_all_symbols_from(testname, line, expected):
|
||||
symbols = m.all_symbols_from(line)
|
||||
assert symbols == expected
|
||||
|
||||
|
||||
handle_definition = [
|
||||
('config',
|
||||
'package/foo/Config.in',
|
||||
5,
|
||||
'config BR2_PACKAGE_FOO',
|
||||
False,
|
||||
{'add_symbol_definition': [call('BR2_PACKAGE_FOO', 'package/foo/Config.in', 5)]}),
|
||||
('ignore comment',
|
||||
'package/foo/Config.in',
|
||||
5,
|
||||
'config BR2_PACKAGE_FOO # BR2_PACKAGE_BAR',
|
||||
False,
|
||||
{'add_symbol_definition': [call('BR2_PACKAGE_FOO', 'package/foo/Config.in', 5)]}),
|
||||
('ignore whitespace',
|
||||
'package/foo/Config.in',
|
||||
5,
|
||||
'\tconfig BR2_PACKAGE_FOO\t # BR2_PACKAGE_BAR',
|
||||
False,
|
||||
{'add_symbol_definition': [call('BR2_PACKAGE_FOO', 'package/foo/Config.in', 5)]}),
|
||||
('menuconfig',
|
||||
'package/gd/Config.in',
|
||||
1,
|
||||
'menuconfig BR2_PACKAGE_GD',
|
||||
False,
|
||||
{'add_symbol_definition': [call('BR2_PACKAGE_GD', 'package/gd/Config.in', 1)]}),
|
||||
('menu',
|
||||
'package/Config.in',
|
||||
100,
|
||||
'menu "Database"',
|
||||
False,
|
||||
{}),
|
||||
('legacy config',
|
||||
'Config.in.legacy',
|
||||
50,
|
||||
'config BR2_PACKAGE_FOO',
|
||||
True,
|
||||
{'add_symbol_legacy_definition': [call('BR2_PACKAGE_FOO', 'Config.in.legacy', 50)]}),
|
||||
]
|
||||
|
||||
|
||||
@pytest.mark.parametrize('testname,filename,lineno,line,legacy,expected_calls', handle_definition)
|
||||
def test_handle_definition(testname, filename, lineno, line, legacy, expected_calls):
|
||||
db = Mock()
|
||||
m.handle_definition(db, filename, lineno, line, legacy)
|
||||
assert_db_calls(db, expected_calls)
|
||||
|
||||
|
||||
handle_usage = [
|
||||
('default with comparison',
|
||||
'package/openblas/Config.in',
|
||||
60,
|
||||
'\tdefault y if BR2_PACKAGE_OPENBLAS_DEFAULT_TARGET != ""',
|
||||
False,
|
||||
{'add_symbol_usage': [call('BR2_PACKAGE_OPENBLAS_DEFAULT_TARGET', 'package/openblas/Config.in', 60)]}),
|
||||
('default with logical operators',
|
||||
'toolchain/toolchain-external/toolchain-external-bootlin/Config.in.options',
|
||||
47,
|
||||
'\tdefault y if BR2_i386 && !BR2_x86_i486 && !BR2_x86_i586 && !BR2_x86_x1000 && !BR2_x86_pentium_mmx && !BR2_x86_geode '
|
||||
'&& !BR2_x86_c3 && !BR2_x86_winchip_c6 && !BR2_x86_winchip2',
|
||||
False,
|
||||
{'add_symbol_usage': [
|
||||
call('BR2_i386', 'toolchain/toolchain-external/toolchain-external-bootlin/Config.in.options', 47),
|
||||
call('BR2_x86_c3', 'toolchain/toolchain-external/toolchain-external-bootlin/Config.in.options', 47),
|
||||
call('BR2_x86_geode', 'toolchain/toolchain-external/toolchain-external-bootlin/Config.in.options', 47),
|
||||
call('BR2_x86_i486', 'toolchain/toolchain-external/toolchain-external-bootlin/Config.in.options', 47),
|
||||
call('BR2_x86_i586', 'toolchain/toolchain-external/toolchain-external-bootlin/Config.in.options', 47),
|
||||
call('BR2_x86_pentium_mmx', 'toolchain/toolchain-external/toolchain-external-bootlin/Config.in.options', 47),
|
||||
call('BR2_x86_winchip2', 'toolchain/toolchain-external/toolchain-external-bootlin/Config.in.options', 47),
|
||||
call('BR2_x86_winchip_c6', 'toolchain/toolchain-external/toolchain-external-bootlin/Config.in.options', 47),
|
||||
call('BR2_x86_x1000', 'toolchain/toolchain-external/toolchain-external-bootlin/Config.in.options', 47)]}),
|
||||
('legacy depends on',
|
||||
'Config.in.legacy',
|
||||
3000,
|
||||
'\tdepends on BR2_LINUX_KERNEL',
|
||||
True,
|
||||
{'add_symbol_usage_in_legacy': [call('BR2_LINUX_KERNEL', 'Config.in.legacy', 3000)]}),
|
||||
('legacy if',
|
||||
'Config.in.legacy',
|
||||
97,
|
||||
'if !BR2_SKIP_LEGACY',
|
||||
True,
|
||||
{'add_symbol_usage_in_legacy': [call('BR2_SKIP_LEGACY', 'Config.in.legacy', 97)]}),
|
||||
('source',
|
||||
'system/Config.in',
|
||||
152,
|
||||
'source "$BR2_BASE_DIR/.br2-external.in.init"',
|
||||
False,
|
||||
{'add_symbol_usage': [call('BR2_BASE_DIR', 'system/Config.in', 152)]}),
|
||||
]
|
||||
|
||||
|
||||
@pytest.mark.parametrize('testname,filename,lineno,line,legacy,expected_calls', handle_usage)
|
||||
def test_handle_usage(testname, filename, lineno, line, legacy, expected_calls):
|
||||
db = Mock()
|
||||
m.handle_usage(db, filename, lineno, line, legacy)
|
||||
assert_db_calls(db, expected_calls)
|
||||
|
||||
|
||||
handle_default = [
|
||||
('default with comparison',
|
||||
'package/openblas/Config.in',
|
||||
60,
|
||||
'\tdefault y if BR2_PACKAGE_OPENBLAS_DEFAULT_TARGET != ""',
|
||||
False,
|
||||
{'add_symbol_usage': [call('BR2_PACKAGE_OPENBLAS_DEFAULT_TARGET', 'package/openblas/Config.in', 60)]}),
|
||||
('default with logical operators',
|
||||
'toolchain/toolchain-external/toolchain-external-bootlin/Config.in.options',
|
||||
47,
|
||||
'\tdefault y if BR2_i386 && !BR2_x86_i486 && !BR2_x86_i586 && !BR2_x86_x1000 && !BR2_x86_pentium_mmx && !BR2_x86_geode '
|
||||
'&& !BR2_x86_c3 && !BR2_x86_winchip_c6 && !BR2_x86_winchip2',
|
||||
False,
|
||||
{'add_symbol_usage': [
|
||||
call('BR2_i386', 'toolchain/toolchain-external/toolchain-external-bootlin/Config.in.options', 47),
|
||||
call('BR2_x86_c3', 'toolchain/toolchain-external/toolchain-external-bootlin/Config.in.options', 47),
|
||||
call('BR2_x86_geode', 'toolchain/toolchain-external/toolchain-external-bootlin/Config.in.options', 47),
|
||||
call('BR2_x86_i486', 'toolchain/toolchain-external/toolchain-external-bootlin/Config.in.options', 47),
|
||||
call('BR2_x86_i586', 'toolchain/toolchain-external/toolchain-external-bootlin/Config.in.options', 47),
|
||||
call('BR2_x86_pentium_mmx', 'toolchain/toolchain-external/toolchain-external-bootlin/Config.in.options', 47),
|
||||
call('BR2_x86_winchip2', 'toolchain/toolchain-external/toolchain-external-bootlin/Config.in.options', 47),
|
||||
call('BR2_x86_winchip_c6', 'toolchain/toolchain-external/toolchain-external-bootlin/Config.in.options', 47),
|
||||
call('BR2_x86_x1000', 'toolchain/toolchain-external/toolchain-external-bootlin/Config.in.options', 47)]}),
|
||||
('legacy default',
|
||||
'Config.in.legacy',
|
||||
3000,
|
||||
'default y if BR2_PACKAGE_REFPOLICY_POLICY_VERSION != ""',
|
||||
True,
|
||||
{'add_symbol_usage_in_legacy': [call('BR2_PACKAGE_REFPOLICY_POLICY_VERSION', 'Config.in.legacy', 3000)]}),
|
||||
('legacy handling on package',
|
||||
'package/uboot-tools/Config.in.host',
|
||||
105,
|
||||
'\tdefault BR2_TARGET_UBOOT_BOOT_SCRIPT_SOURCE if BR2_TARGET_UBOOT_BOOT_SCRIPT_SOURCE != "" # legacy',
|
||||
False,
|
||||
{'add_symbol_legacy_usage': [call('BR2_TARGET_UBOOT_BOOT_SCRIPT_SOURCE', 'package/uboot-tools/Config.in.host', 105)]}),
|
||||
('default on package',
|
||||
'package/uboot-tools/Config.in.host',
|
||||
105,
|
||||
'\tdefault BR2_TARGET_UBOOT_BOOT_SCRIPT_SOURCE if BR2_TARGET_UBOOT_BOOT_SCRIPT_SOURCE != ""',
|
||||
False,
|
||||
{'add_symbol_usage': [
|
||||
call('BR2_TARGET_UBOOT_BOOT_SCRIPT_SOURCE', 'package/uboot-tools/Config.in.host', 105),
|
||||
call('BR2_TARGET_UBOOT_BOOT_SCRIPT_SOURCE', 'package/uboot-tools/Config.in.host', 105)]}),
|
||||
]
|
||||
|
||||
|
||||
@pytest.mark.parametrize('testname,filename,lineno,line,legacy,expected_calls', handle_default)
|
||||
def test_handle_default(testname, filename, lineno, line, legacy, expected_calls):
|
||||
db = Mock()
|
||||
m.handle_default(db, filename, lineno, line, legacy)
|
||||
assert_db_calls(db, expected_calls)
|
||||
|
||||
|
||||
handle_select = [
|
||||
('select with comparison',
|
||||
'package/bcusdk/Config.in',
|
||||
6,
|
||||
'\tselect BR2_PACKAGE_ARGP_STANDALONE if BR2_TOOLCHAIN_USES_UCLIBC || BR2_TOOLCHAIN_USES_MUSL',
|
||||
False,
|
||||
{'add_symbol_select': [call('BR2_PACKAGE_ARGP_STANDALONE', 'package/bcusdk/Config.in', 6)],
|
||||
'add_symbol_usage': [
|
||||
call('BR2_PACKAGE_ARGP_STANDALONE', 'package/bcusdk/Config.in', 6),
|
||||
call('BR2_TOOLCHAIN_USES_UCLIBC', 'package/bcusdk/Config.in', 6),
|
||||
call('BR2_TOOLCHAIN_USES_MUSL', 'package/bcusdk/Config.in', 6)]}),
|
||||
('legacy select',
|
||||
'Config.in.legacy',
|
||||
100,
|
||||
'\tselect BR2_PACKAGE_WPA_SUPPLICANT_DBUS if BR2_TOOLCHAIN_HAS_THREADS',
|
||||
True,
|
||||
{'add_symbol_select': [call('BR2_PACKAGE_WPA_SUPPLICANT_DBUS', 'Config.in.legacy', 100)],
|
||||
'add_symbol_usage_in_legacy': [
|
||||
call('BR2_PACKAGE_WPA_SUPPLICANT_DBUS', 'Config.in.legacy', 100),
|
||||
call('BR2_TOOLCHAIN_HAS_THREADS', 'Config.in.legacy', 100)]}),
|
||||
]
|
||||
|
||||
|
||||
@pytest.mark.parametrize('testname,filename,lineno,line,legacy,expected_calls', handle_select)
|
||||
def test_handle_select(testname, filename, lineno, line, legacy, expected_calls):
|
||||
db = Mock()
|
||||
m.handle_select(db, filename, lineno, line, legacy)
|
||||
assert_db_calls(db, expected_calls)
|
||||
|
||||
|
||||
handle_line = [
|
||||
('select with comparison',
|
||||
'package/bcusdk/Config.in',
|
||||
6,
|
||||
'\tselect BR2_PACKAGE_ARGP_STANDALONE if BR2_TOOLCHAIN_USES_UCLIBC || BR2_TOOLCHAIN_USES_MUSL',
|
||||
False,
|
||||
{'add_symbol_select': [call('BR2_PACKAGE_ARGP_STANDALONE', 'package/bcusdk/Config.in', 6)],
|
||||
'add_symbol_usage': [
|
||||
call('BR2_PACKAGE_ARGP_STANDALONE', 'package/bcusdk/Config.in', 6),
|
||||
call('BR2_TOOLCHAIN_USES_UCLIBC', 'package/bcusdk/Config.in', 6),
|
||||
call('BR2_TOOLCHAIN_USES_MUSL', 'package/bcusdk/Config.in', 6)]}),
|
||||
('legacy select',
|
||||
'Config.in.legacy',
|
||||
100,
|
||||
'\tselect BR2_PACKAGE_WPA_SUPPLICANT_DBUS if BR2_TOOLCHAIN_HAS_THREADS',
|
||||
True,
|
||||
{'add_symbol_select': [call('BR2_PACKAGE_WPA_SUPPLICANT_DBUS', 'Config.in.legacy', 100)],
|
||||
'add_symbol_usage_in_legacy': [
|
||||
call('BR2_PACKAGE_WPA_SUPPLICANT_DBUS', 'Config.in.legacy', 100),
|
||||
call('BR2_TOOLCHAIN_HAS_THREADS', 'Config.in.legacy', 100)]}),
|
||||
('comment with symbol',
|
||||
'Config.in',
|
||||
6,
|
||||
'\tselect # BR2_PACKAGE_ARGP_STANDALONE if BR2_TOOLCHAIN_USES_UCLIBC || BR2_TOOLCHAIN_USES_MUSL',
|
||||
False,
|
||||
{}),
|
||||
('comment',
|
||||
'Config.in',
|
||||
6,
|
||||
'# just a comment',
|
||||
False,
|
||||
{}),
|
||||
]
|
||||
|
||||
|
||||
@pytest.mark.parametrize('testname,filename,lineno,line,legacy,expected_calls', handle_line)
|
||||
def test_handle_line(testname, filename, lineno, line, legacy, expected_calls):
|
||||
db = Mock()
|
||||
m.handle_line(db, filename, lineno, line, legacy)
|
||||
assert_db_calls(db, expected_calls)
|
||||
|
||||
|
||||
handle_config_helper = [
|
||||
('no select',
|
||||
'package/foo/Config.in',
|
||||
[[5, 'config BR2_PACKAGE_FOO']],
|
||||
{}),
|
||||
('select',
|
||||
'package/foo/Config.in',
|
||||
[[5, 'config BR2_PACKAGE_FOO'],
|
||||
[6, '\tselect BR2_PACKAGE_BAR']],
|
||||
{'add_symbol_helper': [call('BR2_PACKAGE_FOO', 'package/foo/Config.in', 5)]}),
|
||||
('ignore comment',
|
||||
'package/foo/Config.in',
|
||||
[[5, 'config BR2_PACKAGE_FOO # BR2_PACKAGE_BAR'],
|
||||
[6, '\tselect BR2_PACKAGE_BAR # BR2_PACKAGE_FOO']],
|
||||
{'add_symbol_helper': [call('BR2_PACKAGE_FOO', 'package/foo/Config.in', 5)]}),
|
||||
('correct symbol',
|
||||
'package/foo/Config.in',
|
||||
[[5, 'config BR2_PACKAGE_FOO'],
|
||||
[6, 'config BR2_PACKAGE_BAR'],
|
||||
[7, '\tselect BR2_PACKAGE_BAZ']],
|
||||
{'add_symbol_helper': [call('BR2_PACKAGE_BAR', 'package/foo/Config.in', 6)]}),
|
||||
('2 selects',
|
||||
'package/foo/Config.in',
|
||||
[[5, 'config BR2_PACKAGE_FOO'],
|
||||
[6, '\tselect BR2_PACKAGE_BAR'],
|
||||
[7, ' select BR2_PACKAGE_BAR']],
|
||||
{'add_symbol_helper': [call('BR2_PACKAGE_FOO', 'package/foo/Config.in', 5)]}),
|
||||
]
|
||||
|
||||
|
||||
@pytest.mark.parametrize('testname,filename,file_content,expected_calls', handle_config_helper)
|
||||
def test_handle_config_helper(testname, filename, file_content, expected_calls):
|
||||
db = Mock()
|
||||
m.handle_config_helper(db, filename, file_content)
|
||||
assert_db_calls(db, expected_calls)
|
||||
|
||||
|
||||
handle_config_choice = [
|
||||
('no choice',
|
||||
'package/foo/Config.in',
|
||||
[[5, 'config BR2_PACKAGE_FOO']],
|
||||
{}),
|
||||
('after',
|
||||
'package/foo/Config.in',
|
||||
[[3, 'choice'],
|
||||
[4, '\tprompt "your choice"'],
|
||||
[5, 'config BR2_PACKAGE_FOO'],
|
||||
[6, 'config BR2_PACKAGE_BAR'],
|
||||
[10, 'endchoice'],
|
||||
[19, 'config BR2_PACKAGE_BAZ']],
|
||||
{'add_symbol_choice': [
|
||||
call('BR2_PACKAGE_FOO', 'package/foo/Config.in', 5),
|
||||
call('BR2_PACKAGE_BAR', 'package/foo/Config.in', 6)]}),
|
||||
('before',
|
||||
'package/foo/Config.in',
|
||||
[[1, 'config BR2_PACKAGE_BAZ'],
|
||||
[3, 'choice'],
|
||||
[4, '\tprompt "your choice"'],
|
||||
[5, 'config BR2_PACKAGE_FOO'],
|
||||
[6, 'config BR2_PACKAGE_BAR'],
|
||||
[10, 'endchoice']],
|
||||
{'add_symbol_choice': [
|
||||
call('BR2_PACKAGE_FOO', 'package/foo/Config.in', 5),
|
||||
call('BR2_PACKAGE_BAR', 'package/foo/Config.in', 6)]}),
|
||||
]
|
||||
|
||||
|
||||
@pytest.mark.parametrize('testname,filename,file_content,expected_calls', handle_config_choice)
|
||||
def test_handle_config_choice(testname, filename, file_content, expected_calls):
|
||||
db = Mock()
|
||||
m.handle_config_choice(db, filename, file_content)
|
||||
assert_db_calls(db, expected_calls)
|
||||
|
||||
|
||||
handle_note = [
|
||||
('example',
|
||||
'Config.in.legacy',
|
||||
[[51, '# # Note: BR2_FOO_1 is still referenced from package/foo/Config.in']],
|
||||
{}),
|
||||
('ok',
|
||||
'Config.in.legacy',
|
||||
[[112, 'menu "Legacy config options"'],
|
||||
[2132, '# Note: BR2_PACKAGE_FOO is still referenced from package/foo/Config.in'],
|
||||
[4958, 'endmenu']],
|
||||
{'add_symbol_legacy_note': [call('BR2_PACKAGE_FOO', 'Config.in.legacy', 2132)]}),
|
||||
('before and after',
|
||||
'Config.in.legacy',
|
||||
[[100, '# Note: BR2_PACKAGE_BAR is still referenced from package/foo/Config.in'],
|
||||
[112, 'menu "Legacy config options"'],
|
||||
[2132, '# Note: BR2_PACKAGE_FOO is still referenced from package/foo/Config.in'],
|
||||
[4958, 'endmenu'],
|
||||
[5000, '# Note: BR2_PACKAGE_BAR is still referenced from package/foo/Config.in']],
|
||||
{'add_symbol_legacy_note': [call('BR2_PACKAGE_FOO', 'Config.in.legacy', 2132)]}),
|
||||
]
|
||||
|
||||
|
||||
@pytest.mark.parametrize('testname,filename,file_content,expected_calls', handle_note)
|
||||
def test_handle_note(testname, filename, file_content, expected_calls):
|
||||
db = Mock()
|
||||
m.handle_note(db, filename, file_content)
|
||||
assert_db_calls(db, expected_calls)
|
||||
|
||||
|
||||
populate_db = [
|
||||
('legacy',
|
||||
'Config.in.legacy',
|
||||
[[112, 'menu "Legacy config options"'],
|
||||
[2100, 'config BR2_PACKAGE_FOO'],
|
||||
[2101, '\tselect BR2_PACKAGE_BAR'],
|
||||
[2132, '# Note: BR2_PACKAGE_FOO is still referenced from package/foo/Config.in'],
|
||||
[4958, 'endmenu']],
|
||||
{'add_symbol_legacy_note': [call('BR2_PACKAGE_FOO', 'Config.in.legacy', 2132)],
|
||||
'add_symbol_helper': [call('BR2_PACKAGE_FOO', 'Config.in.legacy', 2100)],
|
||||
'add_symbol_legacy_definition': [call('BR2_PACKAGE_FOO', 'Config.in.legacy', 2100)],
|
||||
'add_symbol_usage_in_legacy': [call('BR2_PACKAGE_BAR', 'Config.in.legacy', 2101)],
|
||||
'add_symbol_select': [call('BR2_PACKAGE_BAR', 'Config.in.legacy', 2101)]}),
|
||||
('normal',
|
||||
'package/foo/Config.in',
|
||||
[[1, 'config BR2_PACKAGE_BAZ'],
|
||||
[3, 'choice'],
|
||||
[4, '\tprompt "your choice"'],
|
||||
[5, 'config BR2_PACKAGE_FOO'],
|
||||
[6, 'config BR2_PACKAGE_BAR'],
|
||||
[7, '\t select BR2_PACKAGE_FOO_BAR'],
|
||||
[10, 'endchoice']],
|
||||
{'add_symbol_choice': [
|
||||
call('BR2_PACKAGE_FOO', 'package/foo/Config.in', 5),
|
||||
call('BR2_PACKAGE_BAR', 'package/foo/Config.in', 6)],
|
||||
'add_symbol_usage': [
|
||||
call('BR2_PACKAGE_FOO_BAR', 'package/foo/Config.in', 7)],
|
||||
'add_symbol_select': [
|
||||
call('BR2_PACKAGE_FOO_BAR', 'package/foo/Config.in', 7)],
|
||||
'add_symbol_definition': [
|
||||
call('BR2_PACKAGE_BAZ', 'package/foo/Config.in', 1),
|
||||
call('BR2_PACKAGE_FOO', 'package/foo/Config.in', 5),
|
||||
call('BR2_PACKAGE_BAR', 'package/foo/Config.in', 6)],
|
||||
'add_symbol_helper': [
|
||||
call('BR2_PACKAGE_BAR', 'package/foo/Config.in', 6)]}),
|
||||
]
|
||||
|
||||
|
||||
@pytest.mark.parametrize('testname,filename,file_content,expected_calls', populate_db)
|
||||
def test_populate_db(testname, filename, file_content, expected_calls):
|
||||
db = Mock()
|
||||
m.populate_db(db, filename, file_content)
|
||||
assert_db_calls(db, expected_calls)
|
||||
|
||||
|
||||
check_filename = [
|
||||
('Config.in',
|
||||
'Config.in',
|
||||
True),
|
||||
('Config.in.legacy',
|
||||
'Config.in.legacy',
|
||||
True),
|
||||
('arch/Config.in.microblaze',
|
||||
'arch/Config.in.microblaze',
|
||||
True),
|
||||
('package/php/Config.ext',
|
||||
'package/php/Config.ext',
|
||||
True),
|
||||
('package/pru-software-support/Config.in.host',
|
||||
'package/pru-software-support/Config.in.host',
|
||||
True),
|
||||
('toolchain/toolchain-external/toolchain-external-custom/Config.in.options',
|
||||
'toolchain/toolchain-external/toolchain-external-custom/Config.in.options',
|
||||
True),
|
||||
('package/foo/0001-Config.patch',
|
||||
'package/foo/0001-Config.patch',
|
||||
False),
|
||||
('package/pkg-generic.mk',
|
||||
'package/pkg-generic.mk',
|
||||
False),
|
||||
('Makefile',
|
||||
'Makefile',
|
||||
False),
|
||||
]
|
||||
|
||||
|
||||
@pytest.mark.parametrize('testname,filename,expected', check_filename)
|
||||
def test_check_filename(testname, filename, expected):
|
||||
symbols = m.check_filename(filename)
|
||||
assert symbols == expected
|
304
utils/checksymbolslib/test_makefile.py
Normal file
304
utils/checksymbolslib/test_makefile.py
Normal file
@ -0,0 +1,304 @@
|
||||
import pytest
|
||||
from unittest.mock import Mock
|
||||
from unittest.mock import call
|
||||
from checksymbolslib.test_util import assert_db_calls
|
||||
import checksymbolslib.makefile as m
|
||||
|
||||
|
||||
handle_eval = [
|
||||
('generic',
|
||||
'package/foo/foo.mk',
|
||||
5,
|
||||
'$(eval $(generic-package))',
|
||||
{'add_symbol_usage': [call('BR2_PACKAGE_FOO', 'package/foo/foo.mk', 5)]}),
|
||||
('ignore trailing whitespace',
|
||||
'package/foo/foo.mk',
|
||||
5,
|
||||
'$(eval $(generic-package)) ',
|
||||
{'add_symbol_usage': [call('BR2_PACKAGE_FOO', 'package/foo/foo.mk', 5)]}),
|
||||
('ignore indent',
|
||||
'package/foo/foo.mk',
|
||||
5,
|
||||
'\t$(eval $(generic-package))',
|
||||
{'add_symbol_usage': [call('BR2_PACKAGE_FOO', 'package/foo/foo.mk', 5)]}),
|
||||
('rootfs',
|
||||
'fs/foo/foo.mk',
|
||||
5,
|
||||
'$(eval $(rootfs))',
|
||||
{'add_symbol_usage': [
|
||||
call('BR2_TARGET_ROOTFS_FOO', 'fs/foo/foo.mk', 5),
|
||||
call('BR2_TARGET_ROOTFS_FOO_BZIP2', 'fs/foo/foo.mk', 5),
|
||||
call('BR2_TARGET_ROOTFS_FOO_GZIP', 'fs/foo/foo.mk', 5),
|
||||
call('BR2_TARGET_ROOTFS_FOO_LZ4', 'fs/foo/foo.mk', 5),
|
||||
call('BR2_TARGET_ROOTFS_FOO_LZMA', 'fs/foo/foo.mk', 5),
|
||||
call('BR2_TARGET_ROOTFS_FOO_LZO', 'fs/foo/foo.mk', 5),
|
||||
call('BR2_TARGET_ROOTFS_FOO_XZ', 'fs/foo/foo.mk', 5),
|
||||
call('BR2_TARGET_ROOTFS_FOO_ZSTD', 'fs/foo/foo.mk', 5)]}),
|
||||
('kernel module',
|
||||
'package/foo/foo.mk',
|
||||
6,
|
||||
'$(eval $(kernel-module))',
|
||||
{'add_symbol_usage': [call('BR2_PACKAGE_FOO', 'package/foo/foo.mk', 6)]}),
|
||||
('not an eval for package infra',
|
||||
'docs/manual/manual.mk',
|
||||
10,
|
||||
'$(eval $(call asciidoc-document))',
|
||||
{}),
|
||||
('linux',
|
||||
'linux/linux.mk',
|
||||
617,
|
||||
'$(eval $(kconfig-package))',
|
||||
{'add_symbol_usage': [call('BR2_LINUX_KERNEL', 'linux/linux.mk', 617)]}),
|
||||
('virtual toolchain',
|
||||
'toolchain/toolchain-external/toolchain-external.mk',
|
||||
18,
|
||||
'$(eval $(virtual-package))',
|
||||
{'add_symbol_usage': [
|
||||
call('BR2_PACKAGE_PROVIDES_TOOLCHAIN_EXTERNAL', 'toolchain/toolchain-external/toolchain-external.mk', 18),
|
||||
call('BR2_PACKAGE_HAS_TOOLCHAIN_EXTERNAL', 'toolchain/toolchain-external/toolchain-external.mk', 18),
|
||||
call('BR2_TOOLCHAIN_EXTERNAL', 'toolchain/toolchain-external/toolchain-external.mk', 18)],
|
||||
'add_symbol_virtual': [call('BR2_TOOLCHAIN_EXTERNAL', 'toolchain/toolchain-external/toolchain-external.mk', 18)]}),
|
||||
('virtual package',
|
||||
'package/foo/foo.mk',
|
||||
18,
|
||||
'$(eval $(virtual-package))',
|
||||
{'add_symbol_usage': [
|
||||
call('BR2_PACKAGE_PROVIDES_FOO', 'package/foo/foo.mk', 18),
|
||||
call('BR2_PACKAGE_HAS_FOO', 'package/foo/foo.mk', 18),
|
||||
call('BR2_PACKAGE_FOO', 'package/foo/foo.mk', 18)],
|
||||
'add_symbol_virtual': [call('BR2_PACKAGE_FOO', 'package/foo/foo.mk', 18)]}),
|
||||
('host virtual package',
|
||||
'package/foo/foo.mk',
|
||||
18,
|
||||
'$(eval $(host-virtual-package))',
|
||||
{'add_symbol_usage': [
|
||||
call('BR2_PACKAGE_PROVIDES_HOST_FOO', 'package/foo/foo.mk', 18),
|
||||
call('BR2_PACKAGE_HAS_HOST_FOO', 'package/foo/foo.mk', 18),
|
||||
call('BR2_PACKAGE_HOST_FOO', 'package/foo/foo.mk', 18)]}),
|
||||
('host generic package',
|
||||
'package/foo/foo.mk',
|
||||
18,
|
||||
'$(eval $(host-package))',
|
||||
{'add_symbol_usage': [call('BR2_PACKAGE_HOST_FOO', 'package/foo/foo.mk', 18)]}),
|
||||
('boot package',
|
||||
'boot/foo/foo.mk',
|
||||
18,
|
||||
'$(eval $(generic-package))',
|
||||
{'add_symbol_usage': [call('BR2_TARGET_FOO', 'boot/foo/foo.mk', 18)]}),
|
||||
('toolchain package',
|
||||
'toolchain/foo/foo.mk',
|
||||
18,
|
||||
'$(eval $(generic-package))',
|
||||
{'add_symbol_usage': [call('BR2_FOO', 'toolchain/foo/foo.mk', 18)]}),
|
||||
('generic package',
|
||||
'package/foo/foo.mk',
|
||||
18,
|
||||
'$(eval $(generic-package))',
|
||||
{'add_symbol_usage': [call('BR2_PACKAGE_FOO', 'package/foo/foo.mk', 18)]}),
|
||||
('cmake package',
|
||||
'package/foo/foo.mk',
|
||||
18,
|
||||
'$(eval $(cmake-package))',
|
||||
{'add_symbol_usage': [call('BR2_PACKAGE_FOO', 'package/foo/foo.mk', 18)]}),
|
||||
]
|
||||
|
||||
|
||||
@pytest.mark.parametrize('testname,filename,lineno,line,expected_calls', handle_eval)
|
||||
def test_handle_eval(testname, filename, lineno, line, expected_calls):
|
||||
db = Mock()
|
||||
m.handle_eval(db, filename, lineno, line)
|
||||
assert_db_calls(db, expected_calls)
|
||||
|
||||
|
||||
handle_definition = [
|
||||
('legacy attribution',
|
||||
'Makefile.legacy',
|
||||
9,
|
||||
'BR2_LEGACY_FOO := foo',
|
||||
True,
|
||||
{'add_symbol_legacy_definition': [call('BR2_LEGACY_FOO', 'Makefile.legacy', 9)]}),
|
||||
('attribution 1',
|
||||
'Makefile',
|
||||
9,
|
||||
'BR2_FOO ?= foo',
|
||||
False,
|
||||
{'add_symbol_definition': [call('BR2_FOO', 'Makefile', 9)]}),
|
||||
('attribution 2',
|
||||
'Makefile',
|
||||
9,
|
||||
'BR2_FOO = $(BR2_BAR)',
|
||||
False,
|
||||
{'add_symbol_definition': [call('BR2_FOO', 'Makefile', 9)]}),
|
||||
('attribution 3',
|
||||
'Makefile',
|
||||
9,
|
||||
'BR2_FOO := foo',
|
||||
False,
|
||||
{'add_symbol_definition': [call('BR2_FOO', 'Makefile', 9)]}),
|
||||
('normal export',
|
||||
'Makefile',
|
||||
90,
|
||||
'export BR2_FOO',
|
||||
False,
|
||||
{'add_symbol_definition': [call('BR2_FOO', 'Makefile', 90)]}),
|
||||
('legacy export',
|
||||
'Makefile.legacy',
|
||||
90,
|
||||
'export BR2_FOO',
|
||||
True,
|
||||
{'add_symbol_legacy_definition': [call('BR2_FOO', 'Makefile.legacy', 90)]}),
|
||||
]
|
||||
|
||||
|
||||
@pytest.mark.parametrize('testname,filename,lineno,line,legacy,expected_calls', handle_definition)
|
||||
def test_handle_definition(testname, filename, lineno, line, legacy, expected_calls):
|
||||
db = Mock()
|
||||
m.handle_definition(db, filename, lineno, line, legacy)
|
||||
assert_db_calls(db, expected_calls)
|
||||
|
||||
|
||||
handle_usage = [
|
||||
('legacy',
|
||||
'Makefile.legacy',
|
||||
8,
|
||||
'ifeq ($(BR2_LEGACY),y)',
|
||||
True,
|
||||
{'add_symbol_usage_in_legacy': [call('BR2_LEGACY', 'Makefile.legacy', 8)]}),
|
||||
('attribution',
|
||||
'Makefile',
|
||||
9,
|
||||
'BR2_FOO = $(BR2_BAR)',
|
||||
False,
|
||||
{'add_symbol_usage': [call('BR2_BAR', 'Makefile', 9)]}),
|
||||
('host virtual package',
|
||||
'package/foo/foo.mk',
|
||||
18,
|
||||
'$(eval $(host-virtual-package))',
|
||||
False,
|
||||
{'add_symbol_usage': [
|
||||
call('BR2_PACKAGE_PROVIDES_HOST_FOO', 'package/foo/foo.mk', 18),
|
||||
call('BR2_PACKAGE_HAS_HOST_FOO', 'package/foo/foo.mk', 18),
|
||||
call('BR2_PACKAGE_HOST_FOO', 'package/foo/foo.mk', 18)]}),
|
||||
]
|
||||
|
||||
|
||||
@pytest.mark.parametrize('testname,filename,lineno,line,legacy,expected_calls', handle_usage)
|
||||
def test_handle_usage(testname, filename, lineno, line, legacy, expected_calls):
|
||||
db = Mock()
|
||||
m.handle_usage(db, filename, lineno, line, legacy)
|
||||
assert_db_calls(db, expected_calls)
|
||||
|
||||
|
||||
populate_db = [
|
||||
('legacy',
|
||||
'Makefile.legacy',
|
||||
[[8, 'ifeq ($(BR2_LEGACY),y)'],
|
||||
[9, 'BR2_LEGACY_FOO := foo'],
|
||||
[34, 'ifneq ($(BUILDROOT_CONFIG),$(BR2_CONFIG))']],
|
||||
{'add_symbol_usage_in_legacy': [
|
||||
call('BR2_LEGACY', 'Makefile.legacy', 8),
|
||||
call('BR2_CONFIG', 'Makefile.legacy', 34)],
|
||||
'add_symbol_legacy_definition': [call('BR2_LEGACY_FOO', 'Makefile.legacy', 9)]}),
|
||||
('attribution',
|
||||
'Makefile',
|
||||
[[9, 'BR2_FOO = $(BR2_BAR)']],
|
||||
{'add_symbol_definition': [call('BR2_FOO', 'Makefile', 9)],
|
||||
'add_symbol_usage': [call('BR2_BAR', 'Makefile', 9)]}),
|
||||
('legacy attribution',
|
||||
'Makefile.legacy',
|
||||
[[9, 'BR2_FOO = $(BR2_BAR)']],
|
||||
{'add_symbol_legacy_definition': [call('BR2_FOO', 'Makefile.legacy', 9)],
|
||||
'add_symbol_usage_in_legacy': [call('BR2_BAR', 'Makefile.legacy', 9)]}),
|
||||
('generic',
|
||||
'package/foo/foo.mk',
|
||||
[[3, 'ifeq ($(BR2_PACKAGE_FOO_BAR):$(BR2_BAR),y:)'],
|
||||
[4, 'export BR2_PACKAGE_FOO_BAZ'],
|
||||
[5, '$(eval $(generic-package))']],
|
||||
{'add_symbol_usage': [
|
||||
call('BR2_PACKAGE_FOO_BAR', 'package/foo/foo.mk', 3),
|
||||
call('BR2_BAR', 'package/foo/foo.mk', 3),
|
||||
call('BR2_PACKAGE_FOO', 'package/foo/foo.mk', 5)],
|
||||
'add_symbol_definition': [call('BR2_PACKAGE_FOO_BAZ', 'package/foo/foo.mk', 4)]}),
|
||||
('rootfs',
|
||||
'fs/foo/foo.mk',
|
||||
[[4, 'ifeq ($(BR2_TARGET_ROOTFS_FOO_LZ4),y)'],
|
||||
[5, '$(eval $(rootfs))']],
|
||||
{'add_symbol_usage': [
|
||||
call('BR2_TARGET_ROOTFS_FOO', 'fs/foo/foo.mk', 5),
|
||||
call('BR2_TARGET_ROOTFS_FOO_BZIP2', 'fs/foo/foo.mk', 5),
|
||||
call('BR2_TARGET_ROOTFS_FOO_GZIP', 'fs/foo/foo.mk', 5),
|
||||
call('BR2_TARGET_ROOTFS_FOO_LZ4', 'fs/foo/foo.mk', 4),
|
||||
call('BR2_TARGET_ROOTFS_FOO_LZ4', 'fs/foo/foo.mk', 5),
|
||||
call('BR2_TARGET_ROOTFS_FOO_LZMA', 'fs/foo/foo.mk', 5),
|
||||
call('BR2_TARGET_ROOTFS_FOO_LZO', 'fs/foo/foo.mk', 5),
|
||||
call('BR2_TARGET_ROOTFS_FOO_XZ', 'fs/foo/foo.mk', 5),
|
||||
call('BR2_TARGET_ROOTFS_FOO_ZSTD', 'fs/foo/foo.mk', 5)]}),
|
||||
]
|
||||
|
||||
|
||||
@pytest.mark.parametrize('testname,filename,file_content,expected_calls', populate_db)
|
||||
def test_populate_db(testname, filename, file_content, expected_calls):
|
||||
db = Mock()
|
||||
m.populate_db(db, filename, file_content)
|
||||
assert_db_calls(db, expected_calls)
|
||||
|
||||
|
||||
check_filename = [
|
||||
('arch/arch.mk.riscv',
|
||||
'arch/arch.mk.riscv',
|
||||
True),
|
||||
('boot/lpc32xxcdl/lpc32xxcdl.mk',
|
||||
'boot/lpc32xxcdl/lpc32xxcdl.mk',
|
||||
True),
|
||||
('fs/cramfs/cramfs.mk',
|
||||
'fs/cramfs/cramfs.mk',
|
||||
True),
|
||||
('linux/linux-ext-fbtft.mk',
|
||||
'linux/linux-ext-fbtft.mk',
|
||||
True),
|
||||
('package/ace/ace.mk',
|
||||
'package/ace/ace.mk',
|
||||
True),
|
||||
('package/linux-tools/linux-tool-hv.mk.in',
|
||||
'package/linux-tools/linux-tool-hv.mk.in',
|
||||
True),
|
||||
('package/pkg-generic.mk',
|
||||
'package/pkg-generic.mk',
|
||||
True),
|
||||
('package/x11r7/xlib_libXt/xlib_libXt.mk',
|
||||
'package/x11r7/xlib_libXt/xlib_libXt.mk',
|
||||
True),
|
||||
('support/dependencies/check-host-make.mk',
|
||||
'support/dependencies/check-host-make.mk',
|
||||
True),
|
||||
('toolchain/toolchain-external/toolchain-external-arm-aarch64-be/toolchain-external-arm-aarch64-be.mk',
|
||||
'toolchain/toolchain-external/toolchain-external-arm-aarch64-be/toolchain-external-arm-aarch64-be.mk',
|
||||
True),
|
||||
('Makefile.legacy',
|
||||
'Makefile.legacy',
|
||||
True),
|
||||
('boot/common.mk',
|
||||
'boot/common.mk',
|
||||
True),
|
||||
('fs/common.mk',
|
||||
'fs/common.mk',
|
||||
True),
|
||||
('Makefile',
|
||||
'Makefile',
|
||||
True),
|
||||
('package/Makefile.in',
|
||||
'package/Makefile.in',
|
||||
True),
|
||||
('Config.in',
|
||||
'Config.in',
|
||||
False),
|
||||
('package/foo/0001-Makefile.patch',
|
||||
'package/foo/0001-Makefile.patch',
|
||||
False),
|
||||
]
|
||||
|
||||
|
||||
@pytest.mark.parametrize('testname,filename,expected', check_filename)
|
||||
def test_check_filename(testname, filename, expected):
|
||||
symbols = m.check_filename(filename)
|
||||
assert symbols == expected
|
15
utils/checksymbolslib/test_util.py
Normal file
15
utils/checksymbolslib/test_util.py
Normal file
@ -0,0 +1,15 @@
|
||||
def assert_calls(method, expected_calls):
|
||||
method.assert_has_calls(expected_calls, any_order=True)
|
||||
assert method.call_count == len(expected_calls)
|
||||
|
||||
|
||||
def assert_db_calls(db, expected_calls):
|
||||
assert_calls(db.add_symbol_legacy_definition, expected_calls.get('add_symbol_legacy_definition', []))
|
||||
assert_calls(db.add_symbol_definition, expected_calls.get('add_symbol_definition', []))
|
||||
assert_calls(db.add_symbol_usage_in_legacy, expected_calls.get('add_symbol_usage_in_legacy', []))
|
||||
assert_calls(db.add_symbol_usage, expected_calls.get('add_symbol_usage', []))
|
||||
assert_calls(db.add_symbol_legacy_usage, expected_calls.get('add_symbol_legacy_usage', []))
|
||||
assert_calls(db.add_symbol_select, expected_calls.get('add_symbol_select', []))
|
||||
assert_calls(db.add_symbol_helper, expected_calls.get('add_symbol_helper', []))
|
||||
assert_calls(db.add_symbol_legacy_note, expected_calls.get('add_symbol_legacy_note', []))
|
||||
assert_calls(db.add_symbol_virtual, expected_calls.get('add_symbol_virtual', []))
|
Loading…
Reference in New Issue
Block a user