3204 lines
101 KiB
Python
3204 lines
101 KiB
Python
# Copyright (c) 2011-2019, Ulf Magnusson
|
|
# SPDX-License-Identifier: ISC
|
|
|
|
# This is the Kconfiglib test suite. It runs selftests on Kconfigs provided by
|
|
# us and tests compatibility with the C Kconfig implementation by comparing the
|
|
# output of Kconfiglib with the output of the scripts/kconfig/*conf utilities
|
|
# for different targets and defconfigs. It should be run from the top-level
|
|
# kernel directory with
|
|
#
|
|
# $ python Kconfiglib/testsuite.py
|
|
#
|
|
# Some additional options can be turned on by passing them as arguments. They
|
|
# default to off.
|
|
#
|
|
# - obsessive:
|
|
# By default, only valid arch/defconfig pairs are tested. In obsessive mode,
|
|
# every arch will be tested with every defconfig. Increases the testing time
|
|
# by an order of magnitude. Occasionally finds (usually obscure) bugs, and I
|
|
# make sure everything passes with it.
|
|
#
|
|
# - obsessive-min-config:
|
|
# Like obsessive, for the minimal configuation (defconfig) tests.
|
|
#
|
|
# - log:
|
|
# Log timestamped defconfig test failures to the file test_defconfig_fails.
|
|
# Handy in obsessive mode.
|
|
#
|
|
# For example, this commands runs the test suite in obsessive mode with logging
|
|
# enabled:
|
|
#
|
|
# $ python(3) Kconfiglib/testsuite.py obsessive log
|
|
#
|
|
# pypy works too, and runs most tests much faster than CPython.
|
|
#
|
|
# All tests should pass. Report regressions to ulfalizer a.t Google's email
|
|
# service.
|
|
|
|
import difflib
|
|
import errno
|
|
import os
|
|
import re
|
|
import shutil
|
|
import subprocess
|
|
import sys
|
|
import tempfile
|
|
import textwrap
|
|
|
|
from kconfiglib import Kconfig, Symbol, Choice, COMMENT, MENU, MenuNode, \
|
|
BOOL, TRISTATE, HEX, \
|
|
TRI_TO_STR, \
|
|
escape, unescape, \
|
|
expr_str, expr_items, split_expr, \
|
|
_ordered_unique, \
|
|
OR, AND, \
|
|
KconfigError
|
|
|
|
|
|
def shell(cmd):
|
|
with open(os.devnull, "w") as devnull:
|
|
subprocess.call(cmd, shell=True, stdout=devnull, stderr=devnull)
|
|
|
|
|
|
all_passed = True
|
|
|
|
|
|
def fail(msg=None):
|
|
global all_passed
|
|
all_passed = False
|
|
if msg is not None:
|
|
print("fail: " + msg)
|
|
|
|
|
|
def verify(cond, msg):
|
|
if not cond:
|
|
fail(msg)
|
|
|
|
|
|
def verify_equal(x, y):
|
|
if x != y:
|
|
fail("'{}' does not equal '{}'".format(x, y))
|
|
|
|
|
|
# Prevent accidental loading of configuration files by removing
|
|
# KCONFIG_ALLCONFIG from the environment
|
|
os.environ.pop("KCONFIG_ALLCONFIG", None)
|
|
|
|
obsessive = False
|
|
obsessive_min_config = False
|
|
log = False
|
|
|
|
|
|
def run_tests():
|
|
global obsessive, log
|
|
for s in sys.argv[1:]:
|
|
if s == "obsessive":
|
|
obsessive = True
|
|
print("Obsessive mode enabled")
|
|
elif s == "obsessive-min-config":
|
|
obsessive_min_config = True
|
|
print("Obsessive minimal config mode enabled")
|
|
elif s == "log":
|
|
log = True
|
|
print("Log mode enabled")
|
|
else:
|
|
print("Unrecognized option '{}'".format(s))
|
|
return
|
|
|
|
run_selftests()
|
|
run_compatibility_tests()
|
|
|
|
|
|
def run_selftests():
|
|
#
|
|
# Common helper functions. These all expect 'c' to hold the current
|
|
# configuration.
|
|
#
|
|
|
|
def verify_value(sym_name, val):
|
|
# Verifies that a symbol has a particular value.
|
|
|
|
if isinstance(val, int):
|
|
val = TRI_TO_STR[val]
|
|
|
|
sym = c.syms[sym_name]
|
|
verify(sym.str_value == val,
|
|
'expected {} to have the value "{}", had the value "{}"'
|
|
.format(sym_name, val, sym.str_value))
|
|
|
|
def assign_and_verify_value(sym_name, val, new_val):
|
|
# Assigns 'val' to a symbol and verifies that its value becomes
|
|
# 'new_val'. Assumes (and tests) that 'val' is valid for the
|
|
# symbol type.
|
|
|
|
if isinstance(new_val, int):
|
|
new_val = TRI_TO_STR[new_val]
|
|
|
|
sym = c.syms[sym_name]
|
|
old_val = sym.str_value
|
|
verify(sym.set_value(val),
|
|
"assigning '{}' to {} unexpectedly failed"
|
|
.format(val, sym_name))
|
|
verify(sym.str_value == new_val,
|
|
"expected {} to have the value '{}' after being assigned the "
|
|
"value '{}'. Instead, the value is '{}'. The old value was "
|
|
"'{}'."
|
|
.format(sym_name, new_val, val, sym.str_value, old_val))
|
|
|
|
def assign_and_verify(sym_name, user_val):
|
|
# Like assign_and_verify_value(), with the expected value being the
|
|
# value just set.
|
|
|
|
assign_and_verify_value(sym_name, user_val, user_val)
|
|
|
|
def assign_and_verify_user_value(sym_name, val, user_val, valid):
|
|
# Assigns a user value to the symbol and verifies the new user value.
|
|
# If valid is True, the user value is valid for the type, otherwise
|
|
# not. This is used to test the set_value() return value.
|
|
|
|
sym = c.syms[sym_name]
|
|
sym_old_user_val = sym.user_value
|
|
|
|
verify(sym.set_value(val) == valid,
|
|
"expected the user value '{}' to be {} for {}, was not"
|
|
.format(val, "valid" if valid else "invalid", sym_name))
|
|
verify(sym.user_value == user_val,
|
|
"the assigned user value '{}' wasn't reflected in user_value "
|
|
"on the symbol {}. Instead, the new user_value was '{}'. The "
|
|
"old user value was '{}'."
|
|
.format(user_val, sym_name, sym.user_value, sym_old_user_val))
|
|
|
|
#
|
|
# Selftests
|
|
#
|
|
|
|
print("Testing string literal lexing")
|
|
|
|
# Dummy empty configuration just to get a Kconfig object
|
|
c = Kconfig("Kconfiglib/tests/empty")
|
|
|
|
def verify_string_lex(s, expected):
|
|
# Verifies that a constant symbol with the name 'res' is produced from
|
|
# lexing 's'
|
|
|
|
res = c._tokenize("if " + s)[1].name
|
|
verify(res == expected,
|
|
"expected <{}> to produced the constant symbol <{}>, "
|
|
'produced <{}>'.format(s[1:-1], expected, res))
|
|
|
|
verify_string_lex(r""" "" """, "")
|
|
verify_string_lex(r""" '' """, "")
|
|
|
|
verify_string_lex(r""" "a" """, "a")
|
|
verify_string_lex(r""" 'a' """, "a")
|
|
verify_string_lex(r""" "ab" """, "ab")
|
|
verify_string_lex(r""" 'ab' """, "ab")
|
|
verify_string_lex(r""" "abc" """, "abc")
|
|
verify_string_lex(r""" 'abc' """, "abc")
|
|
|
|
verify_string_lex(r""" "'" """, "'")
|
|
verify_string_lex(r""" '"' """, '"')
|
|
|
|
verify_string_lex(r""" "\"" """, '"')
|
|
verify_string_lex(r""" '\'' """, "'")
|
|
|
|
verify_string_lex(r""" "\"\"" """, '""')
|
|
verify_string_lex(r""" '\'\'' """, "''")
|
|
|
|
verify_string_lex(r""" "\'" """, "'")
|
|
verify_string_lex(r""" '\"' """, '"')
|
|
|
|
verify_string_lex(r""" "\\" """, "\\")
|
|
verify_string_lex(r""" '\\' """, "\\")
|
|
|
|
verify_string_lex(r""" "\a\\'\b\c\"'d" """, 'a\\\'bc"\'d')
|
|
verify_string_lex(r""" '\a\\"\b\c\'"d' """, "a\\\"bc'\"d")
|
|
|
|
def verify_string_bad(s):
|
|
# Verifies that tokenizing 's' throws a KconfigError. Strips the first
|
|
# and last characters from 's' so we can use readable raw strings as
|
|
# input.
|
|
|
|
try:
|
|
c.eval_string(s)
|
|
except KconfigError:
|
|
pass
|
|
else:
|
|
fail("expected tokenization of {} to fail, didn't".format(s[1:-1]))
|
|
|
|
verify_string_bad(r""" " """)
|
|
verify_string_bad(r""" ' """)
|
|
verify_string_bad(r""" "' """)
|
|
verify_string_bad(r""" '" """)
|
|
verify_string_bad(r""" "\" """)
|
|
verify_string_bad(r""" '\' """)
|
|
verify_string_bad(r""" "foo """)
|
|
verify_string_bad(r""" 'foo """)
|
|
|
|
|
|
print("Testing escape() and unescape()")
|
|
|
|
def verify_escape_unescape(s, sesc):
|
|
# Verify that 's' escapes to 'sesc' and that 'sesc' unescapes to 's'
|
|
verify_equal(escape(s), sesc)
|
|
verify_equal(unescape(sesc), s)
|
|
|
|
verify_escape_unescape(r'' , r'' )
|
|
verify_escape_unescape(r'foo' , r'foo' )
|
|
verify_escape_unescape(r'"' , r'\"' )
|
|
verify_escape_unescape(r'""' , r'\"\"' )
|
|
verify_escape_unescape('\\' , r'\\' )
|
|
verify_escape_unescape(r'\\' , r'\\\\' )
|
|
verify_escape_unescape(r'\"' , r'\\\"' )
|
|
verify_escape_unescape(r'"ab\cd"ef"', r'\"ab\\cd\"ef\"')
|
|
|
|
# Backslashes before any character should be unescaped, not just before "
|
|
# and \
|
|
verify_equal(unescape(r"\afoo\b\c\\d\\\e\\\\f"), r"afoobc\d\e\\f")
|
|
|
|
|
|
print("Testing _ordered_unique()")
|
|
|
|
verify_equal(_ordered_unique([]), [])
|
|
verify_equal(_ordered_unique([1]), [1])
|
|
verify_equal(_ordered_unique([1, 2]), [1, 2])
|
|
verify_equal(_ordered_unique([1, 1]), [1])
|
|
verify_equal(_ordered_unique([1, 1, 2]), [1, 2])
|
|
verify_equal(_ordered_unique([1, 2, 1]), [1, 2])
|
|
verify_equal(_ordered_unique([1, 2, 2]), [1, 2])
|
|
verify_equal(_ordered_unique([1, 2, 3, 2, 1, 2, 3, 4, 3, 2, 1, 0]),
|
|
[1, 2, 3, 4, 0])
|
|
|
|
|
|
print("Testing expression evaluation")
|
|
|
|
c = Kconfig("Kconfiglib/tests/Keval", warn=False)
|
|
|
|
def verify_eval(expr, val):
|
|
res = c.eval_string(expr)
|
|
verify(res == val,
|
|
"'{}' evaluated to {}, expected {}".format(expr, res, val))
|
|
|
|
# No modules
|
|
verify_eval("n", 0)
|
|
verify_eval("m", 0)
|
|
verify_eval("y", 2)
|
|
verify_eval("'n'", 0)
|
|
verify_eval("'m'", 0)
|
|
verify_eval("'y'", 2)
|
|
verify_eval("M", 2)
|
|
|
|
# Modules
|
|
c.modules.set_value(2)
|
|
verify_eval("n", 0)
|
|
verify_eval("m", 1)
|
|
verify_eval("y", 2)
|
|
verify_eval("'n'", 0)
|
|
verify_eval("'m'", 1)
|
|
verify_eval("'y'", 2)
|
|
verify_eval("M", 1)
|
|
verify_eval("(Y || N) && (m && y)", 1)
|
|
|
|
# Non-bool/non-tristate symbols are always n in a tristate sense
|
|
verify_eval("Y_STRING", 0)
|
|
verify_eval("Y_STRING || m", 1)
|
|
|
|
# As are all constants besides y and m
|
|
verify_eval('"foo"', 0)
|
|
verify_eval('"foo" || "bar"', 0)
|
|
verify_eval('"foo" || m', 1)
|
|
|
|
# Test equality for symbols
|
|
|
|
verify_eval("N = N", 2)
|
|
verify_eval("N = n", 2)
|
|
verify_eval("N = 'n'", 2)
|
|
verify_eval("N != N", 0)
|
|
verify_eval("N != n", 0)
|
|
verify_eval("N != 'n'", 0)
|
|
|
|
verify_eval("M = M", 2)
|
|
verify_eval("M = m", 2)
|
|
verify_eval("M = 'm'", 2)
|
|
verify_eval("M != M", 0)
|
|
verify_eval("M != m", 0)
|
|
verify_eval("M != 'm'", 0)
|
|
|
|
verify_eval("Y = Y", 2)
|
|
verify_eval("Y = y", 2)
|
|
verify_eval("Y = 'y'", 2)
|
|
verify_eval("Y != Y", 0)
|
|
verify_eval("Y != y", 0)
|
|
verify_eval("Y != 'y'", 0)
|
|
|
|
verify_eval("N != M", 2)
|
|
verify_eval("N != Y", 2)
|
|
verify_eval("M != Y", 2)
|
|
|
|
verify_eval("Y_STRING = y", 2)
|
|
verify_eval("Y_STRING = 'y'", 2)
|
|
verify_eval('FOO_BAR_STRING = "foo bar"', 2)
|
|
verify_eval('FOO_BAR_STRING != "foo bar baz"', 2)
|
|
verify_eval('INT_37 = 37', 2)
|
|
verify_eval("INT_37 = '37'", 2)
|
|
verify_eval('HEX_0X37 = 0x37', 2)
|
|
verify_eval("HEX_0X37 = '0x37'", 2)
|
|
|
|
# These should also hold after 31847b67 (kconfig: allow use of relations
|
|
# other than (in)equality)
|
|
verify_eval("HEX_0X37 = '0x037'", 2)
|
|
verify_eval("HEX_0X37 = '0x0037'", 2)
|
|
|
|
# Constant symbol comparisons
|
|
verify_eval('"foo" != "bar"', 2)
|
|
verify_eval('"foo" = "bar"', 0)
|
|
verify_eval('"foo" = "foo"', 2)
|
|
|
|
# Undefined symbols get their name as their value
|
|
c.warn = False
|
|
verify_eval("'not_defined' = not_defined", 2)
|
|
verify_eval("not_defined_2 = not_defined_2", 2)
|
|
verify_eval("not_defined_1 != not_defined_2", 2)
|
|
|
|
# Test less than/greater than
|
|
|
|
# Basic evaluation
|
|
verify_eval("INT_37 < 38", 2)
|
|
verify_eval("38 < INT_37", 0)
|
|
verify_eval("INT_37 < '38'", 2)
|
|
verify_eval("'38' < INT_37", 0)
|
|
verify_eval("INT_37 < 138", 2)
|
|
verify_eval("138 < INT_37", 0)
|
|
verify_eval("INT_37 < '138'", 2)
|
|
verify_eval("'138' < INT_37", 0)
|
|
verify_eval("INT_37 < -138", 0)
|
|
verify_eval("-138 < INT_37", 2)
|
|
verify_eval("INT_37 < '-138'", 0)
|
|
verify_eval("'-138' < INT_37", 2)
|
|
verify_eval("INT_37 < 37", 0)
|
|
verify_eval("37 < INT_37", 0)
|
|
verify_eval("INT_37 < 36", 0)
|
|
verify_eval("36 < INT_37", 2)
|
|
|
|
# Different formats in comparison
|
|
verify_eval("INT_37 < 0x26", 2) # 38
|
|
verify_eval("INT_37 < 0x25", 0) # 37
|
|
verify_eval("INT_37 < 0x24", 0) # 36
|
|
verify_eval("HEX_0X37 < 56", 2) # 0x38
|
|
verify_eval("HEX_0X37 < 55", 0) # 0x37
|
|
verify_eval("HEX_0X37 < 54", 0) # 0x36
|
|
|
|
# Other int comparisons
|
|
verify_eval("INT_37 <= 38", 2)
|
|
verify_eval("INT_37 <= 37", 2)
|
|
verify_eval("INT_37 <= 36", 0)
|
|
verify_eval("INT_37 > 38", 0)
|
|
verify_eval("INT_37 > 37", 0)
|
|
verify_eval("INT_37 > 36", 2)
|
|
verify_eval("INT_37 >= 38", 0)
|
|
verify_eval("INT_37 >= 37", 2)
|
|
verify_eval("INT_37 >= 36", 2)
|
|
|
|
# Other hex comparisons
|
|
verify_eval("HEX_0X37 <= 0x38", 2)
|
|
verify_eval("HEX_0X37 <= 0x37", 2)
|
|
verify_eval("HEX_0X37 <= 0x36", 0)
|
|
verify_eval("HEX_0X37 > 0x38", 0)
|
|
verify_eval("HEX_0X37 > 0x37", 0)
|
|
verify_eval("HEX_0X37 > 0x36", 2)
|
|
verify_eval("HEX_0X37 >= 0x38", 0)
|
|
verify_eval("HEX_0X37 >= 0x37", 2)
|
|
verify_eval("HEX_0X37 >= 0x36", 2)
|
|
|
|
# A hex holding a value without a "0x" prefix should still be treated as
|
|
# hexadecimal
|
|
verify_eval("HEX_37 < 0x38", 2)
|
|
verify_eval("HEX_37 < 0x37", 0)
|
|
verify_eval("HEX_37 < 0x36", 0)
|
|
|
|
# Symbol comparisons
|
|
verify_eval("INT_37 < HEX_0X37", 2)
|
|
verify_eval("INT_37 > HEX_0X37", 0)
|
|
verify_eval("HEX_0X37 < INT_37 ", 0)
|
|
verify_eval("HEX_0X37 > INT_37 ", 2)
|
|
verify_eval("INT_37 < INT_37 ", 0)
|
|
verify_eval("INT_37 <= INT_37 ", 2)
|
|
verify_eval("INT_37 > INT_37 ", 0)
|
|
verify_eval("INT_37 <= INT_37 ", 2)
|
|
|
|
# Tristate value comparisons
|
|
verify_eval("n < n", 0)
|
|
verify_eval("n < m", 2)
|
|
verify_eval("n < y", 2)
|
|
verify_eval("n < N", 0)
|
|
verify_eval("n < M", 2)
|
|
verify_eval("n < Y", 2)
|
|
verify_eval("0 > n", 0)
|
|
verify_eval("1 > n", 2)
|
|
verify_eval("2 > n", 2)
|
|
verify_eval("m < n", 0)
|
|
verify_eval("m < m", 0)
|
|
verify_eval("m < y", 2)
|
|
|
|
# Strings compare lexicographically
|
|
verify_eval("'aa' < 'ab'", 2)
|
|
verify_eval("'aa' > 'ab'", 0)
|
|
verify_eval("'ab' < 'aa'", 0)
|
|
verify_eval("'ab' > 'aa'", 2)
|
|
|
|
# Comparisons where one of the operands doesn't parse as a number also give
|
|
# a lexicographic comparison
|
|
verify_eval("INT_37 < '37a' ", 2)
|
|
verify_eval("'37a' > INT_37", 2)
|
|
verify_eval("INT_37 <= '37a' ", 2)
|
|
verify_eval("'37a' >= INT_37", 2)
|
|
verify_eval("INT_37 >= '37a' ", 0)
|
|
verify_eval("INT_37 > '37a' ", 0)
|
|
verify_eval("'37a' < INT_37", 0)
|
|
verify_eval("'37a' <= INT_37", 0)
|
|
|
|
def verify_eval_bad(expr):
|
|
try:
|
|
c.eval_string(expr)
|
|
except KconfigError:
|
|
pass
|
|
else:
|
|
fail('expected eval_string("{}") to throw KconfigError, '
|
|
"didn't".format(expr))
|
|
|
|
# Verify that some bad stuff throws KconfigError's
|
|
verify_eval_bad("")
|
|
verify_eval_bad("&")
|
|
verify_eval_bad("|")
|
|
verify_eval_bad("!")
|
|
verify_eval_bad("(")
|
|
verify_eval_bad(")")
|
|
verify_eval_bad("=")
|
|
verify_eval_bad("(X")
|
|
verify_eval_bad("X)")
|
|
verify_eval_bad("X X")
|
|
verify_eval_bad("!X X")
|
|
verify_eval_bad("X !X")
|
|
verify_eval_bad("(X) X")
|
|
verify_eval_bad("X &&")
|
|
verify_eval_bad("&& X")
|
|
verify_eval_bad("X && && X")
|
|
verify_eval_bad("X && !&&")
|
|
verify_eval_bad("X ||")
|
|
verify_eval_bad("|| X")
|
|
|
|
|
|
print("Testing Symbol.__str__()/custom_str() and def_{int,hex,string}")
|
|
|
|
def verify_str(item, s):
|
|
verify_equal(str(item), s[1:-1])
|
|
|
|
def verify_custom_str(item, s):
|
|
verify_equal(item.custom_str(lambda sc: "[{}]".format(sc.name)),
|
|
s[1:-1])
|
|
|
|
c = Kconfig("Kconfiglib/tests/Kstr", warn=False)
|
|
|
|
c.modules.set_value(2)
|
|
|
|
verify_str(c.syms["UNDEFINED"], """
|
|
""")
|
|
|
|
verify_str(c.syms["BASIC_NO_PROMPT"], """
|
|
config BASIC_NO_PROMPT
|
|
bool
|
|
help
|
|
blah blah
|
|
|
|
blah blah blah
|
|
|
|
blah
|
|
""")
|
|
|
|
verify_str(c.syms["BASIC_PROMPT"], """
|
|
config BASIC_PROMPT
|
|
bool "basic"
|
|
""")
|
|
|
|
verify_str(c.syms["ADVANCED"], """
|
|
config ADVANCED
|
|
tristate "prompt" if DEP
|
|
default DEFAULT_1
|
|
default DEFAULT_2 if DEP
|
|
select SELECTED_1
|
|
select SELECTED_2 if DEP
|
|
imply IMPLIED_1
|
|
imply IMPLIED_2 if DEP
|
|
help
|
|
first help text
|
|
|
|
config ADVANCED
|
|
tristate "prompt 2"
|
|
|
|
menuconfig ADVANCED
|
|
tristate "prompt 3"
|
|
|
|
config ADVANCED
|
|
tristate
|
|
depends on (A || !B || (C && D) || !(E && F) || G = H || (I && !J && (K || L) && !(M || N) && O = P)) && DEP4 && DEP3
|
|
help
|
|
second help text
|
|
|
|
config ADVANCED
|
|
tristate "prompt 4" if VIS
|
|
depends on DEP4 && DEP3
|
|
""")
|
|
|
|
verify_custom_str(c.syms["ADVANCED"], """
|
|
config ADVANCED
|
|
tristate "prompt" if [DEP]
|
|
default [DEFAULT_1]
|
|
default [DEFAULT_2] if [DEP]
|
|
select [SELECTED_1]
|
|
select [SELECTED_2] if [DEP]
|
|
imply [IMPLIED_1]
|
|
imply [IMPLIED_2] if [DEP]
|
|
help
|
|
first help text
|
|
|
|
config ADVANCED
|
|
tristate "prompt 2"
|
|
|
|
menuconfig ADVANCED
|
|
tristate "prompt 3"
|
|
|
|
config ADVANCED
|
|
tristate
|
|
depends on ([A] || ![B] || ([C] && [D]) || !([E] && [F]) || [G] = [H] || ([I] && ![J] && ([K] || [L]) && !([M] || [N]) && [O] = [P])) && [DEP4] && [DEP3]
|
|
help
|
|
second help text
|
|
|
|
config ADVANCED
|
|
tristate "prompt 4" if [VIS]
|
|
depends on [DEP4] && [DEP3]
|
|
""")
|
|
|
|
|
|
verify_str(c.syms["ONLY_DIRECT_DEPS"], """
|
|
config ONLY_DIRECT_DEPS
|
|
int
|
|
depends on DEP1 && DEP2
|
|
""")
|
|
|
|
verify_str(c.syms["STRING"], """
|
|
config STRING
|
|
string
|
|
default "foo"
|
|
default "bar" if DEP
|
|
default STRING2
|
|
default STRING3 if DEP
|
|
""")
|
|
|
|
verify_str(c.syms["INT"], """
|
|
config INT
|
|
int
|
|
range 1 2
|
|
range FOO BAR
|
|
range BAZ QAZ if DEP
|
|
default 7 if DEP
|
|
""")
|
|
|
|
verify_str(c.syms["HEX"], """
|
|
config HEX
|
|
hex
|
|
range 0x100 0x200
|
|
range FOO BAR
|
|
range BAZ QAZ if DEP
|
|
default 0x123
|
|
""")
|
|
|
|
verify_str(c.modules, """
|
|
config MODULES
|
|
bool "MODULES"
|
|
option modules
|
|
""")
|
|
|
|
verify_str(c.syms["OPTIONS"], """
|
|
config OPTIONS
|
|
option allnoconfig_y
|
|
option defconfig_list
|
|
option env="ENV"
|
|
""")
|
|
|
|
verify_str(c.syms["CORRECT_PROP_LOCS_BOOL"], """
|
|
config CORRECT_PROP_LOCS_BOOL
|
|
bool "prompt 1"
|
|
default DEFAULT_1
|
|
default DEFAULT_2
|
|
select SELECT_1
|
|
select SELECT_2
|
|
imply IMPLY_1
|
|
imply IMPLY_2
|
|
depends on LOC_1
|
|
help
|
|
help 1
|
|
|
|
menuconfig CORRECT_PROP_LOCS_BOOL
|
|
bool "prompt 2"
|
|
default DEFAULT_3
|
|
default DEFAULT_4
|
|
select SELECT_3
|
|
select SELECT_4
|
|
imply IMPLY_3
|
|
imply IMPLY_4
|
|
depends on LOC_2
|
|
help
|
|
help 2
|
|
|
|
config CORRECT_PROP_LOCS_BOOL
|
|
bool "prompt 3"
|
|
default DEFAULT_5
|
|
default DEFAULT_6
|
|
select SELECT_5
|
|
select SELECT_6
|
|
imply IMPLY_5
|
|
imply IMPLY_6
|
|
depends on LOC_3
|
|
help
|
|
help 2
|
|
""")
|
|
|
|
verify_str(c.syms["CORRECT_PROP_LOCS_INT"], """
|
|
config CORRECT_PROP_LOCS_INT
|
|
int
|
|
range 1 2
|
|
range 3 4
|
|
depends on LOC_1
|
|
|
|
config CORRECT_PROP_LOCS_INT
|
|
int
|
|
range 5 6
|
|
range 7 8
|
|
depends on LOC_2
|
|
""")
|
|
|
|
verify_str(c.syms["PROMPT_ONLY"], """
|
|
config PROMPT_ONLY
|
|
prompt "prompt only"
|
|
""")
|
|
|
|
verify_custom_str(c.syms["CORRECT_PROP_LOCS_INT"], """
|
|
config CORRECT_PROP_LOCS_INT
|
|
int
|
|
range [1] [2]
|
|
range [3] [4]
|
|
depends on [LOC_1]
|
|
|
|
config CORRECT_PROP_LOCS_INT
|
|
int
|
|
range [5] [6]
|
|
range [7] [8]
|
|
depends on [LOC_2]
|
|
""")
|
|
|
|
|
|
|
|
print("Testing Choice.__str__()/custom_str()")
|
|
|
|
verify_str(c.named_choices["CHOICE"], """
|
|
choice CHOICE
|
|
tristate "foo"
|
|
default CHOICE_1
|
|
default CHOICE_2 if dep
|
|
""")
|
|
|
|
verify_str(c.named_choices["CHOICE"].nodes[0].next.item, """
|
|
choice
|
|
tristate "no name"
|
|
optional
|
|
""")
|
|
|
|
verify_str(c.named_choices["CORRECT_PROP_LOCS_CHOICE"], """
|
|
choice CORRECT_PROP_LOCS_CHOICE
|
|
bool
|
|
default CHOICE_3
|
|
depends on LOC_1
|
|
|
|
choice CORRECT_PROP_LOCS_CHOICE
|
|
bool
|
|
default CHOICE_4
|
|
depends on LOC_2
|
|
|
|
choice CORRECT_PROP_LOCS_CHOICE
|
|
bool
|
|
default CHOICE_5
|
|
depends on LOC_3
|
|
""")
|
|
|
|
verify_custom_str(c.named_choices["CORRECT_PROP_LOCS_CHOICE"], """
|
|
choice CORRECT_PROP_LOCS_CHOICE
|
|
bool
|
|
default [CHOICE_3]
|
|
depends on [LOC_1]
|
|
|
|
choice CORRECT_PROP_LOCS_CHOICE
|
|
bool
|
|
default [CHOICE_4]
|
|
depends on [LOC_2]
|
|
|
|
choice CORRECT_PROP_LOCS_CHOICE
|
|
bool
|
|
default [CHOICE_5]
|
|
depends on [LOC_3]
|
|
""")
|
|
|
|
|
|
print("Testing MenuNode.__str__()/custom_str() for menus and comments")
|
|
|
|
verify_str(c.syms["SIMPLE_MENU_HOOK"].nodes[0].next, """
|
|
menu "simple menu"
|
|
""")
|
|
|
|
verify_str(c.syms["ADVANCED_MENU_HOOK"].nodes[0].next, """
|
|
menu "advanced menu"
|
|
depends on A
|
|
visible if B && (C || D)
|
|
""")
|
|
|
|
verify_custom_str(c.syms["ADVANCED_MENU_HOOK"].nodes[0].next, """
|
|
menu "advanced menu"
|
|
depends on [A]
|
|
visible if [B] && ([C] || [D])
|
|
""")
|
|
|
|
verify_str(c.syms["SIMPLE_COMMENT_HOOK"].nodes[0].next, """
|
|
comment "simple comment"
|
|
""")
|
|
|
|
verify_str(c.syms["ADVANCED_COMMENT_HOOK"].nodes[0].next, """
|
|
comment "advanced comment"
|
|
depends on A && B
|
|
""")
|
|
|
|
verify_custom_str(c.syms["ADVANCED_COMMENT_HOOK"].nodes[0].next, """
|
|
comment "advanced comment"
|
|
depends on [A] && [B]
|
|
""")
|
|
|
|
|
|
print("Testing {MenuNode,Symbol,Choice}.orig_*")
|
|
|
|
# Just test some corner cases here re. MenuNode.orig_*. They are already
|
|
# indirectly tested above. Use MenuNode.__str__() as a proxy.
|
|
|
|
verify_str(c.syms["DEP_REM_CORNER_CASES"], """
|
|
config DEP_REM_CORNER_CASES
|
|
bool
|
|
default A
|
|
depends on n
|
|
|
|
config DEP_REM_CORNER_CASES
|
|
bool
|
|
default B if n
|
|
|
|
config DEP_REM_CORNER_CASES
|
|
bool
|
|
default C
|
|
depends on m && MODULES
|
|
|
|
config DEP_REM_CORNER_CASES
|
|
bool
|
|
default D if A
|
|
|
|
config DEP_REM_CORNER_CASES
|
|
bool
|
|
default E if !E1
|
|
default F if F1 = F2
|
|
default G if G1 || H1
|
|
depends on !H
|
|
|
|
config DEP_REM_CORNER_CASES
|
|
bool
|
|
default H
|
|
depends on "foo" = "bar"
|
|
|
|
config DEP_REM_CORNER_CASES
|
|
bool "prompt" if FOO || BAR
|
|
depends on BAZ && QAZ
|
|
""")
|
|
|
|
# Test {Symbol,Choice}.orig_*
|
|
|
|
def verify_deps(elms, dep_index, expected):
|
|
verify_equal(" ".join(expr_str(elm[dep_index]) for elm in elms),
|
|
expected)
|
|
|
|
verify_deps(c.syms["BOOL_SYM_ORIG"].orig_defaults, 1, "DEP y y")
|
|
verify_deps(c.syms["BOOL_SYM_ORIG"].orig_selects, 1, "y DEP y")
|
|
verify_deps(c.syms["BOOL_SYM_ORIG"].orig_implies, 1, "y y DEP")
|
|
verify_deps(c.syms["INT_SYM_ORIG"].orig_ranges, 2, "DEP y DEP")
|
|
verify_deps(c.named_choices["CHOICE_ORIG"].orig_defaults, 1, "y DEP DEP")
|
|
|
|
|
|
print("Testing Symbol.__repr__()")
|
|
|
|
def verify_repr(item, s):
|
|
verify_equal(repr(item) + "\n", s[1:])
|
|
|
|
c = Kconfig("Kconfiglib/tests/Krepr", warn=False)
|
|
|
|
verify_repr(c.n, """
|
|
<symbol n, tristate, value n, constant>
|
|
""")
|
|
|
|
verify_repr(c.m, """
|
|
<symbol m, tristate, value m, constant>
|
|
""")
|
|
|
|
verify_repr(c.y, """
|
|
<symbol y, tristate, value y, constant>
|
|
""")
|
|
|
|
verify_repr(c.syms["UNDEFINED"], """
|
|
<symbol UNDEFINED, unknown, value "UNDEFINED", visibility n, direct deps n, undefined>
|
|
""")
|
|
|
|
verify_repr(c.syms["BASIC"], """
|
|
<symbol BASIC, bool, value y, visibility n, direct deps y, Kconfiglib/tests/Krepr:9>
|
|
""")
|
|
|
|
verify_repr(c.syms["VISIBLE"], """
|
|
<symbol VISIBLE, bool, "visible", value n, visibility y, direct deps y, Kconfiglib/tests/Krepr:14>
|
|
""")
|
|
|
|
c.syms["VISIBLE"].set_value(2)
|
|
c.syms["STRING"].set_value("foo")
|
|
|
|
verify_repr(c.syms["VISIBLE"], """
|
|
<symbol VISIBLE, bool, "visible", value y, user value y, visibility y, direct deps y, Kconfiglib/tests/Krepr:14>
|
|
""")
|
|
|
|
verify_repr(c.syms["STRING"], """
|
|
<symbol STRING, string, "visible", value "foo", user value "foo", visibility y, direct deps y, Kconfiglib/tests/Krepr:17>
|
|
""")
|
|
|
|
verify_repr(c.syms["DIR_DEP_N"], """
|
|
<symbol DIR_DEP_N, unknown, value "DIR_DEP_N", visibility n, direct deps n, Kconfiglib/tests/Krepr:20>
|
|
""")
|
|
|
|
verify_repr(c.syms["OPTIONS"], """
|
|
<symbol OPTIONS, unknown, value "OPTIONS", visibility n, allnoconfig_y, is the defconfig_list symbol, from environment variable ENV, direct deps y, Kconfiglib/tests/Krepr:23>
|
|
""")
|
|
|
|
verify_repr(c.syms["MULTI_DEF"], """
|
|
<symbol MULTI_DEF, unknown, value "MULTI_DEF", visibility n, direct deps y, Kconfiglib/tests/Krepr:28, Kconfiglib/tests/Krepr:29>
|
|
""")
|
|
|
|
verify_repr(c.syms["CHOICE_1"], """
|
|
<symbol CHOICE_1, tristate, "choice sym", value n, visibility m, choice symbol, direct deps m, Kconfiglib/tests/Krepr:36>
|
|
""")
|
|
|
|
verify_repr(c.modules, """
|
|
<symbol MODULES, bool, value y, visibility n, is the modules symbol, direct deps y, Kconfiglib/tests/Krepr:1>
|
|
""")
|
|
|
|
|
|
print("Testing Choice.__repr__()")
|
|
|
|
verify_repr(c.named_choices["CHOICE"], """
|
|
<choice CHOICE, tristate, "choice", mode m, visibility y, Kconfiglib/tests/Krepr:33>
|
|
""")
|
|
|
|
c.named_choices["CHOICE"].set_value(2)
|
|
|
|
verify_repr(c.named_choices["CHOICE"], """
|
|
<choice CHOICE, tristate, "choice", mode y, user mode y, CHOICE_1 selected, visibility y, Kconfiglib/tests/Krepr:33>
|
|
""")
|
|
|
|
c.syms["CHOICE_2"].set_value(2)
|
|
|
|
verify_repr(c.named_choices["CHOICE"], """
|
|
<choice CHOICE, tristate, "choice", mode y, user mode y, CHOICE_2 selected, CHOICE_2 selected by user, visibility y, Kconfiglib/tests/Krepr:33>
|
|
""")
|
|
|
|
c.named_choices["CHOICE"].set_value(1)
|
|
|
|
verify_repr(c.named_choices["CHOICE"], """
|
|
<choice CHOICE, tristate, "choice", mode m, user mode m, CHOICE_2 selected by user (overridden), visibility y, Kconfiglib/tests/Krepr:33>
|
|
""")
|
|
|
|
verify_repr(c.syms["CHOICE_HOOK"].nodes[0].next.item, """
|
|
<choice, tristate, "optional choice", mode n, visibility n, optional, Kconfiglib/tests/Krepr:46>
|
|
""")
|
|
|
|
|
|
print("Testing MenuNode.__repr__()")
|
|
|
|
verify_repr(c.syms["BASIC"].nodes[0], """
|
|
<menu node for symbol BASIC, deps y, has help, has next, Kconfiglib/tests/Krepr:9>
|
|
""")
|
|
|
|
verify_repr(c.syms["DIR_DEP_N"].nodes[0], """
|
|
<menu node for symbol DIR_DEP_N, deps n, has next, Kconfiglib/tests/Krepr:20>
|
|
""")
|
|
|
|
verify_repr(c.syms["MULTI_DEF"].nodes[0], """
|
|
<menu node for symbol MULTI_DEF, deps y, has next, Kconfiglib/tests/Krepr:28>
|
|
""")
|
|
|
|
verify_repr(c.syms["MULTI_DEF"].nodes[1], """
|
|
<menu node for symbol MULTI_DEF, deps y, has next, Kconfiglib/tests/Krepr:29>
|
|
""")
|
|
|
|
verify_repr(c.syms["MENUCONFIG"].nodes[0], """
|
|
<menu node for symbol MENUCONFIG, is menuconfig, deps y, has next, Kconfiglib/tests/Krepr:31>
|
|
""")
|
|
|
|
verify_repr(c.named_choices["CHOICE"].nodes[0], """
|
|
<menu node for choice CHOICE, prompt "choice" (visibility y), deps y, has child, has next, Kconfiglib/tests/Krepr:33>
|
|
""")
|
|
|
|
verify_repr(c.syms["CHOICE_HOOK"].nodes[0].next, """
|
|
<menu node for choice, prompt "optional choice" (visibility n), deps y, has next, Kconfiglib/tests/Krepr:46>
|
|
""")
|
|
|
|
verify_repr(c.syms["NO_VISIBLE_IF_HOOK"].nodes[0].next, """
|
|
<menu node for menu, prompt "no visible if" (visibility y), deps y, 'visible if' deps y, has next, Kconfiglib/tests/Krepr:53>
|
|
""")
|
|
|
|
verify_repr(c.syms["VISIBLE_IF_HOOK"].nodes[0].next, """
|
|
<menu node for menu, prompt "visible if" (visibility y), deps y, 'visible if' deps m, has next, Kconfiglib/tests/Krepr:58>
|
|
""")
|
|
|
|
verify_repr(c.syms["COMMENT_HOOK"].nodes[0].next, """
|
|
<menu node for comment, prompt "comment" (visibility y), deps y, Kconfiglib/tests/Krepr:64>
|
|
""")
|
|
|
|
|
|
print("Testing Kconfig.__repr__()")
|
|
|
|
verify_repr(c, """
|
|
<configuration with 15 symbols, main menu prompt "Main menu", srctree is current directory, config symbol prefix "CONFIG_", warnings disabled, printing of warnings to stderr enabled, undef. symbol assignment warnings disabled, overriding symbol assignment warnings enabled, redundant symbol assignment warnings enabled>
|
|
""")
|
|
|
|
os.environ["srctree"] = "Kconfiglib"
|
|
os.environ["CONFIG_"] = "CONFIG_ value"
|
|
|
|
c = Kconfig("tests/Krepr", warn=False)
|
|
c.warn = True
|
|
c.warn_to_stderr = False
|
|
c.warn_assign_override = False
|
|
c.warn_assign_redun = False
|
|
c.warn_assign_undef = True
|
|
|
|
verify_repr(c, """
|
|
<configuration with 15 symbols, main menu prompt "Main menu", srctree "Kconfiglib", config symbol prefix "CONFIG_ value", warnings enabled, printing of warnings to stderr disabled, undef. symbol assignment warnings enabled, overriding symbol assignment warnings disabled, redundant symbol assignment warnings disabled>
|
|
""")
|
|
|
|
os.environ.pop("srctree", None)
|
|
os.environ.pop("CONFIG_", None)
|
|
|
|
|
|
print("Testing tricky help strings")
|
|
|
|
c = Kconfig("Kconfiglib/tests/Khelp")
|
|
|
|
def verify_help(node, s):
|
|
verify_equal(node.help, s[1:-1])
|
|
|
|
verify_help(c.syms["TWO_HELP_STRINGS"].nodes[0], """
|
|
first help string
|
|
""")
|
|
|
|
verify_help(c.syms["TWO_HELP_STRINGS"].nodes[1], """
|
|
second help string
|
|
""")
|
|
|
|
verify_help(c.syms["NO_BLANK_AFTER_HELP"].nodes[0], """
|
|
help for
|
|
NO_BLANK_AFTER_HELP
|
|
""")
|
|
|
|
verify_help(c.named_choices["CHOICE_HELP"].nodes[0], """
|
|
help for
|
|
CHOICE_HELP
|
|
""")
|
|
|
|
verify_help(c.syms["HELP_TERMINATED_BY_COMMENT"].nodes[0], """
|
|
a
|
|
b
|
|
c
|
|
""")
|
|
|
|
verify_help(c.syms["TRICKY_HELP"].nodes[0], """
|
|
a
|
|
b
|
|
c
|
|
|
|
d
|
|
e
|
|
f
|
|
|
|
|
|
g
|
|
h
|
|
i
|
|
""")
|
|
|
|
|
|
print("Testing locations, source/rsource/gsource/grsource, and "
|
|
"Kconfig.kconfig_filenames")
|
|
|
|
def verify_locations(nodes, *expected_locs):
|
|
verify(len(nodes) == len(expected_locs),
|
|
"Wrong number of locations for " + repr(nodes))
|
|
|
|
for node, expected_loc in zip(nodes, expected_locs):
|
|
node_loc = "{}:{}".format(node.filename, node.linenr)
|
|
verify(node_loc == expected_loc,
|
|
"expected {} to have the location {}, had the location {}"
|
|
.format(repr(node), expected_loc, node_loc))
|
|
|
|
# Expanded in the 'source' statement in Klocation
|
|
|
|
os.environ["TESTS_DIR_FROM_ENV"] = "tests"
|
|
os.environ["SUB_DIR_FROM_ENV"] = "sub"
|
|
|
|
os.environ["_SOURCED"] = "_sourced"
|
|
os.environ["_RSOURCED"] = "_rsourced"
|
|
os.environ["_GSOURCED"] = "_gsourced"
|
|
os.environ["_GRSOURCED"] = "_grsourced"
|
|
|
|
# Test twice, with $srctree as a relative and an absolute path,
|
|
# respectively
|
|
for srctree in "Kconfiglib", os.path.abspath("Kconfiglib"):
|
|
os.environ["srctree"] = srctree
|
|
|
|
# Has symbol with empty help text, so disable warnings
|
|
c = Kconfig("tests/Klocation", warn=False)
|
|
|
|
verify_locations(c.syms["UNDEFINED"].nodes)
|
|
verify_equal(c.syms["UNDEFINED"].name_and_loc, "UNDEFINED (undefined)")
|
|
|
|
verify_locations(c.syms["ONE_DEF"].nodes, "tests/Klocation:4")
|
|
verify_equal(c.syms["ONE_DEF"].name_and_loc,
|
|
"ONE_DEF (defined at tests/Klocation:4)")
|
|
|
|
verify_locations(c.syms["TWO_DEF"].nodes,
|
|
"tests/Klocation:7",
|
|
"tests/Klocation:10")
|
|
verify_equal(c.syms["TWO_DEF"].name_and_loc,
|
|
"TWO_DEF (defined at tests/Klocation:7, tests/Klocation:10)")
|
|
|
|
verify_locations(c.syms["MANY_DEF"].nodes,
|
|
"tests/Klocation:13",
|
|
"tests/Klocation:43",
|
|
"tests/Klocation:45",
|
|
"tests/Klocation_sourced:3",
|
|
"tests/sub/Klocation_rsourced:2",
|
|
"tests/sub/Klocation_gsourced1:1",
|
|
"tests/sub/Klocation_gsourced2:1",
|
|
"tests/sub/Klocation_gsourced1:1",
|
|
"tests/sub/Klocation_gsourced2:1",
|
|
"tests/sub/Klocation_grsourced1:1",
|
|
"tests/sub/Klocation_grsourced2:1",
|
|
"tests/sub/Klocation_grsourced1:1",
|
|
"tests/sub/Klocation_grsourced2:1",
|
|
"tests/Klocation:78")
|
|
|
|
verify_locations(c.named_choices["CHOICE_ONE_DEF"].nodes,
|
|
"tests/Klocation_sourced:5")
|
|
verify_equal(c.named_choices["CHOICE_ONE_DEF"].name_and_loc,
|
|
"<choice CHOICE_ONE_DEF> (defined at tests/Klocation_sourced:5)")
|
|
|
|
verify_locations(c.named_choices["CHOICE_TWO_DEF"].nodes,
|
|
"tests/Klocation_sourced:9",
|
|
"tests/Klocation_sourced:13")
|
|
verify_equal(c.named_choices["CHOICE_TWO_DEF"].name_and_loc,
|
|
"<choice CHOICE_TWO_DEF> (defined at tests/Klocation_sourced:9, tests/Klocation_sourced:13)")
|
|
|
|
verify_locations([c.syms["MENU_HOOK"].nodes[0].next],
|
|
"tests/Klocation_sourced:20")
|
|
|
|
verify_locations([c.syms["COMMENT_HOOK"].nodes[0].next],
|
|
"tests/Klocation_sourced:26")
|
|
|
|
# Test Kconfig.kconfig_filenames
|
|
|
|
verify_equal(c.kconfig_filenames, [
|
|
"tests/Klocation",
|
|
"tests/Klocation_sourced",
|
|
"tests/sub/Klocation_rsourced",
|
|
"tests/sub/Klocation_gsourced1",
|
|
"tests/sub/Klocation_gsourced2",
|
|
"tests/sub/Klocation_gsourced1",
|
|
"tests/sub/Klocation_gsourced2",
|
|
"tests/sub/Klocation_grsourced1",
|
|
"tests/sub/Klocation_grsourced2",
|
|
"tests/sub/Klocation_grsourced1",
|
|
"tests/sub/Klocation_grsourced2"
|
|
])
|
|
|
|
# Test recursive 'source' detection
|
|
|
|
try:
|
|
Kconfig("tests/Krecursive1")
|
|
except KconfigError as e:
|
|
verify_equal(str(e), """
|
|
tests/Krecursive2:1: recursive 'source' of 'tests/Krecursive1' detected. Check that environment variables are set correctly.
|
|
Include path:
|
|
tests/Krecursive1:1
|
|
tests/Krecursive2:1
|
|
"""[:-1])
|
|
except:
|
|
fail("recursive 'source' raised wrong exception")
|
|
else:
|
|
fail("recursive 'source' did not raise exception")
|
|
|
|
# Verify that source and rsource throw exceptions for missing files
|
|
|
|
# TODO: Make an exception test helper
|
|
|
|
try:
|
|
Kconfig("tests/Kmissingsource")
|
|
except KconfigError as e:
|
|
if "not found" not in str(e):
|
|
fail("'source' with missing file raised wrong KconfigError")
|
|
except:
|
|
fail("'source' with missing file raised wrong exception")
|
|
else:
|
|
fail("'source' with missing file did not raise exception")
|
|
|
|
try:
|
|
Kconfig("tests/Kmissingrsource")
|
|
except KconfigError as e:
|
|
if "not found" not in str(e):
|
|
fail("'rsource' with missing file raised wrong KconfigError")
|
|
except:
|
|
fail("'rsource' with missing file raised wrong exception")
|
|
else:
|
|
fail("'rsource' with missing file did not raise exception")
|
|
|
|
# Test a tricky case involving symlinks. $srctree is tests/symlink, which
|
|
# points to tests/sub/sub, meaning tests/symlink/.. != tests/. Previously,
|
|
# using 'rsource' from a file sourced with an absolute path triggered an
|
|
# unsafe relpath() with tests/symlink/.. in it, crashing.
|
|
|
|
os.environ["srctree"] = "Kconfiglib/tests/symlink"
|
|
os.environ["KCONFIG_SYMLINK_2"] = os.path.abspath(
|
|
"Kconfiglib/tests/sub/Kconfig_symlink_2")
|
|
if not os.path.isabs(
|
|
Kconfig("Kconfig_symlink_1").syms["FOUNDME"].nodes[0].filename):
|
|
|
|
fail("Symlink + rsource issues")
|
|
|
|
|
|
print("Testing Kconfig.node_iter()")
|
|
|
|
# Reuse tests/Klocation. The node_iter(unique_syms=True) case already gets
|
|
# plenty of testing from write_config() as well.
|
|
|
|
os.environ["srctree"] = "Kconfiglib"
|
|
c = Kconfig("tests/Klocation", warn=False)
|
|
|
|
verify_equal(
|
|
[node.item.name for node in c.node_iter()
|
|
if isinstance(node.item, Symbol)],
|
|
["ONE_DEF", "TWO_DEF", "TWO_DEF", "MANY_DEF", "HELP_1", "HELP_2",
|
|
"HELP_3", "MANY_DEF", "MANY_DEF", "MANY_DEF", "MENU_HOOK",
|
|
"COMMENT_HOOK"] + 10*["MANY_DEF"])
|
|
|
|
verify_equal(
|
|
[node.item.name for node in c.node_iter(True)
|
|
if isinstance(node.item, Symbol)],
|
|
["ONE_DEF", "TWO_DEF", "MANY_DEF", "HELP_1", "HELP_2", "HELP_3",
|
|
"MENU_HOOK", "COMMENT_HOOK"])
|
|
|
|
verify_equal(
|
|
[node.prompt[0] for node in c.node_iter()
|
|
if not isinstance(node.item, Symbol)],
|
|
["one-def choice", "two-def choice 1", "two-def choice 2",
|
|
"menu", "comment"])
|
|
|
|
verify_equal(
|
|
[node.prompt[0] for node in c.node_iter(True)
|
|
if not isinstance(node.item, Symbol)],
|
|
["one-def choice", "two-def choice 1", "two-def choice 2",
|
|
"menu", "comment"])
|
|
|
|
|
|
print("Testing MenuNode.include_path")
|
|
|
|
os.environ["srctree"] = "Kconfiglib/tests"
|
|
|
|
c = Kconfig("Kinclude_path")
|
|
|
|
def verify_node_path(node, *expected):
|
|
if node.include_path != expected:
|
|
fail("Wrong include path for node {!r}. Got {}, expected {}."
|
|
.format(node, node.include_path, expected))
|
|
|
|
def verify_sym_path(sym_name, node_i, *expected):
|
|
verify_node_path(c.syms[sym_name].nodes[node_i], *expected)
|
|
|
|
verify_sym_path("TOP", 0)
|
|
verify_sym_path("TOP", 1)
|
|
verify_sym_path("TOP", 2)
|
|
|
|
verify_sym_path("ONE_DOWN", 0, ("Kinclude_path", 4))
|
|
verify_sym_path("ONE_DOWN", 1, ("Kinclude_path", 4))
|
|
verify_sym_path("ONE_DOWN", 2, ("Kinclude_path", 4))
|
|
verify_sym_path("ONE_DOWN", 3, ("Kinclude_path", 9))
|
|
verify_sym_path("ONE_DOWN", 4, ("Kinclude_path", 9))
|
|
verify_sym_path("ONE_DOWN", 5, ("Kinclude_path", 9))
|
|
|
|
verify_sym_path("TWO_DOWN", 0,
|
|
("Kinclude_path", 4), ("Kinclude_path_sourced_1", 4))
|
|
verify_sym_path("TWO_DOWN", 1,
|
|
("Kinclude_path", 4), ("Kinclude_path_sourced_1", 9))
|
|
verify_sym_path("TWO_DOWN", 2,
|
|
("Kinclude_path", 9), ("Kinclude_path_sourced_1", 4))
|
|
verify_sym_path("TWO_DOWN", 3,
|
|
("Kinclude_path", 9), ("Kinclude_path_sourced_1", 9))
|
|
|
|
verify_node_path(c.top_node)
|
|
verify_node_path(c.menus[0], ("Kinclude_path", 4), ("Kinclude_path_sourced_1", 4))
|
|
verify_node_path(c.comments[0], ("Kinclude_path", 4), ("Kinclude_path_sourced_1", 4))
|
|
verify_node_path(c.choices[0].nodes[0], ("Kinclude_path", 4), ("Kinclude_path_sourced_1", 4))
|
|
|
|
os.environ.pop("srctree", None)
|
|
|
|
|
|
print("Testing Kconfig.choices/menus/comments")
|
|
|
|
c = Kconfig("Kconfiglib/tests/Kitemlists")
|
|
|
|
def verify_prompts(items, *expected_prompts):
|
|
verify(len(items) == len(expected_prompts),
|
|
"Wrong number of prompts for {}".format(items))
|
|
|
|
for item, expected_prompt in zip(items, expected_prompts):
|
|
if not isinstance(item, MenuNode):
|
|
item = item.nodes[0]
|
|
|
|
verify(item.prompt[0] == expected_prompt,
|
|
"Wrong prompt for {}, expected '{}'"
|
|
.format(repr(item), expected_prompt))
|
|
|
|
verify_prompts(c.choices, "choice 1", "choice 2", "choice 3", "choice 2")
|
|
verify_prompts(c.menus, "menu 1", "menu 2", "menu 3", "menu 4", "menu 5")
|
|
verify_prompts(c.comments, "comment 1", "comment 2", "comment 3")
|
|
|
|
|
|
print("Testing Symbol/Choice.direct_dep")
|
|
|
|
c = Kconfig("Kconfiglib/tests/Kdirdep")
|
|
|
|
verify_equal(expr_str(c.syms["NO_DEP_SYM"].direct_dep), 'y')
|
|
verify_equal(expr_str(c.syms["DEP_SYM"].direct_dep), "A || (B && C) || !D")
|
|
|
|
verify_equal(expr_str(c.named_choices["NO_DEP_CHOICE"].direct_dep), 'y')
|
|
verify_equal(expr_str(c.named_choices["DEP_CHOICE"].direct_dep),
|
|
"A || B || C")
|
|
|
|
|
|
print("Testing expr_items()")
|
|
|
|
c = Kconfig("Kconfiglib/tests/Kexpr_items")
|
|
|
|
def verify_expr_items(expr, *sym_names):
|
|
verify_equal(tuple(sorted(item.name for item in expr_items(expr))),
|
|
sym_names)
|
|
|
|
verify_expr_items(
|
|
c.syms["TEST"].defaults[0][0],
|
|
"A", "B", "C", "D", "E", "F", "G", "H"
|
|
)
|
|
|
|
verify_expr_items(
|
|
c.syms["TEST_CHOICE"].nodes[0].prompt[1],
|
|
"A", "CHOICE"
|
|
)
|
|
|
|
|
|
print("Testing MenuNode/Symbol/Choice.referenced")
|
|
|
|
c = Kconfig("Kconfiglib/tests/Kreferenced", warn=False)
|
|
|
|
def verify_deps(item, *dep_names):
|
|
verify_equal(tuple(sorted(item.name for item in item.referenced)),
|
|
dep_names)
|
|
|
|
verify_deps(c.top_node, "y")
|
|
|
|
verify_deps(c.syms["NO_REFS"].nodes[0], "y")
|
|
|
|
verify_deps(c.syms["JUST_DEPENDS_ON_REFS"].nodes[0], "A", "B")
|
|
|
|
verify_deps(c.syms["LOTS_OF_REFS"].nodes[0],
|
|
*(chr(n) for n in range(ord("A"), ord("Z") + 1)))
|
|
|
|
verify_deps(c.syms["INT_REFS"].nodes[0],
|
|
"A", "B", "C", "D", "E", "F", "G", "H", "y")
|
|
|
|
verify_deps(c.syms["CHOICE_REF"].nodes[0], "CHOICE")
|
|
|
|
verify_deps(c.menus[0], "A", "B", "C", "D")
|
|
|
|
verify_deps(c.comments[0], "A", "B")
|
|
|
|
verify_deps(c.syms["MULTI_DEF_SYM"], "A", "B", "C", "y")
|
|
verify_deps(c.named_choices["MULTI_DEF_CHOICE"], "A", "B", "C")
|
|
|
|
|
|
print("Testing split_expr()")
|
|
|
|
c = Kconfig("Kconfiglib/tests/empty")
|
|
c.warn = False
|
|
|
|
def verify_split(to_split, op, operand_strs):
|
|
# The same hackage as in Kconfig.eval_string()
|
|
c._tokens = c._tokenize("if " + to_split)[1:]
|
|
c._tokens_i = 0
|
|
|
|
operands = split_expr(c._parse_expr(False), op)
|
|
|
|
verify(len(operands) == len(operand_strs),
|
|
"Wrong number of operands when {} was split by {}"
|
|
.format(to_split, "OR" if op == OR else "AND"))
|
|
|
|
for operand, operand_str in zip(operands, operand_strs):
|
|
verify_equal(expr_str(operand), operand_str)
|
|
|
|
verify_split("A", OR, ("A", ))
|
|
verify_split("!A", OR, ("!A", ))
|
|
verify_split("A = B", OR, ("A = B", ))
|
|
verify_split("A && B", OR, ("A && B", ))
|
|
verify_split("A || B", OR, ("A", "B" ))
|
|
verify_split("(A || B) || C", OR, ("A", "B", "C" ))
|
|
verify_split("A || (B || C)", OR, ("A", "B", "C" ))
|
|
verify_split("A || !(B || C)", OR, ("A", "!(B || C)" ))
|
|
verify_split("A || (B && (C || D))", OR, ("A", "B && (C || D)"))
|
|
verify_split("(A && (B || C)) || D", OR, ("A && (B || C)", "D"))
|
|
|
|
verify_split("A", AND, ("A", ))
|
|
verify_split("!A", AND, ("!A", ))
|
|
verify_split("A = B", AND, ("A = B", ))
|
|
verify_split("A || B", AND, ("A || B", ))
|
|
verify_split("A && B", AND, ("A", "B" ))
|
|
verify_split("(A && B) && C", AND, ("A", "B", "C" ))
|
|
verify_split("A && (B && C)", AND, ("A", "B", "C" ))
|
|
verify_split("A && !(B && C)", AND, ("A", "!(B && C)" ))
|
|
verify_split("A && (B || (C && D))", AND, ("A", "B || (C && D)"))
|
|
verify_split("(A || (B && C)) && D", AND, ("A || (B && C)", "D"))
|
|
|
|
|
|
print("Testing visibility")
|
|
|
|
c = Kconfig("Kconfiglib/tests/Kvisibility")
|
|
|
|
def verify_visibility(item, no_module_vis, module_vis):
|
|
c.modules.set_value(0)
|
|
verify(item.visibility == no_module_vis,
|
|
"expected {} to have visibility {} without modules, had "
|
|
"visibility {}".
|
|
format(repr(item), no_module_vis, item.visibility))
|
|
|
|
c.modules.set_value(2)
|
|
verify(item.visibility == module_vis,
|
|
"expected {} to have visibility {} with modules, had "
|
|
"visibility {}".
|
|
format(repr(item), module_vis, item.visibility))
|
|
|
|
# Symbol visibility
|
|
|
|
verify_visibility(c.syms["NO_PROMPT"], 0, 0)
|
|
verify_visibility(c.syms["BOOL_N"], 0, 0)
|
|
verify_visibility(c.syms["BOOL_M"], 0, 2)
|
|
verify_visibility(c.syms["BOOL_MOD"], 2, 2)
|
|
verify_visibility(c.syms["BOOL_Y"], 2, 2)
|
|
verify_visibility(c.syms["TRISTATE_M"], 0, 1)
|
|
verify_visibility(c.syms["TRISTATE_MOD"], 2, 1)
|
|
verify_visibility(c.syms["TRISTATE_Y"], 2, 2)
|
|
verify_visibility(c.syms["BOOL_IF_N"], 0, 0)
|
|
verify_visibility(c.syms["BOOL_IF_M"], 0, 2)
|
|
verify_visibility(c.syms["BOOL_IF_Y"], 2, 2)
|
|
verify_visibility(c.syms["BOOL_MENU_N"], 0, 0)
|
|
verify_visibility(c.syms["BOOL_MENU_M"], 0, 2)
|
|
verify_visibility(c.syms["BOOL_MENU_Y"], 2, 2)
|
|
verify_visibility(c.syms["BOOL_CHOICE_N"], 0, 0)
|
|
|
|
# Non-tristate symbols in tristate choices are only visible if the choice
|
|
# is in y mode
|
|
|
|
# The choice can't be brought to y mode because of the 'if m'
|
|
verify_visibility(c.syms["BOOL_CHOICE_M"], 0, 0)
|
|
c.syms["BOOL_CHOICE_M"].choice.set_value(2)
|
|
verify_visibility(c.syms["BOOL_CHOICE_M"], 0, 0)
|
|
|
|
# The choice gets y mode only when running without modules, because it
|
|
# defaults to m mode
|
|
verify_visibility(c.syms["BOOL_CHOICE_Y"], 2, 0)
|
|
c.syms["BOOL_CHOICE_Y"].choice.set_value(2)
|
|
# When set to y mode, the choice symbol becomes visible both with and
|
|
# without modules
|
|
verify_visibility(c.syms["BOOL_CHOICE_Y"], 2, 2)
|
|
|
|
verify_visibility(c.syms["TRISTATE_IF_N"], 0, 0)
|
|
verify_visibility(c.syms["TRISTATE_IF_M"], 0, 1)
|
|
verify_visibility(c.syms["TRISTATE_IF_Y"], 2, 2)
|
|
verify_visibility(c.syms["TRISTATE_MENU_N"], 0, 0)
|
|
verify_visibility(c.syms["TRISTATE_MENU_M"], 0, 1)
|
|
verify_visibility(c.syms["TRISTATE_MENU_Y"], 2, 2)
|
|
verify_visibility(c.syms["TRISTATE_CHOICE_N"], 0, 0)
|
|
verify_visibility(c.syms["TRISTATE_CHOICE_M"], 0, 1)
|
|
verify_visibility(c.syms["TRISTATE_CHOICE_Y"], 2, 2)
|
|
|
|
verify_visibility(c.named_choices["BOOL_CHOICE_N"], 0, 0)
|
|
verify_visibility(c.named_choices["BOOL_CHOICE_M"], 0, 2)
|
|
verify_visibility(c.named_choices["BOOL_CHOICE_Y"], 2, 2)
|
|
verify_visibility(c.named_choices["TRISTATE_CHOICE_N"], 0, 0)
|
|
verify_visibility(c.named_choices["TRISTATE_CHOICE_M"], 0, 1)
|
|
verify_visibility(c.named_choices["TRISTATE_CHOICE_Y"], 2, 2)
|
|
|
|
verify_visibility(c.named_choices["TRISTATE_CHOICE_IF_M_AND_Y"], 0, 1)
|
|
verify_visibility(c.named_choices["TRISTATE_CHOICE_MENU_N_AND_Y"], 0, 0)
|
|
|
|
# Verify that 'visible if' visibility gets propagated to prompts
|
|
|
|
verify_visibility(c.syms["VISIBLE_IF_N"], 0, 0)
|
|
verify_visibility(c.syms["VISIBLE_IF_M"], 0, 1)
|
|
verify_visibility(c.syms["VISIBLE_IF_Y"], 2, 2)
|
|
verify_visibility(c.syms["VISIBLE_IF_M_2"], 0, 1)
|
|
|
|
# Verify that string/int/hex symbols with m visibility accept a user value
|
|
|
|
assign_and_verify("STRING_m", "foo bar")
|
|
assign_and_verify("INT_m", "123")
|
|
assign_and_verify("HEX_m", "0x123")
|
|
|
|
|
|
print("Testing .assignable")
|
|
|
|
c = Kconfig("Kconfiglib/tests/Kassignable")
|
|
|
|
def verify_assignable_imp(item, assignable_no_modules, assignable_modules):
|
|
# Verifies the assignable values for 'item', with and without modules.
|
|
|
|
for modules_val, assignable in (0, assignable_no_modules), \
|
|
(2, assignable_modules):
|
|
|
|
c.modules.set_value(modules_val)
|
|
module_msg = "without modules" if modules_val == 0 else \
|
|
"with modules"
|
|
|
|
verify(item.assignable == assignable,
|
|
"Incorrect assignable values for {} {}. Should be {}, "
|
|
"was {}."
|
|
.format(item.name, module_msg, assignable, item.assignable))
|
|
|
|
# Verify that the values can actually be assigned too
|
|
|
|
for val in item.assignable:
|
|
item.set_value(val)
|
|
verify(item.tri_value == val,
|
|
"Unable to set {} to {} {}, even though it was in "
|
|
".assignable".format(item.name, val, module_msg))
|
|
|
|
def verify_assignable(sym_name, assignable_no_modules, assignable_modules):
|
|
verify_assignable_imp(c.syms[sym_name],
|
|
assignable_no_modules,
|
|
assignable_modules)
|
|
|
|
def verify_const_unassignable(sym_name):
|
|
verify_assignable_imp(c.const_syms[sym_name], (), ())
|
|
|
|
# Things that shouldn't be .assignable
|
|
verify_const_unassignable("n")
|
|
verify_const_unassignable("m")
|
|
verify_const_unassignable("y")
|
|
verify_const_unassignable("const")
|
|
verify_assignable("UNDEFINED", (), ())
|
|
verify_assignable("NO_PROMPT", (), ())
|
|
verify_assignable("STRING", (), ())
|
|
verify_assignable("INT", (), ())
|
|
verify_assignable("HEX", (), ())
|
|
|
|
# Non-selected symbols
|
|
verify_assignable("Y_VIS_BOOL", (0, 2), (0, 2))
|
|
verify_assignable("M_VIS_BOOL", ( ), (0, 2)) # Vis. promoted
|
|
verify_assignable("N_VIS_BOOL", ( ), ( ))
|
|
verify_assignable("Y_VIS_TRI", (0, 2), (0, 1, 2))
|
|
verify_assignable("M_VIS_TRI", ( ), (0, 1 ))
|
|
verify_assignable("N_VIS_TRI", ( ), ( ))
|
|
|
|
# Symbols selected to y
|
|
verify_assignable("Y_SEL_Y_VIS_BOOL", (2,), (2,))
|
|
verify_assignable("Y_SEL_M_VIS_BOOL", ( ), (2,)) # Vis. promoted
|
|
verify_assignable("Y_SEL_N_VIS_BOOL", ( ), ( ))
|
|
verify_assignable("Y_SEL_Y_VIS_TRI", (2,), (2,))
|
|
verify_assignable("Y_SEL_M_VIS_TRI", ( ), (2,))
|
|
verify_assignable("Y_SEL_N_VIS_TRI", ( ), ( ))
|
|
|
|
# Symbols selected to m
|
|
verify_assignable("M_SEL_Y_VIS_BOOL", (2,), ( 2,)) # Value promoted
|
|
verify_assignable("M_SEL_M_VIS_BOOL", ( ), ( 2,)) # Vis./value promoted
|
|
verify_assignable("M_SEL_N_VIS_BOOL", ( ), ( ))
|
|
verify_assignable("M_SEL_Y_VIS_TRI", (2,), (1, 2 ))
|
|
verify_assignable("M_SEL_M_VIS_TRI", ( ), (1, ))
|
|
verify_assignable("M_SEL_N_VIS_TRI", ( ), ( ))
|
|
|
|
# Symbols implied to y
|
|
verify_assignable("Y_IMP_Y_VIS_BOOL", (0, 2), (0, 2))
|
|
verify_assignable("Y_IMP_M_VIS_BOOL", ( ), (0, 2)) # Vis. promoted
|
|
verify_assignable("Y_IMP_N_VIS_BOOL", ( ), ( ))
|
|
verify_assignable("Y_IMP_Y_VIS_TRI", (0, 2), (0, 2)) # m removed by imply
|
|
verify_assignable("Y_IMP_M_VIS_TRI", ( ), (0, 2)) # m promoted to y by imply
|
|
verify_assignable("Y_IMP_N_VIS_TRI", ( ), ( ))
|
|
|
|
# Symbols implied to m (never affects assignable values)
|
|
verify_assignable("M_IMP_Y_VIS_BOOL", (0, 2), (0, 2))
|
|
verify_assignable("M_IMP_M_VIS_BOOL", ( ), (0, 2)) # Vis. promoted
|
|
verify_assignable("M_IMP_N_VIS_BOOL", ( ), ( ))
|
|
verify_assignable("M_IMP_Y_VIS_TRI", (0, 2), (0, 1, 2))
|
|
verify_assignable("M_IMP_M_VIS_TRI", ( ), (0, 1 ))
|
|
verify_assignable("M_IMP_N_VIS_TRI", ( ), ( ))
|
|
|
|
# Symbols in y-mode choice
|
|
verify_assignable("Y_CHOICE_BOOL", (2,), (2,))
|
|
verify_assignable("Y_CHOICE_TRISTATE", (2,), (2,))
|
|
verify_assignable("Y_CHOICE_N_VIS_TRISTATE", ( ), ( ))
|
|
|
|
# Symbols in m/y-mode choice, starting out in m mode, or y mode when
|
|
# running without modules
|
|
verify_assignable("MY_CHOICE_BOOL", (2,), ( ))
|
|
verify_assignable("MY_CHOICE_TRISTATE", (2,), (0, 1))
|
|
verify_assignable("MY_CHOICE_N_VIS_TRISTATE", ( ), ( ))
|
|
|
|
c.named_choices["MY_CHOICE"].set_value(2)
|
|
|
|
# Symbols in m/y-mode choice, now in y mode
|
|
verify_assignable("MY_CHOICE_BOOL", (2,), (2,))
|
|
verify_assignable("MY_CHOICE_TRISTATE", (2,), (2,))
|
|
verify_assignable("MY_CHOICE_N_VIS_TRISTATE", ( ), ( ))
|
|
|
|
def verify_choice_assignable(choice_name, assignable_no_modules,
|
|
assignable_modules):
|
|
verify_assignable_imp(c.named_choices[choice_name],
|
|
assignable_no_modules,
|
|
assignable_modules)
|
|
|
|
# Choices with various possible modes
|
|
verify_choice_assignable("Y_CHOICE", (2, ), ( 2,))
|
|
verify_choice_assignable("MY_CHOICE", (2, ), ( 1, 2 ))
|
|
verify_choice_assignable("NMY_CHOICE", (0, 2), (0, 1, 2 ))
|
|
verify_choice_assignable("NY_CHOICE", (0, 2), (0, 2 ))
|
|
verify_choice_assignable("NM_CHOICE", ( ), (0, 1 ))
|
|
verify_choice_assignable("M_CHOICE", ( ), ( 1, ))
|
|
verify_choice_assignable("N_CHOICE", ( ), ( ))
|
|
|
|
|
|
print("Testing object relations")
|
|
|
|
c = Kconfig("Kconfiglib/tests/Krelation")
|
|
|
|
verify(c.syms["A"].nodes[0].parent is c.top_node,
|
|
"A's parent should be the top node")
|
|
|
|
verify(c.syms["B"].nodes[0].parent.item is c.named_choices["CHOICE_1"],
|
|
"B's parent should be the first choice")
|
|
|
|
verify(c.syms["C"].nodes[0].parent.item is c.syms["B"],
|
|
"C's parent should be B (due to auto menus)")
|
|
|
|
verify(c.syms["E"].nodes[0].parent.item == MENU,
|
|
"E's parent should be a menu")
|
|
|
|
verify(c.syms["E"].nodes[0].parent.parent is c.top_node,
|
|
"E's grandparent should be the top node")
|
|
|
|
verify(c.syms["G"].nodes[0].parent.item is c.named_choices["CHOICE_2"],
|
|
"G's parent should be the second choice")
|
|
|
|
verify(c.syms["G"].nodes[0].parent.parent.item == MENU,
|
|
"G's grandparent should be a menu")
|
|
|
|
|
|
print("Testing hex/int ranges")
|
|
|
|
c = Kconfig("Kconfiglib/tests/Krange", warn=False)
|
|
|
|
for sym_name in "HEX_NO_RANGE", "INT_NO_RANGE", "HEX_40", "INT_40":
|
|
sym = c.syms[sym_name]
|
|
verify(not sym.ranges,
|
|
"{} should not have ranges".format(sym_name))
|
|
|
|
for sym_name in "HEX_ALL_RANGES_DISABLED", "INT_ALL_RANGES_DISABLED", \
|
|
"HEX_RANGE_10_20_LOW_DEFAULT", \
|
|
"INT_RANGE_10_20_LOW_DEFAULT":
|
|
sym = c.syms[sym_name]
|
|
verify(sym.ranges, "{} should have ranges".format(sym_name))
|
|
|
|
# hex/int symbols without defaults should get no default value
|
|
verify_value("HEX_NO_RANGE", "")
|
|
verify_value("INT_NO_RANGE", "")
|
|
# And neither if all ranges are disabled
|
|
verify_value("HEX_ALL_RANGES_DISABLED", "")
|
|
verify_value("INT_ALL_RANGES_DISABLED", "")
|
|
# Make sure they are assignable though, and test that the form of the user
|
|
# value is reflected in the value for hex symbols
|
|
assign_and_verify("HEX_NO_RANGE", "0x123")
|
|
assign_and_verify("HEX_NO_RANGE", "123")
|
|
assign_and_verify("INT_NO_RANGE", "123")
|
|
|
|
# Defaults outside of the valid range should be clamped
|
|
verify_value("HEX_RANGE_10_20_LOW_DEFAULT", "0x10")
|
|
verify_value("HEX_RANGE_10_20_HIGH_DEFAULT", "0x20")
|
|
verify_value("INT_RANGE_10_20_LOW_DEFAULT", "10")
|
|
verify_value("INT_RANGE_10_20_HIGH_DEFAULT", "20")
|
|
# Defaults inside the valid range should be preserved. For hex symbols,
|
|
# they should additionally use the same form as in the assignment.
|
|
verify_value("HEX_RANGE_10_20_OK_DEFAULT", "0x15")
|
|
verify_value("HEX_RANGE_10_20_OK_DEFAULT_ALTERNATE", "15")
|
|
verify_value("INT_RANGE_10_20_OK_DEFAULT", "15")
|
|
|
|
# hex/int symbols with no defaults but valid ranges should default to the
|
|
# lower end of the range if it's > 0
|
|
verify_value("HEX_RANGE_10_20", "0x10")
|
|
verify_value("HEX_RANGE_0_10", "")
|
|
verify_value("INT_RANGE_10_20", "10")
|
|
verify_value("INT_RANGE_0_10", "")
|
|
verify_value("INT_RANGE_NEG_10_10", "")
|
|
|
|
# User values and dependent ranges
|
|
|
|
# Avoid warnings for assigning values outside the active range
|
|
c.warn = False
|
|
|
|
def verify_range(sym_name, low, high, default):
|
|
# Verifies that all values in the range 'low'-'high' can be assigned,
|
|
# and that assigning values outside the range reverts the value back to
|
|
# 'default' (None if it should revert back to "").
|
|
|
|
is_hex = (c.syms[sym_name].type == HEX)
|
|
|
|
for i in range(low, high + 1):
|
|
assign_and_verify_user_value(sym_name, str(i), str(i), True)
|
|
if is_hex:
|
|
# The form of the user value should be preserved for hex
|
|
# symbols
|
|
assign_and_verify_user_value(sym_name, hex(i), hex(i), True)
|
|
|
|
# Verify that assigning a user value just outside the range causes
|
|
# defaults to be used
|
|
|
|
if default is None:
|
|
default_str = ""
|
|
else:
|
|
default_str = hex(default) if is_hex else str(default)
|
|
|
|
if is_hex:
|
|
too_low_str = hex(low - 1)
|
|
too_high_str = hex(high + 1)
|
|
else:
|
|
too_low_str = str(low - 1)
|
|
too_high_str = str(high + 1)
|
|
|
|
assign_and_verify_value(sym_name, too_low_str, default_str)
|
|
assign_and_verify_value(sym_name, too_high_str, default_str)
|
|
|
|
verify_range("HEX_RANGE_10_20_LOW_DEFAULT", 0x10, 0x20, 0x10)
|
|
verify_range("HEX_RANGE_10_20_HIGH_DEFAULT", 0x10, 0x20, 0x20)
|
|
verify_range("HEX_RANGE_10_20_OK_DEFAULT", 0x10, 0x20, 0x15)
|
|
|
|
verify_range("INT_RANGE_10_20_LOW_DEFAULT", 10, 20, 10)
|
|
verify_range("INT_RANGE_10_20_HIGH_DEFAULT", 10, 20, 20)
|
|
verify_range("INT_RANGE_10_20_OK_DEFAULT", 10, 20, 15)
|
|
|
|
verify_range("HEX_RANGE_10_20", 0x10, 0x20, 0x10)
|
|
|
|
verify_range("INT_RANGE_10_20", 10, 20, 10)
|
|
verify_range("INT_RANGE_0_10", 0, 10, None)
|
|
verify_range("INT_RANGE_NEG_10_10", -10, 10, None)
|
|
|
|
# Dependent ranges
|
|
|
|
verify_value("HEX_40", "40")
|
|
verify_value("INT_40", "40")
|
|
|
|
c.syms["HEX_RANGE_10_20"].unset_value()
|
|
c.syms["INT_RANGE_10_20"].unset_value()
|
|
verify_value("HEX_RANGE_10_40_DEPENDENT", "0x10")
|
|
verify_value("INT_RANGE_10_40_DEPENDENT", "10")
|
|
c.syms["HEX_RANGE_10_20"].set_value("15")
|
|
c.syms["INT_RANGE_10_20"].set_value("15")
|
|
verify_value("HEX_RANGE_10_40_DEPENDENT", "0x15")
|
|
verify_value("INT_RANGE_10_40_DEPENDENT", "15")
|
|
c.unset_values()
|
|
verify_range("HEX_RANGE_10_40_DEPENDENT", 0x10, 0x40, 0x10)
|
|
verify_range("INT_RANGE_10_40_DEPENDENT", 10, 40, 10)
|
|
|
|
# Ranges and symbols defined in multiple locations
|
|
|
|
verify_value("INACTIVE_RANGE", "2")
|
|
verify_value("ACTIVE_RANGE", "1")
|
|
|
|
|
|
print("Testing defconfig_filename")
|
|
|
|
c = Kconfig("Kconfiglib/tests/empty")
|
|
verify(c.defconfig_filename is None,
|
|
"defconfig_filename should be None with no defconfig_list symbol")
|
|
|
|
c = Kconfig("Kconfiglib/tests/Kdefconfig_nonexistent")
|
|
verify(c.defconfig_filename is None,
|
|
"defconfig_filename should be None when none of the files in the "
|
|
"defconfig_list symbol exist")
|
|
|
|
# Referenced in Kdefconfig_existent(_but_n)
|
|
os.environ["FOO"] = "defconfig_2"
|
|
|
|
c = Kconfig("Kconfiglib/tests/Kdefconfig_existent_but_n")
|
|
verify(c.defconfig_filename is None,
|
|
"defconfig_filename should be None when the condition is n for all "
|
|
"the defaults")
|
|
|
|
c = Kconfig("Kconfiglib/tests/Kdefconfig_existent")
|
|
verify(c.defconfig_filename == "Kconfiglib/tests/defconfig_2",
|
|
"defconfig_filename should return the existing file "
|
|
"Kconfiglib/tests/defconfig_2")
|
|
|
|
# Should also look relative to $srctree if the specified defconfig is a
|
|
# relative path and can't be opened
|
|
|
|
c = Kconfig("Kconfiglib/tests/Kdefconfig_srctree")
|
|
verify(c.defconfig_filename == "Kconfiglib/tests/defconfig_2",
|
|
"defconfig_filename gave wrong file with $srctree unset")
|
|
|
|
os.environ["srctree"] = "Kconfiglib/tests"
|
|
c = Kconfig("Kdefconfig_srctree")
|
|
verify(c.defconfig_filename == "Kconfiglib/tests/sub/defconfig_in_sub",
|
|
"defconfig_filename gave wrong file with $srctree set")
|
|
|
|
os.environ.pop("srctree", None)
|
|
|
|
|
|
print("Testing mainmenu_text")
|
|
|
|
c = Kconfig("Kconfiglib/tests/empty")
|
|
verify(c.mainmenu_text == "Main menu",
|
|
"An empty Kconfig should get a default main menu prompt")
|
|
|
|
# Expanded in the mainmenu text
|
|
os.environ["FOO"] = "bar baz"
|
|
c = Kconfig("Kconfiglib/tests/Kmainmenu")
|
|
verify(c.mainmenu_text == "---bar baz---",
|
|
"Wrong mainmenu text")
|
|
|
|
|
|
print("Testing user_value")
|
|
|
|
# References undefined env. var. Disable warnings.
|
|
c = Kconfig("Kconfiglib/tests/Kmisc", warn=False)
|
|
|
|
# Avoid warnings from assigning invalid user values and assigning user
|
|
# values to symbols without prompts
|
|
c.warn = False
|
|
|
|
syms = [c.syms[name] for name in
|
|
("BOOL", "TRISTATE", "STRING", "INT", "HEX")]
|
|
|
|
for sym in syms:
|
|
verify(sym.user_value is None,
|
|
"{} should not have a user value to begin with")
|
|
|
|
# Assign valid values for the types
|
|
|
|
assign_and_verify_user_value("BOOL", 0, 0, True)
|
|
assign_and_verify_user_value("BOOL", 2, 2, True)
|
|
assign_and_verify_user_value("TRISTATE", 0, 0, True)
|
|
assign_and_verify_user_value("TRISTATE", 1, 1, True)
|
|
assign_and_verify_user_value("TRISTATE", 2, 2, True)
|
|
assign_and_verify_user_value("STRING", "foo bar", "foo bar", True)
|
|
assign_and_verify_user_value("INT", "123", "123", True)
|
|
assign_and_verify_user_value("HEX", "0x123", "0x123", True)
|
|
|
|
# Assign invalid values for the types. They should retain their old user
|
|
# value.
|
|
|
|
assign_and_verify_user_value("BOOL", 1, 2, False)
|
|
assign_and_verify_user_value("BOOL", "foo", 2, False)
|
|
assign_and_verify_user_value("BOOL", "1", 2, False)
|
|
assign_and_verify_user_value("TRISTATE", "foo", 2, False)
|
|
assign_and_verify_user_value("TRISTATE", "1", 2, False)
|
|
assign_and_verify_user_value("STRING", 0, "foo bar", False)
|
|
assign_and_verify_user_value("INT", "foo", "123", False)
|
|
assign_and_verify_user_value("INT", 0, "123", False)
|
|
assign_and_verify_user_value("HEX", "foo", "0x123", False)
|
|
assign_and_verify_user_value("HEX", 0, "0x123", False)
|
|
assign_and_verify_user_value("HEX", "-0x1", "0x123", False)
|
|
|
|
for s in syms:
|
|
s.unset_value()
|
|
verify(s.user_value is None,
|
|
"{} should not have a user value after being reset".
|
|
format(s.name))
|
|
|
|
|
|
print("Testing is_menuconfig")
|
|
|
|
c = Kconfig("Kconfiglib/tests/Kmenuconfig")
|
|
|
|
for not_menuconfig in c.syms["NOT_MENUCONFIG_1"].nodes[0], \
|
|
c.syms["NOT_MENUCONFIG_2"].nodes[0], \
|
|
c.syms["MENUCONFIG_MULTI_DEF"].nodes[0], \
|
|
c.syms["COMMENT_HOOK"].nodes[0].next:
|
|
|
|
verify(not not_menuconfig.is_menuconfig,
|
|
"'{}' should have is_menuconfig False".format(not_menuconfig))
|
|
|
|
for menuconfig in c.top_node, \
|
|
c.syms["MENUCONFIG_1"].nodes[0], \
|
|
c.syms["MENUCONFIG_MULTI_DEF"].nodes[1], \
|
|
c.syms["MENU_HOOK"].nodes[0].next, \
|
|
c.syms["CHOICE_HOOK"].nodes[0].next:
|
|
|
|
verify(menuconfig.is_menuconfig,
|
|
"'{}' should have is_menuconfig True".format(menuconfig))
|
|
|
|
|
|
print("Testing 'option env' semantics")
|
|
|
|
os.environ["ENV_VAR"] = "ENV_VAR value"
|
|
|
|
# References undefined env. var., so disable warnings
|
|
c = Kconfig("Kconfiglib/tests/Kmisc", warn=False)
|
|
|
|
# Verify that 'option env' is treated like a default
|
|
verify_value("FROM_ENV", "ENV_VAR value")
|
|
verify_value("FROM_ENV_MISSING", "missing")
|
|
|
|
verify_value("FROM_ENV_WEIRD", "weird")
|
|
|
|
|
|
print("Testing defined vs undefined symbols")
|
|
|
|
for name in "A", "B", "C", "D", "BOOL", "TRISTATE", "STRING", "INT", "HEX":
|
|
verify(c.syms[name].nodes,
|
|
"{} should be defined".format(name))
|
|
|
|
for name in "NOT_DEFINED_1", "NOT_DEFINED_2", "NOT_DEFINED_3", \
|
|
"NOT_DEFINED_4":
|
|
sym = c.syms[name]
|
|
verify(not c.syms[name].nodes,
|
|
"{} should not be defined".format(name))
|
|
|
|
|
|
print("Testing Symbol.choice")
|
|
|
|
for name in "A", "B", "C", "D":
|
|
verify(c.syms[name].choice is not None,
|
|
"{} should be a choice symbol".format(name))
|
|
|
|
for name in "Q1", "Q2", "Q3", "BOOL", "TRISTATE", "STRING", "INT", "HEX", \
|
|
"FROM_ENV", "FROM_ENV_MISSING", "NOT_DEFINED_1", \
|
|
"NOT_DEFINED_2", "NOT_DEFINED_3", "NOT_DEFINED_4":
|
|
verify(c.syms[name].choice is None,
|
|
"{} should not be a choice symbol".format(name))
|
|
|
|
|
|
print("Testing is_allnoconfig_y")
|
|
|
|
verify(not c.syms["NOT_ALLNOCONFIG_Y"].is_allnoconfig_y,
|
|
"NOT_ALLNOCONFIG_Y should not be allnoconfig_y")
|
|
verify(c.syms["ALLNOCONFIG_Y"].is_allnoconfig_y,
|
|
"ALLNOCONFIG_Y should be allnoconfig_y")
|
|
|
|
|
|
print("Testing .config reading and writing")
|
|
|
|
config_test_file = "Kconfiglib/tests/config_test"
|
|
|
|
def verify_file_contents(fname, contents):
|
|
with open(fname, "r") as f:
|
|
file_contents = f.read()
|
|
verify(file_contents == contents,
|
|
"{} contains '{}'. Expected '{}'."
|
|
.format(fname, file_contents, contents))
|
|
|
|
# Writing/reading strings with characters that need to be escaped
|
|
|
|
c = Kconfig("Kconfiglib/tests/Kescape")
|
|
|
|
# Test the default value
|
|
c.write_config(config_test_file + "_from_def")
|
|
verify_file_contents(config_test_file + "_from_def",
|
|
r'''CONFIG_STRING="\"\\"''' "\n")
|
|
# Write our own value
|
|
c.syms["STRING"].set_value(r'''\"a'\\''')
|
|
c.write_config(config_test_file + "_from_user")
|
|
verify_file_contents(config_test_file + "_from_user",
|
|
r'''CONFIG_STRING="\\\"a'\\\\"''' "\n")
|
|
|
|
# Read back the two configs and verify the respective values
|
|
c.load_config(config_test_file + "_from_def")
|
|
verify_value("STRING", '"\\')
|
|
c.load_config(config_test_file + "_from_user")
|
|
verify_value("STRING", r'''\"a'\\''')
|
|
|
|
# Appending values from a .config
|
|
|
|
c = Kconfig("Kconfiglib/tests/Kappend")
|
|
|
|
# Values before assigning
|
|
verify_value("BOOL", "n")
|
|
verify_value("STRING", "")
|
|
|
|
# Assign BOOL
|
|
c.load_config("Kconfiglib/tests/config_set_bool", replace=False)
|
|
verify_value("BOOL", "y")
|
|
verify_value("STRING", "")
|
|
|
|
# Assign STRING
|
|
c.load_config("Kconfiglib/tests/config_set_string", replace=False)
|
|
verify_value("BOOL", "y")
|
|
verify_value("STRING", "foo bar")
|
|
|
|
# Reset BOOL
|
|
c.load_config("Kconfiglib/tests/config_set_string")
|
|
verify_value("BOOL", "n")
|
|
verify_value("STRING", "foo bar")
|
|
|
|
# Loading a completely empty .config should reset values
|
|
c.load_config("Kconfiglib/tests/empty")
|
|
verify_value("STRING", "")
|
|
|
|
# An indented assignment in a .config should be ignored
|
|
c.load_config("Kconfiglib/tests/config_indented")
|
|
verify_value("IGNOREME", "y")
|
|
|
|
# Symbol order in headers and minimal configuration files should match
|
|
# definition order, like in .config files
|
|
|
|
c = Kconfig("Kconfiglib/tests/Korder")
|
|
|
|
c.write_autoconf(config_test_file)
|
|
verify_file_contents(config_test_file, """
|
|
#define CONFIG_O 0
|
|
#define CONFIG_R 1
|
|
#define CONFIG_D 2
|
|
#define CONFIG_E 3
|
|
#define CONFIG_R2 4
|
|
#define CONFIG_I 5
|
|
#define CONFIG_N 6
|
|
#define CONFIG_G 7
|
|
"""[1:])
|
|
|
|
# Differs from defaults
|
|
c.syms["O"].set_value("-1")
|
|
c.syms["R"].set_value("-1")
|
|
c.syms["E"].set_value("-1")
|
|
c.syms["R2"].set_value("-1")
|
|
c.syms["N"].set_value("-1")
|
|
c.syms["G"].set_value("-1")
|
|
c.write_min_config(config_test_file)
|
|
verify_file_contents(config_test_file, """
|
|
CONFIG_O=-1
|
|
CONFIG_R=-1
|
|
CONFIG_E=-1
|
|
CONFIG_R2=-1
|
|
CONFIG_N=-1
|
|
CONFIG_G=-1
|
|
"""[1:])
|
|
|
|
# Test header strings in configuration files and headers
|
|
|
|
os.environ["KCONFIG_CONFIG_HEADER"] = "config header from env.\n"
|
|
os.environ["KCONFIG_AUTOHEADER_HEADER"] = "header header from env.\n"
|
|
|
|
c = Kconfig("Kconfiglib/tests/Kheader")
|
|
c.write_config(config_test_file, header="config header from param\n")
|
|
verify_file_contents(config_test_file, """\
|
|
config header from param
|
|
CONFIG_FOO=y
|
|
""")
|
|
c.write_min_config(config_test_file, header="min. config header from param\n")
|
|
verify_file_contents(config_test_file, """\
|
|
min. config header from param
|
|
""")
|
|
c.write_config(config_test_file)
|
|
verify_file_contents(config_test_file, """\
|
|
config header from env.
|
|
CONFIG_FOO=y
|
|
""")
|
|
c.write_min_config(config_test_file)
|
|
verify_file_contents(config_test_file, """\
|
|
config header from env.
|
|
""")
|
|
c.write_autoconf(config_test_file, header="header header from param\n")
|
|
verify_file_contents(config_test_file, """\
|
|
header header from param
|
|
#define CONFIG_FOO 1
|
|
""")
|
|
c.write_autoconf(config_test_file)
|
|
verify_file_contents(config_test_file, """\
|
|
header header from env.
|
|
#define CONFIG_FOO 1
|
|
""")
|
|
|
|
del os.environ["KCONFIG_CONFIG_HEADER"]
|
|
del os.environ["KCONFIG_AUTOHEADER_HEADER"]
|
|
|
|
|
|
print("Testing Kconfig fetching and separation")
|
|
|
|
for c in Kconfig("Kconfiglib/tests/Kmisc", warn=False), \
|
|
Kconfig("Kconfiglib/tests/Kmisc", warn=False):
|
|
for item in c.syms["BOOL"], \
|
|
c.syms["BOOL"].nodes[0], \
|
|
c.named_choices["OPTIONAL"], \
|
|
c.named_choices["OPTIONAL"].nodes[0], \
|
|
c.syms["MENU_HOOK"].nodes[0].next, \
|
|
c.syms["COMMENT_HOOK"].nodes[0].next:
|
|
verify(item.kconfig is c,
|
|
".kconfig not properly set for " + repr(item))
|
|
|
|
|
|
print("Testing imply semantics")
|
|
|
|
c = Kconfig("Kconfiglib/tests/Kimply")
|
|
|
|
verify_value("IMPLY_DIRECT_DEPS", "y")
|
|
verify_value("UNMET_DIRECT_1", "n")
|
|
verify_value("UNMET_DIRECT_2", "n")
|
|
verify_value("UNMET_DIRECT_3", "n")
|
|
verify_value("MET_DIRECT_1", "y")
|
|
verify_value("MET_DIRECT_2", "y")
|
|
verify_value("MET_DIRECT_3", "y")
|
|
verify_value("MET_DIRECT_4", "y")
|
|
|
|
verify_value("IMPLY_COND", "y")
|
|
verify_value("IMPLIED_N_COND", "n")
|
|
verify_value("IMPLIED_M_COND", "m")
|
|
verify_value("IMPLIED_Y_COND", "y")
|
|
|
|
verify_value("IMPLY_N_1", "n")
|
|
verify_value("IMPLY_N_2", "n")
|
|
verify_value("IMPLIED_FROM_N_1", "n")
|
|
verify_value("IMPLIED_FROM_N_2", "n")
|
|
|
|
verify_value("IMPLY_M", "m")
|
|
verify_value("IMPLIED_M", "m")
|
|
verify_value("IMPLIED_M_BOOL", "y")
|
|
|
|
verify_value("IMPLY_M_TO_Y", "y")
|
|
verify_value("IMPLIED_M_TO_Y", "y")
|
|
|
|
# Test user value semantics
|
|
|
|
# Verify that IMPLIED_TRISTATE is invalidated if the direct
|
|
# dependencies change
|
|
|
|
assign_and_verify("IMPLY", 2)
|
|
assign_and_verify("DIRECT_DEP", 2)
|
|
verify_value("IMPLIED_TRISTATE", 2)
|
|
assign_and_verify("DIRECT_DEP", 0)
|
|
verify_value("IMPLIED_TRISTATE", 0)
|
|
# Set back for later tests
|
|
assign_and_verify("DIRECT_DEP", 2)
|
|
|
|
# Verify that IMPLIED_TRISTATE can be set to anything when IMPLY has value
|
|
# n, and that it gets the value n by default (for non-imply-related
|
|
# reasons)
|
|
|
|
assign_and_verify("IMPLY", 0)
|
|
assign_and_verify("IMPLIED_TRISTATE", 0)
|
|
assign_and_verify("IMPLIED_TRISTATE", 1)
|
|
assign_and_verify("IMPLIED_TRISTATE", 2)
|
|
c.syms["IMPLIED_TRISTATE"].unset_value()
|
|
verify_value("IMPLIED_TRISTATE", "n")
|
|
|
|
# Same as above for m. Anything still goes, but m by default now.
|
|
|
|
assign_and_verify("IMPLY", 1)
|
|
assign_and_verify("IMPLIED_TRISTATE", 0)
|
|
assign_and_verify("IMPLIED_TRISTATE", 1)
|
|
assign_and_verify("IMPLIED_TRISTATE", 2)
|
|
c.syms["IMPLIED_TRISTATE"].unset_value()
|
|
verify_value("IMPLIED_TRISTATE", 1)
|
|
|
|
# Same as above for y. Only n and y should be accepted. m gets promoted to
|
|
# y. Default should be y.
|
|
|
|
assign_and_verify("IMPLY", 2)
|
|
assign_and_verify("IMPLIED_TRISTATE", 0)
|
|
assign_and_verify_value("IMPLIED_TRISTATE", 1, 2)
|
|
assign_and_verify("IMPLIED_TRISTATE", 2)
|
|
c.syms["IMPLIED_TRISTATE"].unset_value()
|
|
verify_value("IMPLIED_TRISTATE", 2)
|
|
|
|
# Being implied to either m or y should give a bool the value y
|
|
|
|
c.syms["IMPLY"].unset_value()
|
|
verify_value("IMPLIED_BOOL", 0)
|
|
assign_and_verify("IMPLY", 0)
|
|
verify_value("IMPLIED_BOOL", 0)
|
|
assign_and_verify("IMPLY", 1)
|
|
verify_value("IMPLIED_BOOL", 2)
|
|
assign_and_verify("IMPLY", 2)
|
|
verify_value("IMPLIED_BOOL", 2)
|
|
|
|
# A bool implied to m or y can take the values n and y
|
|
|
|
c.syms["IMPLY"].set_value(1)
|
|
assign_and_verify("IMPLIED_BOOL", 0)
|
|
assign_and_verify("IMPLIED_BOOL", 2)
|
|
|
|
c.syms["IMPLY"].set_value(2)
|
|
assign_and_verify("IMPLIED_BOOL", 0)
|
|
assign_and_verify("IMPLIED_BOOL", 2)
|
|
|
|
|
|
print("Testing choice semantics")
|
|
|
|
# Would warn for choice value symbols defined without a type, even
|
|
# though the type is automatically derived. This is probably more
|
|
# helpful than ignoring those cases, as this feature isn't used
|
|
# deliberately anywhere from what I've seen.
|
|
c = Kconfig("Kconfiglib/tests/Kchoice", warn=False)
|
|
|
|
for name in "BOOL", "BOOL_OPT", "BOOL_M", "DEFAULTS":
|
|
verify(c.named_choices[name].orig_type == BOOL,
|
|
"choice {} should have type bool".format(name))
|
|
|
|
for name in "TRISTATE", "TRISTATE_OPT", "TRISTATE_M":
|
|
verify(c.named_choices[name].orig_type == TRISTATE,
|
|
"choice {} should have type tristate".format(name))
|
|
|
|
def select_and_verify(sym):
|
|
choice = sym.nodes[0].parent.item
|
|
choice.set_value(2)
|
|
|
|
sym.set_value(2)
|
|
|
|
verify(sym.choice.selection is sym,
|
|
sym.name + " should be the selected symbol")
|
|
|
|
verify(choice.user_selection is sym,
|
|
sym.name + " should be the user selection of the choice")
|
|
|
|
verify(sym.tri_value == 2,
|
|
sym.name + " should have value y when selected")
|
|
|
|
verify(sym.user_value == 2,
|
|
sym.name + " should have user value y when selected")
|
|
|
|
for sibling in choice.syms:
|
|
if sibling is not sym:
|
|
verify(sibling.tri_value == 0,
|
|
sibling.name + " should be n when not selected")
|
|
|
|
def select_and_verify_all(choice_name):
|
|
choice = c.named_choices[choice_name]
|
|
|
|
# Select in forward order
|
|
for sym in choice.syms:
|
|
select_and_verify(sym)
|
|
|
|
# Select in reverse order
|
|
for sym in reversed(choice.syms):
|
|
select_and_verify(sym)
|
|
|
|
def verify_mode(choice_name, no_modules_mode, modules_mode):
|
|
choice = c.named_choices[choice_name]
|
|
|
|
c.modules.set_value(0)
|
|
verify(choice.tri_value == no_modules_mode,
|
|
'Wrong mode for choice {} with no modules. Expected {}, got {}.'
|
|
.format(choice.name, no_modules_mode, choice.tri_value))
|
|
|
|
c.modules.set_value(2)
|
|
verify(choice.tri_value == modules_mode,
|
|
'Wrong mode for choice {} with modules. Expected {}, got {}.'
|
|
.format(choice.name, modules_mode, choice.tri_value))
|
|
|
|
verify_mode("BOOL", 2, 2)
|
|
verify_mode("BOOL_OPT", 0, 0)
|
|
verify_mode("TRISTATE", 2, 1)
|
|
verify_mode("TRISTATE_OPT", 0, 0)
|
|
verify_mode("BOOL_M", 0, 2)
|
|
verify_mode("TRISTATE_M", 0, 1)
|
|
|
|
# Test defaults
|
|
|
|
choice = c.named_choices["DEFAULTS"]
|
|
|
|
c.syms["TRISTATE_SYM"].set_value(0)
|
|
verify(choice.selection is c.syms["OPT_4"],
|
|
"Wrong choice default with TRISTATE_SYM = n")
|
|
|
|
c.syms["TRISTATE_SYM"].set_value(2)
|
|
verify(choice.selection is c.syms["OPT_2"],
|
|
"Wrong choice default with TRISTATE_SYM = y")
|
|
|
|
c.syms["OPT_1"].set_value(2)
|
|
verify(choice.selection is c.syms["OPT_1"],
|
|
"User selection should override defaults")
|
|
|
|
verify(c.named_choices["DEFAULTS_NOT_VISIBLE"].selection
|
|
is c.syms["OPT_8"],
|
|
"Non-visible choice symbols should cause the next default to be "
|
|
"considered")
|
|
|
|
# Test y mode selection
|
|
|
|
c.modules.set_value(2)
|
|
|
|
select_and_verify_all("BOOL")
|
|
select_and_verify_all("BOOL_OPT")
|
|
select_and_verify_all("TRISTATE")
|
|
select_and_verify_all("TRISTATE_OPT")
|
|
# For BOOL_M, the mode should have been promoted
|
|
select_and_verify_all("BOOL_M")
|
|
|
|
# Test m mode selection
|
|
|
|
c.named_choices["TRISTATE"].set_value(1)
|
|
|
|
verify(c.named_choices["TRISTATE"].tri_value == 1,
|
|
"TRISTATE choice should have mode m after explicit mode assignment")
|
|
|
|
assign_and_verify_value("T_1", 0, 0)
|
|
assign_and_verify_value("T_2", 0, 0)
|
|
assign_and_verify_value("T_1", 1, 1)
|
|
assign_and_verify_value("T_2", 1, 1)
|
|
assign_and_verify_value("T_1", 2, 1)
|
|
assign_and_verify_value("T_2", 2, 1)
|
|
|
|
# Switching to y mode should cause T_2 to become selected
|
|
c.named_choices["TRISTATE"].set_value(2)
|
|
verify_value("T_1", 0)
|
|
verify_value("T_2", 2)
|
|
|
|
# Verify that choices with no explicitly specified type get the type of the
|
|
# first contained symbol with a type
|
|
|
|
verify(c.named_choices["NO_TYPE_BOOL"].orig_type == BOOL,
|
|
"Expected first choice without explicit type to have type bool")
|
|
|
|
verify(c.named_choices["NO_TYPE_TRISTATE"].orig_type == TRISTATE,
|
|
"Expected second choice without explicit type to have type "
|
|
"tristate")
|
|
|
|
# Verify that symbols without a type in the choice get the type of the
|
|
# choice
|
|
|
|
for name in "MMT_1", "MMT_2", "MMT_4", "MMT_5":
|
|
verify(c.syms[name].orig_type == BOOL,
|
|
"Expected {} to get type bool".format(name))
|
|
|
|
verify(c.syms["MMT_3"].orig_type == TRISTATE,
|
|
"Expected MMT_3 to have type tristate")
|
|
|
|
# Verify that the default selection can change depending on the
|
|
# visibility of the choice symbols
|
|
|
|
default_with_dep_choice = c.named_choices["DEFAULT_WITH_DEP"]
|
|
|
|
verify(default_with_dep_choice.selection is c.syms["B"],
|
|
"Wrong choice default with unsatisfied deps on default")
|
|
|
|
c.syms["DEP"].set_value("y")
|
|
|
|
verify(default_with_dep_choice.selection is c.syms["A"],
|
|
"Wrong choice default with satisfied deps on default")
|
|
|
|
c.syms["DEP"].set_value("n")
|
|
|
|
verify(default_with_dep_choice.selection is c.syms["B"],
|
|
"Wrong choice default with unsatisfied deps on default (round two)")
|
|
|
|
# Verify that symbols in choices that depend on the preceding symbol aren't
|
|
# considered choice symbols
|
|
|
|
weird_choice = c.named_choices["WEIRD_SYMS"]
|
|
|
|
def verify_is_normal_choice_symbol(name):
|
|
sym = c.syms[name]
|
|
verify(sym.choice is not None and
|
|
sym in weird_choice.syms and
|
|
sym.nodes[0].parent.item is weird_choice,
|
|
"{} should be a normal choice symbol".format(sym.name))
|
|
|
|
def verify_is_weird_choice_symbol(name):
|
|
sym = c.syms[name]
|
|
verify(sym.choice is None and
|
|
sym not in weird_choice.syms,
|
|
"{} should be a weird (non-)choice symbol"
|
|
.format(sym.name))
|
|
|
|
verify_is_normal_choice_symbol("WS1")
|
|
verify_is_weird_choice_symbol("WS2")
|
|
verify_is_weird_choice_symbol("WS3")
|
|
verify_is_weird_choice_symbol("WS4")
|
|
verify_is_weird_choice_symbol("WS5")
|
|
verify_is_normal_choice_symbol("WS6")
|
|
verify_is_weird_choice_symbol("WS7")
|
|
verify_is_weird_choice_symbol("WS8")
|
|
verify_is_normal_choice_symbol("WS9")
|
|
|
|
|
|
print("Testing 'if' node removal")
|
|
|
|
c = Kconfig("Kconfiglib/tests/Kifremoval", warn=False)
|
|
|
|
nodes = tuple(c.node_iter())
|
|
verify_equal(nodes[0].item.name, "A")
|
|
verify_equal(nodes[1].item.name, "B")
|
|
verify_equal(nodes[2].item.name, "C")
|
|
verify_equal(nodes[3].item.name, "D")
|
|
verify_equal(nodes[4].prompt[0], "E")
|
|
verify_equal(nodes[5].prompt[0], "F")
|
|
verify_equal(nodes[6].prompt[0], "G")
|
|
verify_equal(nodes[7].item.name, "H")
|
|
verify_equal(nodes[8].item.name, "I")
|
|
verify_equal(nodes[9].item.name, "J")
|
|
verify(len(nodes) == 10,
|
|
"Wrong number of nodes after 'if' removal")
|
|
|
|
|
|
print("Testing multi.def. property copying")
|
|
|
|
c = Kconfig("Kconfiglib/tests/Kdepcopy", warn=False)
|
|
|
|
def verify_props(desc, props, prop_names):
|
|
actual = [prop[0].name for prop in props]
|
|
expected = prop_names.split()
|
|
|
|
verify(actual == expected,
|
|
"Wrong {} properties, expected '{}', got '{}'"
|
|
.format(desc, expected, actual))
|
|
|
|
verify_props("default", c.syms["MULTIDEF"].defaults,
|
|
"A B C D E F G H I J K L M N O P Q R")
|
|
|
|
verify_props("select", c.syms["MULTIDEF"].selects,
|
|
"AA BB CC DD EE FF GG HH II JJ")
|
|
|
|
verify_props("imply", c.syms["MULTIDEF"].selects,
|
|
"AA BB CC DD EE FF GG HH II JJ")
|
|
|
|
verify_props("select", c.syms["MULTIDEF_CHOICE"].selects,
|
|
"A B C")
|
|
|
|
verify_props("range", c.syms["MULTIDEF_RANGE"].ranges,
|
|
"A B C D E F")
|
|
|
|
verify_props("default", c.choices[1].defaults,
|
|
"A B C D E")
|
|
|
|
|
|
print("Testing dependency loop detection")
|
|
|
|
# These are all expected to raise dependency loop errors
|
|
for i in range(11):
|
|
filename = "Kconfiglib/tests/Kdeploop" + str(i)
|
|
try:
|
|
Kconfig(filename)
|
|
except KconfigError as e:
|
|
if "Dependency loop" not in str(e):
|
|
fail("dependency loop in {} raised wrong KconfigError"
|
|
.format(filename))
|
|
except:
|
|
fail("dependency loop in {} raised wrong exception"
|
|
.format(filename))
|
|
else:
|
|
fail("dependency loop in {} not detected".format(filename))
|
|
|
|
# Check the most complicated message completely
|
|
try:
|
|
Kconfig("Kconfiglib/tests/Kdeploop10")
|
|
except KconfigError as e:
|
|
verify_equal(str(e), """
|
|
Dependency loop
|
|
===============
|
|
|
|
A (defined at Kconfiglib/tests/Kdeploop10:1), with definition...
|
|
|
|
config A
|
|
bool
|
|
depends on B
|
|
|
|
...depends on B (defined at Kconfiglib/tests/Kdeploop10:5), with definition...
|
|
|
|
config B
|
|
bool
|
|
depends on C = 7
|
|
|
|
...depends on C (defined at Kconfiglib/tests/Kdeploop10:9), with definition...
|
|
|
|
config C
|
|
int
|
|
range D 8
|
|
|
|
...depends on D (defined at Kconfiglib/tests/Kdeploop10:13), with definition...
|
|
|
|
config D
|
|
int
|
|
default 3 if E
|
|
default 8
|
|
|
|
...depends on E (defined at Kconfiglib/tests/Kdeploop10:18), with definition...
|
|
|
|
config E
|
|
bool
|
|
|
|
(select-related dependencies: F && G)
|
|
|
|
...depends on G (defined at Kconfiglib/tests/Kdeploop10:25), with definition...
|
|
|
|
config G
|
|
bool
|
|
depends on H
|
|
|
|
...depends on the choice symbol H (defined at Kconfiglib/tests/Kdeploop10:32), with definition...
|
|
|
|
config H
|
|
bool "H"
|
|
depends on I && <choice>
|
|
|
|
...depends on the choice symbol I (defined at Kconfiglib/tests/Kdeploop10:41), with definition...
|
|
|
|
config I
|
|
bool "I"
|
|
depends on <choice>
|
|
|
|
...depends on <choice> (defined at Kconfiglib/tests/Kdeploop10:38), with definition...
|
|
|
|
choice
|
|
bool "choice" if J
|
|
|
|
...depends on J (defined at Kconfiglib/tests/Kdeploop10:46), with definition...
|
|
|
|
config J
|
|
bool
|
|
depends on A
|
|
|
|
...depends again on A (defined at Kconfiglib/tests/Kdeploop10:1)
|
|
"""[:-1])
|
|
except:
|
|
fail("Loop detection message check raised wrong exception")
|
|
else:
|
|
fail("Loop detection message check did not raise exception")
|
|
|
|
|
|
print("Testing preprocessor")
|
|
|
|
os.environ["ENV_1"] = "env_1"
|
|
os.environ["ENV_2"] = "env_2"
|
|
os.environ["ENV_3"] = "env_3"
|
|
os.environ["ENV_4"] = "env_4"
|
|
os.environ["ENV_5"] = "n"
|
|
os.environ["ENV_6"] = "Kconfiglib/tests/empty"
|
|
os.environ["ENV_7"] = "env_7"
|
|
# We verify warnings manually
|
|
c = Kconfig("Kconfiglib/tests/Kpreprocess", warn_to_stderr=False)
|
|
|
|
def verify_variable(name, unexp_value, exp_value, recursive, *args):
|
|
var = c.variables[name]
|
|
|
|
verify(var.value == unexp_value,
|
|
"expected variable '{}' to have the unexpanded value '{}', had "
|
|
"the value '{}'".format(name, unexp_value, var.value))
|
|
|
|
if not args:
|
|
verify(var.expanded_value == exp_value,
|
|
"expected expanded_value for {} to be '{}', was '{}'"
|
|
.format(name, exp_value, var.expanded_value))
|
|
|
|
verify(var.expanded_value_w_args(*args) == exp_value,
|
|
"expected expanded_value_w_args() for '{}' to be '{}', was '{}'"
|
|
.format(name, exp_value, var.expanded_value_w_args(*args)))
|
|
|
|
verify(var.is_recursive == recursive,
|
|
"{} was {}, shouldn't be"
|
|
.format(name, "recursive" if var.is_recursive else "simple"))
|
|
|
|
verify_variable("simple-recursive", "foo", "foo", True)
|
|
verify_variable("simple-immediate", "bar", "bar", False)
|
|
verify_variable("simple-recursive-2", "baz", "baz", True)
|
|
|
|
verify_variable("whitespaced", "foo", "foo", True)
|
|
|
|
verify_variable("preserve-recursive", "foo bar", "foo bar", True)
|
|
verify_variable("preserve-immediate", "foo bar", "foo bar", False)
|
|
|
|
verify_variable("recursive",
|
|
"$(foo) $(bar) $($(b-char)a$(z-char)) $(indir)",
|
|
"abc def ghi jkl mno",
|
|
True)
|
|
|
|
verify_variable("immediate", "foofoo", "foofoo", False)
|
|
|
|
verify_variable("messy-fn-res",
|
|
"$($(fn-indir)-unused-arg, a b (,) , c d )",
|
|
'surround-rev-quote " c d " " a b (,) " surround-rev-quote ',
|
|
True)
|
|
|
|
verify_variable("special-chars-fn-res",
|
|
"$(fn,$(comma)$(dollar)$(left-paren)foo$(right-paren))",
|
|
'",$(foo)"',
|
|
True)
|
|
|
|
verify_variable("quote", '"$(1)" "$(2)"', '"" ""', True)
|
|
verify_variable("quote", '"$(1)" "$(2)"', '"one" ""', True,
|
|
"one")
|
|
verify_variable("quote", '"$(1)" "$(2)"', '"one" "two"', True,
|
|
"one", "two")
|
|
verify_variable("quote", '"$(1)" "$(2)"', '"one" "two"', True,
|
|
"one", "two", "three")
|
|
|
|
verify_str(c.syms["PRINT_ME"], r"""
|
|
config PRINT_ME
|
|
string "env_1" if (FOO && BAR) || !BAZ || !QAZ
|
|
default "\"foo\"" if "foo \"bar\" baz" = ""
|
|
""")
|
|
|
|
verify_str(c.syms["PRINT_ME_TOO"], r"""
|
|
config PRINT_ME_TOO
|
|
bool "foo"
|
|
default FOOBARBAZQAZ if QAZ && QAZFOO && xxx
|
|
""")
|
|
|
|
def verify_repr(name, s):
|
|
verify_equal(repr(c.variables[name]), s)
|
|
|
|
verify_repr(
|
|
"simple-immediate",
|
|
"<variable simple-immediate, immediate, value 'bar'>")
|
|
|
|
verify_repr(
|
|
"messy-fn-res",
|
|
"<variable messy-fn-res, recursive, value '$($(fn-indir)-unused-arg, a b (,) , c d )'>")
|
|
|
|
def verify_recursive(name):
|
|
try:
|
|
c.variables[name].expanded_value
|
|
except KconfigError:
|
|
pass
|
|
else:
|
|
fail("Expected '{}' expansion to flag recursive expansion, didn't"
|
|
.format(name))
|
|
|
|
verify_recursive("rec-1")
|
|
# Indirectly verifies that it's not recursive
|
|
verify_variable("safe-fn-rec-res",
|
|
"$(safe-fn-rec,safe-fn-rec-2)",
|
|
"foo",
|
|
True)
|
|
verify_recursive("unsafe-fn-rec")
|
|
|
|
verify_variable("foo-bar-baz", "$(rhs)", "value", True)
|
|
|
|
verify_variable("space-var-res", "$(foo bar)", "value", True)
|
|
|
|
verify_variable("shell-res",
|
|
"$(shell,false && echo foo bar || echo baz qaz)",
|
|
"baz qaz",
|
|
True)
|
|
|
|
verify_variable("shell-stderr-res", "", "", False)
|
|
|
|
verify_variable("parens-res",
|
|
"pre-$(shell,echo '(a,$(b-char),(c,d),e)')-post",
|
|
"pre-(a,b,(c,d),e)-post",
|
|
True)
|
|
|
|
verify_variable("location-res",
|
|
"Kconfiglib/tests/Kpreprocess:129",
|
|
"Kconfiglib/tests/Kpreprocess:129",
|
|
False)
|
|
|
|
verify_variable("warning-res", "", "", False)
|
|
verify_variable("error-n-res", "", "", False)
|
|
|
|
try:
|
|
c.variables["error-y-res"].expanded_value
|
|
except KconfigError:
|
|
pass
|
|
else:
|
|
fail("expanding error-y-res didn't raise an exception")
|
|
|
|
# Check Kconfig.env_vars
|
|
verify_equal(c.env_vars,
|
|
set(("ENV_1", "ENV_2", "ENV_3", "ENV_4", "ENV_5", "ENV_6")))
|
|
|
|
# Check that the expected warnings were generated
|
|
verify_equal(c.warnings, [
|
|
"Kconfiglib/tests/Kpreprocess:122: warning: 'echo message on stderr >&2' wrote to stderr: message on stderr",
|
|
"Kconfiglib/tests/Kpreprocess:134: warning: a warning"
|
|
])
|
|
|
|
|
|
print("Testing user-defined preprocessor functions")
|
|
|
|
# Make Kconfiglib/tests/kconfigfunctions.py importable
|
|
sys.path.insert(0, "Kconfiglib/tests")
|
|
|
|
c = Kconfig("Kconfiglib/tests/Kuserfunctions")
|
|
|
|
verify_variable("add-zero", "$(add)", "0", True)
|
|
verify_variable("add-one", "$(add,1)", "1", True)
|
|
verify_variable("add-three", "$(add,1,-1,2,1)", "3", True)
|
|
|
|
verify_variable("one-one", "$(one,foo bar)", "onefoo barfoo bar", True)
|
|
|
|
verify_variable("one-or-more-one", "$(one-or-more,foo)", "foo + ", True)
|
|
verify_variable("one-or-more-three", "$(one-or-more,foo,bar,baz)",
|
|
"foo + bar,baz", True)
|
|
|
|
verify_variable("location-1", "Kconfiglib/tests/Kuserfunctions:13",
|
|
"Kconfiglib/tests/Kuserfunctions:13", False)
|
|
verify_variable("location-2", "Kconfiglib/tests/Kuserfunctions:14",
|
|
"Kconfiglib/tests/Kuserfunctions:14", False)
|
|
|
|
def verify_bad_argno(name):
|
|
try:
|
|
c.variables[name].expanded_value
|
|
except KconfigError:
|
|
pass
|
|
else:
|
|
fail("Expected '{}' expansion to flag wrong number of arguments, "
|
|
"didn't".format(name))
|
|
|
|
verify_bad_argno("one-zero")
|
|
verify_bad_argno("one-two")
|
|
verify_bad_argno("one-or-more-zero")
|
|
|
|
sys.path.pop(0)
|
|
|
|
# This test can fail on older Python 3.x versions, because they don't
|
|
# preserve dict insertion order during iteration. The output is still
|
|
# correct, just different.
|
|
if not (3, 0) <= sys.version_info <= (3, 5):
|
|
print("Testing KCONFIG_WARN_UNDEF")
|
|
|
|
os.environ["KCONFIG_WARN_UNDEF"] = "y"
|
|
c = Kconfig("Kconfiglib/tests/Kundef", warn_to_stderr=False)
|
|
|
|
verify_equal("\n".join(c.warnings), """
|
|
warning: the int symbol INT (defined at Kconfiglib/tests/Kundef:8) has a non-int range [UNDEF_2 (undefined), 8 (undefined)]
|
|
warning: undefined symbol UNDEF_1:
|
|
|
|
- Referenced at Kconfiglib/tests/Kundef:4:
|
|
|
|
config BOOL
|
|
bool "foo" if DEF || !UNDEF_1
|
|
default UNDEF_2
|
|
|
|
- Referenced at Kconfiglib/tests/Kundef:19:
|
|
|
|
menu "menu"
|
|
depends on UNDEF_1
|
|
visible if UNDEF_3
|
|
warning: undefined symbol UNDEF_2:
|
|
|
|
- Referenced at Kconfiglib/tests/Kundef:4:
|
|
|
|
config BOOL
|
|
bool "foo" if DEF || !UNDEF_1
|
|
default UNDEF_2
|
|
|
|
- Referenced at Kconfiglib/tests/Kundef:8:
|
|
|
|
config INT
|
|
int
|
|
range UNDEF_2 8
|
|
range 5 15
|
|
default 10
|
|
warning: undefined symbol UNDEF_3:
|
|
|
|
- Referenced at Kconfiglib/tests/Kundef:19:
|
|
|
|
menu "menu"
|
|
depends on UNDEF_1
|
|
visible if UNDEF_3
|
|
"""[1:-1])
|
|
|
|
os.environ.pop("KCONFIG_WARN_UNDEF")
|
|
|
|
|
|
print("\nAll selftests passed\n" if all_passed else
|
|
"\nSome selftests failed\n")
|
|
|
|
|
|
def run_compatibility_tests():
|
|
# Runs tests on configurations from the kernel. Tests compability with the
|
|
# C implementation by comparing outputs.
|
|
|
|
# Referenced inside the kernel Kconfig files.
|
|
#
|
|
# The str() makes the type of the value 'str' on both Python 2 and Python 3,
|
|
# which is nice for some later dictionary key sanity checks.
|
|
|
|
os.environ["KERNELVERSION"] = str(
|
|
subprocess.check_output("make kernelversion", shell=True)
|
|
.decode("utf-8").rstrip()
|
|
)
|
|
|
|
os.environ["CC_VERSION_TEXT"] = str(
|
|
subprocess.check_output("gcc --version | head -n1", shell=True)
|
|
.decode("utf-8").rstrip()
|
|
)
|
|
|
|
os.environ["srctree"] = "."
|
|
os.environ["CC"] = "gcc"
|
|
os.environ["LD"] = "ld"
|
|
|
|
|
|
if not os.path.exists("scripts/kconfig/conf"):
|
|
print("\nscripts/kconfig/conf does not exist -- running "
|
|
"'make allnoconfig' to build it...")
|
|
shell("make allnoconfig")
|
|
|
|
|
|
print("Running compatibility tests...\n")
|
|
|
|
test_fns = (test_defconfig,
|
|
# Fails for a few defconfigs due to a bug in the C tools. Will
|
|
# be enabled once patches get in.
|
|
#test_min_config,
|
|
test_alldefconfig,
|
|
test_allnoconfig,
|
|
test_allnoconfig_walk,
|
|
test_allmodconfig,
|
|
test_allyesconfig,
|
|
test_sanity)
|
|
|
|
for test_fn in test_fns:
|
|
# The test description is taken from the docstring of the corresponding
|
|
# function
|
|
print(textwrap.dedent(test_fn.__doc__))
|
|
|
|
for arch, srcarch in all_arch_srcarch():
|
|
# Referenced inside the Kconfig files
|
|
os.environ["ARCH"] = arch
|
|
os.environ["SRCARCH"] = srcarch
|
|
|
|
rm_configs()
|
|
|
|
test_fn(arch, srcarch)
|
|
|
|
if all_passed:
|
|
print("All selftests and compatibility tests passed")
|
|
else:
|
|
sys.exit("Some tests failed")
|
|
|
|
|
|
def all_arch_srcarch():
|
|
for srcarch in os.listdir("arch"):
|
|
# arc and h8300 are currently broken with the C tools on linux-next as
|
|
# well. Perhaps they require cross-compilers to be installed.
|
|
#
|
|
# User-mode Linux has an unorthodox Kconfig setup that would require a
|
|
# different testing setup. Skip it too.
|
|
if srcarch in ("arc", "h8300", "um"):
|
|
continue
|
|
|
|
if os.path.exists(os.path.join("arch", srcarch, "Kconfig")):
|
|
yield (srcarch, srcarch)
|
|
|
|
# Some arches define additional ARCH settings with ARCH != SRCARCH
|
|
# (search for "Additional ARCH settings for" in the top-level Makefile)
|
|
|
|
yield ("i386", "x86")
|
|
yield ("x86_64", "x86")
|
|
|
|
yield ("sparc32", "sparc")
|
|
yield ("sparc64", "sparc")
|
|
|
|
yield ("sh64", "sh")
|
|
|
|
|
|
def test_allnoconfig(arch, srcarch):
|
|
"""
|
|
Verify that allnoconfig.py generates the same .config as
|
|
'make allnoconfig', for each architecture. Runs the script via
|
|
'make scriptconfig'.
|
|
"""
|
|
shell("make scriptconfig SCRIPT=Kconfiglib/allnoconfig.py "
|
|
"PYTHONCMD='{}'".format(sys.executable))
|
|
shell("mv .config ._config")
|
|
shell("scripts/kconfig/conf --allnoconfig Kconfig")
|
|
|
|
compare_configs(arch)
|
|
|
|
|
|
def test_allnoconfig_walk(arch, srcarch):
|
|
"""
|
|
Verify that examples/allnoconfig_walk.py generates the same .config as
|
|
'make allnoconfig', for each architecture. Runs the script via
|
|
'make scriptconfig'.
|
|
"""
|
|
shell("make scriptconfig SCRIPT=Kconfiglib/examples/allnoconfig_walk.py "
|
|
"PYTHONCMD='{}'".format(sys.executable))
|
|
shell("mv .config ._config")
|
|
shell("scripts/kconfig/conf --allnoconfig Kconfig")
|
|
|
|
compare_configs(arch)
|
|
|
|
|
|
def test_allmodconfig(arch, srcarch):
|
|
"""
|
|
Verify that allmodconfig.py generates the same .config as
|
|
'make allmodconfig', for each architecture. Runs the script via
|
|
'make scriptconfig'.
|
|
"""
|
|
shell("make scriptconfig SCRIPT=Kconfiglib/allmodconfig.py "
|
|
"PYTHONCMD='{}'".format(sys.executable))
|
|
shell("mv .config ._config")
|
|
shell("scripts/kconfig/conf --allmodconfig Kconfig")
|
|
|
|
compare_configs(arch)
|
|
|
|
|
|
def test_allyesconfig(arch, srcarch):
|
|
"""
|
|
Verify that allyesconfig.py generates the same .config as
|
|
'make allyesconfig', for each architecture. Runs the script via
|
|
'make scriptconfig'.
|
|
"""
|
|
shell("make scriptconfig SCRIPT=Kconfiglib/allyesconfig.py "
|
|
"PYTHONCMD='{}'".format(sys.executable))
|
|
shell("mv .config ._config")
|
|
shell("scripts/kconfig/conf --allyesconfig Kconfig")
|
|
|
|
compare_configs(arch)
|
|
|
|
|
|
def test_sanity(arch, srcarch):
|
|
"""
|
|
Do sanity checks on each configuration and call all public methods on all
|
|
symbols, choices, and menu nodes for all architectures to make sure we
|
|
never crash or hang.
|
|
"""
|
|
print("For {}...".format(arch))
|
|
|
|
kconf = Kconfig()
|
|
|
|
for sym in kconf.defined_syms:
|
|
verify(sym._visited == 2,
|
|
"{} has broken dependency loop detection (_visited = {})"
|
|
.format(sym.name, sym._visited))
|
|
|
|
kconf.modules
|
|
kconf.defconfig_list
|
|
kconf.defconfig_filename
|
|
|
|
# Legacy warning functions
|
|
kconf.enable_redun_warnings()
|
|
kconf.disable_redun_warnings()
|
|
kconf.enable_undef_warnings()
|
|
kconf.disable_undef_warnings()
|
|
kconf.enable_warnings()
|
|
kconf.disable_warnings()
|
|
kconf.enable_stderr_warnings()
|
|
kconf.disable_stderr_warnings()
|
|
|
|
kconf.mainmenu_text
|
|
kconf.unset_values()
|
|
|
|
kconf.write_autoconf("/dev/null")
|
|
|
|
# No tempfile.TemporaryDirectory in Python 2
|
|
tmpdir = tempfile.mkdtemp()
|
|
kconf.sync_deps(os.path.join(tmpdir, "deps")) # Create
|
|
kconf.sync_deps(os.path.join(tmpdir, "deps")) # Update
|
|
shutil.rmtree(tmpdir)
|
|
|
|
# Python 2/3 compatible
|
|
for key, sym in kconf.syms.items():
|
|
verify(isinstance(key, str), "weird key '{}' in syms dict".format(key))
|
|
|
|
verify(not sym.is_constant, sym.name + " in 'syms' and constant")
|
|
|
|
verify(sym not in kconf.const_syms,
|
|
sym.name + " in both 'syms' and 'const_syms'")
|
|
|
|
for dep in sym._dependents:
|
|
verify(not dep.is_constant,
|
|
"the constant symbol {} depends on {}"
|
|
.format(dep.name, sym.name))
|
|
|
|
sym.__repr__()
|
|
sym.__str__()
|
|
sym.assignable
|
|
kconf.disable_warnings()
|
|
sym.set_value(2)
|
|
sym.set_value("foo")
|
|
sym.unset_value()
|
|
kconf.enable_warnings() # Legacy warning function
|
|
sym.str_value
|
|
sym.tri_value
|
|
sym.type
|
|
sym.user_value
|
|
sym.visibility
|
|
|
|
for sym in kconf.defined_syms:
|
|
verify(sym.nodes, sym.name + " is defined but lacks menu nodes")
|
|
|
|
verify(not (sym.orig_type not in (BOOL, TRISTATE) and sym.choice),
|
|
sym.name + " is a choice symbol but not bool/tristate")
|
|
|
|
for key, sym in kconf.const_syms.items():
|
|
verify(isinstance(key, str),
|
|
"weird key '{}' in const_syms dict".format(key))
|
|
|
|
verify(sym.is_constant,
|
|
'"{}" is in const_syms but not marked constant'
|
|
.format(sym.name))
|
|
|
|
verify(not sym.nodes,
|
|
'"{}" is constant but has menu nodes'.format(sym.name))
|
|
|
|
verify(not sym._dependents,
|
|
'"{}" is constant but is a dependency of some symbol'
|
|
.format(sym.name))
|
|
|
|
verify(not sym.choice,
|
|
'"{}" is constant and a choice symbol'.format(sym.name))
|
|
|
|
sym.__repr__()
|
|
sym.__str__()
|
|
sym.assignable
|
|
kconf.disable_warnings()
|
|
sym.set_value(2)
|
|
sym.set_value("foo")
|
|
sym.unset_value()
|
|
kconf.enable_warnings() # Legacy warning function
|
|
sym.str_value
|
|
sym.tri_value
|
|
sym.type
|
|
sym.visibility
|
|
|
|
for choice in kconf.choices:
|
|
for sym in choice.syms:
|
|
verify(sym.choice is choice,
|
|
"{0} is in choice.syms but 'sym.choice' is not the choice"
|
|
.format(sym.name))
|
|
|
|
verify(sym.type in (BOOL, TRISTATE),
|
|
"{} is a choice symbol but is not a bool/tristate"
|
|
.format(sym.name))
|
|
|
|
choice.__str__()
|
|
choice.__repr__()
|
|
choice.str_value
|
|
choice.tri_value
|
|
choice.user_value
|
|
choice.assignable
|
|
choice.selection
|
|
choice.type
|
|
choice.visibility
|
|
|
|
# Menu nodes
|
|
|
|
node = kconf.top_node
|
|
|
|
while 1:
|
|
# Everything else should be well exercised elsewhere
|
|
node.__repr__()
|
|
node.__str__()
|
|
verify(isinstance(node.item, (Symbol, Choice)) or \
|
|
node.item in (MENU, COMMENT),
|
|
"'{}' appeared as a menu item".format(node.item))
|
|
|
|
if node.list is not None:
|
|
node = node.list
|
|
|
|
elif node.next is not None:
|
|
node = node.next
|
|
|
|
else:
|
|
while node.parent is not None:
|
|
node = node.parent
|
|
if node.next is not None:
|
|
node = node.next
|
|
break
|
|
else:
|
|
break
|
|
|
|
|
|
def test_alldefconfig(arch, srcarch):
|
|
"""
|
|
Verify that alldefconfig.py generates the same .config as
|
|
'make alldefconfig', for each architecture. Runs the script via
|
|
'make scriptconfig'.
|
|
"""
|
|
shell("make scriptconfig SCRIPT=Kconfiglib/alldefconfig.py "
|
|
"PYTHONCMD='{}'".format(sys.executable))
|
|
shell("mv .config ._config")
|
|
shell("scripts/kconfig/conf --alldefconfig Kconfig")
|
|
|
|
compare_configs(arch)
|
|
|
|
|
|
def test_defconfig(arch, srcarch):
|
|
"""
|
|
Verify that Kconfiglib generates the same .config as scripts/kconfig/conf,
|
|
for each architecture/defconfig pair. In obsessive mode, this test includes
|
|
nonsensical groupings of arches with defconfigs from other arches (every
|
|
arch/defconfig combination) and takes an order of magnitude longer time to
|
|
run.
|
|
|
|
With logging enabled, this test appends any failures to a file
|
|
test_defconfig_fails in the root.
|
|
"""
|
|
kconf = Kconfig()
|
|
|
|
if obsessive:
|
|
defconfigs = []
|
|
|
|
# Collect all defconfigs. This could be done once instead, but it's
|
|
# a speedy operation comparatively.
|
|
for srcarch_ in os.listdir("arch"):
|
|
defconfigs.extend(defconfig_files(srcarch_))
|
|
else:
|
|
defconfigs = defconfig_files(srcarch)
|
|
|
|
# Test architecture for each defconfig
|
|
|
|
for defconfig in defconfigs:
|
|
rm_configs()
|
|
|
|
kconf.load_config(defconfig)
|
|
kconf.write_config("._config")
|
|
shell("scripts/kconfig/conf --defconfig='{}' Kconfig".
|
|
format(defconfig))
|
|
|
|
arch_defconfig_str = " {:14}with {:60} ".format(arch, defconfig)
|
|
|
|
if equal_configs():
|
|
print(arch_defconfig_str + "OK")
|
|
else:
|
|
print(arch_defconfig_str + "FAIL")
|
|
fail()
|
|
if log:
|
|
with open("test_defconfig_fails", "a") as fail_log:
|
|
fail_log.write("{} with {} did not match\n"
|
|
.format(arch, defconfig))
|
|
|
|
|
|
def test_min_config(arch, srcarch):
|
|
"""
|
|
Verify that Kconfiglib generates the same .config as 'make savedefconfig'
|
|
for each architecture/defconfig pair.
|
|
"""
|
|
kconf = Kconfig()
|
|
|
|
if obsessive_min_config:
|
|
defconfigs = []
|
|
for srcarch_ in os.listdir("arch"):
|
|
defconfigs.extend(defconfig_files(srcarch_))
|
|
else:
|
|
defconfigs = defconfig_files(srcarch)
|
|
|
|
for defconfig in defconfigs:
|
|
rm_configs()
|
|
|
|
kconf.load_config(defconfig)
|
|
kconf.write_min_config("._config")
|
|
|
|
shell("cp {} .config".format(defconfig))
|
|
|
|
shell("scripts/kconfig/conf --savedefconfig=.config Kconfig")
|
|
|
|
arch_defconfig_str = " {:14}with {:60} ".format(arch, defconfig)
|
|
|
|
if equal_configs():
|
|
print(arch_defconfig_str + "OK")
|
|
else:
|
|
print(arch_defconfig_str + "FAIL")
|
|
|
|
|
|
#
|
|
# Helper functions
|
|
#
|
|
|
|
|
|
def defconfig_files(srcarch):
|
|
# Yields a list of defconfig file filenames for a particular srcarch
|
|
# subdirectory (arch/<srcarch>/)
|
|
|
|
srcarch_dir = os.path.join("arch", srcarch)
|
|
|
|
# Some arches have a defconfig in the root of their arch/<arch>/ directory
|
|
root_defconfig = os.path.join(srcarch_dir, "defconfig")
|
|
if os.path.exists(root_defconfig):
|
|
yield root_defconfig
|
|
|
|
# Assume all files in the arch/<arch>/configs/ directory (if it exists) are
|
|
# configurations
|
|
defconfigs_dir = os.path.join(srcarch_dir, "configs")
|
|
|
|
if not os.path.isdir(defconfigs_dir):
|
|
return
|
|
|
|
for dirpath, _, filenames in os.walk(defconfigs_dir):
|
|
for filename in filenames:
|
|
yield os.path.join(dirpath, filename)
|
|
|
|
|
|
def rm_configs():
|
|
# Delete any old ".config" (generated by the C implementation) and
|
|
# "._config" (generated by us), if present.
|
|
|
|
def rm_if_exists(f):
|
|
if os.path.exists(f):
|
|
os.remove(f)
|
|
|
|
rm_if_exists(".config")
|
|
rm_if_exists("._config")
|
|
|
|
|
|
def compare_configs(arch):
|
|
if equal_configs():
|
|
print("{:14}OK".format(arch))
|
|
else:
|
|
print("{:14}FAIL".format(arch))
|
|
fail()
|
|
|
|
|
|
def equal_configs():
|
|
with open(".config") as f:
|
|
their = f.readlines()
|
|
|
|
# Strip the header generated by 'conf'
|
|
i = 0
|
|
for line in their:
|
|
if not line.startswith("#") or \
|
|
re.match(r"# CONFIG_(\w+) is not set", line):
|
|
break
|
|
i += 1
|
|
their = their[i:]
|
|
|
|
try:
|
|
f = open("._config")
|
|
except EnvironmentError as e:
|
|
if e.errno != errno.ENOENT:
|
|
raise
|
|
print("._config not found. Did you forget to apply the Makefile patch?")
|
|
return False
|
|
else:
|
|
with f:
|
|
our = f.readlines()
|
|
|
|
if their == our:
|
|
return True
|
|
|
|
# Print a unified diff to help debugging
|
|
print("Mismatched .config's! Unified diff:")
|
|
sys.stdout.writelines(difflib.unified_diff(their, our, fromfile="their",
|
|
tofile="our"))
|
|
|
|
return False
|
|
|
|
|
|
if __name__ == "__main__":
|
|
run_tests()
|