1
0
mirror of https://gitlab.com/fdroid/fdroidserver.git synced 2024-11-09 00:40:11 +01:00

Merge branch 'normalize-type-list-int' into 'master'

metadata: refactor parsing normalization

See merge request fdroid/fdroidserver!1359
This commit is contained in:
Hans-Christoph Steiner 2023-05-25 15:05:01 +00:00
commit 65a1698ba3
3 changed files with 249 additions and 70 deletions

View File

@ -57,6 +57,7 @@ metadata_v0:
- cd fdroiddata - cd fdroiddata
- ../tests/dump_internal_metadata_format.py - ../tests/dump_internal_metadata_format.py
- sed -i - sed -i
-e '/RequiresRoot:/d'
-e "/buildozer/d" -e "/buildozer/d"
-e '/^comments\W /d' -e '/^comments\W /d'
-e 's,maven\(\W\) false,maven\1 null,' -e 's,maven\(\W\) false,maven\1 null,'

View File

@ -20,6 +20,7 @@
import git import git
from pathlib import Path from pathlib import Path
import math
import platform import platform
import os import os
import re import re
@ -883,6 +884,21 @@ def parse_localized_antifeatures(app):
app['AntiFeatures'][f.stem][locale] = f.read_text() app['AntiFeatures'][f.stem][locale] = f.read_text()
def _normalize_type_int(k, v):
"""Normalize anything that can be reliably converted to an integer."""
if isinstance(v, int) and not isinstance(v, bool):
return v
if v is None:
return None
if isinstance(v, str):
try:
return int(v)
except ValueError:
pass
msg = _('{build_flag} must be an integer, found: {value}')
_warn_or_exception(msg.format(build_flag=k, value=v))
def _normalize_type_string(v): def _normalize_type_string(v):
"""Normalize any data to TYPE_STRING. """Normalize any data to TYPE_STRING.
@ -892,11 +908,27 @@ def _normalize_type_string(v):
numbers. Like "versionName: 1.0" would be a YAML float, but numbers. Like "versionName: 1.0" would be a YAML float, but
should be a string. should be a string.
SHA-256 values are string values, but YAML 1.2 can interpret some
unquoted values as decimal ints. This converts those to a string
if they are over 50 digits. In the wild, the longest 0 padding on
a SHA-256 key fingerprint I found was 8 zeros.
""" """
if isinstance(v, bool): if isinstance(v, bool):
if v: if v:
return 'true' return 'true'
return 'false' return 'false'
if isinstance(v, float):
# YAML 1.2 values for NaN, Inf, and -Inf
if math.isnan(v):
return '.nan'
if math.isinf(v):
if v > 0:
return '.inf'
return '-.inf'
if v and isinstance(v, int):
if math.log10(v) > 50: # only if the int has this many digits
return '%064d' % v
return str(v) return str(v)
@ -955,30 +987,47 @@ def _normalize_type_stringmap(k, v):
return retdict return retdict
def _normalize_type_list(k, v):
"""Normalize any data to TYPE_LIST, which is always a list of strings."""
if isinstance(v, dict):
msg = _('{build_flag} must be list or string, found: {value}')
_warn_or_exception(msg.format(build_flag=k, value=v))
elif type(v) not in (list, tuple, set):
v = [v]
return [_normalize_type_string(i) for i in v]
def post_parse_yaml_metadata(yamldata): def post_parse_yaml_metadata(yamldata):
"""Convert human-readable metadata data structures into consistent data structures. """Convert human-readable metadata data structures into consistent data structures.
"Be conservative in what is written out, be liberal in what is parsed."
https://en.wikipedia.org/wiki/Robustness_principle
This also handles conversions that make metadata YAML behave This also handles conversions that make metadata YAML behave
something like StrictYAML. Specifically, a field should have a something like StrictYAML. Specifically, a field should have a
fixed value type, regardless of YAML 1.2's type auto-detection. fixed value type, regardless of YAML 1.2's type auto-detection.
TODO: None values should probably be treated as the string 'null',
since YAML 1.2 uses that for nulls
""" """
for k, v in yamldata.items(): for k, v in yamldata.items():
_fieldtype = fieldtype(k) _fieldtype = fieldtype(k)
if _fieldtype == TYPE_LIST: if _fieldtype == TYPE_LIST:
if isinstance(v, str): if v or v == 0:
yamldata[k] = [v] yamldata[k] = _normalize_type_list(k, v)
elif v:
yamldata[k] = [str(i) for i in v]
elif _fieldtype == TYPE_INT: elif _fieldtype == TYPE_INT:
if v: v = _normalize_type_int(k, v)
yamldata[k] = int(v) if v or v == 0:
yamldata[k] = v
elif _fieldtype == TYPE_STRING: elif _fieldtype == TYPE_STRING:
if v or v == 0: if v or v == 0:
yamldata[k] = _normalize_type_string(v) yamldata[k] = _normalize_type_string(v)
elif _fieldtype == TYPE_STRINGMAP: elif _fieldtype == TYPE_STRINGMAP:
if v or v == 0: # TODO probably want just `if v:` if v or v == 0: # TODO probably want just `if v:`
yamldata[k] = _normalize_type_stringmap(k, v) yamldata[k] = _normalize_type_stringmap(k, v)
elif _fieldtype == TYPE_BOOL:
yamldata[k] = bool(v)
else: else:
if type(v) in (float, int): if type(v) in (float, int):
yamldata[k] = str(v) yamldata[k] = str(v)
@ -994,29 +1043,17 @@ def post_parse_yaml_metadata(yamldata):
if v or v == 0: if v or v == 0:
build[k] = _normalize_type_string(v) build[k] = _normalize_type_string(v)
elif _flagtype == TYPE_INT: elif _flagtype == TYPE_INT:
v = _normalize_type_int(k, v)
if v or v == 0:
build[k] = v build[k] = v
# versionCode must be int
if not isinstance(v, int):
_warn_or_exception(
_('{build_flag} must be an integer, found: {value}').format(
build_flag=k, value=v
)
)
elif _flagtype in (TYPE_LIST, TYPE_SCRIPT): elif _flagtype in (TYPE_LIST, TYPE_SCRIPT):
if isinstance(v, str) or isinstance(v, int): if v or v == 0:
build[k] = [_normalize_type_string(v)] build[k] = _normalize_type_list(k, v)
else:
build[k] = v
# float and dict are here only to keep things compatible
if type(build[k]) not in (list, tuple, set, float, dict):
_warn_or_exception(
_('{build_flag} must be list or string, found: {value}').format(
build_flag=k, value=v
)
)
elif _flagtype == TYPE_STRINGMAP: elif _flagtype == TYPE_STRINGMAP:
if v or v == 0: if v or v == 0:
build[k] = _normalize_type_stringmap(k, v) build[k] = _normalize_type_stringmap(k, v)
elif _flagtype == TYPE_BOOL:
build[k] = bool(v)
builds.append(build) builds.append(build)

View File

@ -343,6 +343,13 @@ class MetadataTest(unittest.TestCase):
self.assertEqual('false', metadata._normalize_type_string(False)) self.assertEqual('false', metadata._normalize_type_string(False))
self.assertEqual('true', metadata._normalize_type_string(True)) self.assertEqual('true', metadata._normalize_type_string(True))
def test_normalize_type_string_sha256(self):
"""SHA-256 values are TYPE_STRING, which YAML can parse as decimal ints."""
yaml = ruamel.yaml.YAML(typ='safe')
for v in range(1, 1000):
s = '%064d' % (v * (10**51))
self.assertEqual(s, metadata._normalize_type_string(yaml.load(s)))
def test_normalize_type_stringmap_none(self): def test_normalize_type_stringmap_none(self):
self.assertEqual(dict(), metadata._normalize_type_stringmap('key', None)) self.assertEqual(dict(), metadata._normalize_type_stringmap('key', None))
@ -355,6 +362,57 @@ class MetadataTest(unittest.TestCase):
metadata._normalize_type_stringmap('AntiFeatures', ['Ads', 'Tracking']), metadata._normalize_type_stringmap('AntiFeatures', ['Ads', 'Tracking']),
) )
def test_normalize_type_int(self):
"""TYPE_INT should be an int whenever possible."""
self.assertEqual(0, metadata._normalize_type_int('key', 0))
self.assertEqual(1, metadata._normalize_type_int('key', 1))
self.assertEqual(-5, metadata._normalize_type_int('key', -5))
self.assertEqual(0, metadata._normalize_type_int('key', '0'))
self.assertEqual(1, metadata._normalize_type_int('key', '1'))
self.assertEqual(-5, metadata._normalize_type_int('key', '-5'))
self.assertEqual(
12345678901234567890,
metadata._normalize_type_int('key', 12345678901234567890),
)
def test_normalize_type_int_fails(self):
with self.assertRaises(MetaDataException):
metadata._normalize_type_int('key', '1a')
with self.assertRaises(MetaDataException):
metadata._normalize_type_int('key', 1.1)
with self.assertRaises(MetaDataException):
metadata._normalize_type_int('key', True)
def test_normalize_type_list(self):
"""TYPE_LIST is always a list of strings, no matter what YAML thinks."""
k = 'placeholder'
yaml = ruamel.yaml.YAML(typ='safe')
self.assertEqual(['1.0'], metadata._normalize_type_list(k, 1.0))
self.assertEqual(['1234567890'], metadata._normalize_type_list(k, 1234567890))
self.assertEqual(['false'], metadata._normalize_type_list(k, False))
self.assertEqual(['true'], metadata._normalize_type_list(k, True))
self.assertEqual(['foo'], metadata._normalize_type_list(k, 'foo'))
self.assertEqual([], metadata._normalize_type_list(k, list()))
self.assertEqual([], metadata._normalize_type_list(k, tuple()))
self.assertEqual([], metadata._normalize_type_list(k, set()))
self.assertEqual(['0', '1', '2'], metadata._normalize_type_list(k, {0, 1, 2}))
self.assertEqual(
['a', 'b', 'c', '0', '0.0'],
metadata._normalize_type_list(k, yaml.load('[a, b, c, 0, 0.0]')),
)
self.assertEqual(
['1', '1.0', 's', 'true', '{}'],
metadata._normalize_type_list(k, yaml.load('[1, 1.0, s, true, {}]')),
)
self.assertEqual(
['1', '1.0', 's', 'true', '{}'],
metadata._normalize_type_list(k, (1, 1.0, 's', True, dict())),
)
def test_normalize_type_list_fails(self):
with self.assertRaises(MetaDataException):
metadata._normalize_type_list('placeholder', dict())
def test_post_parse_yaml_metadata(self): def test_post_parse_yaml_metadata(self):
yamldata = dict() yamldata = dict()
metadata.post_parse_yaml_metadata(yamldata) metadata.post_parse_yaml_metadata(yamldata)
@ -365,10 +423,18 @@ class MetadataTest(unittest.TestCase):
metadata.post_parse_yaml_metadata(yamldata) metadata.post_parse_yaml_metadata(yamldata)
def test_post_parse_yaml_metadata_fails(self): def test_post_parse_yaml_metadata_fails(self):
yamldata = {'AllowedAPKSigningKeys': True} yamldata = {'AllowedAPKSigningKeys': {'bad': 'dict-placement'}}
with self.assertRaises(TypeError): with self.assertRaises(MetaDataException):
metadata.post_parse_yaml_metadata(yamldata) metadata.post_parse_yaml_metadata(yamldata)
def test_post_parse_yaml_metadata_0padding_sha256(self):
"""SHA-256 values are strings, but YAML 1.2 will read some as decimal ints."""
v = '0027293472934293872934729834729834729834729834792837487293847926'
yaml = ruamel.yaml.YAML(typ='safe')
yamldata = yaml.load('AllowedAPKSigningKeys: ' + v)
metadata.post_parse_yaml_metadata(yamldata)
self.assertEqual(yamldata['AllowedAPKSigningKeys'], [v])
def test_post_parse_yaml_metadata_builds(self): def test_post_parse_yaml_metadata_builds(self):
yamldata = OrderedDict() yamldata = OrderedDict()
builds = [] builds = []
@ -383,7 +449,7 @@ class MetadataTest(unittest.TestCase):
yamldata, yamldata,
) )
build['versionCode'] = '1' build['versionCode'] = '1a'
self.assertRaises( self.assertRaises(
fdroidserver.exception.MetaDataException, fdroidserver.exception.MetaDataException,
fdroidserver.metadata.post_parse_yaml_metadata, fdroidserver.metadata.post_parse_yaml_metadata,
@ -475,14 +541,14 @@ class MetadataTest(unittest.TestCase):
) )
def test_parse_yaml_metadata_app_type_list_fails(self): def test_parse_yaml_metadata_app_type_list_fails(self):
mf = _get_mock_mf('AllowedAPKSigningKeys: true') mf = _get_mock_mf('AllowedAPKSigningKeys: {t: f}')
with self.assertRaises(TypeError): with self.assertRaises(MetaDataException):
metadata.parse_yaml_metadata(mf)
mf = _get_mock_mf('AllowedAPKSigningKeys: 1')
with self.assertRaises(TypeError):
metadata.parse_yaml_metadata(mf) metadata.parse_yaml_metadata(mf)
self.assertEqual(fdroidserver.metadata.parse_yaml_metadata(mf), dict()) def test_parse_yaml_metadata_build_type_list_fails(self):
mf = _get_mock_mf('Builds: [{versionCode: 1, rm: {bad: dict-placement}}]')
with self.assertRaises(MetaDataException):
metadata.parse_yaml_metadata(mf)
def test_parse_yaml_metadata_unknown_app_field(self): def test_parse_yaml_metadata_unknown_app_field(self):
mf = io.StringIO( mf = io.StringIO(
@ -965,6 +1031,24 @@ class MetadataTest(unittest.TestCase):
{'AntiFeatures': {'true': {}}}, {'AntiFeatures': {'true': {}}},
) )
def test_parse_yaml_app_antifeatures_float_nan(self):
self.assertEqual(
metadata.parse_yaml_metadata(io.StringIO('AntiFeatures: .nan')),
{'AntiFeatures': {'.nan': {}}},
)
def test_parse_yaml_app_antifeatures_float_inf(self):
self.assertEqual(
metadata.parse_yaml_metadata(io.StringIO('AntiFeatures: .inf')),
{'AntiFeatures': {'.inf': {}}},
)
def test_parse_yaml_app_antifeatures_float_negative_inf(self):
self.assertEqual(
metadata.parse_yaml_metadata(io.StringIO('AntiFeatures: -.inf')),
{'AntiFeatures': {'-.inf': {}}},
)
def test_parse_yaml_app_antifeatures_int(self): def test_parse_yaml_app_antifeatures_int(self):
self.assertEqual( self.assertEqual(
metadata.parse_yaml_metadata(io.StringIO('AntiFeatures: 1')), metadata.parse_yaml_metadata(io.StringIO('AntiFeatures: 1')),
@ -1106,6 +1190,34 @@ class MetadataTest(unittest.TestCase):
}, },
) )
def test_parse_yaml_build_type_int_fail(self):
mf = io.StringIO('Builds: [{versionCode: 1a}]')
with self.assertRaises(MetaDataException):
fdroidserver.metadata.parse_yaml_metadata(mf)
def test_parse_yaml_int_strict_typing_fails(self):
"""Things that cannot be preserved when parsing as YAML."""
mf = io.StringIO('Builds: [{versionCode: 1, rm: 0xf}]')
self.assertEqual(
{'Builds': [{'rm': ['15'], 'versionCode': 1}]}, # 15 != 0xf
fdroidserver.metadata.parse_yaml_metadata(mf),
)
mf = io.StringIO('Builds: [{versionCode: 1, rm: 0x010}]')
self.assertEqual(
{'Builds': [{'rm': ['16'], 'versionCode': 1}]}, # 16 != 0x010
fdroidserver.metadata.parse_yaml_metadata(mf),
)
mf = io.StringIO('Builds: [{versionCode: 1, rm: 0o015}]')
self.assertEqual(
{'Builds': [{'rm': ['13'], 'versionCode': 1}]}, # 13 != 0o015
fdroidserver.metadata.parse_yaml_metadata(mf),
)
mf = io.StringIO('Builds: [{versionCode: 1, rm: 10_000}]')
self.assertEqual(
{'Builds': [{'rm': ['10000'], 'versionCode': 1}]}, # 10000 != 10_000
fdroidserver.metadata.parse_yaml_metadata(mf),
)
def test_write_yaml_1_line_scripts_as_string(self): def test_write_yaml_1_line_scripts_as_string(self):
mf = io.StringIO() mf = io.StringIO()
app = fdroidserver.metadata.App() app = fdroidserver.metadata.App()
@ -1999,22 +2111,49 @@ class PostMetadataParseTest(unittest.TestCase):
app['Builds'][0][tested_key] = expected app['Builds'][0][tested_key] = expected
return app, post return app, post
def test_post_metadata_parse_none(self):
"""Run None aka YAML null or blank through the various field and flag types."""
self.assertEqual(*self._post_metadata_parse_app_list(None, None))
self.assertEqual(*self._post_metadata_parse_app_string(None, None))
self.assertEqual(*self._post_metadata_parse_build_bool(None, None))
self.assertEqual(*self._post_metadata_parse_build_int(None, None))
self.assertEqual(*self._post_metadata_parse_build_list(None, None))
self.assertEqual(*self._post_metadata_parse_build_script(None, None))
self.assertEqual(*self._post_metadata_parse_build_string(None, None))
def test_post_metadata_parse_int(self): def test_post_metadata_parse_int(self):
"""Run the int 123456 through the various field and flag types.""" """Run the int 123456 through the various field and flag types."""
with self.assertRaises(TypeError): self.assertEqual(*self._post_metadata_parse_app_list(123456, ['123456']))
self._post_metadata_parse_app_list(123456, TypeError)
self.assertEqual(*self._post_metadata_parse_app_string(123456, '123456')) self.assertEqual(*self._post_metadata_parse_app_string(123456, '123456'))
self.assertEqual(*self._post_metadata_parse_build_bool(123456, 123456)) self.assertEqual(*self._post_metadata_parse_build_bool(123456, True))
self.assertEqual(*self._post_metadata_parse_build_int(123456, 123456)) self.assertEqual(*self._post_metadata_parse_build_int(123456, 123456))
self.assertEqual(*self._post_metadata_parse_build_list(123456, ['123456'])) self.assertEqual(*self._post_metadata_parse_build_list(123456, ['123456']))
self.assertEqual(*self._post_metadata_parse_build_script(123456, ['123456'])) self.assertEqual(*self._post_metadata_parse_build_script(123456, ['123456']))
self.assertEqual(*self._post_metadata_parse_build_string(123456, '123456')) self.assertEqual(*self._post_metadata_parse_build_string(123456, '123456'))
def test_post_metadata_parse_sha256(self):
"""Run a SHA-256 that YAML calls an int through the various types.
The current f-droid.org signer set has SHA-256 values with a
maximum of two leading zeros, but this will handle more.
"""
yaml = ruamel.yaml.YAML(typ='safe', pure=True)
str_sha256 = '0000000000000498456908409534729834729834729834792837487293847926'
sha256 = yaml.load('a: ' + str_sha256)['a']
self.assertEqual(*self._post_metadata_parse_app_list(sha256, [str_sha256]))
self.assertEqual(*self._post_metadata_parse_app_string(sha256, str_sha256))
self.assertEqual(*self._post_metadata_parse_build_bool(sha256, True))
self.assertEqual(*self._post_metadata_parse_build_int(sha256, sha256))
self.assertEqual(*self._post_metadata_parse_build_list(sha256, [str_sha256]))
self.assertEqual(*self._post_metadata_parse_build_script(sha256, [str_sha256]))
self.assertEqual(*self._post_metadata_parse_build_string(sha256, str_sha256))
def test_post_metadata_parse_int_0(self): def test_post_metadata_parse_int_0(self):
"""Run the int 0 through the various field and flag types.""" """Run the int 0 through the various field and flag types."""
self.assertEqual(*self._post_metadata_parse_app_list(0, 0)) self.assertEqual(*self._post_metadata_parse_app_list(0, ['0']))
self.assertEqual(*self._post_metadata_parse_app_string(0, '0')) self.assertEqual(*self._post_metadata_parse_app_string(0, '0'))
self.assertEqual(*self._post_metadata_parse_build_bool(0, 0)) self.assertEqual(*self._post_metadata_parse_build_bool(0, False))
self.assertEqual(*self._post_metadata_parse_build_int(0, 0)) self.assertEqual(*self._post_metadata_parse_build_int(0, 0))
self.assertEqual(*self._post_metadata_parse_build_list(0, ['0'])) self.assertEqual(*self._post_metadata_parse_build_list(0, ['0']))
self.assertEqual(*self._post_metadata_parse_build_script(0, ['0'])) self.assertEqual(*self._post_metadata_parse_build_script(0, ['0']))
@ -2022,43 +2161,41 @@ class PostMetadataParseTest(unittest.TestCase):
def test_post_metadata_parse_float_0_0(self): def test_post_metadata_parse_float_0_0(self):
"""Run the float 0.0 through the various field and flag types.""" """Run the float 0.0 through the various field and flag types."""
self.assertEqual(*self._post_metadata_parse_app_list(0.0, 0.0)) self.assertEqual(*self._post_metadata_parse_app_list(0.0, ['0.0']))
self.assertEqual(*self._post_metadata_parse_app_string(0.0, '0.0')) self.assertEqual(*self._post_metadata_parse_app_string(0.0, '0.0'))
self.assertEqual(*self._post_metadata_parse_build_bool(0.0, 0.0)) self.assertEqual(*self._post_metadata_parse_build_bool(0.0, False))
with self.assertRaises(MetaDataException): with self.assertRaises(MetaDataException):
self._post_metadata_parse_build_int(0.0, MetaDataException) self._post_metadata_parse_build_int(0.0, MetaDataException)
self.assertEqual(*self._post_metadata_parse_build_list(0.0, 0.0)) self.assertEqual(*self._post_metadata_parse_build_list(0.0, ['0.0']))
self.assertEqual(*self._post_metadata_parse_build_script(0.0, 0.0)) self.assertEqual(*self._post_metadata_parse_build_script(0.0, ['0.0']))
self.assertEqual(*self._post_metadata_parse_build_string(0.0, '0.0')) self.assertEqual(*self._post_metadata_parse_build_string(0.0, '0.0'))
def test_post_metadata_parse_float_0_1(self): def test_post_metadata_parse_float_0_1(self):
"""Run the float 0.1 through the various field and flag types.""" """Run the float 0.1 through the various field and flag types."""
with self.assertRaises(TypeError): self.assertEqual(*self._post_metadata_parse_app_list(0.1, ['0.1']))
self._post_metadata_parse_app_list(0.1, TypeError)
self.assertEqual(*self._post_metadata_parse_app_string(0.1, '0.1')) self.assertEqual(*self._post_metadata_parse_app_string(0.1, '0.1'))
self.assertEqual(*self._post_metadata_parse_build_bool(0.1, 0.1)) self.assertEqual(*self._post_metadata_parse_build_bool(0.1, True))
with self.assertRaises(MetaDataException): with self.assertRaises(MetaDataException):
self._post_metadata_parse_build_int(0.1, MetaDataException) self._post_metadata_parse_build_int(0.1, MetaDataException)
self.assertEqual(*self._post_metadata_parse_build_list(0.1, 0.1)) self.assertEqual(*self._post_metadata_parse_build_list(0.1, ['0.1']))
self.assertEqual(*self._post_metadata_parse_build_script(0.1, 0.1)) self.assertEqual(*self._post_metadata_parse_build_script(0.1, ['0.1']))
self.assertEqual(*self._post_metadata_parse_build_string(0.1, '0.1')) self.assertEqual(*self._post_metadata_parse_build_string(0.1, '0.1'))
def test_post_metadata_parse_float_1_0(self): def test_post_metadata_parse_float_1_0(self):
"""Run the float 1.0 through the various field and flag types.""" """Run the float 1.0 through the various field and flag types."""
with self.assertRaises(TypeError): self.assertEqual(*self._post_metadata_parse_app_list(1.0, ['1.0']))
self._post_metadata_parse_app_list(1.0, TypeError)
self.assertEqual(*self._post_metadata_parse_app_string(1.0, '1.0')) self.assertEqual(*self._post_metadata_parse_app_string(1.0, '1.0'))
self.assertEqual(*self._post_metadata_parse_build_bool(1.0, 1.0)) self.assertEqual(*self._post_metadata_parse_build_bool(1.0, True))
with self.assertRaises(MetaDataException): with self.assertRaises(MetaDataException):
self._post_metadata_parse_build_int(1.0, MetaDataException) self._post_metadata_parse_build_int(1.0, MetaDataException)
self.assertEqual(*self._post_metadata_parse_build_list(1.0, 1.0)) self.assertEqual(*self._post_metadata_parse_build_list(1.0, ['1.0']))
self.assertEqual(*self._post_metadata_parse_build_script(1.0, 1.0)) self.assertEqual(*self._post_metadata_parse_build_script(1.0, ['1.0']))
self.assertEqual(*self._post_metadata_parse_build_string(1.0, '1.0')) self.assertEqual(*self._post_metadata_parse_build_string(1.0, '1.0'))
def test_post_metadata_parse_empty_list(self): def test_post_metadata_parse_empty_list(self):
self.assertEqual(*self._post_metadata_parse_app_list(list(), list())) self.assertEqual(*self._post_metadata_parse_app_list(list(), list()))
self.assertEqual(*self._post_metadata_parse_app_string(list(), list())) self.assertEqual(*self._post_metadata_parse_app_string(list(), list()))
self.assertEqual(*self._post_metadata_parse_build_bool(list(), list())) self.assertEqual(*self._post_metadata_parse_build_bool(list(), False))
with self.assertRaises(MetaDataException): with self.assertRaises(MetaDataException):
self._post_metadata_parse_build_int(list(), MetaDataException) self._post_metadata_parse_build_int(list(), MetaDataException)
self.assertEqual(*self._post_metadata_parse_build_list(list(), list())) self.assertEqual(*self._post_metadata_parse_build_list(list(), list()))
@ -2068,17 +2205,17 @@ class PostMetadataParseTest(unittest.TestCase):
def test_post_metadata_parse_set_of_1(self): def test_post_metadata_parse_set_of_1(self):
self.assertEqual(*self._post_metadata_parse_app_list({1}, ['1'])) self.assertEqual(*self._post_metadata_parse_app_list({1}, ['1']))
self.assertEqual(*self._post_metadata_parse_app_string({1}, '{1}')) self.assertEqual(*self._post_metadata_parse_app_string({1}, '{1}'))
self.assertEqual(*self._post_metadata_parse_build_bool({1}, {1})) self.assertEqual(*self._post_metadata_parse_build_bool({1}, True))
with self.assertRaises(MetaDataException): with self.assertRaises(MetaDataException):
self._post_metadata_parse_build_int({1}, MetaDataException) self._post_metadata_parse_build_int({1}, MetaDataException)
self.assertEqual(*self._post_metadata_parse_build_list({1}, {1})) self.assertEqual(*self._post_metadata_parse_build_list({1}, ['1']))
self.assertEqual(*self._post_metadata_parse_build_script({1}, {1})) self.assertEqual(*self._post_metadata_parse_build_script({1}, ['1']))
self.assertEqual(*self._post_metadata_parse_build_string({1}, '{1}')) self.assertEqual(*self._post_metadata_parse_build_string({1}, '{1}'))
def test_post_metadata_parse_empty_dict(self): def test_post_metadata_parse_empty_dict(self):
self.assertEqual(*self._post_metadata_parse_app_list(dict(), dict())) self.assertEqual(*self._post_metadata_parse_app_list(dict(), dict()))
self.assertEqual(*self._post_metadata_parse_app_string(dict(), dict())) self.assertEqual(*self._post_metadata_parse_app_string(dict(), dict()))
self.assertEqual(*self._post_metadata_parse_build_bool(dict(), dict())) self.assertEqual(*self._post_metadata_parse_build_bool(dict(), False))
with self.assertRaises(MetaDataException): with self.assertRaises(MetaDataException):
self._post_metadata_parse_build_int(dict(), MetaDataException) self._post_metadata_parse_build_int(dict(), MetaDataException)
self.assertEqual(*self._post_metadata_parse_build_list(dict(), dict())) self.assertEqual(*self._post_metadata_parse_build_list(dict(), dict()))
@ -2088,38 +2225,42 @@ class PostMetadataParseTest(unittest.TestCase):
def test_post_metadata_parse_list_int_string(self): def test_post_metadata_parse_list_int_string(self):
self.assertEqual(*self._post_metadata_parse_app_list([1, 'a'], ['1', 'a'])) self.assertEqual(*self._post_metadata_parse_app_list([1, 'a'], ['1', 'a']))
self.assertEqual(*self._post_metadata_parse_app_string([1, 'a'], "[1, 'a']")) self.assertEqual(*self._post_metadata_parse_app_string([1, 'a'], "[1, 'a']"))
self.assertEqual(*self._post_metadata_parse_build_bool([1, 'a'], [1, 'a'])) self.assertEqual(*self._post_metadata_parse_build_bool([1, 'a'], True))
with self.assertRaises(MetaDataException): with self.assertRaises(MetaDataException):
self._post_metadata_parse_build_int([1, 'a'], MetaDataException) self._post_metadata_parse_build_int([1, 'a'], MetaDataException)
self.assertEqual(*self._post_metadata_parse_build_list([1, 'a'], [1, 'a'])) self.assertEqual(*self._post_metadata_parse_build_list([1, 'a'], ['1', 'a']))
self.assertEqual(*self._post_metadata_parse_build_script([1, 'a'], [1, 'a'])) self.assertEqual(*self._post_metadata_parse_build_script([1, 'a'], ['1', 'a']))
self.assertEqual(*self._post_metadata_parse_build_string([1, 'a'], "[1, 'a']")) self.assertEqual(*self._post_metadata_parse_build_string([1, 'a'], "[1, 'a']"))
def test_post_metadata_parse_dict_int_string(self): def test_post_metadata_parse_dict_int_string(self):
self.assertEqual(*self._post_metadata_parse_app_list({'k': 1}, ['k'])) with self.assertRaises(MetaDataException):
self._post_metadata_parse_app_list({'k': 1}, MetaDataException)
self.assertEqual(*self._post_metadata_parse_app_string({'k': 1}, "{'k': 1}")) self.assertEqual(*self._post_metadata_parse_app_string({'k': 1}, "{'k': 1}"))
self.assertEqual(*self._post_metadata_parse_build_bool({'k': 1}, {'k': 1})) self.assertEqual(*self._post_metadata_parse_build_bool({'k': 1}, True))
with self.assertRaises(MetaDataException): with self.assertRaises(MetaDataException):
self._post_metadata_parse_build_int({'k': 1}, MetaDataException) self._post_metadata_parse_build_int({'k': 1}, MetaDataException)
self.assertEqual(*self._post_metadata_parse_build_list({'k': 1}, {'k': 1})) with self.assertRaises(MetaDataException):
self.assertEqual(*self._post_metadata_parse_build_script({'k': 1}, {'k': 1})) self._post_metadata_parse_build_list({'k': 1}, MetaDataException)
with self.assertRaises(MetaDataException):
self._post_metadata_parse_build_script({'k': 1}, MetaDataException)
self.assertEqual(*self._post_metadata_parse_build_string({'k': 1}, "{'k': 1}")) self.assertEqual(*self._post_metadata_parse_build_string({'k': 1}, "{'k': 1}"))
def test_post_metadata_parse_false(self): def test_post_metadata_parse_false(self):
self.assertEqual(*self._post_metadata_parse_app_list(False, False)) self.assertEqual(*self._post_metadata_parse_app_list(False, ['false']))
self.assertEqual(*self._post_metadata_parse_app_string(False, 'false')) self.assertEqual(*self._post_metadata_parse_app_string(False, 'false'))
self.assertEqual(*self._post_metadata_parse_build_bool(False, False)) self.assertEqual(*self._post_metadata_parse_build_bool(False, False))
self.assertEqual(*self._post_metadata_parse_build_int(False, False)) with self.assertRaises(MetaDataException):
self._post_metadata_parse_build_int(False, MetaDataException)
self.assertEqual(*self._post_metadata_parse_build_list(False, ['false'])) self.assertEqual(*self._post_metadata_parse_build_list(False, ['false']))
self.assertEqual(*self._post_metadata_parse_build_script(False, ['false'])) self.assertEqual(*self._post_metadata_parse_build_script(False, ['false']))
self.assertEqual(*self._post_metadata_parse_build_string(False, 'false')) self.assertEqual(*self._post_metadata_parse_build_string(False, 'false'))
def test_post_metadata_parse_true(self): def test_post_metadata_parse_true(self):
with self.assertRaises(TypeError): self.assertEqual(*self._post_metadata_parse_app_list(True, ['true']))
self._post_metadata_parse_app_list(True, TypeError)
self.assertEqual(*self._post_metadata_parse_app_string(True, 'true')) self.assertEqual(*self._post_metadata_parse_app_string(True, 'true'))
self.assertEqual(*self._post_metadata_parse_build_bool(True, True)) self.assertEqual(*self._post_metadata_parse_build_bool(True, True))
self.assertEqual(*self._post_metadata_parse_build_int(True, True)) with self.assertRaises(MetaDataException):
self._post_metadata_parse_build_int(True, MetaDataException)
self.assertEqual(*self._post_metadata_parse_build_list(True, ['true'])) self.assertEqual(*self._post_metadata_parse_build_list(True, ['true']))
self.assertEqual(*self._post_metadata_parse_build_script(True, ['true'])) self.assertEqual(*self._post_metadata_parse_build_script(True, ['true']))
self.assertEqual(*self._post_metadata_parse_build_string(True, 'true')) self.assertEqual(*self._post_metadata_parse_build_string(True, 'true'))