Initial commit: Linux kernel 4.19 for Unplugged OS

This commit is contained in:
ziv committed 2025-10-06 13:52:42 +00:00
commit d30235b04c
80519 files changed
+35800681

No files matched your search

@@ -0,0 +1,50 @@
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,12 @@
"""
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)
+54
View File
@@ -0,0 +1,54 @@
config MODULES
bool "Enable loadable module support"
option modules
default y
choice
prompt "boolean choice"
default BOOL_CHOICE1
config BOOL_CHOICE0
bool "choice 0"
config BOOL_CHOICE1
bool "choice 1"
endchoice
choice
prompt "optional boolean choice"
optional
default OPT_BOOL_CHOICE1
config OPT_BOOL_CHOICE0
bool "choice 0"
config OPT_BOOL_CHOICE1
bool "choice 1"
endchoice
choice
prompt "tristate choice"
default TRI_CHOICE1
config TRI_CHOICE0
tristate "choice 0"
config TRI_CHOICE1
tristate "choice 1"
endchoice
choice
prompt "optional tristate choice"
optional
default OPT_TRI_CHOICE1
config OPT_TRI_CHOICE0
tristate "choice 0"
config OPT_TRI_CHOICE1
tristate "choice 1"
endchoice
+40
View File
@@ -0,0 +1,40 @@
"""
Basic choice tests.
The handling of 'choice' is a bit complicated part in Kconfig.
The behavior of 'y' choice is intuitive. If choice values are tristate,
the choice can be 'm' where each value can be enabled independently.
Also, if a choice is marked as 'optional', the whole choice can be
invisible.
"""
def test_oldask0(conf):
assert conf.oldaskconfig() == 0
assert conf.stdout_contains('oldask0_expected_stdout')
def test_oldask1(conf):
assert conf.oldaskconfig('oldask1_config') == 0
assert conf.stdout_contains('oldask1_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,5 @@
CONFIG_MODULES=y
# CONFIG_BOOL_CHOICE0 is not set
CONFIG_BOOL_CHOICE1=y
# CONFIG_TRI_CHOICE0 is not set
# CONFIG_TRI_CHOICE1 is not set
@@ -0,0 +1,9 @@
CONFIG_MODULES=y
# CONFIG_BOOL_CHOICE0 is not set
CONFIG_BOOL_CHOICE1=y
# CONFIG_OPT_BOOL_CHOICE0 is not set
CONFIG_OPT_BOOL_CHOICE1=y
CONFIG_TRI_CHOICE0=m
CONFIG_TRI_CHOICE1=m
CONFIG_OPT_TRI_CHOICE0=m
CONFIG_OPT_TRI_CHOICE1=m
@@ -0,0 +1,5 @@
# CONFIG_MODULES is not set
# CONFIG_BOOL_CHOICE0 is not set
CONFIG_BOOL_CHOICE1=y
# CONFIG_TRI_CHOICE0 is not set
CONFIG_TRI_CHOICE1=y
@@ -0,0 +1,9 @@
CONFIG_MODULES=y
# CONFIG_BOOL_CHOICE0 is not set
CONFIG_BOOL_CHOICE1=y
# CONFIG_OPT_BOOL_CHOICE0 is not set
CONFIG_OPT_BOOL_CHOICE1=y
# CONFIG_TRI_CHOICE0 is not set
CONFIG_TRI_CHOICE1=y
# CONFIG_OPT_TRI_CHOICE0 is not set
CONFIG_OPT_TRI_CHOICE1=y
@@ -0,0 +1,10 @@
Enable loadable module support (MODULES) [Y/n/?] (NEW)
boolean choice
1. choice 0 (BOOL_CHOICE0) (NEW)
> 2. choice 1 (BOOL_CHOICE1) (NEW)
choice[1-2?]:
optional boolean choice [N/y/?] (NEW)
tristate choice [M/y/?] (NEW)
choice 0 (TRI_CHOICE0) [N/m/?] (NEW)
choice 1 (TRI_CHOICE1) [N/m/?] (NEW)
optional tristate choice [N/m/y/?] (NEW)
@@ -0,0 +1,2 @@
# CONFIG_MODULES is not set
CONFIG_OPT_BOOL_CHOICE0=y
@@ -0,0 +1,15 @@
Enable loadable module support (MODULES) [N/y/?]
boolean choice
1. choice 0 (BOOL_CHOICE0) (NEW)
> 2. choice 1 (BOOL_CHOICE1) (NEW)
choice[1-2?]:
optional boolean choice [Y/n/?] (NEW)
optional boolean choice
> 1. choice 0 (OPT_BOOL_CHOICE0)
2. choice 1 (OPT_BOOL_CHOICE1) (NEW)
choice[1-2?]:
tristate choice
1. choice 0 (TRI_CHOICE0) (NEW)
> 2. choice 1 (TRI_CHOICE1) (NEW)
choice[1-2?]:
optional tristate choice [N/y/?]
@@ -0,0 +1,19 @@
config MODULES
def_bool y
option modules
config DEP
tristate
default m
choice
prompt "Tristate Choice"
config CHOICE0
tristate "Choice 0"
config CHOICE1
tristate "Choice 1"
depends on DEP
endchoice
@@ -0,0 +1,15 @@
"""
Hide tristate choice values with mod dependency in y choice.
If tristate choice values depend on symbols set to 'm', they should be
hidden when the choice containing them is changed from 'm' to 'y'
(i.e. exclusive choice).
Related Linux commit: fa64e5f6a35efd5e77d639125d973077ca506074
"""
def test(conf):
assert conf.oldaskconfig('config', 'y') == 0
assert conf.config_contains('expected_config')
assert conf.stdout_contains('expected_stdout')
@@ -0,0 +1,2 @@
CONFIG_CHOICE0=m
CONFIG_CHOICE1=m
@@ -0,0 +1,3 @@
CONFIG_MODULES=y
CONFIG_DEP=m
CONFIG_CHOICE0=y
@@ -0,0 +1,4 @@
Tristate Choice [M/y/?] y
Tristate Choice
> 1. Choice 0 (CHOICE0)
choice[1]: 1
+291
View File
@@ -0,0 +1,291 @@
# 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
# 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:
ps.stdin.write(b'\n')
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):
if all_config:
all_config_path = os.path.join(self._test_dir, all_config)
extra_env = {'KCONFIG_ALLCONFIG': all_config_path}
else:
extra_env = {}
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):
"""Run randconfig.
all_config: fragment config file for KCONFIG_ALLCONFIG (optional)
returncode: exit status of the Kconfig executable
"""
return self._allconfig('rand', all_config)
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 @@
Kconfig:11:error: recursive dependency detected!
Kconfig:11: symbol B is selected by B
For a resolution refer to Documentation/kbuild/kconfig-language.txt
subsection "Kconfig recursive dependency limitations"
Kconfig:5:error: recursive dependency detected!
Kconfig:5: symbol A depends on A
For a resolution refer to Documentation/kbuild/kconfig-language.txt
subsection "Kconfig recursive dependency limitations"
Kconfig:17:error: recursive dependency detected!
Kconfig:17: symbol C1 depends on C2
Kconfig:21: symbol C2 depends on C1
For a resolution refer to Documentation/kbuild/kconfig-language.txt
subsection "Kconfig recursive dependency limitations"
Kconfig:32:error: recursive dependency detected!
Kconfig:32: symbol D2 is selected by D1
Kconfig:27: symbol D1 depends on D2
For a resolution refer to Documentation/kbuild/kconfig-language.txt
subsection "Kconfig recursive dependency limitations"
Kconfig:37:error: recursive dependency detected!
Kconfig:37: symbol E1 depends on E2
Kconfig:42: symbol E2 is implied by E1
For a resolution refer to Documentation/kbuild/kconfig-language.txt
subsection "Kconfig recursive dependency limitations"
Kconfig:60:error: recursive dependency detected!
Kconfig:60: symbol G depends on G
For a resolution refer to Documentation/kbuild/kconfig-language.txt
subsection "Kconfig recursive dependency limitations"
Kconfig:51:error: recursive dependency detected!
Kconfig:51: symbol F2 depends on F1
Kconfig:49: symbol F1 default value contains F2
For a resolution refer to Documentation/kbuild/kconfig-language.txt
subsection "Kconfig recursive dependency limitations"
@@ -0,0 +1 @@
source "Kconfig.inc1"
@@ -0,0 +1,4 @@
source "Kconfig.inc2"
@@ -0,0 +1,3 @@
source "Kconfig.inc3"
@@ -0,0 +1 @@
source "Kconfig.inc1"
@@ -0,0 +1,10 @@
"""
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:1
included from: Kconfig.inc2:3
included from: Kconfig.inc1:4
@@ -0,0 +1,23 @@
config MODULES
def_bool y
option modules
choice
prompt "Choice"
config CHOICE_VAL0
tristate "Choice 0"
config CHOIVE_VAL1
tristate "Choice 1"
endchoice
choice
prompt "Another choice"
depends on CHOICE_VAL0
config DUMMY
bool "dummy"
endchoice
@@ -0,0 +1,14 @@
"""
Do not affect user-assigned choice value by another choice.
Handling of state flags for choices is complecated. In old days,
the defconfig result of a choice could be affected by another choice
if those choices interact by 'depends on', 'select', etc.
Related Linux commit: fbe98bb9ed3dae23e320c6b113e35f129538d14a
"""
def test(conf):
assert conf.defconfig('defconfig') == 0
assert conf.config_contains('expected_config')
@@ -0,0 +1 @@
CONFIG_CHOICE_VAL0=y
@@ -0,0 +1,4 @@
CONFIG_MODULES=y
CONFIG_CHOICE_VAL0=y
# CONFIG_CHOIVE_VAL1 is not set
CONFIG_DUMMY=y
@@ -0,0 +1,37 @@
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,14 @@
"""
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,14 @@
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,19 @@
"""
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.
+7
View File
@@ -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,33 @@
choice
prompt "choice"
config A
bool "A"
config B
bool "B"
if B
choice
prompt "sub choice"
config C
bool "C"
config D
bool "D"
if D
choice
prompt "subsub choice"
config E
bool "E"
endchoice
endif # D
endchoice
endif # B
endchoice
@@ -0,0 +1,16 @@
"""
Set random values recursively in nested choices.
Kconfig can create a choice-in-choice structure by using 'if' statement.
randconfig should correctly set random choice values.
Related Linux commit: 3b9a19e08960e5cdad5253998637653e592a3c29
"""
def test(conf):
for i in range(20):
assert conf.randconfig() == 0
assert (conf.config_contains('expected_stdout0') or
conf.config_contains('expected_stdout1') or
conf.config_contains('expected_stdout2'))
@@ -0,0 +1,2 @@
CONFIG_A=y
# CONFIG_B is not set
@@ -0,0 +1,4 @@
# CONFIG_A is not set
CONFIG_B=y
CONFIG_C=y
# CONFIG_D is not set
@@ -0,0 +1,5 @@
# CONFIG_A is not set
CONFIG_B=y
# CONFIG_C is not set
CONFIG_D=y
CONFIG_E=y