CONFIGURATION!
This commit is contained in:
@@ -0,0 +1,52 @@
|
||||
# SPDX-License-Identifier: GPL-2.0
|
||||
|
||||
config A
|
||||
bool "A"
|
||||
default y
|
||||
|
||||
config A0
|
||||
bool "A0"
|
||||
depends on A
|
||||
default y
|
||||
help
|
||||
This depends on A, so should be a submenu of A.
|
||||
|
||||
config A0_0
|
||||
bool "A1_0"
|
||||
depends on A0
|
||||
help
|
||||
Submenus are created recursively.
|
||||
This should be a submenu of A0.
|
||||
|
||||
config A1
|
||||
bool "A1"
|
||||
depends on A
|
||||
default y
|
||||
help
|
||||
This should line up with A0.
|
||||
|
||||
choice
|
||||
prompt "choice"
|
||||
depends on A1
|
||||
help
|
||||
Choice should become a submenu as well.
|
||||
|
||||
config A1_0
|
||||
bool "A1_0"
|
||||
|
||||
config A1_1
|
||||
bool "A1_1"
|
||||
|
||||
endchoice
|
||||
|
||||
config B
|
||||
bool "B"
|
||||
help
|
||||
This is independent of A.
|
||||
|
||||
config C
|
||||
bool "C"
|
||||
depends on A
|
||||
help
|
||||
This depends on A, but not a consecutive item, so can/should not
|
||||
be a submenu.
|
||||
@@ -0,0 +1,13 @@
|
||||
# SPDX-License-Identifier: GPL-2.0
|
||||
"""
|
||||
Create submenu for symbols that depend on the preceding one.
|
||||
|
||||
If a symbols has dependency on the preceding symbol, the menu entry
|
||||
should become the submenu of the preceding one, and displayed with
|
||||
deeper indentation.
|
||||
"""
|
||||
|
||||
|
||||
def test(conf):
|
||||
assert conf.oldaskconfig() == 0
|
||||
assert conf.stdout_contains('expected_stdout')
|
||||
@@ -0,0 +1,10 @@
|
||||
A (A) [Y/n/?] (NEW)
|
||||
A0 (A0) [Y/n/?] (NEW)
|
||||
A1_0 (A0_0) [N/y/?] (NEW)
|
||||
A1 (A1) [Y/n/?] (NEW)
|
||||
choice
|
||||
> 1. A1_0 (A1_0) (NEW)
|
||||
2. A1_1 (A1_1) (NEW)
|
||||
choice[1-2?]:
|
||||
B (B) [N/y/?] (NEW)
|
||||
C (C) [N/y/?] (NEW)
|
||||
@@ -0,0 +1,13 @@
|
||||
# SPDX-License-Identifier: GPL-2.0
|
||||
|
||||
choice
|
||||
prompt "boolean choice"
|
||||
default BOOL_CHOICE1
|
||||
|
||||
config BOOL_CHOICE0
|
||||
bool "choice 0"
|
||||
|
||||
config BOOL_CHOICE1
|
||||
bool "choice 1"
|
||||
|
||||
endchoice
|
||||
@@ -0,0 +1,29 @@
|
||||
# SPDX-License-Identifier: GPL-2.0
|
||||
"""
|
||||
Basic choice tests.
|
||||
"""
|
||||
|
||||
|
||||
def test_oldask0(conf):
|
||||
assert conf.oldaskconfig() == 0
|
||||
assert conf.stdout_contains('oldask0_expected_stdout')
|
||||
|
||||
|
||||
def test_allyes(conf):
|
||||
assert conf.allyesconfig() == 0
|
||||
assert conf.config_contains('allyes_expected_config')
|
||||
|
||||
|
||||
def test_allmod(conf):
|
||||
assert conf.allmodconfig() == 0
|
||||
assert conf.config_contains('allmod_expected_config')
|
||||
|
||||
|
||||
def test_allno(conf):
|
||||
assert conf.allnoconfig() == 0
|
||||
assert conf.config_contains('allno_expected_config')
|
||||
|
||||
|
||||
def test_alldef(conf):
|
||||
assert conf.alldefconfig() == 0
|
||||
assert conf.config_contains('alldef_expected_config')
|
||||
@@ -0,0 +1,2 @@
|
||||
# CONFIG_BOOL_CHOICE0 is not set
|
||||
CONFIG_BOOL_CHOICE1=y
|
||||
@@ -0,0 +1,2 @@
|
||||
# CONFIG_BOOL_CHOICE0 is not set
|
||||
CONFIG_BOOL_CHOICE1=y
|
||||
@@ -0,0 +1,2 @@
|
||||
# CONFIG_BOOL_CHOICE0 is not set
|
||||
CONFIG_BOOL_CHOICE1=y
|
||||
@@ -0,0 +1,2 @@
|
||||
# CONFIG_BOOL_CHOICE0 is not set
|
||||
CONFIG_BOOL_CHOICE1=y
|
||||
@@ -0,0 +1,4 @@
|
||||
boolean choice
|
||||
1. choice 0 (BOOL_CHOICE0) (NEW)
|
||||
> 2. choice 1 (BOOL_CHOICE1) (NEW)
|
||||
choice[1-2?]:
|
||||
@@ -0,0 +1,22 @@
|
||||
choice
|
||||
prompt "choose A or B"
|
||||
|
||||
config A
|
||||
bool "A"
|
||||
|
||||
config B
|
||||
bool "B"
|
||||
|
||||
endchoice
|
||||
|
||||
choice
|
||||
prompt "choose X or Y"
|
||||
depends on B
|
||||
|
||||
config X
|
||||
bool "X"
|
||||
|
||||
config Y
|
||||
bool "Y"
|
||||
|
||||
endchoice
|
||||
@@ -0,0 +1,34 @@
|
||||
# SPDX-License-Identifier: GPL-2.0-only
|
||||
"""
|
||||
Randomize all dependent choices
|
||||
|
||||
This is a somewhat tricky case for randconfig; the visibility of one choice is
|
||||
determined by a member of another choice. Randconfig should be able to generate
|
||||
all possible patterns.
|
||||
"""
|
||||
|
||||
|
||||
def test(conf):
|
||||
|
||||
expected0 = False
|
||||
expected1 = False
|
||||
expected2 = False
|
||||
|
||||
for i in range(100):
|
||||
assert conf.randconfig(seed=i) == 0
|
||||
|
||||
if conf.config_matches('expected_config0'):
|
||||
expected0 = True
|
||||
elif conf.config_matches('expected_config1'):
|
||||
expected1 = True
|
||||
elif conf.config_matches('expected_config2'):
|
||||
expected2 = True
|
||||
else:
|
||||
assert False
|
||||
|
||||
if expected0 and expected1 and expected2:
|
||||
break
|
||||
|
||||
assert expected0
|
||||
assert expected1
|
||||
assert expected2
|
||||
@@ -0,0 +1,6 @@
|
||||
#
|
||||
# Automatically generated file; DO NOT EDIT.
|
||||
# Main menu
|
||||
#
|
||||
CONFIG_A=y
|
||||
# CONFIG_B is not set
|
||||
@@ -0,0 +1,8 @@
|
||||
#
|
||||
# Automatically generated file; DO NOT EDIT.
|
||||
# Main menu
|
||||
#
|
||||
# CONFIG_A is not set
|
||||
CONFIG_B=y
|
||||
CONFIG_X=y
|
||||
# CONFIG_Y is not set
|
||||
@@ -0,0 +1,8 @@
|
||||
#
|
||||
# Automatically generated file; DO NOT EDIT.
|
||||
# Main menu
|
||||
#
|
||||
# CONFIG_A is not set
|
||||
CONFIG_B=y
|
||||
# CONFIG_X is not set
|
||||
CONFIG_Y=y
|
||||
@@ -0,0 +1,32 @@
|
||||
choice
|
||||
prompt "This is always invisible"
|
||||
depends on n
|
||||
|
||||
config DUMMY
|
||||
bool "DUMMY"
|
||||
|
||||
endchoice
|
||||
|
||||
choice
|
||||
prompt "Choose A or B"
|
||||
|
||||
config A
|
||||
bool "A"
|
||||
|
||||
config B
|
||||
bool "B"
|
||||
|
||||
endchoice
|
||||
|
||||
config FOO
|
||||
bool "FOO"
|
||||
depends on A
|
||||
|
||||
choice
|
||||
prompt "Choose X"
|
||||
depends on FOO
|
||||
|
||||
config X
|
||||
bool "X"
|
||||
|
||||
endchoice
|
||||
@@ -0,0 +1,18 @@
|
||||
# SPDX-License-Identifier: GPL-2.0-only
|
||||
"""
|
||||
Randomize choices with correct dependencies
|
||||
|
||||
When shuffling a choice may potentially disrupt certain dependencies, symbol
|
||||
values must be recalculated.
|
||||
|
||||
Related Linux commits:
|
||||
- c8fb7d7e48d11520ad24808cfce7afb7b9c9f798
|
||||
"""
|
||||
|
||||
|
||||
def test(conf):
|
||||
for i in range(20):
|
||||
assert conf.randconfig(seed=i) == 0
|
||||
assert (conf.config_matches('expected_config0') or
|
||||
conf.config_matches('expected_config1') or
|
||||
conf.config_matches('expected_config2'))
|
||||
@@ -0,0 +1,8 @@
|
||||
#
|
||||
# Automatically generated file; DO NOT EDIT.
|
||||
# Main menu
|
||||
#
|
||||
CONFIG_A=y
|
||||
# CONFIG_B is not set
|
||||
CONFIG_FOO=y
|
||||
CONFIG_X=y
|
||||
@@ -0,0 +1,7 @@
|
||||
#
|
||||
# Automatically generated file; DO NOT EDIT.
|
||||
# Main menu
|
||||
#
|
||||
CONFIG_A=y
|
||||
# CONFIG_B is not set
|
||||
# CONFIG_FOO is not set
|
||||
@@ -0,0 +1,6 @@
|
||||
#
|
||||
# Automatically generated file; DO NOT EDIT.
|
||||
# Main menu
|
||||
#
|
||||
# CONFIG_A is not set
|
||||
CONFIG_B=y
|
||||
@@ -0,0 +1,32 @@
|
||||
# SPDX-License-Identifier: GPL-2.0
|
||||
# Test Kconfig file for conditional dependencies.
|
||||
|
||||
# Enable module support for tristate testing
|
||||
config MODULES
|
||||
bool "Enable loadable module support"
|
||||
modules
|
||||
default y
|
||||
|
||||
config FOO
|
||||
bool "FOO symbol"
|
||||
|
||||
config BAR
|
||||
bool "BAR symbol"
|
||||
|
||||
config TEST_BASIC
|
||||
bool "Test basic conditional dependency"
|
||||
depends on FOO if BAR
|
||||
default y
|
||||
|
||||
config TEST_COMPLEX
|
||||
bool "Test complex conditional dependency"
|
||||
depends on (FOO && BAR) if (FOO || BAR)
|
||||
default y
|
||||
|
||||
config BAZ
|
||||
tristate "BAZ symbol"
|
||||
|
||||
config TEST_OPTIONAL
|
||||
tristate "Test simple optional dependency"
|
||||
depends on BAZ if BAZ
|
||||
default y
|
||||
@@ -0,0 +1,14 @@
|
||||
# SPDX-License-Identifier: GPL-2.0
|
||||
"""
|
||||
Correctly handle conditional dependencies.
|
||||
"""
|
||||
|
||||
def test(conf):
|
||||
assert conf.oldconfig('test_config1') == 0
|
||||
assert conf.config_matches('expected_config1')
|
||||
|
||||
assert conf.oldconfig('test_config2') == 0
|
||||
assert conf.config_matches('expected_config2')
|
||||
|
||||
assert conf.oldconfig('test_config3') == 0
|
||||
assert conf.config_matches('expected_config3')
|
||||
@@ -0,0 +1,11 @@
|
||||
#
|
||||
# Automatically generated file; DO NOT EDIT.
|
||||
# Main menu
|
||||
#
|
||||
CONFIG_MODULES=y
|
||||
CONFIG_FOO=y
|
||||
CONFIG_BAR=y
|
||||
CONFIG_TEST_BASIC=y
|
||||
CONFIG_TEST_COMPLEX=y
|
||||
CONFIG_BAZ=m
|
||||
CONFIG_TEST_OPTIONAL=m
|
||||
@@ -0,0 +1,9 @@
|
||||
#
|
||||
# Automatically generated file; DO NOT EDIT.
|
||||
# Main menu
|
||||
#
|
||||
CONFIG_MODULES=y
|
||||
# CONFIG_FOO is not set
|
||||
CONFIG_BAR=y
|
||||
CONFIG_BAZ=y
|
||||
CONFIG_TEST_OPTIONAL=y
|
||||
@@ -0,0 +1,11 @@
|
||||
#
|
||||
# Automatically generated file; DO NOT EDIT.
|
||||
# Main menu
|
||||
#
|
||||
CONFIG_MODULES=y
|
||||
# CONFIG_FOO is not set
|
||||
# CONFIG_BAR is not set
|
||||
CONFIG_TEST_BASIC=y
|
||||
CONFIG_TEST_COMPLEX=y
|
||||
# CONFIG_BAZ is not set
|
||||
CONFIG_TEST_OPTIONAL=y
|
||||
@@ -0,0 +1,6 @@
|
||||
# Basic check that everything can be configured if selected.
|
||||
CONFIG_FOO=y
|
||||
CONFIG_BAR=y
|
||||
CONFIG_BAZ=m
|
||||
# Ensure that TEST_OPTIONAL=y with BAZ=m is converted to TEST_OPTIONAL=m
|
||||
CONFIG_TEST_OPTIONAL=y
|
||||
@@ -0,0 +1,7 @@
|
||||
# If FOO is not selected, then TEST_BASIC should fail the conditional
|
||||
# dependency since BAR is set.
|
||||
# TEST_COMPLEX will fail dependency as it depends on both FOO and BAR
|
||||
# if either of those is selected.
|
||||
CONFIG_FOO=n
|
||||
CONFIG_BAR=y
|
||||
CONFIG_BAZ=y
|
||||
@@ -0,0 +1,6 @@
|
||||
# If FOO is not selected, but BAR is also not selected, then TEST_BASIC
|
||||
# should pass since the dependency on FOO is conditional on BAR.
|
||||
# TEST_COMPLEX should be also set since neither FOO nor BAR are selected
|
||||
# so it has no dependencies.
|
||||
CONFIG_FOO=n
|
||||
CONFIG_BAR=n
|
||||
@@ -0,0 +1,314 @@
|
||||
# SPDX-License-Identifier: GPL-2.0
|
||||
#
|
||||
# Copyright (C) 2018 Masahiro Yamada <yamada.masahiro@socionext.com>
|
||||
#
|
||||
|
||||
"""
|
||||
Kconfig unit testing framework.
|
||||
|
||||
This provides fixture functions commonly used from test files.
|
||||
"""
|
||||
|
||||
import os
|
||||
import pytest
|
||||
import shutil
|
||||
import subprocess
|
||||
import tempfile
|
||||
|
||||
CONF_PATH = os.path.abspath(os.path.join('scripts', 'kconfig', 'conf'))
|
||||
|
||||
|
||||
class Conf:
|
||||
"""Kconfig runner and result checker.
|
||||
|
||||
This class provides methods to run text-based interface of Kconfig
|
||||
(scripts/kconfig/conf) and retrieve the resulted configuration,
|
||||
stdout, and stderr. It also provides methods to compare those
|
||||
results with expectations.
|
||||
"""
|
||||
|
||||
def __init__(self, request):
|
||||
"""Create a new Conf instance.
|
||||
|
||||
request: object to introspect the requesting test module
|
||||
"""
|
||||
# the directory of the test being run
|
||||
self._test_dir = os.path.dirname(str(request.fspath))
|
||||
|
||||
# runners
|
||||
def _run_conf(self, mode, dot_config=None, out_file='.config',
|
||||
interactive=False, in_keys=None, extra_env={}):
|
||||
"""Run text-based Kconfig executable and save the result.
|
||||
|
||||
mode: input mode option (--oldaskconfig, --defconfig=<file> etc.)
|
||||
dot_config: .config file to use for configuration base
|
||||
out_file: file name to contain the output config data
|
||||
interactive: flag to specify the interactive mode
|
||||
in_keys: key inputs for interactive modes
|
||||
extra_env: additional environments
|
||||
returncode: exit status of the Kconfig executable
|
||||
"""
|
||||
command = [CONF_PATH, mode, 'Kconfig']
|
||||
|
||||
# Override 'srctree' environment to make the test as the top directory
|
||||
extra_env['srctree'] = self._test_dir
|
||||
|
||||
# Clear KCONFIG_DEFCONFIG_LIST to keep unit tests from being affected
|
||||
# by the user's environment.
|
||||
extra_env['KCONFIG_DEFCONFIG_LIST'] = ''
|
||||
|
||||
# Run Kconfig in a temporary directory.
|
||||
# This directory is automatically removed when done.
|
||||
with tempfile.TemporaryDirectory() as temp_dir:
|
||||
|
||||
# if .config is given, copy it to the working directory
|
||||
if dot_config:
|
||||
shutil.copyfile(os.path.join(self._test_dir, dot_config),
|
||||
os.path.join(temp_dir, '.config'))
|
||||
|
||||
ps = subprocess.Popen(command,
|
||||
stdin=subprocess.PIPE,
|
||||
stdout=subprocess.PIPE,
|
||||
stderr=subprocess.PIPE,
|
||||
cwd=temp_dir,
|
||||
env=dict(os.environ, **extra_env))
|
||||
|
||||
# If input key sequence is given, feed it to stdin.
|
||||
if in_keys:
|
||||
ps.stdin.write(in_keys.encode('utf-8'))
|
||||
|
||||
while ps.poll() is None:
|
||||
# For interactive modes such as oldaskconfig, oldconfig,
|
||||
# send 'Enter' key until the program finishes.
|
||||
if interactive:
|
||||
try:
|
||||
ps.stdin.write(b'\n')
|
||||
ps.stdin.flush()
|
||||
except (BrokenPipeError, OSError):
|
||||
# Process has exited, stop sending input
|
||||
break
|
||||
|
||||
# Close stdin gracefully
|
||||
try:
|
||||
ps.stdin.close()
|
||||
except (BrokenPipeError, OSError):
|
||||
# Ignore broken pipe on close
|
||||
pass
|
||||
|
||||
# Wait for process to complete
|
||||
ps.wait()
|
||||
|
||||
self.retcode = ps.returncode
|
||||
self.stdout = ps.stdout.read().decode()
|
||||
self.stderr = ps.stderr.read().decode()
|
||||
|
||||
# Retrieve the resulted config data only when .config is supposed
|
||||
# to exist. If the command fails, the .config does not exist.
|
||||
# 'listnewconfig' does not produce .config in the first place.
|
||||
if self.retcode == 0 and out_file:
|
||||
with open(os.path.join(temp_dir, out_file)) as f:
|
||||
self.config = f.read()
|
||||
else:
|
||||
self.config = None
|
||||
|
||||
# Logging:
|
||||
# Pytest captures the following information by default. In failure
|
||||
# of tests, the captured log will be displayed. This will be useful to
|
||||
# figure out what has happened.
|
||||
|
||||
print("[command]\n{}\n".format(' '.join(command)))
|
||||
|
||||
print("[retcode]\n{}\n".format(self.retcode))
|
||||
|
||||
print("[stdout]")
|
||||
print(self.stdout)
|
||||
|
||||
print("[stderr]")
|
||||
print(self.stderr)
|
||||
|
||||
if self.config is not None:
|
||||
print("[output for '{}']".format(out_file))
|
||||
print(self.config)
|
||||
|
||||
return self.retcode
|
||||
|
||||
def oldaskconfig(self, dot_config=None, in_keys=None):
|
||||
"""Run oldaskconfig.
|
||||
|
||||
dot_config: .config file to use for configuration base (optional)
|
||||
in_key: key inputs (optional)
|
||||
returncode: exit status of the Kconfig executable
|
||||
"""
|
||||
return self._run_conf('--oldaskconfig', dot_config=dot_config,
|
||||
interactive=True, in_keys=in_keys)
|
||||
|
||||
def oldconfig(self, dot_config=None, in_keys=None):
|
||||
"""Run oldconfig.
|
||||
|
||||
dot_config: .config file to use for configuration base (optional)
|
||||
in_key: key inputs (optional)
|
||||
returncode: exit status of the Kconfig executable
|
||||
"""
|
||||
return self._run_conf('--oldconfig', dot_config=dot_config,
|
||||
interactive=True, in_keys=in_keys)
|
||||
|
||||
def olddefconfig(self, dot_config=None):
|
||||
"""Run olddefconfig.
|
||||
|
||||
dot_config: .config file to use for configuration base (optional)
|
||||
returncode: exit status of the Kconfig executable
|
||||
"""
|
||||
return self._run_conf('--olddefconfig', dot_config=dot_config)
|
||||
|
||||
def defconfig(self, defconfig):
|
||||
"""Run defconfig.
|
||||
|
||||
defconfig: defconfig file for input
|
||||
returncode: exit status of the Kconfig executable
|
||||
"""
|
||||
defconfig_path = os.path.join(self._test_dir, defconfig)
|
||||
return self._run_conf('--defconfig={}'.format(defconfig_path))
|
||||
|
||||
def _allconfig(self, mode, all_config, extra_env={}):
|
||||
if all_config:
|
||||
all_config_path = os.path.join(self._test_dir, all_config)
|
||||
extra_env['KCONFIG_ALLCONFIG'] = all_config_path
|
||||
|
||||
return self._run_conf('--{}config'.format(mode), extra_env=extra_env)
|
||||
|
||||
def allyesconfig(self, all_config=None):
|
||||
"""Run allyesconfig.
|
||||
|
||||
all_config: fragment config file for KCONFIG_ALLCONFIG (optional)
|
||||
returncode: exit status of the Kconfig executable
|
||||
"""
|
||||
return self._allconfig('allyes', all_config)
|
||||
|
||||
def allmodconfig(self, all_config=None):
|
||||
"""Run allmodconfig.
|
||||
|
||||
all_config: fragment config file for KCONFIG_ALLCONFIG (optional)
|
||||
returncode: exit status of the Kconfig executable
|
||||
"""
|
||||
return self._allconfig('allmod', all_config)
|
||||
|
||||
def allnoconfig(self, all_config=None):
|
||||
"""Run allnoconfig.
|
||||
|
||||
all_config: fragment config file for KCONFIG_ALLCONFIG (optional)
|
||||
returncode: exit status of the Kconfig executable
|
||||
"""
|
||||
return self._allconfig('allno', all_config)
|
||||
|
||||
def alldefconfig(self, all_config=None):
|
||||
"""Run alldefconfig.
|
||||
|
||||
all_config: fragment config file for KCONFIG_ALLCONFIG (optional)
|
||||
returncode: exit status of the Kconfig executable
|
||||
"""
|
||||
return self._allconfig('alldef', all_config)
|
||||
|
||||
def randconfig(self, all_config=None, seed=None):
|
||||
"""Run randconfig.
|
||||
|
||||
all_config: fragment config file for KCONFIG_ALLCONFIG (optional)
|
||||
seed: the seed for randconfig (optional)
|
||||
returncode: exit status of the Kconfig executable
|
||||
"""
|
||||
if seed is not None:
|
||||
extra_env = {'KCONFIG_SEED': hex(seed)}
|
||||
else:
|
||||
extra_env = {}
|
||||
|
||||
return self._allconfig('rand', all_config, extra_env=extra_env)
|
||||
|
||||
def savedefconfig(self, dot_config):
|
||||
"""Run savedefconfig.
|
||||
|
||||
dot_config: .config file for input
|
||||
returncode: exit status of the Kconfig executable
|
||||
"""
|
||||
return self._run_conf('--savedefconfig', out_file='defconfig')
|
||||
|
||||
def listnewconfig(self, dot_config=None):
|
||||
"""Run listnewconfig.
|
||||
|
||||
dot_config: .config file to use for configuration base (optional)
|
||||
returncode: exit status of the Kconfig executable
|
||||
"""
|
||||
return self._run_conf('--listnewconfig', dot_config=dot_config,
|
||||
out_file=None)
|
||||
|
||||
# checkers
|
||||
def _read_and_compare(self, compare, expected):
|
||||
"""Compare the result with expectation.
|
||||
|
||||
compare: function to compare the result with expectation
|
||||
expected: file that contains the expected data
|
||||
"""
|
||||
with open(os.path.join(self._test_dir, expected)) as f:
|
||||
expected_data = f.read()
|
||||
return compare(self, expected_data)
|
||||
|
||||
def _contains(self, attr, expected):
|
||||
return self._read_and_compare(
|
||||
lambda s, e: getattr(s, attr).find(e) >= 0,
|
||||
expected)
|
||||
|
||||
def _matches(self, attr, expected):
|
||||
return self._read_and_compare(lambda s, e: getattr(s, attr) == e,
|
||||
expected)
|
||||
|
||||
def config_contains(self, expected):
|
||||
"""Check if resulted configuration contains expected data.
|
||||
|
||||
expected: file that contains the expected data
|
||||
returncode: True if result contains the expected data, False otherwise
|
||||
"""
|
||||
return self._contains('config', expected)
|
||||
|
||||
def config_matches(self, expected):
|
||||
"""Check if resulted configuration exactly matches expected data.
|
||||
|
||||
expected: file that contains the expected data
|
||||
returncode: True if result matches the expected data, False otherwise
|
||||
"""
|
||||
return self._matches('config', expected)
|
||||
|
||||
def stdout_contains(self, expected):
|
||||
"""Check if resulted stdout contains expected data.
|
||||
|
||||
expected: file that contains the expected data
|
||||
returncode: True if result contains the expected data, False otherwise
|
||||
"""
|
||||
return self._contains('stdout', expected)
|
||||
|
||||
def stdout_matches(self, expected):
|
||||
"""Check if resulted stdout exactly matches expected data.
|
||||
|
||||
expected: file that contains the expected data
|
||||
returncode: True if result matches the expected data, False otherwise
|
||||
"""
|
||||
return self._matches('stdout', expected)
|
||||
|
||||
def stderr_contains(self, expected):
|
||||
"""Check if resulted stderr contains expected data.
|
||||
|
||||
expected: file that contains the expected data
|
||||
returncode: True if result contains the expected data, False otherwise
|
||||
"""
|
||||
return self._contains('stderr', expected)
|
||||
|
||||
def stderr_matches(self, expected):
|
||||
"""Check if resulted stderr exactly matches expected data.
|
||||
|
||||
expected: file that contains the expected data
|
||||
returncode: True if result matches the expected data, False otherwise
|
||||
"""
|
||||
return self._matches('stderr', expected)
|
||||
|
||||
|
||||
@pytest.fixture(scope="module")
|
||||
def conf(request):
|
||||
"""Create a Conf instance and provide it to test functions."""
|
||||
return Conf(request)
|
||||
@@ -0,0 +1,63 @@
|
||||
# SPDX-License-Identifier: GPL-2.0
|
||||
|
||||
# depends on itself
|
||||
|
||||
config A
|
||||
bool "A"
|
||||
depends on A
|
||||
|
||||
# select itself
|
||||
|
||||
config B
|
||||
bool
|
||||
select B
|
||||
|
||||
# depends on each other
|
||||
|
||||
config C1
|
||||
bool "C1"
|
||||
depends on C2
|
||||
|
||||
config C2
|
||||
bool "C2"
|
||||
depends on C1
|
||||
|
||||
# depends on and select
|
||||
|
||||
config D1
|
||||
bool "D1"
|
||||
depends on D2
|
||||
select D2
|
||||
|
||||
config D2
|
||||
bool
|
||||
|
||||
# depends on and imply
|
||||
|
||||
config E1
|
||||
bool "E1"
|
||||
depends on E2
|
||||
imply E2
|
||||
|
||||
config E2
|
||||
bool "E2"
|
||||
|
||||
# property
|
||||
|
||||
config F1
|
||||
bool "F1"
|
||||
default F2
|
||||
|
||||
config F2
|
||||
bool "F2"
|
||||
depends on F1
|
||||
|
||||
# menu
|
||||
|
||||
menu "menu depending on its content"
|
||||
depends on G
|
||||
|
||||
config G
|
||||
bool "G"
|
||||
|
||||
endmenu
|
||||
@@ -0,0 +1,10 @@
|
||||
# SPDX-License-Identifier: GPL-2.0
|
||||
"""
|
||||
Detect recursive dependency error.
|
||||
|
||||
Recursive dependency should be treated as an error.
|
||||
"""
|
||||
|
||||
def test(conf):
|
||||
assert conf.oldaskconfig() == 1
|
||||
assert conf.stderr_contains('expected_stderr')
|
||||
@@ -0,0 +1,38 @@
|
||||
error: recursive dependency detected!
|
||||
symbol A depends on A
|
||||
For a resolution refer to Documentation/kbuild/kconfig-language.rst
|
||||
subsection "Kconfig recursive dependency limitations"
|
||||
|
||||
error: recursive dependency detected!
|
||||
symbol B is selected by B
|
||||
For a resolution refer to Documentation/kbuild/kconfig-language.rst
|
||||
subsection "Kconfig recursive dependency limitations"
|
||||
|
||||
error: recursive dependency detected!
|
||||
symbol C1 depends on C2
|
||||
symbol C2 depends on C1
|
||||
For a resolution refer to Documentation/kbuild/kconfig-language.rst
|
||||
subsection "Kconfig recursive dependency limitations"
|
||||
|
||||
error: recursive dependency detected!
|
||||
symbol D1 depends on D2
|
||||
symbol D2 is selected by D1
|
||||
For a resolution refer to Documentation/kbuild/kconfig-language.rst
|
||||
subsection "Kconfig recursive dependency limitations"
|
||||
|
||||
error: recursive dependency detected!
|
||||
symbol E1 depends on E2
|
||||
symbol E2 is implied by E1
|
||||
For a resolution refer to Documentation/kbuild/kconfig-language.rst
|
||||
subsection "Kconfig recursive dependency limitations"
|
||||
|
||||
error: recursive dependency detected!
|
||||
symbol F1 default value contains F2
|
||||
symbol F2 depends on F1
|
||||
For a resolution refer to Documentation/kbuild/kconfig-language.rst
|
||||
subsection "Kconfig recursive dependency limitations"
|
||||
|
||||
error: recursive dependency detected!
|
||||
symbol G depends on G
|
||||
For a resolution refer to Documentation/kbuild/kconfig-language.rst
|
||||
subsection "Kconfig recursive dependency limitations"
|
||||
@@ -0,0 +1,2 @@
|
||||
# SPDX-License-Identifier: GPL-2.0-only
|
||||
source "Kconfig.inc1"
|
||||
@@ -0,0 +1,5 @@
|
||||
# SPDX-License-Identifier: GPL-2.0-only
|
||||
|
||||
|
||||
|
||||
source "Kconfig.inc2"
|
||||
@@ -0,0 +1,4 @@
|
||||
# SPDX-License-Identifier: GPL-2.0-only
|
||||
|
||||
|
||||
source "Kconfig.inc3"
|
||||
@@ -0,0 +1,2 @@
|
||||
# SPDX-License-Identifier: GPL-2.0-only
|
||||
source "Kconfig.inc1"
|
||||
@@ -0,0 +1,11 @@
|
||||
# SPDX-License-Identifier: GPL-2.0
|
||||
"""
|
||||
Detect recursive inclusion error.
|
||||
|
||||
If recursive inclusion is detected, it should fail with error messages.
|
||||
"""
|
||||
|
||||
|
||||
def test(conf):
|
||||
assert conf.oldaskconfig() != 0
|
||||
assert conf.stderr_contains('expected_stderr')
|
||||
@@ -0,0 +1,6 @@
|
||||
Recursive inclusion detected.
|
||||
Inclusion path:
|
||||
current file : Kconfig.inc1
|
||||
included from: Kconfig.inc3:2
|
||||
included from: Kconfig.inc2:4
|
||||
included from: Kconfig.inc1:5
|
||||
@@ -0,0 +1,3 @@
|
||||
# SPDX-License-Identifier: GPL-2.0-only
|
||||
|
||||
source "Kconfig.inc1"
|
||||
@@ -0,0 +1,4 @@
|
||||
# SPDX-License-Identifier: GPL-2.0-only
|
||||
|
||||
source "Kconfig.inc2"
|
||||
source "Kconfig.inc3"
|
||||
@@ -0,0 +1,3 @@
|
||||
# SPDX-License-Identifier: GPL-2.0-only
|
||||
|
||||
source "Kconfig.inc3"
|
||||
@@ -0,0 +1 @@
|
||||
# SPDX-License-Identifier: GPL-2.0-only
|
||||
@@ -0,0 +1,10 @@
|
||||
# SPDX-License-Identifier: GPL-2.0
|
||||
"""
|
||||
Detect repeated inclusion error.
|
||||
|
||||
If repeated inclusion is detected, it should fail with error message.
|
||||
"""
|
||||
|
||||
def test(conf):
|
||||
assert conf.oldaskconfig() != 0
|
||||
assert conf.stderr_contains('expected_stderr')
|
||||
@@ -0,0 +1,2 @@
|
||||
Kconfig.inc1:4: error: repeated inclusion of Kconfig.inc3
|
||||
Kconfig.inc2:3: note: location of first inclusion of Kconfig.inc3
|
||||
@@ -0,0 +1,52 @@
|
||||
# SPDX-License-Identifier: GPL-2.0
|
||||
# Test that transitional symbols cannot have properties other than help
|
||||
|
||||
config BAD_DEFAULT
|
||||
bool
|
||||
transitional
|
||||
default y
|
||||
help
|
||||
This transitional symbol illegally has a default property.
|
||||
|
||||
config BAD_PROMPT
|
||||
bool
|
||||
transitional
|
||||
prompt "Bad prompt"
|
||||
help
|
||||
This transitional symbol illegally has a prompt.
|
||||
|
||||
config BAD_SELECT
|
||||
bool
|
||||
transitional
|
||||
select OTHER_SYMBOL
|
||||
help
|
||||
This transitional symbol illegally has a select.
|
||||
|
||||
config BAD_IMPLY
|
||||
bool
|
||||
transitional
|
||||
imply OTHER_SYMBOL
|
||||
help
|
||||
This transitional symbol illegally has an imply.
|
||||
|
||||
config BAD_DEPENDS
|
||||
bool
|
||||
transitional
|
||||
depends on OTHER_SYMBOL
|
||||
help
|
||||
This transitional symbol illegally has a depends.
|
||||
|
||||
config BAD_RANGE
|
||||
int
|
||||
transitional
|
||||
range 1 10
|
||||
help
|
||||
This transitional symbol illegally has a range.
|
||||
|
||||
config BAD_NO_TYPE
|
||||
transitional
|
||||
help
|
||||
This transitional symbol illegally has no type specified.
|
||||
|
||||
config OTHER_SYMBOL
|
||||
bool
|
||||
@@ -0,0 +1,14 @@
|
||||
# SPDX-License-Identifier: GPL-2.0
|
||||
"""
|
||||
Test that transitional symbols with invalid properties are rejected.
|
||||
|
||||
Transitional symbols can only have help sections. Any other properties
|
||||
(default, select, depends, etc.) should cause a parser error.
|
||||
"""
|
||||
|
||||
def test(conf):
|
||||
# This should fail with exit code 1 due to invalid transitional symbol
|
||||
assert conf.olddefconfig() == 1
|
||||
|
||||
# Check that the error message is about transitional symbols
|
||||
assert conf.stderr_contains('expected_stderr')
|
||||
@@ -0,0 +1,7 @@
|
||||
Kconfig:46:warning: config symbol defined without type
|
||||
Kconfig:7: error: transitional symbols can only have help sections
|
||||
Kconfig:14: error: transitional symbols can only have help sections
|
||||
Kconfig:21: error: transitional symbols can only have help sections
|
||||
Kconfig:28: error: transitional symbols can only have help sections
|
||||
Kconfig:32: error: transitional symbols can only have help sections
|
||||
Kconfig:42: error: transitional symbols can only have help sections
|
||||
@@ -0,0 +1,39 @@
|
||||
# SPDX-License-Identifier: GPL-2.0
|
||||
|
||||
config A
|
||||
bool "A"
|
||||
help
|
||||
This is a new symbol.
|
||||
|
||||
choice
|
||||
prompt "Choice ?"
|
||||
depends on A
|
||||
help
|
||||
"depends on A" has been newly added.
|
||||
|
||||
config CHOICE_B
|
||||
bool "Choice B"
|
||||
|
||||
config CHOICE_C
|
||||
bool "Choice C"
|
||||
help
|
||||
This is a new symbol, so should be asked.
|
||||
|
||||
endchoice
|
||||
|
||||
choice
|
||||
prompt "Choice2 ?"
|
||||
|
||||
config CHOICE_D
|
||||
bool "Choice D"
|
||||
|
||||
config CHOICE_E
|
||||
bool "Choice E"
|
||||
|
||||
config CHOICE_F
|
||||
bool "Choice F"
|
||||
depends on A
|
||||
help
|
||||
This is a new symbol, so should be asked.
|
||||
|
||||
endchoice
|
||||
@@ -0,0 +1,15 @@
|
||||
# SPDX-License-Identifier: GPL-2.0
|
||||
"""
|
||||
Ask new choice values when they become visible.
|
||||
|
||||
If new choice values are added with new dependency, and they become
|
||||
visible during user configuration, oldconfig should recognize them
|
||||
as (NEW), and ask the user for choice.
|
||||
|
||||
Related Linux commit: 5d09598d488f081e3be23f885ed65cbbe2d073b5
|
||||
"""
|
||||
|
||||
|
||||
def test(conf):
|
||||
assert conf.oldconfig('config', 'y') == 0
|
||||
assert conf.stdout_contains('expected_stdout')
|
||||
@@ -0,0 +1,3 @@
|
||||
CONFIG_CHOICE_B=y
|
||||
# CONFIG_CHOICE_D is not set
|
||||
CONFIG_CHOICE_E=y
|
||||
@@ -0,0 +1,10 @@
|
||||
A (A) [N/y/?] (NEW) y
|
||||
Choice ?
|
||||
> 1. Choice B (CHOICE_B)
|
||||
2. Choice C (CHOICE_C) (NEW)
|
||||
choice[1-2?]:
|
||||
Choice2 ?
|
||||
1. Choice D (CHOICE_D)
|
||||
> 2. Choice E (CHOICE_E)
|
||||
3. Choice F (CHOICE_F) (NEW)
|
||||
choice[1-3?]:
|
||||
@@ -0,0 +1,16 @@
|
||||
# SPDX-License-Identifier: GPL-2.0
|
||||
|
||||
config A
|
||||
bool "A"
|
||||
|
||||
choice
|
||||
prompt "Choice ?"
|
||||
depends on A
|
||||
|
||||
config CHOICE_B
|
||||
bool "Choice B"
|
||||
|
||||
config CHOICE_C
|
||||
bool "Choice C"
|
||||
|
||||
endchoice
|
||||
@@ -0,0 +1,20 @@
|
||||
# SPDX-License-Identifier: GPL-2.0
|
||||
"""
|
||||
Do not write choice values to .config if the dependency is unmet.
|
||||
|
||||
"# CONFIG_... is not set" should not be written into the .config file
|
||||
for symbols with unmet dependency.
|
||||
|
||||
This was not working correctly for choice values because choice needs
|
||||
a bit different symbol computation.
|
||||
|
||||
This checks that no unneeded "# COFIG_... is not set" is contained in
|
||||
the .config file.
|
||||
|
||||
Related Linux commit: cb67ab2cd2b8abd9650292c986c79901e3073a59
|
||||
"""
|
||||
|
||||
|
||||
def test(conf):
|
||||
assert conf.oldaskconfig('config', 'n') == 0
|
||||
assert conf.config_matches('expected_config')
|
||||
@@ -0,0 +1 @@
|
||||
CONFIG_A=y
|
||||
@@ -0,0 +1,5 @@
|
||||
#
|
||||
# Automatically generated file; DO NOT EDIT.
|
||||
# Main menu
|
||||
#
|
||||
# CONFIG_A is not set
|
||||
@@ -0,0 +1,27 @@
|
||||
# SPDX-License-Identifier: GPL-2.0
|
||||
|
||||
# 'info' prints the argument to stdout.
|
||||
$(info,hello world 0)
|
||||
|
||||
# 'warning-if', if the first argument is y, sends the second argument to stderr,
|
||||
# and the message is prefixed with the current file name and line number.
|
||||
$(warning-if,y,hello world 1)
|
||||
|
||||
# 'error-if' is similar, but it terminates the parsing immediately.
|
||||
# The following is just no-op since the first argument is not y.
|
||||
$(error-if,n,this should not be printed)
|
||||
|
||||
# Shorthand
|
||||
warning = $(warning-if,y,$(1))
|
||||
|
||||
# 'shell' executes a command, and returns its stdout.
|
||||
$(warning,$(shell,echo hello world 3))
|
||||
|
||||
# Every newline in the output is replaced with a space,
|
||||
# but any trailing newlines are deleted.
|
||||
$(warning,$(shell,printf 'hello\nworld\n\n4\n\n\n'))
|
||||
|
||||
# 'filename' is expanded to the currently parsed file name,
|
||||
# 'lineno' to the line number.
|
||||
$(warning,filename=$(filename))
|
||||
$(warning,lineno=$(lineno))
|
||||
@@ -0,0 +1,9 @@
|
||||
# SPDX-License-Identifier: GPL-2.0
|
||||
"""
|
||||
Built-in function tests.
|
||||
"""
|
||||
|
||||
def test(conf):
|
||||
assert conf.oldaskconfig() == 0
|
||||
assert conf.stdout_contains('expected_stdout')
|
||||
assert conf.stderr_matches('expected_stderr')
|
||||
@@ -0,0 +1,5 @@
|
||||
Kconfig:8: hello world 1
|
||||
Kconfig:18: hello world 3
|
||||
Kconfig:22: hello world 4
|
||||
Kconfig:26: filename=Kconfig
|
||||
Kconfig:27: lineno=27
|
||||
@@ -0,0 +1 @@
|
||||
hello world 0
|
||||
@@ -0,0 +1,5 @@
|
||||
# SPDX-License-Identifier: GPL-2.0
|
||||
|
||||
X = $(Y)
|
||||
Y = $(X)
|
||||
$(info $(X))
|
||||
@@ -0,0 +1,11 @@
|
||||
# SPDX-License-Identifier: GPL-2.0
|
||||
"""
|
||||
Detect circular variable expansion.
|
||||
|
||||
If a recursively expanded variable references itself (eventually),
|
||||
it should fail with an error message.
|
||||
"""
|
||||
|
||||
def test(conf):
|
||||
assert conf.oldaskconfig() != 0
|
||||
assert conf.stderr_matches('expected_stderr')
|
||||
@@ -0,0 +1 @@
|
||||
Kconfig:5: Recursive variable 'X' references itself (eventually)
|
||||
@@ -0,0 +1,44 @@
|
||||
# SPDX-License-Identifier: GPL-2.0
|
||||
|
||||
# Shorthand
|
||||
warning = $(warning-if,y,$(1))
|
||||
|
||||
# You can not pass commas directly to a function since they are treated as
|
||||
# delimiters. You can use the following trick to do so.
|
||||
comma := ,
|
||||
$(warning,hello$(comma) world)
|
||||
|
||||
# Like Make, single quotes, double quotes, spaces are treated verbatim.
|
||||
# The following prints the text as-is.
|
||||
$(warning, ' " '" ' ''' "'")
|
||||
|
||||
# Unlike Make, '$' has special meaning only when it is followed by '('.
|
||||
# No need to escape '$' itself.
|
||||
$(warning,$)
|
||||
$(warning,$$)
|
||||
$ := 1
|
||||
$(warning,$($))
|
||||
|
||||
# You need a trick to escape '$' followed by '('
|
||||
# The following should print "$(X)". It should not be expanded further.
|
||||
dollar := $
|
||||
$(warning,$(dollar)(X))
|
||||
|
||||
# You need a trick to treat unbalanced parentheses.
|
||||
# The following should print "(".
|
||||
left_paren := (
|
||||
$(warning,$(left_paren))
|
||||
|
||||
# A simple expanded should not be expanded multiple times.
|
||||
# The following should print "$(X)". It should not be expanded further.
|
||||
Y := $(dollar)(X)
|
||||
$(warning,$(Y))
|
||||
|
||||
# The following should print "$(X)" as well.
|
||||
Y = $(dollar)(X)
|
||||
$(warning,$(Y))
|
||||
|
||||
# The following should print "$(".
|
||||
# It should not be emit "unterminated reference" error.
|
||||
unterminated := $(dollar)(
|
||||
$(warning,$(unterminated))
|
||||
@@ -0,0 +1,8 @@
|
||||
# SPDX-License-Identifier: GPL-2.0
|
||||
"""
|
||||
Escape sequence tests.
|
||||
"""
|
||||
|
||||
def test(conf):
|
||||
assert conf.oldaskconfig() == 0
|
||||
assert conf.stderr_matches('expected_stderr')
|
||||
@@ -0,0 +1,10 @@
|
||||
Kconfig:9: hello, world
|
||||
Kconfig:13: ' " '" ' ''' "'"
|
||||
Kconfig:17: $
|
||||
Kconfig:18: $$
|
||||
Kconfig:20: 1
|
||||
Kconfig:25: $(X)
|
||||
Kconfig:30: (
|
||||
Kconfig:35: $(X)
|
||||
Kconfig:39: $(X)
|
||||
Kconfig:44: $(
|
||||
@@ -0,0 +1,53 @@
|
||||
# SPDX-License-Identifier: GPL-2.0
|
||||
|
||||
# Shorthand
|
||||
warning = $(warning-if,y,$(1))
|
||||
|
||||
# Simply expanded variable.
|
||||
X := 1
|
||||
SIMPLE := $(X)
|
||||
X := 2
|
||||
$(warning,SIMPLE = $(SIMPLE))
|
||||
|
||||
# Recursively expanded variable.
|
||||
X := 1
|
||||
RECURSIVE = $(X)
|
||||
X := 2
|
||||
$(warning,RECURSIVE = $(RECURSIVE))
|
||||
|
||||
# Append something to a simply expanded variable.
|
||||
Y := 3
|
||||
SIMPLE += $(Y)
|
||||
Y := 4
|
||||
$(warning,SIMPLE = $(SIMPLE))
|
||||
|
||||
# Append something to a recursively expanded variable.
|
||||
Y := 3
|
||||
RECURSIVE += $(Y)
|
||||
Y := 4
|
||||
$(warning,RECURSIVE = $(RECURSIVE))
|
||||
|
||||
# Use += operator to an undefined variable.
|
||||
# This works as a recursively expanded variable.
|
||||
Y := 3
|
||||
UNDEFINED_VARIABLE += $(Y)
|
||||
Y := 4
|
||||
$(warning,UNDEFINED_VARIABLE = $(UNDEFINED_VARIABLE))
|
||||
|
||||
# You can use variable references for the lefthand side of assignment statement.
|
||||
X := A
|
||||
Y := B
|
||||
$(X)$(Y) := 5
|
||||
$(warning,AB = $(AB))
|
||||
|
||||
# User-defined function.
|
||||
greeting = $(1), my name is $(2).
|
||||
$(warning,$(greeting,Hello,John))
|
||||
|
||||
# The number of arguments is not checked for user-defined functions.
|
||||
# If some arguments are optional, it is useful to pass fewer parameters.
|
||||
# $(2) will be blank in this case.
|
||||
$(warning,$(greeting,Hello))
|
||||
|
||||
# Unreferenced parameters are just ignored.
|
||||
$(warning,$(greeting,Hello,John,ignored,ignored))
|
||||
@@ -0,0 +1,8 @@
|
||||
# SPDX-License-Identifier: GPL-2.0
|
||||
"""
|
||||
Variable and user-defined function tests.
|
||||
"""
|
||||
|
||||
def test(conf):
|
||||
assert conf.oldaskconfig() == 0
|
||||
assert conf.stderr_matches('expected_stderr')
|
||||
@@ -0,0 +1,9 @@
|
||||
Kconfig:10: SIMPLE = 1
|
||||
Kconfig:16: RECURSIVE = 2
|
||||
Kconfig:22: SIMPLE = 1 3
|
||||
Kconfig:28: RECURSIVE = 2 4
|
||||
Kconfig:35: UNDEFINED_VARIABLE = 4
|
||||
Kconfig:41: AB = 5
|
||||
Kconfig:45: Hello, my name is John.
|
||||
Kconfig:50: Hello, my name is .
|
||||
Kconfig:53: Hello, my name is John.
|
||||
@@ -0,0 +1,7 @@
|
||||
[pytest]
|
||||
addopts = --verbose
|
||||
|
||||
# Pytest requires that test files have unique names, because pytest imports
|
||||
# them as top-level modules. It is silly to prefix or suffix a test file with
|
||||
# the directory name that contains it. Use __init__.py for all test files.
|
||||
python_files = __init__.py
|
||||
@@ -0,0 +1,132 @@
|
||||
# SPDX-License-Identifier: GPL-2.0
|
||||
# Test transitional symbols for config migration with all Kconfig types
|
||||
|
||||
# Enable module support for tristate testing
|
||||
config MODULES
|
||||
bool "Enable loadable module support"
|
||||
modules
|
||||
default y
|
||||
|
||||
# Basic migration tests for all types
|
||||
config NEW_BOOL
|
||||
bool "New bool option"
|
||||
default OLD_BOOL
|
||||
|
||||
config OLD_BOOL
|
||||
bool
|
||||
transitional
|
||||
|
||||
config NEW_TRISTATE
|
||||
tristate "New tristate option"
|
||||
default OLD_TRISTATE
|
||||
|
||||
config OLD_TRISTATE
|
||||
tristate
|
||||
transitional
|
||||
|
||||
config NEW_STRING
|
||||
string "New string option"
|
||||
default OLD_STRING
|
||||
|
||||
config OLD_STRING
|
||||
string
|
||||
transitional
|
||||
|
||||
config NEW_HEX
|
||||
hex "New hex option"
|
||||
default OLD_HEX
|
||||
|
||||
config OLD_HEX
|
||||
hex
|
||||
transitional
|
||||
|
||||
config NEW_INT
|
||||
int "New int option"
|
||||
default OLD_INT
|
||||
|
||||
config OLD_INT
|
||||
int
|
||||
transitional
|
||||
|
||||
# Precedence tests for all types
|
||||
config NEW_BOOL_PRECEDENCE
|
||||
bool "New bool option with precedence"
|
||||
default OLD_BOOL_PRECEDENCE
|
||||
|
||||
config OLD_BOOL_PRECEDENCE
|
||||
bool
|
||||
transitional
|
||||
|
||||
config NEW_STRING_PRECEDENCE
|
||||
string "New string option with precedence"
|
||||
default OLD_STRING_PRECEDENCE
|
||||
|
||||
config OLD_STRING_PRECEDENCE
|
||||
string
|
||||
transitional
|
||||
|
||||
config NEW_TRISTATE_PRECEDENCE
|
||||
tristate "New tristate option with precedence"
|
||||
default OLD_TRISTATE_PRECEDENCE
|
||||
|
||||
config OLD_TRISTATE_PRECEDENCE
|
||||
tristate
|
||||
transitional
|
||||
|
||||
config NEW_HEX_PRECEDENCE
|
||||
hex "New hex option with precedence"
|
||||
default OLD_HEX_PRECEDENCE
|
||||
|
||||
config OLD_HEX_PRECEDENCE
|
||||
hex
|
||||
transitional
|
||||
|
||||
config NEW_INT_PRECEDENCE
|
||||
int "New int option with precedence"
|
||||
default OLD_INT_PRECEDENCE
|
||||
|
||||
config OLD_INT_PRECEDENCE
|
||||
int
|
||||
transitional
|
||||
|
||||
# Test that help sections are allowed for transitional symbols
|
||||
config OLD_WITH_HELP
|
||||
bool
|
||||
transitional
|
||||
help
|
||||
This transitional symbol has a help section to validate that help is allowed.
|
||||
|
||||
# Test that we can set something to =n via transitional symbol
|
||||
config NEW_DISABLED
|
||||
tristate "Check for setting to disabled"
|
||||
default OLD_DISABLED
|
||||
|
||||
config OLD_DISABLED
|
||||
tristate
|
||||
transitional
|
||||
|
||||
# Test that a potential new value disappears if it lacks a prompt
|
||||
config NEW_DISABLED_UNSAVED
|
||||
tristate
|
||||
default OLD_DISABLED
|
||||
|
||||
config OLD_DISABLED_UNSAVED
|
||||
tristate
|
||||
transitional
|
||||
|
||||
# Test conditional default: transitional value should not prevent prompting
|
||||
# when default visibility makes the expression evaluate to 'no'
|
||||
config DEPENDENCY_TEST
|
||||
bool "Dependency for testing"
|
||||
default n
|
||||
|
||||
config NEW_CONDITIONAL_DEFAULT
|
||||
bool "New option with conditional default"
|
||||
default OLD_CONDITIONAL_DEFAULT if DEPENDENCY_TEST
|
||||
|
||||
config OLD_CONDITIONAL_DEFAULT
|
||||
bool
|
||||
transitional
|
||||
|
||||
config REGULAR_OPTION
|
||||
bool "Regular option"
|
||||
@@ -0,0 +1,25 @@
|
||||
# SPDX-License-Identifier: GPL-2.0
|
||||
"""
|
||||
Test transitional symbol migration functionality for all Kconfig types.
|
||||
|
||||
This tests that:
|
||||
- OLD_* options in existing .config cause NEW_* options to be set
|
||||
- OLD_* options are not written to the new .config file
|
||||
- NEW_* options appear in the new .config file with correct values
|
||||
- NEW_* options with defaults from transitional symbols are not prompted
|
||||
- All Kconfig types work correctly: bool, tristate, string, hex, int
|
||||
- User-set NEW values take precedence over conflicting OLD transitional values
|
||||
"""
|
||||
|
||||
def test(conf):
|
||||
# Run olddefconfig to process the migration with the initial config
|
||||
assert conf.olddefconfig(dot_config='initial_config') == 0
|
||||
|
||||
# Check that the configuration matches expected output
|
||||
assert conf.config_contains('expected_config')
|
||||
|
||||
# Test oldconfig to ensure symbols with transitional defaults are not prompted
|
||||
assert conf.oldconfig(dot_config='initial_config', in_keys='n\n') == 0
|
||||
|
||||
# Except for when conditional default evaluates to 'no'
|
||||
assert conf.stdout_contains('expected_stdout')
|
||||
@@ -0,0 +1,15 @@
|
||||
CONFIG_MODULES=y
|
||||
CONFIG_NEW_BOOL=y
|
||||
CONFIG_NEW_TRISTATE=m
|
||||
CONFIG_NEW_STRING="test string"
|
||||
CONFIG_NEW_HEX=0x1234
|
||||
CONFIG_NEW_INT=42
|
||||
# CONFIG_NEW_BOOL_PRECEDENCE is not set
|
||||
CONFIG_NEW_STRING_PRECEDENCE="user value"
|
||||
CONFIG_NEW_TRISTATE_PRECEDENCE=y
|
||||
CONFIG_NEW_HEX_PRECEDENCE=0xABCD
|
||||
CONFIG_NEW_INT_PRECEDENCE=100
|
||||
# CONFIG_NEW_DISABLED is not set
|
||||
# CONFIG_DEPENDENCY_TEST is not set
|
||||
# CONFIG_NEW_CONDITIONAL_DEFAULT is not set
|
||||
# CONFIG_REGULAR_OPTION is not set
|
||||
@@ -0,0 +1 @@
|
||||
New option with conditional default (NEW_CONDITIONAL_DEFAULT) [N/y/?] (NEW) n
|
||||
@@ -0,0 +1,20 @@
|
||||
CONFIG_MODULES=y
|
||||
CONFIG_OLD_BOOL=y
|
||||
CONFIG_OLD_TRISTATE=m
|
||||
CONFIG_OLD_STRING="test string"
|
||||
CONFIG_OLD_HEX=0x1234
|
||||
CONFIG_OLD_INT=42
|
||||
# CONFIG_NEW_BOOL_PRECEDENCE is not set
|
||||
CONFIG_OLD_BOOL_PRECEDENCE=y
|
||||
CONFIG_NEW_STRING_PRECEDENCE="user value"
|
||||
CONFIG_OLD_STRING_PRECEDENCE="old value"
|
||||
CONFIG_NEW_TRISTATE_PRECEDENCE=y
|
||||
CONFIG_OLD_TRISTATE_PRECEDENCE=m
|
||||
CONFIG_NEW_HEX_PRECEDENCE=0xABCD
|
||||
CONFIG_OLD_HEX_PRECEDENCE=0x5678
|
||||
CONFIG_NEW_INT_PRECEDENCE=100
|
||||
CONFIG_OLD_INT_PRECEDENCE=200
|
||||
# CONFIG_OLD_DISABLED is not set
|
||||
# CONFIG_OLD_DISABLED_UNSAVED is not set
|
||||
# CONFIG_DEPENDENCY_TEST is not set
|
||||
CONFIG_OLD_CONDITIONAL_DEFAULT=y
|
||||
Reference in New Issue
Block a user