rougail/tests/test_others.py

165 lines
6.4 KiB
Python

from pytest import raises
from lxml.etree import DTD
from os.path import isfile
from copy import copy
from rougail import RougailConvert, RougailConfig
from rougail.error import DictConsistencyError
def parse_dtd_subelement(obj_name, content, default_required=False):
if not content:
return
if content.type == 'pcdata':
if obj_name in ['value', 'param']:
type_ = 'any'
else:
type_ = 'str'
yield {'name': 'text', 'type': type_, 'required': False}
elif content.name:
yield {'name': content.name, 'type': None, 'required': default_required}
if content.left:
if content.left.type == 'pcdata':
# choice
yield {'name': 'text', 'type': 'any', 'required': False}
else:
yield {'name': content.left.name, 'type': None, 'required': default_required}
if content.right:
if content.occur == 'once':
if content.right and content.right.name:
yield {'name': content.right.name, 'type': None, 'required': default_required}
else:
yield from parse_dtd_subelement(obj_name, content.right, default_required=False)
elif content.occur == 'mult':
yield from parse_dtd_subelement(obj_name, content.right, default_required=False)
elif content.occur == 'plus':
yield from parse_dtd_subelement(obj_name, content.right, default_required=False)
else:
raise Exception('pffff')
def parse_dtd(elt_name, elts, space=0):
elt = elts.get(elt_name)
if not elt:
return ''
schema = ''
if space:
schema += " " * space + "type: seq\n"
schema += " " * space + "sequence:\n"
space = space + 2
schema += " " * space + "- type: map\n"
space = space + 2
schema += " " * space + "mapping:\n"
if elt_name == 'variables':
# type
subspace = space + 2
schema += " " * subspace + "variable:\n"
schema += parse_dtd('variable', elts, subspace + 2)
# variables
if subspace < 50:
schema += " " * subspace + "family:\n"
schema += parse_dtd('family', elts, subspace + 2)
subspace = subspace + 8
schema += " " * subspace + "variables:\n"
schema += parse_dtd(elt_name, elts, subspace + 2)
else:
schema += " " * space + "type: map\n"
schema += " " * space + "mapping:\n"
space = space + 2
if elt_name != 'variables':
if 'subelts' in elt:
for subelt in elt['subelts']:
schema += " " * space + subelt['name'] + ":\n"
subspace = space + 2
schema += " " * subspace + 'required: ' + {False: 'false', True: 'true'}[subelt['required']] + "\n"
if subelt['type']:
schema += " " * subspace + 'type: ' + subelt['type'] + "\n"
if subelt['name'] != 'family' or subspace < 26:
schema += parse_dtd(subelt['name'], elts, subspace)
attributes = {attr.name: attr for attr in elt['elt'].iterattributes()}
for name, dtd_attr in attributes.items():
enum = list(dtd_attr.itervalues())
if set(enum) == {'True', 'False'} or set(enum) == {'True', 'False', 'nil'}:
# it's a boolean
type_ = 'bool'
elif enum == ['number']:
continue
elif f'{name}_type' in attributes and list(attributes[f'{name}_type'].itervalues()) == ['number']:
type_ = 'int'
else:
type_ = 'str'
schema += " " * space + name + ':\n'
subspace = space + 2
schema += " " * subspace + "type: " + type_ + '\n'
if type_ != 'bool' and enum:
enumspace = subspace + 2
schema += " " * subspace + 'enum:\n'
for value in enum:
schema += " " * enumspace + '- "' + value + '"\n'
return schema
def test_valid_dtd_schema_equal():
with open(RougailConfig['dtdfilename'], 'r') as dtdfd:
dtd = DTD(dtdfd)
elts = {}
for dtd_elt in dtd.iterelements():
subelts = tuple(parse_dtd_subelement(dtd_elt.name, dtd_elt.content))
ret = {'elt': dtd_elt}
if subelts:
ret['subelts'] = subelts
elts[dtd_elt.name] = ret
schema = parse_dtd('rougail', elts)
if not isfile(RougailConfig['yamlschema_filename']):
with open(RougailConfig['yamlschema_filename'], 'w') as ymldf:
ymldf.write(schema)
with open(RougailConfig['yamlschema_filename'], 'r') as ymldf:
ori_schema = ymldf.read()
assert schema == ori_schema, f'DTD and YAML schema ({RougailConfig["yamlschema_filename"]}) are different'
def test_no_dtd():
cfg = RougailConfig.copy()
cfg['dtdfilename'] = 'notexists.dtd'
with raises(IOError):
eolobj = RougailConvert(cfg)
def test_mode_invalid_default():
# default variable mode is not in modes_level
RougailConfig['dictionaries_dir'] = ['tests/personalize_mode/dictionary']
RougailConfig['modes_level'] = ('level1', 'level2')
eolobj = RougailConvert()
with raises(DictConsistencyError) as err:
eolobj.reflexion()
assert err.value.errno == 72
def test_mode_invalid_default_family():
# default family mode is not in modes_level
RougailConfig['dictionaries_dir'] = ['tests/personalize_mode/dictionary']
RougailConfig['modes_level'] = ('level1', 'level2')
RougailConfig['default_variable_mode'] = 'level1'
eolobj = RougailConvert()
with raises(DictConsistencyError) as err:
eolobj.reflexion()
assert err.value.errno == 73
def test_personalize_mode():
RougailConfig['dictionaries_dir'] = ['tests/personalize_mode/dictionary']
RougailConfig['modes_level'] = ('level1', 'level2')
RougailConfig['default_variable_mode'] = 'level1'
RougailConfig['default_family_mode'] = 'level1'
eolobj = RougailConvert()
eolobj.save(None)
def test_personalize_mode_unknown():
# a variable has an unknown mode
RougailConfig['dictionaries_dir'] = ['tests/personalize_mode/dictionary']
RougailConfig['modes_level'] = ('level1',)
RougailConfig['default_variable_mode'] = 'level1'
RougailConfig['default_family_mode'] = 'level1'
eolobj = RougailConvert()
with raises(DictConsistencyError) as err:
eolobj.reflexion()
assert err.value.errno == 71