diff options
Diffstat (limited to 'testsuite.py')
| -rw-r--r-- | testsuite.py | 3210 |
1 files changed, 1343 insertions, 1867 deletions
diff --git a/testsuite.py b/testsuite.py index 11822ce..8ba0edc 100644 --- a/testsuite.py +++ b/testsuite.py @@ -1,48 +1,45 @@ -# This is a test suite for Kconfiglib. 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 +# 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 +# $ python Kconfiglib/testsuite.py # -# Some additional options can be turned on by passing arguments. With no argument, -# they default to off. +# Some additional options can be turned on by passing them as arguments. They +# default to off. # # - speedy: -# Run scripts/kconfig/conf directly when comparing outputs instead of using -# 'make' targets. Makes things a lot faster, but could break if Kconfig -# files start depending on additional environment variables besides ARCH and -# SRCARCH. (These would be set in the Makefiles in that case.) Safe as of -# Linux 4.1.0-rc8. +# Run scripts/kconfig/conf directly instead of using 'make' targets. Makes +# things a lot faster, but could break if Kconfig files start referencing +# additional environment variables beyond ARCH, SRCARCH, and KERNELVERSION. +# Safe as of Linux 4.14-rc3. # # - obsessive: -# By default, only valid arch/defconfig pairs will be tested. With this -# enabled, every arch will be tested with every defconfig, which increases -# the test time by an order of magnitude. Occasionally finds (usually very -# obscure) bugs, and I make sure everything passes with it. +# 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. # # - log: -# Log timestamped failures of the defconfig test to test_defconfig_fails in -# the root. Especially handy in obsessive mode. +# Log timestamped defconfig test failures to the file test_defconfig_fails. +# Handy in obsessive mode. # -# For example, to run in speedy mode with logging, run +# For example, this commands runs the test suite in speedy mode with logging +# enabled: # -# $ python Kconfiglib/testsuite.py speedy log +# $ python(3) Kconfiglib/testsuite.py speedy log # -# (PyPy also works, and runs the defconfig tests roughly 20% faster on my -# machine. Some of the other tests get an even greater speed-up.) -# -# The tests have been roughly arranged in order of time needed. +# 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. -from __future__ import print_function - +from kconfiglib import Kconfig, Symbol, Choice, COMMENT, MENU, \ + BOOL, TRISTATE, HEX, STRING, \ + KconfigSyntaxError, expr_value import difflib import errno -import kconfiglib import os import platform import re @@ -51,140 +48,147 @@ import sys import textwrap import time -speedy_mode = False -obsessive_mode = False -log_mode = False +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)) # Assign this to avoid warnings from Kconfiglib. Nothing in the kernel's # Kconfig files seems to actually look at the value as of 3.7.0-rc8. This is # only relevant for the test suite, as this will get set by the kernel Makefile # when using (i)scriptconfig. -os.environ["KERNELVERSION"] = "3.7.0" +os.environ["KERNELVERSION"] = "1" # Prevent accidental loading of configuration files by removing # KCONFIG_ALLCONFIG from the environment os.environ.pop("KCONFIG_ALLCONFIG", None) +speedy = False +obsessive = False +log = False + # Number of arch/defconfig pairs tested so far nconfigs = 0 def run_tests(): - global speedy_mode, obsessive_mode, log_mode + global speedy, obsessive, log for s in sys.argv[1:]: if s == "speedy": - speedy_mode = True + speedy = True print("Speedy mode enabled") elif s == "obsessive": - obsessive_mode = True + obsessive = True print("Obsessive mode enabled") elif s == "log": - log_mode = True + log = True print("Log mode enabled") else: print("Unrecognized option '{}'".format(s)) - return run_selftests() run_compatibility_tests() def run_selftests(): - """Runs tests on specific configurations provided by us.""" - # - # Helper functions + # Common helper functions. These all expect 'c' to hold the current + # configuration. # + TRI_TO_STR = {0: "n", 1: "m", 2: "y"} + def verify_value(sym_name, val): - """Verifies that a symbol has a particular value.""" - sym = c[sym_name] - sym_val = sym.get_value() - verify(sym_val == val, - "{} should have the value '{}' but has the value '{}'" - .format(sym_name, val, sym_val)) - - def assign_and_verify_new_value(sym_name, user_val, new_val): - """Assigns a user value to the symbol and verifies the new value.""" - sym = c[sym_name] - sym_old_val = sym.get_value() - sym.set_user_value(user_val) - sym_new_val = sym.get_value() - verify(sym_new_val == new_val, - "{} should have the new value '{}' after being assigned the " - "user value '{}'. Instead, the value is '{}'. The old " - "value was '{}'." - .format(sym_name, new_val, user_val, sym_new_val, sym_old_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_new_value(), with the expected value being - the value just set.""" - assign_and_verify_new_value(sym_name, user_val, user_val) - - def assign_and_verify_new_user_value(sym_name, user_val, new_user_val): - """Assigns a user value to the symbol and verifies the new user - value.""" - sym = c[sym_name] - sym_old_user_val = sym.get_user_value() - sym.set_user_value(user_val) - sym_new_user_val = sym.get_user_value() - verify(sym_new_user_val == new_user_val, - "{} should have the user value '{}' after being assigned " - "the user value '{}'. Instead, the new user value was '{}'. " - "The old user value was '{}'." - .format(sym_name, new_user_val, user_val, sym_new_user_val, - sym_old_user_val)) - - print("Running selftests...\n") - - print("Testing tristate comparisons...") - - def verify_truth_table(comp_fn, *bools): - bools_list = list(bools) - for (x, y) in (("n", "n"), ("n", "m"), ("n", "y"), - ("m", "n"), ("m", "m"), ("m", "y"), - ("y", "n"), ("y", "m"), ("y", "y")): - expected = bools_list.pop(0) - verify(comp_fn(x, y) == expected, - "Expected {} on ('{}', '{}') to be {}". - format(comp_fn, x, y, expected)) - - verify_truth_table(kconfiglib.tri_less, - False, True, True, - False, False, True, - False, False, False) - - verify_truth_table(kconfiglib.tri_less_eq, - True, True, True, - False, True, True, - False, False, True) - - verify_truth_table(kconfiglib.tri_greater, - False, False, False, - True, False, False, - True, True, False) - - verify_truth_table(kconfiglib.tri_greater_eq, - True, False, False, - True, True, False, - True, True, True) + """ + 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)) # - # String literal lexing. (This tests an internal API.) + # Selftests # - print("Testing string literal (constant symbol) lexing...") + print("Testing string literal lexing") - c = kconfiglib.Config("Kconfiglib/tests/empty") + # Dummy empty configuration just to get a Kconfig object + c = Kconfig("Kconfiglib/tests/empty") def verify_string_lex(s, res): - """Verifies that the string token 'res' is produced from lexing 's'. - Strips the first and last characters from 's' so we can use readable - raw strings as input.""" - s = s[1:-1] - s_res = c._tokenize(s, for_eval = True).get_next() - verify(s_res == res, - "'{}' produced the string token '{}'. Expected '{}'." - .format(s, s_res, res)) + """ + Verifies that a constant symbol with the name 'res' is produced from + lexing 's' + """ + c.eval_string(s) + verify(c._tokens[0].name == res, + "expected <{}> to produced the constant symbol <{}>, " + 'produced <{}>'.format(s[1:-1], c._tokens[0].name, res)) verify_string_lex(r""" "" """, "") verify_string_lex(r""" '' """, "") @@ -215,16 +219,17 @@ def run_selftests(): verify_string_lex(r""" '\a\\"\b\c\'"d' """, "a\\\"bc'\"d") def verify_string_bad(s): - """Verifies that tokenizing 's' throws a Kconfig_Syntax_Error. Strips - the first and last characters from 's' so we can use readable raw - strings as input.""" - s = s[1:-1] + """ + Verifies that tokenizing 's' throws a KconfigSyntaxError. Strips the + first and last characters from 's' so we can use readable raw strings + as input. + """ try: - c._tokenize(s, for_eval = True) - except kconfiglib.Kconfig_Syntax_Error: + c.eval_string(s) + except KconfigSyntaxError: pass else: - fail("Tokenization of '{}' should have failed.".format(s)) + fail("expected tokenization of {} to fail, didn't".format(s[1:-1])) verify_string_bad(r""" " """) verify_string_bad(r""" ' """) @@ -235,279 +240,192 @@ def run_selftests(): verify_string_bad(r""" "foo """) verify_string_bad(r""" 'foo """) - # - # is_modifiable() - # - - print("Testing is_modifiable() and range queries...") - - c = kconfiglib.Config("Kconfiglib/tests/Kmodifiable") - - for sym_name in ("VISIBLE", "TRISTATE_SELECTED_TO_M", "VISIBLE_STRING", - "VISIBLE_INT", "VISIBLE_HEX"): - sym = c[sym_name] - verify(sym.is_modifiable(), - "{} should be modifiable".format(sym_name)) - - for sym_name in ("n", "m", "y", "NOT_VISIBLE", "SELECTED_TO_Y", - "BOOL_SELECTED_TO_M", "M_VISIBLE_TRISTATE_SELECTED_TO_M", - "NOT_VISIBLE_STRING", "NOT_VISIBLE_INT", "NOT_VISIBLE_HEX"): - sym = c[sym_name] - verify(not sym.is_modifiable(), - "{} should not be modifiable".format(sym_name)) - # - # get_lower/upper_bound() and get_assignable_values() - # - - c = kconfiglib.Config("Kconfiglib/tests/Kbounds") - - def verify_bounds(sym_name, low, high): - sym = c[sym_name] - sym_low = sym.get_lower_bound() - sym_high = sym.get_upper_bound() - verify(sym_low == low and sym_high == high, - "Incorrectly calculated bounds for {}: {}-{}. " - "Expected {}-{}.".format(sym_name, sym_low, sym_high, - low, high)) - # See that we get back the corresponding range from - # get_assignable_values() - if sym_low is None: - vals = sym.get_assignable_values() - verify(vals == [], - "get_assignable_values() thinks there should be assignable " - "values for {} ({}) but not get_lower/upper_bound()". - format(sym_name, vals)) - if sym.get_type() in (kconfiglib.BOOL, kconfiglib.TRISTATE): - verify(not sym.is_modifiable(), - "get_lower_bound() thinks there should be no " - "assignable values for the bool/tristate {} but " - "is_modifiable() thinks it should be modifiable". - format(sym_name)) - else: - tri_to_int = { "n" : 0, "m" : 1, "y" : 2 } - bound_range = ["n", "m", "y"][tri_to_int[sym_low] : - tri_to_int[sym_high] + 1] - assignable_range = sym.get_assignable_values() - verify(bound_range == assignable_range, - "get_lower/upper_bound() thinks the range for {} should " - "be {} while get_assignable_values() thinks it should be " - "{}".format(sym_name, bound_range, assignable_range)) - if sym.get_type() in (kconfiglib.BOOL, kconfiglib.TRISTATE): - verify(sym.is_modifiable(), - "get_lower/upper_bound() thinks the range for the " - "bool/tristate {} should be {} while is_modifiable() " - "thinks the symbol should not be modifiable". - format(sym_name, bound_range)) - - verify_bounds("n", None, None) - verify_bounds("m", None, None) - verify_bounds("y", None, None) - verify_bounds("Y_VISIBLE_BOOL", "n", "y") - verify_bounds("Y_VISIBLE_TRISTATE", "n", "y") - verify_bounds("M_VISIBLE_BOOL", "n", "y") - verify_bounds("M_VISIBLE_TRISTATE", "n", "m") - verify_bounds("Y_SELECTED_BOOL", None, None) - verify_bounds("M_SELECTED_BOOL", None, None) - verify_bounds("Y_SELECTED_TRISTATE", None, None) - verify_bounds("M_SELECTED_TRISTATE", "m", "y") - verify_bounds("M_SELECTED_M_VISIBLE_TRISTATE", None, None) - verify_bounds("N_IMPLIED_BOOL", "n", "y") - verify_bounds("N_IMPLIED_TRISTATE", "n", "y") - verify_bounds("M_IMPLIED_BOOL", "n", "y") - verify_bounds("M_IMPLIED_TRISTATE", "n", "y") - verify_bounds("Y_IMPLIED_BOOL", "n", "y") - verify_bounds("Y_IMPLIED_TRISTATE", "n", "y") - verify_bounds("STRING", None, None) - verify_bounds("INT", None, None) - verify_bounds("HEX", None, None) - - # - # eval() - # + print("Testing expression evaluation") - print("Testing eval()...") - - c = kconfiglib.Config("Kconfiglib/tests/Keval") + c = Kconfig("Kconfiglib/tests/Keval") def verify_eval(expr, val): - res = c.eval(expr) + res = c.eval_string(expr) verify(res == val, "'{}' evaluated to {}, expected {}".format(expr, res, val)) - def verify_eval_bad(expr): - try: - c.eval(expr) - except kconfiglib.Kconfig_Syntax_Error: - pass - else: - fail('eval("{}") should throw Kconfig_Syntax_Error' - .format(expr)) - # No modules - verify_eval("n", "n") - verify_eval("m", "n") - verify_eval("y", "y") - verify_eval("'n'", "n") - verify_eval("'m'", "n") - verify_eval("'y'", "y") - verify_eval("M", "y") + 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_user_value("y") - verify_eval("n", "n") - verify_eval("m", "m") - verify_eval("y", "y") - verify_eval("'n'", "n") - verify_eval("'m'", "m") - verify_eval("'y'", "y") - verify_eval("M", "m") - verify_eval("(Y || N) && (m && y)", "m") - - # Non-bool/non-tristate symbols are always "n" in a tristate sense - verify_eval("Y_STRING", "n") - verify_eval("Y_STRING || m", "m") - - # As are all constants besides "y" and "m" - verify_eval('"foo"', "n") - verify_eval('"foo" || "bar"', "n") + 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", "y") - verify_eval("N = n", "y") - verify_eval("N = 'n'", "y") - verify_eval("N != N", "n") - verify_eval("N != n", "n") - verify_eval("N != 'n'", "n") - - verify_eval("M = M", "y") - verify_eval("M = m", "y") - verify_eval("M = 'm'", "y") - verify_eval("M != M", "n") - verify_eval("M != m", "n") - verify_eval("M != 'm'", "n") - - verify_eval("Y = Y", "y") - verify_eval("Y = y", "y") - verify_eval("Y = 'y'", "y") - verify_eval("Y != Y", "n") - verify_eval("Y != y", "n") - verify_eval("Y != 'y'", "n") - - verify_eval("N != M", "y") - verify_eval("N != Y", "y") - verify_eval("M != Y", "y") - - # string/int/hex - verify_eval("Y_STRING = y", "y") - verify_eval("Y_STRING = 'y'", "y") - verify_eval('FOO_BAR_STRING = "foo bar"', "y") - verify_eval('FOO_BAR_STRING != "foo bar baz"', "y") - verify_eval('INT_37 = 37', "y") - verify_eval("INT_37 = '37'", "y") - verify_eval('HEX_0X37 = 0x37', "y") - verify_eval("HEX_0X37 = '0x37'", "y") + 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'", "y") - verify_eval("HEX_0X37 = '0x0037'", "y") + 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) - # Compare some constants... - verify_eval('"foo" != "bar"', "y") - verify_eval('"foo" = "bar"', "n") - verify_eval('"foo" = "foo"', "y") # Undefined symbols get their name as their value - c.set_print_warnings(False) - verify_eval("'not_defined' = not_defined", "y") - verify_eval("not_defined_2 = not_defined_2", "y") - verify_eval("not_defined_1 != not_defined_2", "y") + c.disable_warnings() + 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", "y") - verify_eval("38 < INT_37", "n") - verify_eval("INT_37 < '38'", "y") - verify_eval("'38' < INT_37", "n") - verify_eval("INT_37 < 138", "y") - verify_eval("138 < INT_37", "n") - verify_eval("INT_37 < '138'", "y") - verify_eval("'138' < INT_37", "n") - verify_eval("INT_37 < -138", "n") - verify_eval("-138 < INT_37", "y") - verify_eval("INT_37 < '-138'", "n") - verify_eval("'-138' < INT_37", "y") - verify_eval("INT_37 < 37", "n") - verify_eval("37 < INT_37", "n") - verify_eval("INT_37 < 36", "n") - verify_eval("36 < INT_37", "y") + 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", "y") # 38 - verify_eval("INT_37 < 0x25", "n") # 37 - verify_eval("INT_37 < 0x24", "n") # 36 - verify_eval("HEX_0X37 < 56", "y") # 0x38 - verify_eval("HEX_0X37 < 55", "n") # 0x37 - verify_eval("HEX_0X37 < 54", "n") # 0x36 + 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", "y") - verify_eval("INT_37 <= 37", "y") - verify_eval("INT_37 <= 36", "n") - verify_eval("INT_37 > 38", "n") - verify_eval("INT_37 > 37", "n") - verify_eval("INT_37 > 36", "y") - verify_eval("INT_37 >= 38", "n") - verify_eval("INT_37 >= 37", "y") - verify_eval("INT_37 >= 36", "y") + 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", "y") - verify_eval("HEX_0X37 <= 0x37", "y") - verify_eval("HEX_0X37 <= 0x36", "n") - verify_eval("HEX_0X37 > 0x38", "n") - verify_eval("HEX_0X37 > 0x37", "n") - verify_eval("HEX_0X37 > 0x36", "y") - verify_eval("HEX_0X37 >= 0x38", "n") - verify_eval("HEX_0X37 >= 0x37", "y") - verify_eval("HEX_0X37 >= 0x36", "y") + 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", "y") - verify_eval("HEX_37 < 0x37", "n") - verify_eval("HEX_37 < 0x36", "n") + 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", "y") - verify_eval("INT_37 > HEX_0X37", "n") - verify_eval("HEX_0X37 < INT_37 ", "n") - verify_eval("HEX_0X37 > INT_37 ", "y") - verify_eval("INT_37 < INT_37 ", "n") - verify_eval("INT_37 <= INT_37 ", "y") - verify_eval("INT_37 > INT_37 ", "n") - verify_eval("INT_37 <= INT_37 ", "y") + 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) # Strings compare lexicographically - verify_eval("'aa' < 'ab'", "y") - verify_eval("'aa' > 'ab'", "n") - verify_eval("'ab' < 'aa'", "n") - verify_eval("'ab' > 'aa'", "y") - - # If one operand is numeric and the other not a valid number, we get 'n' - verify_eval("INT_37 < oops ", "n") - verify_eval("INT_37 <= oops ", "n") - verify_eval("INT_37 > oops ", "n") - verify_eval("INT_37 >= oops ", "n") - verify_eval("oops < INT_37", "n") - verify_eval("oops <= INT_37", "n") - verify_eval("oops > INT_37", "n") - verify_eval("oops >= INT_37", "n") + 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 KconfigSyntaxError: + pass + else: + fail('expected eval_string("{}") to throw KconfigSyntaxError, ' + "didn't".format(expr)) # The C implementation's parser can be pretty lax about syntax. Kconfiglib # sometimes needs to emulate that. Verify that some bad stuff throws - # Kconfig_Syntax_Error at least. + # KconfigSyntaxError at least. verify_eval_bad("") verify_eval_bad("&") verify_eval_bad("|") @@ -521,722 +439,593 @@ def run_selftests(): verify_eval_bad("X ||") verify_eval_bad("|| X") - # - # Text queries - # - print("Testing text queries...") + print("Testing Symbol.__str__()") + + def verify_str(item, s): + verify_equal(str(item), s[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 + prompt "basic" +""") + + verify_str(c.syms["ADVANCED"], """ +config ADVANCED + tristate + prompt "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 + prompt "prompt 2" + +menuconfig ADVANCED + prompt "prompt 3" if DEP2 + +config ADVANCED + help + second help text +""") + + 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 +""") + + verify_str(c.modules, """ +config MODULES + bool + prompt "MODULES" + option modules +""") + + verify_str(c.syms["OPTIONS"], """ +config OPTIONS + option allnoconfig_y + option defconfig_list + option env="ENV" +""") - def verify_print(o, s): - verify_equals(str(o), textwrap.dedent(s[1:])) + print("Testing Choice.__str__()") + + verify_str(c.named_choices["CHOICE"], """ +choice CHOICE + tristate + prompt "foo" + default CHOICE_1 + default CHOICE_2 if dep +""") - for var in ("ARCH", "SRCARCH", "srctree"): - os.environ.pop(var, None) + verify_str(c.named_choices["CHOICE"].nodes[0].next.item, """ +choice + tristate + prompt "no name" + optional +""") + + + 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> +""") - # The tests below aren't meant to imply that the format is set in stone. - # It's just to verify that the strings do not change unexpectedly. + verify_repr(c.syms["VISIBLE"], """ +<symbol VISIBLE, bool, "visible", value n, visibility y, direct deps y, Kconfiglib/tests/Krepr:14> +""") - # Printing of Config + c.syms["VISIBLE"].set_value(2) - c = kconfiglib.Config("Kconfiglib/tests/Ktext") + verify_repr(c.syms["VISIBLE"], """ +<symbol VISIBLE, bool, "visible", value y, user value y, visibility y, direct deps y, Kconfiglib/tests/Krepr:14> +""") - verify_print(c, """ - Configuration - File : Kconfiglib/tests/Ktext - Base directory : . - Value of $ARCH at creation time : (not set) - Value of $SRCARCH at creation time : (not set) - Value of $srctree at creation time : (not set) - Most recently loaded .config : (no .config loaded) - Print warnings : True - Print assignments to undefined symbols : False""") + verify_repr(c.syms["DIR_DEP_N"], """ +<symbol DIR_DEP_N, unknown, value "DIR_DEP_N", visibility n, direct deps n, Kconfiglib/tests/Krepr:17> +""") - os.environ["ARCH"] = "foo" - os.environ["SRCARCH"] = "bar" - os.environ["srctree"] = "baz" + 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:20> +""") - c = kconfiglib.Config("Kconfiglib/tests/Ktext", base_dir="foobar") - c.load_config("Kconfiglib/tests/empty") - c.set_print_warnings(False) - c.set_print_undef_assign(True) - - choice_print, choice_no_help, choice_empty_help, choice_help = \ - c.get_choices() - - verify_print(c, """ - Configuration - File : Kconfiglib/tests/Ktext - Base directory : foobar - Value of $ARCH at creation time : foo - Value of $SRCARCH at creation time : bar - Value of $srctree at creation time : baz - Most recently loaded .config : Kconfiglib/tests/empty - Print warnings : False - Print assignments to undefined symbols : True""") - - # Printing of Symbol - - verify_print(c["BASIC"], """ - Symbol BASIC - Type : bool - Value : "n" - User value : (no user value) - Visibility : "n" - Is choice item : False - Is defined : True - Is from env. : False - Is special : False - Prompts: - (no prompts) - Default values: - (no default values) - Selects: - (no selects) - Implies: - (no implies) - Reverse (select-related) dependencies: - (no reverse dependencies) - Weak reverse (imply-related) dependencies: - (no weak reverse dependencies) - Additional dependencies from enclosing menus and ifs: - (no additional dependencies) - Locations: Kconfiglib/tests/Ktext:1""") - - c["ADVANCED"].set_user_value("m") - - verify_print(c["ADVANCED"], """ - Symbol ADVANCED - Type : tristate - Value : "y" - User value : "m" - Visibility : "y" - Is choice item : False - Is defined : True - Is from env. : False - Is special : False - Prompts: - "advanced prompt 1" if y || BASIC && BASIC (value: "y") - "advanced prompt 2" - Default values: - y (value: "y") - Condition: BASIC && !BASIC (value: "n") - n (value: "n") - Condition: BASIC = DUMMY && X < Y && X <= Y && X > Y && X >= Y (value: "n") - Selects: - SELECTED_1 if BASIC && DUMMY (value: "n") - SELECTED_2 if !(DUMMY || BASIC) (value: "y") - Implies: - IMPLIED_1 if BASIC || DUMMY (value: "n") - IMPLIED_2 if !(DUMMY && BASIC) (value: "y") - Reverse (select-related) dependencies: - SELECTING_1 && BASIC || SELECTING_2 && !BASIC (value: "n") - Weak reverse (imply-related) dependencies: - IMPLYING_1 && DUMMY || IMPLYING_2 && !DUMMY (value: "n") - Additional dependencies from enclosing menus and ifs: - !BASIC && !BASIC (value: "y") - Locations: Kconfiglib/tests/Ktext:6 Kconfiglib/tests/Ktext:15""") - - verify_print(c["STRING"], """ - Symbol STRING - Type : string - Value : "foo" - User value : (no user value) - Visibility : "n" - Is choice item : False - Is defined : True - Is from env. : False - Is special : False - Prompts: - (no prompts) - Default values: - "foo" - Condition: (none) - "bar" - Condition: BAR (value: "n") - STRING2 (value: "baz") - Condition: BAZ (value: "n") - Selects: - (no selects) - Implies: - (no implies) - Reverse (select-related) dependencies: - (no reverse dependencies) - Weak reverse (imply-related) dependencies: - (no weak reverse dependencies) - Additional dependencies from enclosing menus and ifs: - !BASIC && !BASIC (value: "y") - Locations: Kconfiglib/tests/Ktext:18""") - - verify_print(c["HAS_RANGES"], """ - Symbol HAS_RANGES - Type : int - Value : "1" - User value : (no user value) - Visibility : "y" - Is choice item : False - Is defined : True - Is from env. : False - Is special : False - Ranges: - [1, 2] if !DUMMY (value: "y") - [INT, INT] if DUMMY (value: "n") - [123, 456] - Prompts: - "ranged" - Default values: - (no default values) - Selects: - (no selects) - Implies: - (no implies) - Reverse (select-related) dependencies: - (no reverse dependencies) - Weak reverse (imply-related) dependencies: - (no weak reverse dependencies) - Additional dependencies from enclosing menus and ifs: - (no additional dependencies) - Locations: Kconfiglib/tests/Ktext:45""") - - # Printing of Choice - - verify_print(choice_print, """ - Choice - Name (for named choices): (no name) - Type : bool - Selected symbol : CHOICE_ITEM_1 - User value : (no user value) - Mode : "y" - Visibility : "y" - Optional : False - Prompts: - "choice" - Defaults: - (no default values) - Choice symbols: - CHOICE_ITEM_1 CHOICE_ITEM_2 CHOICE_ITEM_3 - Additional dependencies from enclosing menus and ifs: - (no additional dependencies) - Locations: Kconfiglib/tests/Ktext:51""") - - c["CHOICE_ITEM_2"].set_user_value("y") - - verify_print(choice_print, """ - Choice - Name (for named choices): (no name) - Type : bool - Selected symbol : CHOICE_ITEM_2 - User value : CHOICE_ITEM_2 - Mode : "y" - Visibility : "y" - Optional : False - Prompts: - "choice" - Defaults: - (no default values) - Choice symbols: - CHOICE_ITEM_1 CHOICE_ITEM_2 CHOICE_ITEM_3 - Additional dependencies from enclosing menus and ifs: - (no additional dependencies) - Locations: Kconfiglib/tests/Ktext:51""") - - # Printing of Menu - - verify_print(c.get_menus()[0], """ - Menu - Title : simple menu - 'depends on' dependencies : (no dependencies) - 'visible if' dependencies : (no dependencies) - Additional dependencies from enclosing menus and ifs: - (no additional dependencies) - Location: Kconfiglib/tests/Ktext:63""") - - verify_print(c.get_menus()[1], """ - Menu - Title : advanced menu - 'depends on' dependencies : !BASIC (value: "y") - 'visible if' dependencies : !DUMMY (value: "y") - Additional dependencies from enclosing menus and ifs: - !DUMMY (value: "y") - Location: Kconfiglib/tests/Ktext:67""") - - # Printing of Comment - - verify_print(c.get_comments()[0], """ - Comment - Text: simple comment - Dependencies: (no dependencies) - Additional dependencies from enclosing menus and ifs: - (no additional dependencies) - Location: Kconfiglib/tests/Ktext:73""") - - verify_print(c.get_comments()[1], """ - Comment - Text: advanced comment - Dependencies: !BASIC (value: "y") - Additional dependencies from enclosing menus and ifs: - !DUMMY (value: "y") - Location: Kconfiglib/tests/Ktext:76""") - - verify_equals(c["NO_HELP"].get_help(), None) - verify_equals(choice_no_help.get_help(), None) - verify_equals(c["EMPTY_HELP"].get_help(), "") - verify_equals(choice_empty_help.get_help(), "") - verify_equals(c["HELP_TERMINATED_BY_COMMENT"].get_help(), "a\nb\nc\n") - verify_equals(c["TRICKY_HELP"].get_help(), - "a\n b\n c\n\n d\n e\n f\n\n\ng\n h\n i\n") - verify_equals(c["S"].get_help(), "help for\nS\n") - verify_equals(choice_help.get_help(), "help for\nC\n") - - verify_equals(c["S"].get_name(), "S") - verify_equals(c.get_comments()[2].get_text(), "a comment") - verify_equals(c.get_menus()[2].get_title(), "a menu") + verify_repr(c.syms["MULTI_DEF"], """ +<symbol MULTI_DEF, unknown, value "MULTI_DEF", visibility n, direct deps y, Kconfiglib/tests/Krepr:25, Kconfiglib/tests/Krepr:26> +""") - # - # Prompt queries - # + verify_repr(c.syms["CHOICE_1"], """ +<symbol CHOICE_1, tristate, "choice sym", value n, visibility m, choice symbol, direct deps m, Kconfiglib/tests/Krepr:33> +""") - print("Testing prompt queries...") + verify_repr(c.modules, """ +<symbol MODULES, bool, value y, visibility n, is the modules symbol, direct deps y, Kconfiglib/tests/Krepr:1> +""") - def verify_prompts(sym_or_choice, prompts): - sym_or_choice_prompts = sym_or_choice.get_prompts() - verify(len(sym_or_choice_prompts) == len(prompts), - "Wrong number of prompts for " + sym_or_choice.get_name()) - for i in range(0, len(sym_or_choice_prompts)): - verify(sym_or_choice_prompts[i] == prompts[i], - "Prompt {} wrong for {}: Was '{}', should be '{}'". - format(i, sym_or_choice.get_name(), sym_or_choice_prompts[i], - prompts[i])) - def verify_sym_prompts(sym_name, *prompts): - verify_prompts(c[sym_name], prompts) + print("Testing Choice.__repr__()") - def verify_choice_prompts(choice, *prompts): - verify_prompts(choice, prompts) + verify_repr(c.named_choices["CHOICE"], """ +<choice CHOICE, tristate, "choice", mode m, visibility y, Kconfiglib/tests/Krepr:30> +""") - c = kconfiglib.Config("Kconfiglib/tests/Kprompt") + c.named_choices["CHOICE"].set_value(2) - # Symbols - verify_sym_prompts("NO_PROMPT") - verify_sym_prompts("SINGLE_PROMPT_1", "single prompt 1") - verify_sym_prompts("SINGLE_PROMPT_2", "single prompt 2") - verify_sym_prompts("MULTI_PROMPT", "prompt 1", "prompt 2", "prompt 3", "prompt 4") + verify_repr(c.named_choices["CHOICE"], """ +<choice CHOICE, tristate, "choice", mode y, user mode y, CHOICE_1 selected, visibility y, Kconfiglib/tests/Krepr:30> +""") - no_prompt_choice, single_prompt_1_choice, single_prompt_2_choice, multi_prompt_choice = \ - c.get_choices() + c.syms["CHOICE_2"].set_value(2) - # Choices - verify_choice_prompts(no_prompt_choice) - verify_choice_prompts(single_prompt_1_choice, "single prompt 1 choice") - verify_choice_prompts(single_prompt_2_choice, "single prompt 2 choice") - verify_choice_prompts(multi_prompt_choice, - "prompt 1 choice", "prompt 2 choice", "prompt 3 choice") + 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:30> +""") - # - # Location queries - # + 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:30> +""") + + verify_repr(c.syms["CHOICE_HOOK"].nodes[0].next.item, """ +<choice, tristate, "optional choice", mode n, visibility n, optional, Kconfiglib/tests/Krepr:43> +""") + + + 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:17> +""") + + verify_repr(c.syms["MULTI_DEF"].nodes[0], """ +<menu node for symbol MULTI_DEF, deps y, has next, Kconfiglib/tests/Krepr:25> +""") + + verify_repr(c.syms["MULTI_DEF"].nodes[1], """ +<menu node for symbol MULTI_DEF, deps y, has next, Kconfiglib/tests/Krepr:26> +""") + + verify_repr(c.syms["MENUCONFIG"].nodes[0], """ +<menu node for symbol MENUCONFIG, is menuconfig, deps y, has next, Kconfiglib/tests/Krepr:28> +""") - print("Testing location queries...") + 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:30> +""") - def verify_def_locations(sym_name, *locs): - sym_locs = c[sym_name].get_def_locations() - verify(len(sym_locs) == len(locs), - "Wrong number of def. locations for " + sym_name) - for i in range(0, len(sym_locs)): - verify(sym_locs[i] == locs[i], - "Wrong def. location for {}: Was {}, should be {}". - format(sym_name, sym_locs[i], locs[i])) + 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:43> +""") + + 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:50> +""") + + 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:55> +""") + + verify_repr(c.syms["COMMENT_HOOK"].nodes[0].next, """ +<menu node for comment, prompt "comment" (visibility y), deps y, Kconfiglib/tests/Krepr:61> +""") + + + print("Testing Kconfig.__repr__()") + + verify_repr(c, """ +<configuration with 15 symbols, main menu prompt "Linux Kernel Configuration", srctree not set, config symbol prefix "CONFIG_", warnings disabled, undef. symbol assignment warnings disabled> +""") + + os.environ["srctree"] = "srctree value" + os.environ["CONFIG_"] = "CONFIG_ value" + + c = Kconfig("Kconfiglib/tests/Krepr", warn=False) + c.enable_warnings() + c.enable_undef_warnings() + + verify_repr(c, """ +<configuration with 15 symbols, main menu prompt "Linux Kernel Configuration", srctree "srctree value", config symbol prefix "CONFIG_ value", warnings enabled, undef. symbol assignment warnings enabled> +""") + + 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:]) + + 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 and 'source'") + + 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["FOO"] = "tests" - - c = kconfiglib.Config("Kconfiglib/tests/Klocation", base_dir="Kconfiglib/") - - verify_def_locations("n") - verify_def_locations("m") - verify_def_locations("y") - - verify_def_locations("A", - ("Kconfiglib/tests/Klocation", 4), - ("Kconfiglib/tests/Klocation", 28), - ("Kconfiglib/tests/Klocation_included", 1), - ("Kconfiglib/tests/Klocation_included", 3)) - verify_def_locations("C", - ("Kconfiglib/tests/Klocation", 18)) - verify_def_locations("M", - ("Kconfiglib/tests/Klocation_included", 6)) - verify_def_locations("N", - ("Kconfiglib/tests/Klocation_included", 19)) - verify_def_locations("O", - ("Kconfiglib/tests/Klocation_included", 21)) - verify_def_locations("NOT_DEFINED") # No locations - - def verify_ref_locations(sym_name, *locs): - sym_locs = c[sym_name].get_ref_locations() - verify(len(sym_locs) == len(locs), - "Wrong number of ref. locations for " + sym_name) - for i in range(0, len(sym_locs)): - verify(sym_locs[i] == locs[i], - "Wrong ref. location for {}: Was {}, should be {}". - format(sym_name, sym_locs[i], locs[i])) - - # Reload without the slash at the end of 'base_dir' to get coverage for - # that as well - c = kconfiglib.Config("Kconfiglib/tests/Klocation", base_dir="Kconfiglib") - - verify_ref_locations("A", - ("Kconfiglib/tests/Klocation", 10), - ("Kconfiglib/tests/Klocation", 12), - ("Kconfiglib/tests/Klocation", 16), - ("Kconfiglib/tests/Klocation", 34), - ("Kconfiglib/tests/Klocation", 35), - ("Kconfiglib/tests/Klocation_included", 7), - ("Kconfiglib/tests/Klocation_included", 8), - ("Kconfiglib/tests/Klocation_included", 9), - ("Kconfiglib/tests/Klocation_included", 12), - ("Kconfiglib/tests/Klocation_included", 13), - ("Kconfiglib/tests/Klocation_included", 14), - ("Kconfiglib/tests/Klocation_included", 15), - ("Kconfiglib/tests/Klocation_included", 35), - ("Kconfiglib/tests/Klocation_included", 40), - ("Kconfiglib/tests/Klocation", 65), - ("Kconfiglib/tests/Klocation", 66), - ("Kconfiglib/tests/Klocation", 67), - ("Kconfiglib/tests/Klocation", 68), - ("Kconfiglib/tests/Klocation", 69), - ("Kconfiglib/tests/Klocation", 70), - ("Kconfiglib/tests/Klocation", 71), - ("Kconfiglib/tests/Klocation", 72), - ("Kconfiglib/tests/Klocation", 73)) - verify_ref_locations("C") - verify_ref_locations("NOT_DEFINED", - ("Kconfiglib/tests/Klocation", 12), - ("Kconfiglib/tests/Klocation", 29), - ("Kconfiglib/tests/Klocation_included", 12), - ("Kconfiglib/tests/Klocation_included", 35), - ("Kconfiglib/tests/Klocation_included", 41)) - - # Location queries for choices - - def verify_choice_locations(choice, *locs): - choice_locs = choice.get_def_locations() - verify(len(choice_locs) == len(locs), - "Wrong number of def. locations for choice") - for i in range(0, len(choice_locs)): - verify(choice_locs[i] == locs[i], - "Wrong def. location for choice: Was {}, should be {}". - format(choice_locs[i], locs[i])) - - choice_1, choice_2 = c.get_choices() - - # Throw in named choice test - verify(choice_1.get_name() == "B", - "The first choice should be called B") - verify(choice_2.get_name() is None, - "The second choice should have no name") - - verify_choice_locations(choice_1, - ("Kconfiglib/tests/Klocation", 15), - ("Kconfiglib/tests/Klocation_included", 24)) - verify_choice_locations(choice_2, - ("Kconfiglib/tests/Klocation_included", 17)) - - # Location queries for menus and comments - - def verify_location(menu_or_comment, loc): - menu_or_comment_loc = menu_or_comment.get_location() - verify(menu_or_comment_loc == loc, - "Wrong location for {} with text '{}': Was {}, should be " - "{}".format("menu" if menu_or_comment.is_menu() else "comment", - menu_or_comment.get_title() if - menu_or_comment.is_menu() else - menu_or_comment.get_text(), - menu_or_comment_loc, - loc)) - - menu_1, menu_2 = c.get_menus()[:-1] - comment_1, comment_2 = c.get_comments() - - verify_location(menu_1, ("Kconfiglib/tests/Klocation", 9)) - verify_location(menu_2, ("Kconfiglib/tests/Klocation_included", 5)) - verify_location(comment_1, ("Kconfiglib/tests/Klocation", 31)) - verify_location(comment_2, ("Kconfiglib/tests/Klocation_included", 36)) + os.environ["EXPANDED_FROM_ENV"] = "tests" + os.environ["srctree"] = "Kconfiglib/" - # - # Visibility queries - # + c = Kconfig("tests/Klocation") + + os.environ.pop("EXPANDED_FROM_ENV", None) + os.environ.pop("srctree", None) + + verify_locations(c.syms["SINGLE_DEF"].nodes, "tests/Klocation:4") + + verify_locations(c.syms["MULTI_DEF"].nodes, + "tests/Klocation:6", + "tests/Klocation:16", + "tests/Klocation_included:3", + "tests/Klocation:32") - print("Testing visibility queries...") + verify_locations(c.named_choices["CHOICE"].nodes, + "tests/Klocation_included:5") - c = kconfiglib.Config("Kconfiglib/tests/Kvisibility") + verify_locations([c.syms["MENU_HOOK"].nodes[0].next], + "tests/Klocation_included:10") - def verify_sym_visibility(sym_name, no_module_vis, module_vis): - sym = c[sym_name] + verify_locations([c.syms["COMMENT_HOOK"].nodes[0].next], + "tests/Klocation_included:15") - c["MODULES"].set_user_value("n") - sym_vis = sym.get_visibility() - verify(sym_vis == no_module_vis, - "{} should have visibility '{}' without modules, had " - "visibility '{}'". - format(sym_name, no_module_vis, sym_vis)) - c["MODULES"].set_user_value("y") - sym_vis = sym.get_visibility() - verify(sym_vis == module_vis, - "{} should have visibility '{}' with modules, had " - "visibility '{}'". - format(sym_name, module_vis, sym_vis)) + 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_sym_visibility("NO_PROMPT", "n", "n") - verify_sym_visibility("BOOL_n", "n", "n") - verify_sym_visibility("BOOL_m", "n", "y") # Promoted - verify_sym_visibility("BOOL_MOD", "y", "y") # Promoted - verify_sym_visibility("BOOL_y", "y", "y") - verify_sym_visibility("TRISTATE_m", "n", "m") - verify_sym_visibility("TRISTATE_MOD", "y", "m") # Promoted - verify_sym_visibility("TRISTATE_y", "y", "y") - verify_sym_visibility("BOOL_if_n", "n", "n") - verify_sym_visibility("BOOL_if_m", "n", "y") # Promoted - verify_sym_visibility("BOOL_if_y", "y", "y") - verify_sym_visibility("BOOL_menu_n", "n", "n") - verify_sym_visibility("BOOL_menu_m", "n", "y") # Promoted - verify_sym_visibility("BOOL_menu_y", "y", "y") - verify_sym_visibility("BOOL_choice_n", "n", "n") + 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 - verify_sym_visibility("BOOL_choice_m", "n", "n") - verify_sym_visibility("BOOL_choice_y", "y", "n") - c["TRISTATE_choice_m"].set_user_value("y") - c["TRISTATE_choice_y"].set_user_value("y") - # Still limited by the visibility of the choice - verify_sym_visibility("BOOL_choice_m", "n", "n") - # This one should become visible now though - verify_sym_visibility("BOOL_choice_y", "y", "y") - - verify_sym_visibility("TRISTATE_if_n", "n", "n") - verify_sym_visibility("TRISTATE_if_m", "n", "m") - verify_sym_visibility("TRISTATE_if_y", "y", "y") - verify_sym_visibility("TRISTATE_menu_n", "n", "n") - verify_sym_visibility("TRISTATE_menu_m", "n", "m") - verify_sym_visibility("TRISTATE_menu_y", "y", "y") - verify_sym_visibility("TRISTATE_choice_n", "n", "n") - verify_sym_visibility("TRISTATE_choice_m", "n", "m") - verify_sym_visibility("TRISTATE_choice_y", "y", "y") - - # Choice visibility - - def verify_choice_visibility(choice, no_module_vis, module_vis): - c["MODULES"].set_user_value("n") - choice_vis = choice.get_visibility() - verify(choice_vis == no_module_vis, - "choice {} should have visibility '{}' without modules, " - "has visibility '{}'". - format(choice.get_name(), no_module_vis, choice_vis)) - - c["MODULES"].set_user_value("y") - choice_vis = choice.get_visibility() - verify(choice_vis == module_vis, - "choice {} should have visibility '{}' with modules, " - "has visibility '{}'". - format(choice.get_name(), module_vis, choice_vis)) - - choice_bool_n, choice_bool_m, choice_bool_y, choice_tristate_n, \ - choice_tristate_m, choice_tristate_y, choice_tristate_if_m_and_y, \ - choice_tristate_menu_n_and_y \ - = c.get_choices()[3:] - - verify_choice_visibility(choice_bool_n, "n", "n") - verify_choice_visibility(choice_bool_m, "n", "y") # Promoted - verify_choice_visibility(choice_bool_y, "y", "y") - verify_choice_visibility(choice_tristate_n, "n", "n") - verify_choice_visibility(choice_tristate_m, "n", "m") - verify_choice_visibility(choice_tristate_y, "y", "y") - - verify_choice_visibility(choice_tristate_if_m_and_y, "n", "m") - verify_choice_visibility(choice_tristate_menu_n_and_y, "n", "n") - - # Menu visibility - - def verify_menu_visibility(menu, no_module_vis, module_vis): - c["MODULES"].set_user_value("n") - menu_vis = menu.get_visibility() - verify(menu_vis == no_module_vis, - "menu \"{}\" should have visibility '{}' without modules, " - "has visibility '{}'". - format(menu.get_title(), no_module_vis, menu_vis)) - - c["MODULES"].set_user_value("y") - menu_vis = menu.get_visibility() - verify(menu_vis == module_vis, - "menu \"{}\" should have visibility '{}' with modules, " - "has visibility '{}'". - format(menu.get_title(), module_vis, menu_vis)) - - menu_n, menu_m, menu_y, menu_if_n, menu_if_m, menu_if_y, \ - menu_if_m_and_y = c.get_menus()[4:-5] - verify(menu_n.get_title() == "menu n", "Ops - testing the wrong menus") - - verify_menu_visibility(menu_n, "n", "n") - verify_menu_visibility(menu_m, "n", "m") - verify_menu_visibility(menu_y, "y", "y") - verify_menu_visibility(menu_if_n, "n", "n") - verify_menu_visibility(menu_if_m, "n", "m") - verify_menu_visibility(menu_if_y, "y", "y") - verify_menu_visibility(menu_if_m_and_y, "n", "m") - - # Menu 'visible if' visibility - - menu_visible_if_n, menu_visible_if_m, menu_visible_if_y, \ - menu_visible_if_m_2 = c.get_menus()[12:] - - def verify_visible_if_visibility(menu, no_module_vis, module_vis): - c["MODULES"].set_user_value("n") - menu_vis = menu.get_visible_if_visibility() - verify(menu_vis == no_module_vis, - "menu \"{}\" should have 'visible if' visibility '{}' " - "without modules, has 'visible if' visibility '{}'". - format(menu.get_title(), no_module_vis, menu_vis)) - - c["MODULES"].set_user_value("y") - menu_vis = menu.get_visible_if_visibility() - verify(menu_vis == module_vis, - "menu \"{}\" should have 'visible if' visibility '{}' " - "with modules, has 'visible if' visibility '{}'". - format(menu.get_title(), module_vis, menu_vis)) - - # Ordinary visibility should not affect 'visible if' visibility - verify_visible_if_visibility(menu_n, "y", "y") - verify_visible_if_visibility(menu_if_n, "y", "y") - verify_visible_if_visibility(menu_m, "y", "y") - verify_visible_if_visibility(menu_if_m, "y", "y") - - verify_visible_if_visibility(menu_visible_if_n, "n", "n") - verify_visible_if_visibility(menu_visible_if_m, "n", "m") - verify_visible_if_visibility(menu_visible_if_y, "y", "y") - verify_visible_if_visibility(menu_visible_if_m_2, "n", "m") - - # Verify that 'visible if' visibility gets propagated to contained symbols - verify_sym_visibility("VISIBLE_IF_n", "n", "n") - verify_sym_visibility("VISIBLE_IF_m", "n", "m") - verify_sym_visibility("VISIBLE_IF_y", "y", "y") - verify_sym_visibility("VISIBLE_IF_m_2", "n", "m") - - # Comment visibility - - def verify_comment_visibility(comment, no_module_vis, module_vis): - c["MODULES"].set_user_value("n") - comment_vis = comment.get_visibility() - verify(comment_vis == no_module_vis, - "comment \"{}\" should have visibility '{}' without " - "modules, has visibility '{}'". - format(comment.get_text(), no_module_vis, comment_vis)) - - c["MODULES"].set_user_value("y") - comment_vis = comment.get_visibility() - verify(comment_vis == module_vis, - "comment \"{}\" should have visibility '{}' with " - "modules, has visibility '{}'". - format(comment.get_text(), module_vis, comment_vis)) - - comment_n, comment_m, comment_y, comment_if_n, comment_if_m, \ - comment_if_y, comment_m_nested = c.get_comments() - - verify_comment_visibility(comment_n, "n", "n") - verify_comment_visibility(comment_m, "n", "m") - verify_comment_visibility(comment_y, "y", "y") - verify_comment_visibility(comment_if_n, "n", "n") - verify_comment_visibility(comment_if_m, "n", "m") - verify_comment_visibility(comment_if_y, "y", "y") - verify_comment_visibility(comment_m_nested, "n", "m") + # 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_new_value("STRING_m", "foo bar", "foo bar") - assign_and_verify_new_value("INT_m", "123", "123") - assign_and_verify_new_value("HEX_m", "0x123", "0x123") - - # - # Object relations - # - - c = kconfiglib.Config("Kconfiglib/tests/Krelation") - - A, B, C, D, E, F, G, H, I = c["A"], c["B"], c["C"], c["D"], c["E"], c["F"],\ - c["G"], c["H"], c["I"] - choice_1, choice_2 = c.get_choices() - verify([menu.get_title() for menu in c.get_menus()] == - ["m1", "m2", "m3", "m4"], - "menu ordering is broken") - menu_1, menu_2, menu_3, menu_4 = c.get_menus() - - print("Testing object relations...") - - verify(A.get_parent() is None, "A should not have a parent") - verify(B.get_parent() is choice_1, "B's parent should be the first choice") - verify(C.get_parent() is choice_1, "C's parent should be the first choice") - verify(E.get_parent() is menu_1, "E's parent should be the first menu") - verify(E.get_parent().get_parent() is None, - "E's grandparent should be None") - verify(G.get_parent() is choice_2, + 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_const_unassignable("UNAME_RELEASE") + 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(G.get_parent().get_parent() is menu_2, - "G's grandparent should be the second menu") - # - # Object fetching (same test file) - # + verify(c.syms["G"].nodes[0].parent.parent.item == MENU, + "G's grandparent should be a menu") - print("Testing object fetching...") - - verify_equals(c.get_symbol("NON_EXISTENT"), None) - verify(c.get_symbol("A") is A, "get_symbol() is broken") - - verify(c.get_top_level_items() == [A, choice_1, menu_1, menu_3, menu_4], - "Wrong items at top level") - verify(c.get_symbols(False) == [A, B, C, D, E, F, G, H, I], - "get_symbols() is broken") - - verify(choice_1.get_items() == [B, C, D], - "Wrong get_items() items in 'choice'") - # Test Kconfig quirk - verify(choice_1.get_symbols() == [B, D], - "Wrong get_symbols() symbols in 'choice'") - - verify(menu_1.get_items() == [E, menu_2, I], "Wrong items in first menu") - verify(menu_1.get_symbols() == [E, I], "Wrong symbols in first menu") - verify(menu_1.get_items(True) == [E, menu_2, F, choice_2, G, H, I], - "Wrong recursive items in first menu") - verify(menu_1.get_symbols(True) == [E, F, G, H, I], - "Wrong recursive symbols in first menu") - verify(menu_2.get_items() == [F, choice_2], - "Wrong items in second menu") - verify(menu_2.get_symbols() == [F], - "Wrong symbols in second menu") - verify(menu_2.get_items(True) == [F, choice_2, G, H], - "Wrong recursive items in second menu") - verify(menu_2.get_symbols(True) == [F, G, H], - "Wrong recursive symbols in second menu") - # - # hex/int ranges - # + print("Testing hex/int ranges") - print("Testing hex/int ranges...") + c = Kconfig("Kconfiglib/tests/Krange") - c = kconfiglib.Config("Kconfiglib/tests/Krange") - - for sym_name in ("HEX_NO_RANGE", "INT_NO_RANGE", "HEX_40", "INT_40"): - sym = c[sym_name] - verify(not sym.has_ranges(), + 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[sym_name] - verify(sym.has_ranges(), "{} should 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", "") @@ -1246,9 +1035,9 @@ def run_selftests(): 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_new_value("HEX_NO_RANGE", "0x123", "0x123") - assign_and_verify_new_value("HEX_NO_RANGE", "123", "123") - assign_and_verify_new_value("INT_NO_RANGE", "123", "123") + 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") @@ -1272,16 +1061,19 @@ def run_selftests(): # User values and dependent ranges def verify_range(sym_name, low, high, default): - """Tests that the values in the range 'low'-'high' can be assigned, and + """ + Tests that the values in the range 'low'-'high' can be assigned, and that assigning values outside this range reverts the value back to - 'default' (None if it should revert back to "").""" - is_hex = (c[sym_name].get_type() == kconfiglib.HEX) + '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_new_user_value(sym_name, str(i), str(i)) + 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_new_user_value(sym_name, hex(i), hex(i)) + 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 @@ -1298,8 +1090,8 @@ def run_selftests(): too_low_str = str(low - 1) too_high_str = str(high + 1) - assign_and_verify_new_value(sym_name, too_low_str, default_str) - assign_and_verify_new_value(sym_name, too_high_str, default_str) + 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) @@ -1310,7 +1102,6 @@ def run_selftests(): verify_range("INT_RANGE_10_20_OK_DEFAULT", 10, 20, 15) verify_range("HEX_RANGE_10_20", 0x10, 0x20, 0x10) - verify_range("HEX_RANGE_0_10", 0x0, 0x10, None) verify_range("INT_RANGE_10_20", 10, 20, 10) verify_range("INT_RANGE_0_10", 0, 10, None) @@ -1321,15 +1112,15 @@ def run_selftests(): verify_value("HEX_40", "40") verify_value("INT_40", "40") - c["HEX_RANGE_10_20"].unset_user_value() - c["INT_RANGE_10_20"].unset_user_value() + 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["HEX_RANGE_10_20"].set_user_value("15") - c["INT_RANGE_10_20"].set_user_value("15") + 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_user_values() + c.unset_values() verify_range("HEX_RANGE_10_40_DEPENDENT", 0x10, 0x40, 0x10) verify_range("INT_RANGE_10_40_DEPENDENT", 10, 40, 10) @@ -1339,334 +1130,161 @@ def run_selftests(): verify_value("ACTIVE_RANGE", "1") # - # get_referenced_symbols() - # - - c = kconfiglib.Config("Kconfiglib/tests/Kref") - - # General function for checking get_referenced_symbols() output. - # Specialized for symbols below. - def verify_refs(item, refs_no_enclosing, refs_enclosing): - item_refs = item.get_referenced_symbols() - item_refs_enclosing = item.get_referenced_symbols(True) - - # For failure messages - if item.is_symbol(): - item_string = item.get_name() - elif item.is_choice(): - if item.get_name() is None: - item_string = "choice" - else: - item_string = "choice " + item.get_name() - elif item.is_menu(): - item_string = 'menu "{}"'.format(item.get_title()) - else: - # Comment - item_string = 'comment "{}"'.format(item.get_text()) - - verify(len(item_refs) == len(refs_no_enclosing), - "Wrong number of refs excluding enclosing for {}". - format(item_string)) - verify(len(item_refs_enclosing) == len(refs_enclosing), - "Wrong number of refs including enclosing for {}". - format(item_string)) - for r in [c[name] for name in refs_no_enclosing]: - verify(r in item_refs, - "{} should reference {} when excluding enclosing". - format(item_string, r.get_name())) - for r in [c[name] for name in refs_enclosing]: - verify(r in item_refs_enclosing, - "{} should reference {} when including enclosing". - format(item_string, r.get_name())) - - # Symbols referenced by symbols - - def verify_sym_refs(sym_name, refs_no_enclosing, refs_enclosing): - verify_refs(c[sym_name], refs_no_enclosing, refs_enclosing) - - verify_sym_refs("NO_REF", [], []) - verify_sym_refs("ONE_REF", ["A"], ["A"]) - own_refs = ["A", "B", "C", "D", "E", "F", "G", "H", "I", "J", "K", "L", - "M", "N", "O", "P", "Q", "R", "S", "T", "U", "V", "W", "X", - "Y", "Z", "AA"] - verify_sym_refs("MANY_REF", - own_refs, - own_refs + ["IF_REF_1", "IF_REF_2", "MENU_REF_1", - "MENU_REF_2"]) - - # Symbols referenced by choices - - own_refs = ["CHOICE_REF_4", "CHOICE_REF_5", "CHOICE_REF_6"] - verify_refs(c.get_choices()[0], - own_refs, - own_refs + ["CHOICE_REF_1", "CHOICE_REF_2", "CHOICE_REF_3"]) - - # Symbols referenced by menus - - own_refs = ["NO_REF", "MENU_REF_3"] - verify_refs(c.get_menus()[1], - own_refs, - own_refs + ["MENU_REF_1", "MENU_REF_2"]) - - # Symbols referenced by comments - - own_refs = ["COMMENT_REF_3", "COMMENT_REF_4", "COMMENT_REF_5"] - verify_refs(c.get_comments()[0], - own_refs, - own_refs + ["COMMENT_REF_1", "COMMENT_REF_2"]) - - # - # get_selected_symbols() (same test file) + # defconfig_filename # - def verify_selects(sym_name, selection_names): - sym = c[sym_name] - sym_selections = sym.get_selected_symbols() - verify(len(sym_selections) == len(selection_names), - "Wrong number of selects for {}".format(sym_name)) - for sel_name in selection_names: - sel_sym = c[sel_name] - verify(sel_sym in sym_selections, - "{} should be selected by {}".format(sel_name, sym_name)) - - verify_selects("n", []) - verify_selects("m", []) - verify_selects("y", []) - verify_selects("UNAME_RELEASE", []) + print("Testing defconfig_filename") - verify_selects("NO_REF", []) - verify_selects("MANY_REF", ["I", "N"]) - - # - # get_implied_symbols() (same test file) - # + c = Kconfig("Kconfiglib/tests/empty") + verify(c.defconfig_filename is None, + "defconfig_filename should be None with no defconfig_list symbol") - def verify_implies(sym_name, imply_names): - sym = c[sym_name] - sym_implies = sym.get_implied_symbols() - verify(len(sym_implies) == len(imply_names), - "Wrong number of implies for {}".format(sym_name)) - for imply_name in imply_names: - implied_sym = c[imply_name] - verify(implied_sym in sym_implies, - "{} should be implied by {}".format(imply_name, sym_name)) - - verify_implies("n", []) - verify_implies("m", []) - verify_implies("y", []) - verify_implies("UNAME_RELEASE", []) - - verify_implies("NO_REF", []) - verify_implies("MANY_REF", ["P", "U"]) - - # - # get_defconfig_filename() - # - - print("Testing get_defconfig_filename()...") - - c = kconfiglib.Config("Kconfiglib/tests/empty") - verify(c.get_defconfig_filename() is None, - "get_defconfig_filename() should be None with no defconfig_list " - "symbol") - - c = kconfiglib.Config("Kconfiglib/tests/Kdefconfig_nonexistent") - verify(c.get_defconfig_filename() is None, - "get_defconfig_filename() should be None when none of the files " - "in the defconfig_list symbol exist") + 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["BAR"] = "defconfig_2" - c = kconfiglib.Config("Kconfiglib/tests/Kdefconfig_existent_but_n") - verify(c.get_defconfig_filename() is None, - "get_defconfig_filename() should be None when the condition is " - "n for all the defaults") + 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 = kconfiglib.Config("Kconfiglib/tests/Kdefconfig_existent") - verify(c.get_defconfig_filename() == "Kconfiglib/tests/defconfig_2", - "get_defconfig_filename() should return the existent file " + c = Kconfig("Kconfiglib/tests/Kdefconfig_existent") + verify(c.defconfig_filename == "Kconfiglib/tests/defconfig_2", + "defconfig_filename should return the existent file " "Kconfiglib/tests/defconfig_2") - # Should also look relative to $srctree if the defconfig is an absolute - # path and not found + # Should also look relative to $srctree if the specified defconfig is a + # relative path and can't be opened - del os.environ["srctree"] - c = kconfiglib.Config("Kconfiglib/tests/Kdefconfig_srctree") - verify(c.get_defconfig_filename() == "Kconfiglib/tests/defconfig_2", - "get_defconfig_filename() returned wrong file with $srctree unset") + 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 = kconfiglib.Config("Kconfiglib/tests/Kdefconfig_srctree") - verify(c.get_defconfig_filename() == - "Kconfiglib/tests/sub/defconfig_in_sub", - "get_defconfig_filename() returned wrong file with $srctree set") + c = Kconfig("Kconfiglib/tests/Kdefconfig_srctree") + verify(c.defconfig_filename == "Kconfiglib/tests/sub/defconfig_in_sub", + "defconfig_filename gave wrong file with $srctree set") - # - # get_mainmenu_text() - # - print("Testing get_mainmenu_text()...") + print("Testing mainmenu_text") - c = kconfiglib.Config("Kconfiglib/tests/empty") - verify(c.get_mainmenu_text() is None, - "An empty Kconfig should not have a mainmenu text") + c = Kconfig("Kconfiglib/tests/empty") + verify(c.mainmenu_text == "Linux Kernel Configuration", + "An empty Kconfig should get a default main menu prompt") # Expanded in the mainmenu text os.environ["FOO"] = "bar baz" - c = kconfiglib.Config("Kconfiglib/tests/Kmainmenu") - verify(c.get_mainmenu_text() == "---bar baz---", + c = Kconfig("Kconfiglib/tests/Kmainmenu") + verify(c.mainmenu_text == "---bar baz---", "Wrong mainmenu text") - # - # Misc. minor APIs - # - os.environ["ENV_VAR"] = "foo" - # Contains reference to undefined environment variable, so disable warnings - c = kconfiglib.Config("Kconfiglib/tests/Kmisc", print_warnings = False) + print("Testing user_value") - print("Testing is_optional()...") - - verify(not c.get_choices()[0].is_optional(), - "First choice should not be optional") - verify(c.get_choices()[1].is_optional(), - "Second choice should be optional") - - print("Testing get_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.set_print_warnings(False) + c.disable_warnings() - syms = [c[name] for name in \ - ("BOOL", "TRISTATE", "STRING", "INT", "HEX")] + syms = [c.syms[name] for name in + ("BOOL", "TRISTATE", "STRING", "INT", "HEX")] for sym in syms: - verify(sym.get_user_value() is None, + verify(sym.user_value is None, "{} should not have a user value to begin with") # Assign valid values for the types - assign_and_verify_new_user_value("BOOL", "n", "n") - assign_and_verify_new_user_value("BOOL", "y", "y") - assign_and_verify_new_user_value("TRISTATE", "n", "n") - assign_and_verify_new_user_value("TRISTATE", "m", "m") - assign_and_verify_new_user_value("TRISTATE", "y", "y") - assign_and_verify_new_user_value("STRING", "foo bar", "foo bar") - assign_and_verify_new_user_value("INT", "123", "123") - assign_and_verify_new_user_value("HEX", "0x123", "0x123") + 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_new_user_value("BOOL", "m", "y") - assign_and_verify_new_user_value("BOOL", "foo", "y") - assign_and_verify_new_user_value("BOOL", "1", "y") - assign_and_verify_new_user_value("TRISTATE", "foo", "y") - assign_and_verify_new_user_value("TRISTATE", "1", "y") - assign_and_verify_new_user_value("INT", "foo", "123") - assign_and_verify_new_user_value("HEX", "foo", "0x123") + 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_user_value() - verify(s.get_user_value() is None, + s.unset_value() + verify(s.user_value is None, "{} should not have a user value after being reset". - format(s.get_name())) - - print("Testing is_defined()...") - - for sym_name in ("n", "m", "y", "UNAME_RELEASE", "A", "B", "C", "D", - "BOOL", "TRISTATE", "STRING", "INT", "HEX"): - sym = c[sym_name] - verify(sym.is_defined(), - "{} should be defined".format(sym_name)) - - for sym_name in ("NOT_DEFINED_1", "NOT_DEFINED_2", "NOT_DEFINED_3", - "NOT_DEFINED_4"): - sym = c[sym_name] - verify(not sym.is_defined(), - "{} should not be defined".format(sym_name)) - - print("Testing is_special()...") - - for sym_name in ("n", "m", "y", "UNAME_RELEASE", "FROM_ENV", - "FROM_ENV_MISSING"): - sym = c[sym_name] - verify(sym.is_special(), - "{} should be special".format(sym_name)) - - for sym_name in ("A", "B", "C", "D", "BOOL", "TRISTATE", "STRING", - "INT", "HEX", "NOT_DEFINED_1", "NOT_DEFINED_2", - "NOT_DEFINED_3", "NOT_DEFINED_4"): - sym = c[sym_name] - verify(not sym.is_special(), - "{} should not be special".format(sym_name)) - - print("Testing is_from_environment()...") - - for sym_name in ("FROM_ENV", "FROM_ENV_MISSING"): - sym = c[sym_name] - verify(sym.is_from_environment(), - "{} should be from the environment".format(sym_name)) - - for sym_name in ("n", "m", "y", "UNAME_RELEASE", "A", "B", "C", "D", - "BOOL", "TRISTATE", "STRING", "INT", "HEX", - "NOT_DEFINED_1", "NOT_DEFINED_2", "NOT_DEFINED_3", - "NOT_DEFINED_4"): - sym = c[sym_name] - verify(not sym.is_from_environment(), - "{} should not be from the environment".format(sym_name)) - - print("Testing is_choice_symbol()...") - - for sym_name in ("A", "B", "C", "D"): - sym = c[sym_name] - verify(sym.is_choice_symbol(), - "{} should be a choice symbol".format(sym_name)) - - for sym_name in ("n", "m", "y", "UNAME_RELEASE", "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"): - sym = c[sym_name] - verify(not sym.is_choice_symbol(), - "{} should not be a choice symbol".format(sym_name)) - - print("Testing is_allnoconfig_y()...") - - verify(not c["NOT_ALLNOCONFIG_Y"].is_allnoconfig_y(), + format(s.name)) + + + 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["ALLNOCONFIG_Y"].is_allnoconfig_y(), + verify(c.syms["ALLNOCONFIG_Y"].is_allnoconfig_y, "ALLNOCONFIG_Y should be allnoconfig_y") - print("Testing UNAME_RELEASE value...") + print("Testing UNAME_RELEASE") verify_value("UNAME_RELEASE", platform.uname()[2]) + ur = c.syms["UNAME_RELEASE"] + verify(ur.kconfig is c and + ur.type == STRING and + ur.env_var == "<uname release>", + "UNAME_RELEASE has wrong fields") - # Expansion of environment variables in Config.__init__'s base_dir - # parameter. Just make sure we don't crash when Kbase_dir 'source's a file - # from the same directory. - - os.environ["EnV_VaR1"] = "Kconfigl" - os.environ["EnV_VaR2"] = "ib/tests" - kconfiglib.Config("Kconfiglib/tests/Kbase_dir", - base_dir="$EnV_VaR1$EnV_VaR2/") - - # - # .config reading and writing - # - print("Testing .config reading and writing...") + print("Testing .config reading and writing") config_test_file = "Kconfiglib/tests/config_test" def write_and_verify_header(header): c.write_config(config_test_file, header) c.load_config(config_test_file) - verify(c.get_config_header() == header, + verify(c.config_header == header, "The header {} morphed into {} on loading" - .format(repr(header), repr(c.get_config_header()))) + .format(repr(header), repr(c.config_header))) def verify_file_contents(fname, contents): with open(fname, "r") as f: @@ -1677,15 +1295,15 @@ def run_selftests(): # Writing/reading strings with characters that need to be escaped - c = kconfiglib.Config("Kconfiglib/tests/Kescape") + c = Kconfig("Kconfiglib/tests/Kescape") # Test the default value - c.write_config(config_test_file + "_from_def") + c.write_config(config_test_file + "_from_def", header="") verify_file_contents(config_test_file + "_from_def", r'''CONFIG_STRING="\"\\"''' "\n") # Write our own value - c["STRING"].set_user_value(r'''\"a'\\''') - c.write_config(config_test_file + "_from_user") + c.syms["STRING"].set_value(r'''\"a'\\''') + c.write_config(config_test_file + "_from_user", header="") verify_file_contents(config_test_file + "_from_user", r'''CONFIG_STRING="\\\"a'\\\\"''' "\n") @@ -1695,61 +1313,21 @@ def run_selftests(): c.load_config(config_test_file + "_from_user") verify_value("STRING", r'''\"a'\\''') - # Reading and writing of .config headers - - verify(c.get_config_header() is None, - "Expected no header before .config loaded, got '{}'". - format(c.get_config_header())) - - write_and_verify_header("") - write_and_verify_header(" ") - write_and_verify_header("\n") - write_and_verify_header("\n\n") - write_and_verify_header("#") - write_and_verify_header("a") - write_and_verify_header("a\n") - write_and_verify_header("a\n\n") - write_and_verify_header("abcdef") - write_and_verify_header("foo\nbar baz\n\n\n qaz#") - - c.load_config("Kconfiglib/tests/empty") - verify(c.get_config_header() is None, - "Expected no header in empty .config, got '{}'". - format(c.get_config_header())) - - c.load_config("Kconfiglib/tests/config_hash") - verify(c.get_config_header() == "", - "Expected empty header in file with just '#', got '{}'". - format(c.get_config_header())) - - # TODO: Line joining (which stems from _FileFeed reuse) probably doesn't - # make sense within .config files. (The C implementation has no notion of - # continuation lines within .config files.) It's harmless except for fairly - # obscure cases though. - # - # Add a test for now just to get test coverage for _FileFeed.peek_next(), - # which is only used while reading .config files as of writing. - - c.load_config("Kconfiglib/tests/config_continuation") - verify(c.get_config_header() == - " Foo # Bar\n Baz # Foo # Bar\n Baz\n Foo", - "Continuation line handling within .config headers is broken") - # Appending values from a .config - c = kconfiglib.Config("Kconfiglib/tests/Kappend") + 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) + 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) + c.load_config("Kconfiglib/tests/config_set_string", replace=False) verify_value("BOOL", "y") verify_value("STRING", "foo bar") @@ -1766,79 +1344,24 @@ def run_selftests(): c.load_config("Kconfiglib/tests/config_indented") verify_value("IGNOREME", "y") - # - # get_config() - # - - print("Testing get_config()...") - c1 = kconfiglib.Config("Kconfiglib/tests/Kmisc", print_warnings = False) - c2 = kconfiglib.Config("Kconfiglib/tests/Kmisc", print_warnings = False) + print("Testing Kconfig fetching and separation") - c1_bool, c1_choice, c1_menu, c1_comment = c1["BOOL"], \ - c1.get_choices()[0], c1.get_menus()[0], c1.get_comments()[0] - c2_bool, c2_choice, c2_menu, c2_comment = c2["BOOL"], \ - c2.get_choices()[0], c2.get_menus()[0], c2.get_comments()[0] + 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)) - verify((c1_bool is not c2_bool) and (c1_choice is not c2_choice) and - (c1_menu is not c2_menu) and (c1_comment is not c2_comment) and - (c1_bool.get_config() is c1) and (c2_bool.get_config() is c2) and - (c1_choice.get_config() is c1) and (c2_choice.get_config() is c2) and - (c1_menu.get_config() is c1) and (c2_menu.get_config() is c2) and - (c1_comment.get_config() is c1) and (c2_comment.get_config() is c2), - "Config instance state separation or get_config() is broken") - # - # get_arch/srcarch/srctree/kconfig_filename() - # + print("Testing imply semantics") - del os.environ["ARCH"] - del os.environ["SRCARCH"] - del os.environ["srctree"] - - c = kconfiglib.Config("Kconfiglib/tests/Kmisc", print_warnings = False) - arch = c.get_arch() - verify(arch is None, "Expected None arch, got '{}'".format(arch)) - srcarch = c.get_srcarch() - verify(srcarch is None, "Expected None srcarch, got '{}'".format(srcarch)) - srctree = c.get_srctree() - verify(srctree is None, "Expected None srctree, got '{}'".format(srctree)) - - os.environ["ARCH"] = "ARCH value" - os.environ["SRCARCH"] = "SRCARCH value" - os.environ["srctree"] = "srctree value" - c = kconfiglib.Config("Kconfiglib/tests/Kmisc", print_warnings = False) - c.load_config("Kconfiglib/tests/empty") - - arch = c.get_arch() - srcarch = c.get_srcarch() - srctree = c.get_srctree() - config_filename = c.get_config_filename() - kconfig_filename = c.get_kconfig_filename() - - print("Testing get_arch()...") - verify(arch == "ARCH value", - "Wrong arch value - got '{}'".format(arch)) - print("Testing get_srcarch()...") - verify(srcarch == "SRCARCH value", - "Wrong srcarch value - got '{}'".format(srcarch)) - print("Testing get_srctree()...") - verify(srctree == "srctree value", - "Wrong srctree value - got '{}'".format(srctree)) - print("Testing get_config_filename()...") - verify(config_filename == "Kconfiglib/tests/empty", - "Wrong config filename - got '{}'".format(config_filename)) - print("Testing get_kconfig_filename()...") - verify(kconfig_filename == "Kconfiglib/tests/Kmisc", - "Wrong Kconfig filename - got '{}'".format(kconfig_filename)) - - # - # Imply semantics - # - - print("Testing imply semantics...") - - c = kconfiglib.Config("Kconfiglib/tests/Kimply") + c = Kconfig("Kconfiglib/tests/Kimply") verify_value("IMPLY_DIRECT_DEPS", "y") verify_value("UNMET_DIRECT_1", "n") @@ -1871,293 +1394,263 @@ def run_selftests(): # Verify that IMPLIED_TRISTATE is invalidated if the direct # dependencies change - assign_and_verify("IMPLY", "y") - assign_and_verify("DIRECT_DEP", "y") - verify_value("IMPLIED_TRISTATE", "y") - assign_and_verify("DIRECT_DEP", "n") - verify_value("IMPLIED_TRISTATE", "n") + 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", "y") + 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 + # n, and that it gets the value n by default (for non-imply-related # reasons) - assign_and_verify("IMPLY", "n") - assign_and_verify("IMPLIED_TRISTATE", "n") - assign_and_verify("IMPLIED_TRISTATE", "m") - assign_and_verify("IMPLIED_TRISTATE", "y") - c["IMPLIED_TRISTATE"].unset_user_value() + 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", "m") - assign_and_verify("IMPLIED_TRISTATE", "n") - assign_and_verify("IMPLIED_TRISTATE", "m") - assign_and_verify("IMPLIED_TRISTATE", "y") - c["IMPLIED_TRISTATE"].unset_user_value() - verify_value("IMPLIED_TRISTATE", "m") + # Same as above for m. Anything still goes, but m by default now. - # 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", 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) - assign_and_verify("IMPLY", "y") - assign_and_verify("IMPLIED_TRISTATE", "n") - assign_and_verify_new_value("IMPLIED_TRISTATE", "m", "y") - assign_and_verify("IMPLIED_TRISTATE", "y") - c["IMPLIED_TRISTATE"].unset_user_value() - verify_value("IMPLIED_TRISTATE", "y") + # Same as above for y. Only n and y should be accepted. m gets promoted to + # y. Default should be y. - # Being implied to either "m" or "y" should give a bool the value "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) - c["IMPLY"].unset_user_value() - verify_value("IMPLIED_BOOL", "n") - assign_and_verify("IMPLY", "n") - verify_value("IMPLIED_BOOL", "n") - assign_and_verify("IMPLY", "m") - verify_value("IMPLIED_BOOL", "y") - assign_and_verify("IMPLY", "y") - verify_value("IMPLIED_BOOL", "y") + # Being implied to either m or y should give a bool the value y - # A bool implied to "m" or "y" can take the values "n" and "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) - c["IMPLY"].set_user_value("m") - assign_and_verify("IMPLIED_BOOL", "n") - assign_and_verify("IMPLIED_BOOL", "y") + # A bool implied to m or y can take the values n and y - c["IMPLY"].set_user_value("y") - assign_and_verify("IMPLIED_BOOL", "n") - assign_and_verify("IMPLIED_BOOL", "y") + c.syms["IMPLY"].set_value(1) + assign_and_verify("IMPLIED_BOOL", 0) + assign_and_verify("IMPLIED_BOOL", 2) - # - # Choice semantics - # + c.syms["IMPLY"].set_value(2) + assign_and_verify("IMPLIED_BOOL", 0) + assign_and_verify("IMPLIED_BOOL", 2) - print("Testing choice semantics...") - c = kconfiglib.Config("Kconfiglib/tests/Kchoice") + print("Testing choice semantics") - choice_bool, choice_bool_opt, choice_tristate, choice_tristate_opt, \ - choice_bool_m, choice_tristate_m, choice_defaults, \ - choice_defaults_not_visible, choice_no_type_bool, \ - choice_no_type_tristate, choice_missing_member_type_1, \ - choice_missing_member_type_2, choice_weird_syms = c.get_choices() + c = Kconfig("Kconfiglib/tests/Kchoice") - for choice in (choice_bool, choice_bool_opt, choice_bool_m, - choice_defaults): - verify(choice.get_type() == kconfiglib.BOOL, - "choice {} should have type bool".format(choice.get_name())) + 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 choice in (choice_tristate, choice_tristate_opt, choice_tristate_m): - verify(choice.get_type() == kconfiglib.TRISTATE, - "choice {} should have type tristate" - .format(choice.get_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.get_parent() - sym.set_user_value("y") - verify(choice.get_mode() == "y", - 'The mode of the choice should be "y" after selecting a ' - "symbol") - verify(sym.is_choice_selection(), - "is_choice_selection() should be true for {}" - .format(sym.get_name())) - verify(choice.get_selection() is sym, - "{} should be the selected symbol".format(sym.get_name())) - verify(choice.get_user_selection() is sym, - "{} should be the user selection of the choice" - .format(sym.get_name())) - - def select_and_verify_all(choice): - choice_syms = choice.get_symbols() + 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 be y when selected") + + verify(sym.user_value != 2, + sym.name + " should not have user value y, because choice " + "y mode selections are remembered on the choice " + "itself") + + 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: + for sym in choice.syms: select_and_verify(sym) + # Select in reverse order - for i in range(len(choice_syms) - 1, 0, -1): - select_and_verify(choice_syms[i]) - - def verify_mode(choice, no_modules_mode, modules_mode): - c["MODULES"].set_user_value("n") - choice_mode = choice.get_mode() - verify(choice_mode == no_modules_mode, - 'Wrong mode for choice {} with no modules. Expected "{}", ' - 'got "{}".'.format(choice.get_name(), no_modules_mode, - choice_mode)) - - c["MODULES"].set_user_value("y") - choice_mode = choice.get_mode() - verify(choice_mode == modules_mode, - 'Wrong mode for choice {} with modules. Expected "{}", ' - 'got "{}".'.format(choice.get_name(), modules_mode, - choice_mode)) - - verify_mode(choice_bool, "y", "y") - verify_mode(choice_bool_opt, "n", "n") - verify_mode(choice_tristate, "y", "m") - verify_mode(choice_tristate_opt, "n", "n") - verify_mode(choice_bool_m, "n", "y") # Promoted - verify_mode(choice_tristate_m, "n", "m") + 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 - c["TRISTATE_SYM"].set_user_value("n") - verify(choice_defaults.get_selection_from_defaults() is c["OPT_4"] and - choice_defaults.get_selection() is c["OPT_4"], + 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["TRISTATE_SYM"].set_user_value("y") - verify(choice_defaults.get_selection_from_defaults() is c["OPT_2"] and - choice_defaults.get_selection() is c["OPT_2"], + + c.syms["TRISTATE_SYM"].set_value(2) + verify(choice.selection is c.syms["OPT_2"], "Wrong choice default with TRISTATE_SYM = y") - c["OPT_1"].set_user_value("y") - verify(choice_defaults.get_selection_from_defaults() is c["OPT_2"], - "User selection changed default selection - shouldn't have") - verify(choice_defaults.get_selection() is c["OPT_1"], + + c.syms["OPT_1"].set_value(2) + verify(choice.selection is c.syms["OPT_1"], "User selection should override defaults") - verify(choice_defaults_not_visible.get_selection_from_defaults() - is c["OPT_8"] and - choice_defaults_not_visible.get_selection() - is c["OPT_8"], + 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 + # Test y mode selection - c["MODULES"].set_user_value("y") + c.modules.set_value(2) - select_and_verify_all(choice_bool) - select_and_verify_all(choice_bool_opt) - select_and_verify_all(choice_tristate) - select_and_verify_all(choice_tristate_opt) + 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(choice_bool_m) + select_and_verify_all("BOOL_M") + + # Test m mode selection - # Test "m" mode selection... + c.named_choices["TRISTATE"].set_value(1) + assign_and_verify_value("T_1", 1, 1) + assign_and_verify_value("T_2", 1, 1) - # ...for a choice that can also be in "y" mode + c.syms["T_1"].set_value(0) # Check that this is remembered later - for sym_name in ("T_1", "T_2"): - assign_and_verify_new_value(sym_name, "m", "m") - verify(choice_tristate.get_mode() == "m", - 'Selecting {} to "m" should have changed the mode of the ' - 'choice to "m"'.format(sym_name)) + # Switching to y mode should cause T_1 to become selected + c.named_choices["TRISTATE"].set_value(2) + verify_value("T_1", 2) + verify_value("T_2", 0) - assign_and_verify_new_value(sym_name, "y", "y") - verify(choice_tristate.get_mode() == "y" and - choice_tristate.get_selection() is c[sym_name], - 'Selecting {} to "y" should have changed the mode of the ' - 'choice to "y" and made it the selection'.format(sym_name)) + # Switching back to m mode should restore the old values + c.named_choices["TRISTATE"].set_value(1) + verify_value("T_1", 0) + verify_value("T_2", 1) - # ...for a choice that can only be in "m" mode + assign_and_verify_value("TM_1", 1, 1) + assign_and_verify_value("TM_1", 2, 1) # Ignored + verify(c.named_choices["TRISTATE"].tri_value == 1, + "m-visible choice got invalid mode") - for sym_name in ("TM_1", "TM_2"): - assign_and_verify_new_value(sym_name, "m", "m") - assign_and_verify_new_value(sym_name, "n", "n") - # "y" should be truncated - assign_and_verify_new_value(sym_name, "y", "m") - verify(choice_tristate_m.get_mode() == "m", - 'A choice that can only be in "m" mode was not') + assign_and_verify_value("TM_1", 0, 0) + assign_and_verify_value("TM_1", 2, 0) # Ignored # Verify that choices with no explicitly specified type get the type of the # first contained symbol with a type - verify(choice_no_type_bool.get_type() == kconfiglib.BOOL, + verify(c.named_choices["NO_TYPE_BOOL"].orig_type == BOOL, "Expected first choice without explicit type to have type bool") - verify(choice_no_type_tristate.get_type() == kconfiglib.TRISTATE, + + 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 - verify((c["MMT_1"].get_type(), c["MMT_2"].get_type(), - c["MMT_3"].get_type()) == - (kconfiglib.BOOL, kconfiglib.BOOL, kconfiglib.TRISTATE), - "Wrong types for first choice with missing member types") + 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["MMT_4"].get_type(), c["MMT_5"].get_type()) == - (kconfiglib.BOOL, kconfiglib.BOOL), - "Wrong types for second choice with missing member types") + verify(c.syms["MMT_3"].orig_type == TRISTATE, + "Expected MMT_3 to have type tristate") # Verify that symbols in choices that depend on the preceding symbol aren't # considered choice symbols - def verify_is_normal_choice_symbol(sym): - verify(sym.is_choice_symbol() and - sym in choice_weird_syms.get_symbols() and - sym.get_parent() is choice_weird_syms, - "{} should be a normal choice symbol".format(sym.get_name())) - - def verify_is_weird_choice_symbol(sym): - verify(not sym.is_choice_symbol() and - sym not in choice_weird_syms.get_symbols() and - sym in choice_weird_syms.get_items() and - sym.get_parent() is choice_weird_syms, - "{} should be a weird (non-)choice symbol") - - verify_is_normal_choice_symbol(c["WS1"]) - verify_is_weird_choice_symbol(c["WS2"]) - verify_is_weird_choice_symbol(c["WS3"]) - verify_is_weird_choice_symbol(c["WS4"]) - verify_is_normal_choice_symbol(c["WS5"]) - verify_is_weird_choice_symbol(c["WS6"]) - - # - # Object dependencies - # - - print("Testing object dependencies...") - - # Note: This tests an internal API - - c = kconfiglib.Config("Kconfiglib/tests/Kdep") - - def verify_dependent(sym_name, deps_names): - sym = c[sym_name] - deps = [c[name] for name in deps_names] - sym_deps = sym._get_dependent() - verify(len(sym_deps) == len(deps), - "Wrong number of dependent symbols for {}".format(sym_name)) - verify(len(sym_deps) == len(set(sym_deps)), - "{}'s dependencies contains duplicates".format(sym_name)) - for dep in deps: - verify(dep in sym_deps, "{} should depend on {}". - format(dep.get_name(), sym_name)) - - # Test twice to cover dependency caching - for i in range(0, 2): - n_deps = 39 - # Verify that D1, D2, .., D<n_deps> are dependent on D - verify_dependent("D", ["D{}".format(i) for i in range(1, n_deps + 1)]) - # Choices - verify_dependent("A", ["B", "C"]) - verify_dependent("B", ["A", "C"]) - verify_dependent("C", ["A", "B"]) - verify_dependent("S", ["A", "B", "C"]) - - # Verify that the last symbol depends on the first in a long chain of - # dependencies. Test twice to cover dependency caching. - - c = kconfiglib.Config("Kconfiglib/tests/Kchain") - - for i in range(0, 2): - verify(c["CHAIN_26"] in c["CHAIN_1"]._get_dependent(), - "Dependency chain broken") - - print("\nAll selftests passed\n" if _all_ok else + 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 compatibility with weird selects/implies") + + # Check that Kconfiglib doesn't crash for stuff like 'select n' (seen in + # U-Boot). These probably originate from misunderstandings of how Kconfig + # works. + Kconfig("Kconfiglib/tests/Kwtf") + + 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.""" + """ + Runs tests on configurations from the kernel. Tests compability with the + C implementation by comparing outputs. + """ - del os.environ["ARCH"] - del os.environ["SRCARCH"] - del os.environ["srctree"] + os.environ.pop("ARCH", None) + os.environ.pop("SRCARCH", None) + os.environ.pop("srctree", None) - if speedy_mode and not os.path.exists("scripts/kconfig/conf"): + if speedy and not os.path.exists("scripts/kconfig/conf"): print("\nscripts/kconfig/conf does not exist -- running " "'make allnoconfig' to build it...") shell("make allnoconfig") @@ -2168,15 +1661,15 @@ def run_compatibility_tests(): # tree -- currently, all tests. The boolean flag indicates whether .config # (generated by the C implementation) should be compared to ._config # (generated by us) after each invocation. - all_arch_tests = [(test_load, False), - (test_config_absent, True), - (test_call_all, False), - (test_all_no, True), - (test_all_yes, True), - (test_all_no_simpler, True), + all_arch_tests = ((test_load, False), + (test_alldefconfig, True), # Needs to report success/failure for each arch/defconfig # combo, hence False. - (test_defconfig, False)] + (test_defconfig, False), + (test_sanity, False), + (test_all_no, True), + (test_all_no_simpler, True), + (test_all_yes, True)) arch_srcarch_list = get_arch_srcarch_list() @@ -2193,29 +1686,31 @@ def run_compatibility_tests(): # Previously we used to load all the arches once and keep them # around for the tests. That now uses a huge amount of memory (pypy # helps a bit), so reload them for each test instead. - test_fn(kconfiglib.Config(base_dir=".")) + test_fn(Kconfig(), arch) # Let kbuild infer SRCARCH from ARCH if we aren't in speedy mode. # This could detect issues with the test suite. - if not speedy_mode: + if not speedy: del os.environ["SRCARCH"] if compare_configs: if equal_confs(): - print(" {:14}OK".format(arch)) + print("{:14}OK".format(arch)) else: - print(" {:14}FAIL".format(arch)) + print("{:14}FAIL".format(arch)) fail() - if all_ok(): + if all_passed: print("All selftests and compatibility tests passed") - print(nconfigs, "arch/defconfig pairs tested") + print("{} arch/defconfig pairs tested".format(nconfigs)) else: print("Some tests failed") + sys.exit(1) def get_arch_srcarch_list(): - """Returns a list of (ARCH, SRCARCH) tuples to test.""" - + """ + Returns a list of (ARCH, SRCARCH) tuples to test. + """ res = [] def add_arch(arch): @@ -2240,203 +1735,204 @@ def get_arch_srcarch_list(): return res -def test_load(conf): - """Load all arch Kconfigs to make sure we don't throw any errors""" - print(" {:14}OK".format(conf.get_arch())) +def test_load(conf, arch): + """ + Load all arch Kconfigs to make sure we don't throw any errors + """ + print("{:14}OK".format(arch)) -# The weird docstring formatting is to get the format right when we print the -# docstring ourselves -def test_all_no(conf): +def test_all_no(conf, arch): """ Verify that our examples/allnoconfig.py script generates the same .config as 'make allnoconfig', for each architecture. Runs the script via - 'make scriptconfig', so kinda slow even in speedy mode.""" + 'make scriptconfig', so kinda slow even in speedy mode. + """ # TODO: Support speedy mode for running the script shell("make scriptconfig SCRIPT=Kconfiglib/examples/allnoconfig.py " "PYTHONCMD='{}'".format(sys.executable)) shell("mv .config ._config") - if speedy_mode: + if speedy: shell("scripts/kconfig/conf --allnoconfig Kconfig") else: shell("make allnoconfig") -def test_all_no_simpler(conf): +def test_all_no_simpler(conf, arch): """ Verify that our examples/allnoconfig_simpler.py script generates the same .config as 'make allnoconfig', for each architecture. Runs the script via - 'make scriptconfig', so kinda slow even in speedy mode.""" + 'make scriptconfig', so kinda slow even in speedy mode. + """ # TODO: Support speedy mode for running the script shell("make scriptconfig SCRIPT=Kconfiglib/examples/allnoconfig_simpler.py " "PYTHONCMD='{}'".format(sys.executable)) shell("mv .config ._config") - if speedy_mode: + if speedy: shell("scripts/kconfig/conf --allnoconfig Kconfig") else: shell("make allnoconfig") -def test_all_yes(conf): +def test_all_yes(conf, arch): """ Verify that our examples/allyesconfig.py script generates the same .config as 'make allyesconfig', for each architecture. Runs the script via - 'make scriptconfig', so kinda slow even in speedy mode.""" + 'make scriptconfig', so kinda slow even in speedy mode. + """ # TODO: Support speedy mode for running the script shell("make scriptconfig SCRIPT=Kconfiglib/examples/allyesconfig.py " "PYTHONCMD='{}'".format(sys.executable)) shell("mv .config ._config") - if speedy_mode: + if speedy: shell("scripts/kconfig/conf --allyesconfig Kconfig") else: shell("make allyesconfig") -def test_call_all(conf): +def test_sanity(conf, arch): """ - Call all public methods on all symbols, menus, choices, and comments for - all architectures to make sure we never crash or hang. (Nearly all public - methods: some are hard to test like this, but are exercised by other - tests.) Also do misc. sanity checks.""" - print(" For {}...".format(conf.get_arch())) - - conf.__str__() - conf.get_arch() - conf.get_base_dir() - conf.get_config_filename() - conf.get_config_header() - conf.get_defconfig_filename() - conf.get_kconfig_filename() - conf.get_mainmenu_text() - conf.get_srcarch() - conf.get_srctree() - conf.get_symbol("y") - conf.get_symbols(False) - conf.get_top_level_items() - conf.set_print_undef_assign(True) - conf.set_print_undef_assign(False) - conf.set_print_warnings(False) - conf.set_print_warnings(True) - conf.unset_user_values() - - conf.eval("y && ARCH") - - for s in conf.get_symbols(): - s.__str__() - s.get_assignable_values() - s.get_config() - s.get_help() - s.get_implied_symbols() - s.get_lower_bound() - s.get_name() - s.get_parent() - s.get_prompts() - s.get_ref_locations() - s.get_referenced_symbols() - s.get_referenced_symbols(True) - s.get_selected_symbols() - s.get_type() - s.get_upper_bound() - s.get_user_value() - s.get_value() - s.get_visibility() - s.has_ranges() - s.is_choice_selection() - s.is_choice_symbol() - s.is_defined() - s.is_from_environment() - s.is_modifiable() - s.is_allnoconfig_y() - s.unset_user_value() - - # Check get_ref/def_location() sanity - - if s.is_special(): - if s.is_from_environment(): - # Special symbols from the environment should have define - # locations - verify(s.get_def_locations() != [], - "The symbol '{}' is from the environment but lacks " - "define locations".format(s.get_name())) - else: - # Special symbols that are not from the environment should be - # defined and have no define locations - verify(s.is_defined(), - "The special symbol '{}' is not defined". - format(s.get_name())) - verify(s.get_def_locations() == [], - "The special symbol '{}' has recorded def. locations". - format(s.get_name())) + 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)) + + conf.modules + conf.defconfig_list + conf.defconfig_filename + conf.enable_undef_warnings() + conf.disable_undef_warnings() + conf.enable_warnings() + conf.disable_warnings() + conf.mainmenu_text + conf.unset_values() + + # Python 2/3 compatible + for key, sym in conf.syms.items(): + verify(isinstance(key, str), "weird key '{}' in syms dict".format(key)) + + if sym.name != "UNAME_RELEASE": + verify(not sym.is_constant, sym.name + " in 'syms' and constant") + + verify(sym not in conf.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 + conf.disable_warnings() + sym.set_value(2) + sym.set_value("foo") + sym.unset_value() + conf.enable_warnings() + sym.str_value + sym.tri_value + sym.type + sym.user_value + sym.visibility + + for sym in conf.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 conf.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 + conf.disable_warnings() + sym.set_value(2) + sym.set_value("foo") + sym.unset_value() + conf.enable_warnings() + sym.str_value + sym.tri_value + sym.type + sym.visibility + + # Cheat with internals + for choice in conf._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 = conf.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: - # Non-special symbols should have define locations iff they are - # defined - if s.is_defined(): - verify(s.get_def_locations() != [], - "'{}' defined but lacks recorded locations". - format(s.get_name())) + while node.parent is not None: + node = node.parent + if node.next is not None: + node = node.next + break else: - verify(s.get_def_locations() == [], - "'{}' undefined but has recorded locations". - format(s.get_name())) - verify(s.get_ref_locations() != [], - "'{}' both undefined and unreferenced". - format(s.get_name())) - - for c in conf.get_choices(): - c.__str__() - c.get_config() - c.get_def_locations() - c.get_help() - c.get_items() - c.get_mode() - c.get_name() - c.get_parent() - c.get_prompts() - c.get_referenced_symbols() - c.get_referenced_symbols(True) - c.get_selection() - c.get_selection_from_defaults() - c.get_symbols() - c.get_type() - c.get_user_selection() - c.get_visibility() - c.is_optional() - - for m in conf.get_menus(): - m.__str__() - m.get_config() - m.get_items() - m.get_items(True) - m.get_location() - m.get_parent() - m.get_referenced_symbols() - m.get_referenced_symbols(True) - m.get_symbols() - m.get_symbols(True) - m.get_title() - m.get_visibility() - m.get_visible_if_visibility() - - for c in conf.get_comments(): - c.__str__() - c.get_config() - c.get_location() - c.get_parent() - c.get_referenced_symbols() - c.get_referenced_symbols(True) - c.get_text() - c.get_visibility() - -def test_config_absent(conf): + break + +def test_alldefconfig(conf, arch): """ Verify that Kconfiglib generates the same .config as 'make alldefconfig', - for each architecture""" + for each architecture + """ conf.write_config("._config") - if speedy_mode: + if speedy: shell("scripts/kconfig/conf --alldefconfig Kconfig") else: shell("make alldefconfig") -def test_defconfig(conf): +def test_defconfig(conf, arch): """ Verify that Kconfiglib generates the same .config as scripts/kconfig/conf, for each architecture/defconfig pair. In obsessive mode, this test includes @@ -2445,38 +1941,43 @@ def test_defconfig(conf): run. With logging enabled, this test appends any failures to a file - test_defconfig_fails in the root.""" + test_defconfig_fails in the root. + """ global nconfigs defconfigs = [] - def add_configs_for_arch(arch): - arch_dir = os.path.join("arch", arch) + def add_configs_for_arch(arch_): + arch_dir = os.path.join("arch", arch_) + # Some arches have a "defconfig" in the root of their arch/<arch>/ # directory root_defconfig = os.path.join(arch_dir, "defconfig") if os.path.exists(root_defconfig): defconfigs.append(root_defconfig) + # Assume all files in the arch/<arch>/configs directory (if it # exists) are configurations defconfigs_dir = os.path.join(arch_dir, "configs") if not os.path.exists(defconfigs_dir): return + if not os.path.isdir(defconfigs_dir): print("Warning: '{}' is not a directory - skipping" .format(defconfigs_dir)) return + for dirpath, _, filenames in os.walk(defconfigs_dir): for filename in filenames: defconfigs.append(os.path.join(dirpath, filename)) - if obsessive_mode: + if obsessive: # Collect all defconfigs. This could be done once instead, but it's # a speedy operation comparatively. - for arch in os.listdir("arch"): - add_configs_for_arch(arch) + for arch_ in os.listdir("arch"): + add_configs_for_arch(arch_) else: - add_configs_for_arch(conf.get_arch()) + add_configs_for_arch(arch) # Test architecture for each defconfig @@ -2487,7 +1988,7 @@ def test_defconfig(conf): conf.load_config(defconfig) conf.write_config("._config") - if speedy_mode: + if speedy: shell("scripts/kconfig/conf --defconfig='{}' Kconfig". format(defconfig)) else: @@ -2500,34 +2001,29 @@ def test_defconfig(conf): # bugs. shell("make kconfiglibtestconfig") - arch_defconfig_str = " {:14}with {:60} " \ - .format(conf.get_arch(), defconfig) + arch_defconfig_str = " {:14}with {:60} ".format(arch, defconfig) if equal_confs(): print(arch_defconfig_str + "OK") else: print(arch_defconfig_str + "FAIL") fail() - if log_mode: + if log: with open("test_defconfig_fails", "a") as fail_log: fail_log.write("{} {} with {} did not match\n" .format(time.strftime("%d %b %Y %H:%M:%S", time.localtime()), - conf.get_arch(), - defconfig)) + arch, defconfig)) # # Helper functions # -devnull = open(os.devnull, "w") - -def shell(cmd): - subprocess.call(cmd, shell = True, stdout = devnull, stderr = devnull) - def rm_configs(): - """Delete any old ".config" (generated by the C implementation) and - "._config" (generated by us), if present.""" + """ + 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) @@ -2557,7 +2053,8 @@ def equal_confs(): return False else: with f: - our = f.readlines() + # [1:] strips the default header + our = f.readlines()[1:] if their == our: return True @@ -2569,26 +2066,5 @@ def equal_confs(): return False -_all_ok = True - -def verify(cond, msg): - """Fails and prints 'msg' if 'cond' is False.""" - if not cond: - fail(msg) - -def verify_equals(x, y): - """Fails if 'x' does not equal 'y'.""" - if x != y: - fail("'{}' does not equal '{}'".format(x, y)) - -def fail(msg = None): - global _all_ok - if msg is not None: - print("Fail: " + msg) - _all_ok = False - -def all_ok(): - return _all_ok - if __name__ == "__main__": run_tests() |
