Merge branch 'bugfix/kconfig_hex_values' into 'master'

kconfig: Fix two cases of hex values being handled incorrectly

Closes VSC-292

See merge request espressif/esp-idf!8372
This commit is contained in:
Angus Gratton 2020-05-18 14:57:46 +08:00
commit 0e4cd93ee9
3 changed files with 64 additions and 13 deletions

View file

@ -355,14 +355,24 @@ def write_makefile(deprecated_options, config, filename):
def get_makefile_config_string(name, value, orig_type): def get_makefile_config_string(name, value, orig_type):
if orig_type in (kconfiglib.BOOL, kconfiglib.TRISTATE): if orig_type in (kconfiglib.BOOL, kconfiglib.TRISTATE):
return "{}{}={}\n".format(config.config_prefix, name, '' if value == 'n' else value) value = '' if value == 'n' else value
elif orig_type in (kconfiglib.INT, kconfiglib.HEX): elif orig_type == kconfiglib.INT:
return "{}{}={}\n".format(config.config_prefix, name, value) try:
value = int(value)
except ValueError:
value = ""
elif orig_type == kconfiglib.HEX:
try:
value = hex(int(value, 16)) # ensure 0x prefix
except ValueError:
value = ""
elif orig_type == kconfiglib.STRING: elif orig_type == kconfiglib.STRING:
return '{}{}="{}"\n'.format(config.config_prefix, name, kconfiglib.escape(value)) value = '"{}"'.format(kconfiglib.escape(value))
else: else:
raise RuntimeError('{}{}: unknown type {}'.format(config.config_prefix, name, orig_type)) raise RuntimeError('{}{}: unknown type {}'.format(config.config_prefix, name, orig_type))
return '{}{}={}\n'.format(config.config_prefix, name, value)
def write_makefile_node(node): def write_makefile_node(node):
item = node.item item = node.item
if isinstance(item, kconfiglib.Symbol) and item.env_var is None: if isinstance(item, kconfiglib.Symbol) and item.env_var is None:
@ -419,13 +429,14 @@ def write_cmake(deprecated_options, config, filename):
val = "" # write unset values as empty variables val = "" # write unset values as empty variables
elif sym.orig_type == kconfiglib.STRING: elif sym.orig_type == kconfiglib.STRING:
val = kconfiglib.escape(val) val = kconfiglib.escape(val)
write("set({}{} \"{}\")\n".format( elif sym.orig_type == kconfiglib.HEX:
prefix, sym.name, val)) val = hex(int(val, 16)) # ensure 0x prefix
write('set({}{} "{}")\n'.format(prefix, sym.name, val))
configs_list.append(prefix + sym.name) configs_list.append(prefix + sym.name)
dep_opt = deprecated_options.get_deprecated_option(sym.name) dep_opt = deprecated_options.get_deprecated_option(sym.name)
if dep_opt: if dep_opt:
tmp_dep_list.append("set({}{} \"{}\")\n".format(prefix, dep_opt, val)) tmp_dep_list.append('set({}{} "{}")\n'.format(prefix, dep_opt, val))
configs_list.append(prefix + dep_opt) configs_list.append(prefix + dep_opt)
for n in config.node_iter(): for n in config.node_iter():

View file

@ -228,7 +228,7 @@ def handle_set(config, error, to_set):
try: try:
if not isinstance(val, int): if not isinstance(val, int):
val = int(val, 16) # input can be a decimal JSON value or a string of hex digits val = int(val, 16) # input can be a decimal JSON value or a string of hex digits
sym.set_value("%x" % val) sym.set_value(hex(val))
except ValueError: except ValueError:
error.append("Hex symbol %s can accept a decimal integer or a string of hex digits, only") error.append("Hex symbol %s can accept a decimal integer or a string of hex digits, only")
else: else:

View file

@ -25,7 +25,7 @@ class ConfgenBaseTestCase(unittest.TestCase):
# Python 2 fallback # Python 2 fallback
regex_func = self.assertRegexpMatches regex_func = self.assertRegexpMatches
finally: finally:
self.functions['regex'] = regex_func self.functions['regex'] = lambda instance, s, expr: regex_func(instance, expr, s) # reverse args order
def setUp(self): def setUp(self):
with tempfile.NamedTemporaryFile(prefix='test_confgen_', delete=False) as f: with tempfile.NamedTemporaryFile(prefix='test_confgen_', delete=False) as f:
@ -47,6 +47,16 @@ class ConfgenBaseTestCase(unittest.TestCase):
subprocess.check_call(call_args) subprocess.check_call(call_args)
def invoke_and_test(self, in_text, out_text, test='in'): def invoke_and_test(self, in_text, out_text, test='in'):
"""
Main utility function for testing confgen:
- Runs confgen via invoke_confgen(), using output method pre-set in test class setup
- in_text is the Kconfig file input content
- out_text is some expected output from confgen
- 'test' can be any function key from self.functions dict (see above). Default is 'in' to test if
out_text is a substring of the full confgen output.
"""
with tempfile.NamedTemporaryFile(mode='w+', prefix='test_confgen_', delete=False) as f: with tempfile.NamedTemporaryFile(mode='w+', prefix='test_confgen_', delete=False) as f:
self.addCleanup(os.remove, f.name) self.addCleanup(os.remove, f.name)
f.write(textwrap.dedent(in_text)) f.write(textwrap.dedent(in_text))
@ -58,10 +68,12 @@ class ConfgenBaseTestCase(unittest.TestCase):
with open(self.output_file) as f_result: with open(self.output_file) as f_result:
result = f_result.read() result = f_result.read()
if test == 'regex': # need to reverse the argument order try:
self.functions[test](self, result, out_text) out_text = textwrap.dedent(out_text)
else: except TypeError:
self.functions[test](self, textwrap.dedent(out_text), result) pass # probably a regex
self.functions[test](self, out_text, result)
class CmakeTestCase(ConfgenBaseTestCase): class CmakeTestCase(ConfgenBaseTestCase):
@ -77,6 +89,10 @@ class CmakeTestCase(ConfgenBaseTestCase):
default "\\\\~!@#$%^&*()\\\"" default "\\\\~!@#$%^&*()\\\""
""", 'set(CONFIG_PASSWORD "\\\\~!@#$%^&*()\\\"")') """, 'set(CONFIG_PASSWORD "\\\\~!@#$%^&*()\\\"")')
def testHexPrefix(self):
self.invoke_and_test(HEXPREFIX_KCONFIG, 'set(CONFIG_HEX_NOPREFIX "0x33")')
self.invoke_and_test(HEXPREFIX_KCONFIG, 'set(CONFIG_HEX_PREFIX "0x77")')
class JsonTestCase(ConfgenBaseTestCase): class JsonTestCase(ConfgenBaseTestCase):
@classmethod @classmethod
@ -91,6 +107,11 @@ class JsonTestCase(ConfgenBaseTestCase):
default "\\\\~!@#$%^&*()\\\"" default "\\\\~!@#$%^&*()\\\""
""", '"PASSWORD": "\\\\~!@#$%^&*()\\\""') """, '"PASSWORD": "\\\\~!@#$%^&*()\\\""')
def testHexPrefix(self):
# hex values come out as integers in JSON, due to no hex type
self.invoke_and_test(HEXPREFIX_KCONFIG, '"HEX_NOPREFIX": %d' % 0x33)
self.invoke_and_test(HEXPREFIX_KCONFIG, '"HEX_PREFIX": %d' % 0x77)
class JsonMenuTestCase(ConfgenBaseTestCase): class JsonMenuTestCase(ConfgenBaseTestCase):
@classmethod @classmethod
@ -168,6 +189,10 @@ class MakefileTestCase(ConfgenBaseTestCase):
with open(os.path.join(os.environ['IDF_PATH'], 'Kconfig')) as f: with open(os.path.join(os.environ['IDF_PATH'], 'Kconfig')) as f:
self.invoke_and_test(f.read(), 'CONFIG_IDF_TARGET="esp32"') self.invoke_and_test(f.read(), 'CONFIG_IDF_TARGET="esp32"')
def testHexPrefix(self):
self.invoke_and_test(HEXPREFIX_KCONFIG, 'CONFIG_HEX_NOPREFIX=0x33')
self.invoke_and_test(HEXPREFIX_KCONFIG, 'CONFIG_HEX_PREFIX=0x77')
class HeaderTestCase(ConfgenBaseTestCase): class HeaderTestCase(ConfgenBaseTestCase):
@classmethod @classmethod
@ -182,6 +207,10 @@ class HeaderTestCase(ConfgenBaseTestCase):
default "\\\\~!@#$%^&*()\\\"" default "\\\\~!@#$%^&*()\\\""
""", '#define CONFIG_PASSWORD "\\\\~!@#$%^&*()\\\""') """, '#define CONFIG_PASSWORD "\\\\~!@#$%^&*()\\\""')
def testHexPrefix(self):
self.invoke_and_test(HEXPREFIX_KCONFIG, '#define CONFIG_HEX_NOPREFIX 0x33')
self.invoke_and_test(HEXPREFIX_KCONFIG, '#define CONFIG_HEX_PREFIX 0x77')
class DocsTestCase(ConfgenBaseTestCase): class DocsTestCase(ConfgenBaseTestCase):
@classmethod @classmethod
@ -230,5 +259,16 @@ class DocsTestCase(ConfgenBaseTestCase):
""") # this is more readable than regex """) # this is more readable than regex
# Used by multiple testHexPrefix() test cases to verify correct hex output for each format
HEXPREFIX_KCONFIG = """
config HEX_NOPREFIX
hex "Hex Item default no prefix"
default 33
config HEX_PREFIX
hex "Hex Item default prefix"
default 0x77
"""
if __name__ == "__main__": if __name__ == "__main__":
unittest.main() unittest.main()