metadata: break out write_yaml to standalone function and add unit tests

This commit is contained in:
Hans-Christoph Steiner 2023-05-09 18:15:10 +02:00
parent 784bebfee9
commit 2cb12f9594
2 changed files with 127 additions and 80 deletions

View file

@ -1044,6 +1044,89 @@ def _del_duplicated_NoSourceSince(app):
del app['AntiFeatures'][key] del app['AntiFeatures'][key]
def _field_to_yaml(typ, value):
"""Convert data to YAML 1.2 format that keeps the right TYPE_*."""
if typ == TYPE_STRING:
return str(value)
elif typ == TYPE_INT:
return int(value)
elif typ == TYPE_MULTILINE:
if '\n' in value:
return ruamel.yaml.scalarstring.preserve_literal(str(value))
else:
return str(value)
elif typ == TYPE_SCRIPT:
if type(value) == list:
if len(value) == 1:
return value[0]
else:
return value
else:
return value
def _builds_to_yaml(app):
builds = ruamel.yaml.comments.CommentedSeq()
for build in app.get('Builds', []):
if not isinstance(build, Build):
build = Build(build)
b = ruamel.yaml.comments.CommentedMap()
for field in build_flags:
if hasattr(build, field):
value = getattr(build, field)
if field == 'gradle' and value == ['off']:
value = [
ruamel.yaml.scalarstring.SingleQuotedScalarString('off')
]
typ = flagtype(field)
# don't check value == True for TYPE_INT as it could be 0
if value is not None and (typ == TYPE_INT or value):
b.update({field: _field_to_yaml(typ, value)})
builds.append(b)
# insert extra empty lines between build entries
for i in range(1, len(builds)):
builds.yaml_set_comment_before_after_key(i, 'bogus')
builds.ca.items[i][1][-1].value = '\n'
return builds
def _app_to_yaml(app):
cm = ruamel.yaml.comments.CommentedMap()
insert_newline = False
for field in yaml_app_field_order:
if field == '\n':
# next iteration will need to insert a newline
insert_newline = True
else:
if app.get(field) or field == 'Builds':
if field == 'Builds':
if app.get('Builds'):
cm.update({field: _builds_to_yaml(app)})
elif field == 'CurrentVersionCode':
cm.update({field: _field_to_yaml(TYPE_INT, getattr(app, field))})
elif field == 'AllowedAPKSigningKeys':
value = getattr(app, field)
if value:
value = [str(i).lower() for i in value]
if len(value) == 1:
cm.update({field: _field_to_yaml(TYPE_STRING, value[0])})
else:
cm.update({field: _field_to_yaml(TYPE_LIST, value)})
else:
cm.update({field: _field_to_yaml(fieldtype(field), getattr(app, field))})
if insert_newline:
# we need to prepend a newline in front of this field
insert_newline = False
# inserting empty lines is not supported so we add a
# bogus comment and over-write its value
cm.yaml_set_comment_before_after_key(field, 'bogus')
cm.ca.items[field][1][-1].value = '\n'
return cm
def write_yaml(mf, app): def write_yaml(mf, app):
"""Write metadata in yaml format. """Write metadata in yaml format.
@ -1053,87 +1136,8 @@ def write_yaml(mf, app):
active file discriptor for writing active file discriptor for writing
app app
app metadata to written to the yaml file app metadata to written to the yaml file
""" """
def _field_to_yaml(typ, value):
"""Convert data to YAML 1.2 format that keeps the right TYPE_*."""
if typ == TYPE_STRING:
return str(value)
elif typ == TYPE_INT:
return int(value)
elif typ == TYPE_MULTILINE:
if '\n' in value:
return ruamel.yaml.scalarstring.preserve_literal(str(value))
else:
return str(value)
elif typ == TYPE_SCRIPT:
if type(value) == list:
if len(value) == 1:
return value[0]
else:
return value
else:
return value
def _app_to_yaml(app):
cm = ruamel.yaml.comments.CommentedMap()
insert_newline = False
for field in yaml_app_field_order:
if field == '\n':
# next iteration will need to insert a newline
insert_newline = True
else:
if app.get(field) or field == 'Builds':
if field == 'Builds':
if app.get('Builds'):
cm.update({field: _builds_to_yaml(app)})
elif field == 'CurrentVersionCode':
cm.update({field: _field_to_yaml(TYPE_INT, getattr(app, field))})
elif field == 'AllowedAPKSigningKeys':
value = getattr(app, field)
if value:
value = [str(i).lower() for i in value]
if len(value) == 1:
cm.update({field: _field_to_yaml(TYPE_STRING, value[0])})
else:
cm.update({field: _field_to_yaml(TYPE_LIST, value)})
else:
cm.update({field: _field_to_yaml(fieldtype(field), getattr(app, field))})
if insert_newline:
# we need to prepend a newline in front of this field
insert_newline = False
# inserting empty lines is not supported so we add a
# bogus comment and over-write its value
cm.yaml_set_comment_before_after_key(field, 'bogus')
cm.ca.items[field][1][-1].value = '\n'
return cm
def _builds_to_yaml(app):
builds = ruamel.yaml.comments.CommentedSeq()
for build in app.get('Builds', []):
if not isinstance(build, Build):
build = Build(build)
b = ruamel.yaml.comments.CommentedMap()
for field in build_flags:
if hasattr(build, field):
value = getattr(build, field)
if field == 'gradle' and value == ['off']:
value = [
ruamel.yaml.scalarstring.SingleQuotedScalarString('off')
]
typ = flagtype(field)
# don't check value == True for TYPE_INT as it could be 0
if value is not None and (typ == TYPE_INT or value):
b.update({field: _field_to_yaml(typ, value)})
builds.append(b)
# insert extra empty lines between build entries
for i in range(1, len(builds)):
builds.yaml_set_comment_before_after_key(i, 'bogus')
builds.ca.items[i][1][-1].value = '\n'
return builds
_del_duplicated_NoSourceSince(app) _del_duplicated_NoSourceSince(app)
yaml_app = _app_to_yaml(app) yaml_app = _app_to_yaml(app)
yaml = ruamel.yaml.YAML() yaml = ruamel.yaml.YAML()

View file

@ -1684,6 +1684,49 @@ class MetadataTest(unittest.TestCase):
), ),
) )
def test_app_to_yaml_smokecheck(self):
self.assertTrue(
isinstance(metadata._app_to_yaml(dict()), ruamel.yaml.comments.CommentedMap)
)
def test_app_to_yaml_build_list_empty(self):
app = metadata.App({'Builds': [metadata.Build({'rm': []})]})
self.assertEqual(dict(), metadata._app_to_yaml(app)['Builds'][0])
def test_app_to_yaml_build_list_string(self):
app = metadata.App({'Builds': [metadata.Build({'rm': 'one'})]})
self.assertEqual({'rm': 'one'}, metadata._app_to_yaml(app)['Builds'][0])
def test_app_to_yaml_build_list_one(self):
app = metadata.App({'Builds': [metadata.Build({'rm': ['one']})]})
self.assertEqual({'rm': ['one']}, metadata._app_to_yaml(app)['Builds'][0])
def test_app_to_yaml_build_list(self):
app = metadata.App({'Builds': [metadata.Build({'rm': ['b2', 'NO1']})]})
self.assertEqual({'rm': ['b2', 'NO1']}, metadata._app_to_yaml(app)['Builds'][0])
def test_app_to_yaml_AllowedAPKSigningKeys_two(self):
cm = metadata._app_to_yaml(metadata.App({'AllowedAPKSigningKeys': ['b', 'A']}))
self.assertEqual(['b', 'a'], cm['AllowedAPKSigningKeys'])
def test_app_to_yaml_AllowedAPKSigningKeys_one(self):
cm = metadata._app_to_yaml(metadata.App({'AllowedAPKSigningKeys': ['One']}))
self.assertEqual('one', cm['AllowedAPKSigningKeys'])
def test_app_to_yaml_int_hex(self):
cm = metadata._app_to_yaml(metadata.App({'CurrentVersionCode': 0xFF}))
self.assertEqual(255, cm['CurrentVersionCode'])
def test_app_to_yaml_int_underscore(self):
cm = metadata._app_to_yaml(metadata.App({'CurrentVersionCode': 1_2_3}))
self.assertEqual(123, cm['CurrentVersionCode'])
def test_app_to_yaml_int_0(self):
"""Document that 0 values fail to make it through."""
# TODO it should be possible to use `CurrentVersionCode: 0`
cm = metadata._app_to_yaml(metadata.App({'CurrentVersionCode': 0}))
self.assertFalse('CurrentVersionCode' in cm)
class PostMetadataParseTest(unittest.TestCase): class PostMetadataParseTest(unittest.TestCase):
"""Test the functions that post process the YAML input. """Test the functions that post process the YAML input.