# coding: utf-8
from .autopath import do_autopath
do_autopath()

from tiramisu.setting import groups, owners
from tiramisu.option import BoolOption, StrOption, ChoiceOption, IPOption, \
    NetworkOption, NetmaskOption, IntOption, FloatOption, \
    UnicodeOption, PortOption, BroadcastOption, DomainnameOption, \
    EmailOption, URLOption, UsernameOption, FilenameOption, SymLinkOption, \
    OptionDescription, DynOptionDescription, DynSymLinkOption, submulti, MasterSlaves
from tiramisu.config import Config
from tiramisu.error import PropertiesOptionError, ConfigError, ConflictError
from tiramisu.storage import delete_session
from .test_state import _diff_opts, _diff_conf

from py.test import raises


def return_true(value, param=None, suffix=None):
    if value == 'val' and param in [None, 'yes']:
        return
    raise ValueError('no value')


def return_dynval(value='val', suffix=None):
    return value


def return_list2(suffix):
    return [str(suffix), 'val2']


def return_list(val=None, suffix=None):
    if val:
        return val
    else:
        return ['val1', 'val2']


def return_same_list():
    return ['val1', 'val1']


def return_wrong_list():
    return ['---', ' ']


def return_raise():
    raise Exception('error')


def test_build_dyndescription():
    st = StrOption('st', '')
    dod = DynOptionDescription('dod', '', [st], callback=return_list)
    od = OptionDescription('od', '', [dod])
    cfg = Config(od)
    assert str(cfg) == """[dodval1]
[dodval2]"""
    assert str(cfg.dodval1) == "stval1 = None"
    assert str(cfg.dodval2) == "stval2 = None"


def test_build_dyndescription_raise():
    st = StrOption('st', '')
    dod = DynOptionDescription('dod', '', [st], callback=return_raise)
    od = OptionDescription('od', '', [dod])
    cfg = Config(od)
    raises(ConfigError, "str(cfg)")


def test_subpath_dyndescription():
    st = StrOption('st', '')
    dod = DynOptionDescription('dod', '', [st], callback=return_list)
    od = OptionDescription('od', '', [dod])
    od2 = OptionDescription('od', '', [od])
    cfg = Config(od2)
    assert str(cfg) == "[od]"
    assert str(cfg.od) == """[dodval1]
[dodval2]"""
    assert str(cfg.od.dodval1) == "stval1 = None"
    assert str(cfg.od.dodval2) == "stval2 = None"


def test_list_dyndescription():
    st = StrOption('st', '')
    dod = DynOptionDescription('dod', '', [st], callback=return_list)
    od = OptionDescription('od', '', [dod])
    od2 = OptionDescription('od', '', [od])
    cfg = Config(od2)
    assert cfg.od.dodval1.stval1 is None
    assert cfg.od.dodval2.stval2 is None


def test_unknown_dyndescription():
    st = StrOption('st', '')
    dod = DynOptionDescription('dod', '', [st], callback=return_list)
    od = OptionDescription('od', '', [dod])
    od2 = OptionDescription('od', '', [od])
    cfg = Config(od2)
    cfg
    raises(AttributeError, "cfg.od.dodval3")
    raises(AttributeError, "cfg.od.dodval1.novalue")


def test_getdoc_dyndescription():
    st = StrOption('st', 'doc1')
    dod = DynOptionDescription('dod', 'doc2', [st], callback=return_list)
    od = OptionDescription('od', '', [dod])
    od2 = OptionDescription('od', '', [od])
    cfg = Config(od2)
    stval1 = cfg.unwrap_from_path('od.dodval1.stval1')
    stval2 = cfg.unwrap_from_path('od.dodval2.stval2')
    dodval1 = cfg.unwrap_from_path('od.dodval1')
    dodval2 = cfg.unwrap_from_path('od.dodval2')
    assert stval1.impl_getname() == 'stval1'
    assert stval2.impl_getname() == 'stval2'
    assert dodval1.impl_getname() == 'dodval1'
    assert dodval2.impl_getname() == 'dodval2'
    assert stval1.impl_getdoc() == 'doc1'
    assert stval2.impl_getdoc() == 'doc1'
    assert dodval1.impl_getdoc() == 'doc2'
    assert dodval2.impl_getdoc() == 'doc2'


def test_getpaths_dyndescription():
    st = StrOption('st', '')
    dod = DynOptionDescription('dod', '', [st], callback=return_list)
    od = OptionDescription('od', '', [dod])
    od2 = OptionDescription('od', '', [od])
    cfg = Config(od2)
    assert cfg.cfgimpl_get_description().impl_getpaths() == ['od.dodval1.stval1', 'od.dodval2.stval2']
    assert cfg.cfgimpl_get_description().impl_getpaths(include_groups=True) == ['od', 'od.dodval1', 'od.dodval1.stval1', 'od.dodval2', 'od.dodval2.stval2']


def test_mod_dyndescription():
    st = StrOption('st', '')
    dod = DynOptionDescription('dod', '', [st], callback=return_list)
    od = OptionDescription('od', '', [dod])
    od2 = OptionDescription('od', '', [od])
    cfg = Config(od2)
    owner = cfg.cfgimpl_get_settings().getowner()
    stval1 = cfg.unwrap_from_path('od.dodval1.stval1')
    stval2 = cfg.unwrap_from_path('od.dodval2.stval2')
    assert cfg.od.dodval1.stval1 is None
    assert cfg.od.dodval2.stval2 is None
    assert cfg.getowner(stval1) == owners.default
    assert cfg.getowner(stval2) == owners.default
    cfg.od.dodval1.stval1 = 'yes'
    assert cfg.od.dodval1.stval1 == 'yes'
    assert cfg.od.dodval2.stval2 is None
    assert cfg.getowner(stval1) == owner
    assert cfg.getowner(stval2) == owners.default
    cfg.od.dodval2.stval2 = 'no'
    assert cfg.od.dodval1.stval1 == 'yes'
    assert cfg.od.dodval2.stval2 == 'no'
    #assert cfg.getowner(st) == owners.default
    assert cfg.getowner(stval1) == owner
    assert cfg.getowner(stval2) == owner


def test_del_dyndescription():
    st = StrOption('st', '')
    dod = DynOptionDescription('dod', '', [st], callback=return_list)
    od = OptionDescription('od', '', [dod])
    od2 = OptionDescription('od', '', [od])
    cfg = Config(od2)
    owner = cfg.cfgimpl_get_settings().getowner()
    stval1 = cfg.unwrap_from_path('od.dodval1.stval1')
    assert cfg.od.dodval1.stval1 is None
    assert cfg.od.dodval2.stval2 is None
    cfg.od.dodval1.stval1 = 'yes'
    assert cfg.getowner(stval1) == owner
    del(cfg.od.dodval1.stval1)
    assert cfg.getowner(stval1) == owners.default


def test_multi_dyndescription():
    st = StrOption('st', '', multi=True)
    dod = DynOptionDescription('dod', '', [st], callback=return_list)
    od = OptionDescription('od', '', [dod])
    od2 = OptionDescription('od', '', [od])
    cfg = Config(od2)
    owner = cfg.cfgimpl_get_settings().getowner()
    stval1 = cfg.unwrap_from_path('od.dodval1.stval1')
    stval2 = cfg.unwrap_from_path('od.dodval2.stval2')
    assert cfg.od.dodval1.stval1 == []
    assert cfg.od.dodval2.stval2 == []
    assert cfg.getowner(stval1) == owners.default
    assert cfg.getowner(stval2) == owners.default
    cfg.od.dodval1.stval1.append('yes')
    assert cfg.od.dodval1.stval1 == ['yes']
    assert cfg.od.dodval2.stval2 == []
    assert cfg.getowner(stval1) == owner
    assert cfg.getowner(stval2) == owners.default
    cfg.od.dodval2.stval2 = ['no']
    assert cfg.od.dodval1.stval1 == ['yes']
    assert cfg.od.dodval2.stval2 == ['no']
    #assert cfg.getowner(st) == owners.default
    assert cfg.getowner(stval1) == owner
    assert cfg.getowner(stval2) == owner
    cfg.od.dodval1.stval1.append('yes')
    assert cfg.od.dodval1.stval1 == ['yes', 'yes']
    cfg.od.dodval1.stval1.pop(0)
    assert cfg.od.dodval1.stval1 == ['yes']


def test_prop_dyndescription():
    st = StrOption('st', '', properties=('test',))
    dod = DynOptionDescription('dod', '', [st], callback=return_list)
    od = OptionDescription('od', '', [dod])
    od2 = OptionDescription('od', '', [od])
    cfg = Config(od2)
    stval1 = cfg.unwrap_from_path('od.dodval1.stval1')
    stval2 = cfg.unwrap_from_path('od.dodval2.stval2')
    dodval1 = cfg.unwrap_from_path('od.dodval1')
    dodval2 = cfg.unwrap_from_path('od.dodval2')
    assert set(cfg.cfgimpl_get_settings()[stval1].get()) == set(['test'])
    assert set(cfg.cfgimpl_get_settings()[stval2].get()) == set(['test'])
    cfg.cfgimpl_get_settings()[stval2].append('test2')
    assert set(cfg.cfgimpl_get_settings()[stval1].get()) == set(['test'])
    assert set(cfg.cfgimpl_get_settings()[stval2].get()) == set(['test', 'test2'])
    cfg.cfgimpl_get_settings()[stval1].remove('test')
    assert str(cfg.cfgimpl_get_settings()[stval1]) == str([])
    #
    assert str(cfg.cfgimpl_get_settings()[dodval1]) == str([])
    assert str(cfg.cfgimpl_get_settings()[dodval2]) == str([])
    cfg.cfgimpl_get_settings()[dodval1].append('test1')
    assert set(cfg.cfgimpl_get_settings()[dodval1].get()) == set(['test1'])
    assert str(cfg.cfgimpl_get_settings()[dodval2]) == str([])
    cfg.cfgimpl_get_settings()[dodval1].remove('test1')
    assert str(cfg.cfgimpl_get_settings()[dodval1]) == str([])
    assert str(cfg.cfgimpl_get_settings()[dodval2]) == str([])


def test_prop_dyndescription_force_store_value():
    st = StrOption('st', '', properties=('force_store_value',))
    dod = DynOptionDescription('dod', '', [st], callback=return_list)
    od = OptionDescription('od', '', [dod])
    od2 = OptionDescription('od', '', [od])
    raises(ConfigError, "Config(od2)")


def test_callback_dyndescription():
    st = StrOption('st', '', callback=return_dynval)
    dod = DynOptionDescription('dod', '', [st], callback=return_list)
    od = OptionDescription('od', '', [dod])
    od2 = OptionDescription('od', '', [od])
    cfg = Config(od2)
    owner = cfg.cfgimpl_get_settings().getowner()
    stval1 = cfg.unwrap_from_path('od.dodval1.stval1')
    stval2 = cfg.unwrap_from_path('od.dodval2.stval2')
    assert cfg.od.dodval1.stval1 == 'val'
    assert cfg.od.dodval2.stval2 == 'val'
    assert cfg.getowner(stval1) == owners.default
    assert cfg.getowner(stval2) == owners.default
    cfg.od.dodval1.stval1 = 'val2'
    assert cfg.od.dodval1.stval1 == 'val2'
    assert cfg.od.dodval2.stval2 == 'val'
    assert cfg.getowner(stval1) == owner
    assert cfg.getowner(stval2) == owners.default
    del(cfg.od.dodval1.stval1)
    assert cfg.od.dodval1.stval1 == 'val'
    assert cfg.od.dodval2.stval2 == 'val'
    assert cfg.getowner(stval1) == owners.default
    assert cfg.getowner(stval2) == owners.default


def test_callback_list_dyndescription():
    st = StrOption('st', '', callback=return_list2, multi=True)
    dod = DynOptionDescription('dod', '', [st], callback=return_list)
    od = OptionDescription('od', '', [dod])
    od2 = OptionDescription('od', '', [od])
    cfg = Config(od2)
    owner = cfg.cfgimpl_get_settings().getowner()
    stval1 = cfg.unwrap_from_path('od.dodval1.stval1')
    stval2 = cfg.unwrap_from_path('od.dodval2.stval2')
    assert cfg.od.dodval1.stval1 == ['val1', 'val2']
    assert cfg.od.dodval2.stval2 == ['val2', 'val2']
    assert cfg.getowner(stval1) == owners.default
    assert cfg.getowner(stval2) == owners.default
    cfg.od.dodval1.stval1 = ['val3', 'val2']
    assert cfg.od.dodval1.stval1 == ['val3', 'val2']
    assert cfg.od.dodval2.stval2 == ['val2', 'val2']
    assert cfg.getowner(stval1) == owner
    assert cfg.getowner(stval2) == owners.default


def test_mandatory_dyndescription():
    st = StrOption('st', '', properties=('mandatory',))
    dod = DynOptionDescription('dod', '', [st], callback=return_list)
    od = OptionDescription('od', '', [dod])
    od2 = OptionDescription('od', '', [od])
    cfg = Config(od2)
    cfg.read_only()
    raises(PropertiesOptionError, "cfg.od.dodval1.stval1")
    raises(PropertiesOptionError, "cfg.od.dodval2.stval2")
    cfg.read_write()
    cfg.od.dodval1.stval1 = 'val'
    cfg.read_only()
    assert cfg.od.dodval1.stval1 == 'val'
    raises(PropertiesOptionError, "cfg.od.dodval2.stval2")
    cfg.read_write()
    del(cfg.od.dodval1.stval1)
    cfg.read_only()
    raises(PropertiesOptionError, "cfg.od.dodval1.stval1")
    assert list(cfg.cfgimpl_get_values().mandatory_warnings()) == ['od.dodval1.stval1', 'od.dodval2.stval2']


def test_build_dyndescription_context():
    val1 = StrOption('val1', '', ['val1', 'val2'], multi=True)
    st = StrOption('st', '')
    dod = DynOptionDescription('dod', '', [st], callback=return_list, callback_params={'': ((val1, False),)})
    od = OptionDescription('od', '', [dod, val1])
    cfg = Config(od)
    cfg._impl_test = True
    assert str(cfg) == """[dodval1]
[dodval2]
val1 = ['val1', 'val2']"""
    assert str(cfg.dodval1) == "stval1 = None"
    assert str(cfg.dodval2) == "stval2 = None"
    cfg.unwrap_from_path('dodval2')


def test_subpath_dyndescription_context():
    val1 = StrOption('val1', '', ['val1', 'val2'], multi=True)
    st = StrOption('st', '')
    dod = DynOptionDescription('dod', '', [st], callback=return_list, callback_params={'': ((val1, False),)})
    od = OptionDescription('od', '', [dod, val1])
    od2 = OptionDescription('od', '', [od])
    cfg = Config(od2)
    assert str(cfg) == "[od]"
    assert str(cfg.od) == """[dodval1]
[dodval2]
val1 = ['val1', 'val2']"""
    assert str(cfg.od.dodval1) == "stval1 = None"
    assert str(cfg.od.dodval2) == "stval2 = None"


def test_list_dyndescription_context():
    val1 = StrOption('val1', '', ['val1', 'val2'], multi=True)
    st = StrOption('st', '')
    dod = DynOptionDescription('dod', '', [st], callback=return_list, callback_params={'': ((val1, False),)})
    od = OptionDescription('od', '', [dod, val1])
    od2 = OptionDescription('od', '', [od])
    cfg = Config(od2)
    assert cfg.od.dodval1.stval1 is None
    assert cfg.od.dodval2.stval2 is None
    raises(AttributeError, "cfg.od.dodval3")


def test_mod_dyndescription_context():
    val1 = StrOption('val1', '', ['val1', 'val2'], multi=True)
    st = StrOption('st', '')
    dod = DynOptionDescription('dod', '', [st], callback=return_list, callback_params={'': ((val1, False),)})
    od = OptionDescription('od', '', [dod, val1])
    od2 = OptionDescription('od', '', [od])
    cfg = Config(od2)
    owner = cfg.cfgimpl_get_settings().getowner()
    stval1 = cfg.unwrap_from_path('od.dodval1.stval1')
    stval2 = cfg.unwrap_from_path('od.dodval2.stval2')
    assert cfg.od.dodval1.stval1 is None
    assert cfg.od.dodval2.stval2 is None
    assert cfg.getowner(stval1) == owners.default
    assert cfg.getowner(stval2) == owners.default
    cfg.od.dodval1.stval1 = 'yes'
    assert cfg.od.dodval1.stval1 == 'yes'
    assert cfg.od.dodval2.stval2 is None
    assert cfg.getowner(stval1) == owner
    assert cfg.getowner(stval2) == owners.default
    cfg.od.dodval2.stval2 = 'no'
    assert cfg.od.dodval1.stval1 == 'yes'
    assert cfg.od.dodval2.stval2 == 'no'
    #assert cfg.getowner(st) == owners.default
    assert cfg.getowner(stval1) == owner
    assert cfg.getowner(stval2) == owner


def test_del_dyndescription_context():
    val1 = StrOption('val1', '', ['val1', 'val2'], multi=True)
    st = StrOption('st', '')
    dod = DynOptionDescription('dod', '', [st], callback=return_list, callback_params={'': ((val1, False),)})
    od = OptionDescription('od', '', [dod, val1])
    od2 = OptionDescription('od', '', [od])
    cfg = Config(od2)
    owner = cfg.cfgimpl_get_settings().getowner()
    stval1 = cfg.unwrap_from_path('od.dodval1.stval1')
    assert cfg.od.dodval1.stval1 is None
    assert cfg.od.dodval2.stval2 is None
    cfg.od.dodval1.stval1 = 'yes'
    assert cfg.getowner(stval1) == owner
    del(cfg.od.dodval1.stval1)
    assert cfg.getowner(stval1) == owners.default


def test_multi_dyndescription_context():
    val1 = StrOption('val1', '', ['val1', 'val2'], multi=True)
    st = StrOption('st', '', multi=True)
    dod = DynOptionDescription('dod', '', [st], callback=return_list, callback_params={'': ((val1, False),)})
    od = OptionDescription('od', '', [dod, val1])
    od2 = OptionDescription('od', '', [od])
    cfg = Config(od2)
    owner = cfg.cfgimpl_get_settings().getowner()
    stval1 = cfg.unwrap_from_path('od.dodval1.stval1')
    stval2 = cfg.unwrap_from_path('od.dodval2.stval2')
    assert cfg.od.dodval1.stval1 == []
    assert cfg.od.dodval2.stval2 == []
    assert cfg.getowner(stval1) == owners.default
    assert cfg.getowner(stval2) == owners.default
    cfg.od.dodval1.stval1.append('yes')
    assert cfg.od.dodval1.stval1 == ['yes']
    assert cfg.od.dodval2.stval2 == []
    assert cfg.getowner(stval1) == owner
    assert cfg.getowner(stval2) == owners.default
    cfg.od.dodval2.stval2 = ['no']
    assert cfg.od.dodval1.stval1 == ['yes']
    assert cfg.od.dodval2.stval2 == ['no']
    #assert cfg.getowner(st) == owners.default
    assert cfg.getowner(stval1) == owner
    assert cfg.getowner(stval2) == owner
    cfg.od.dodval1.stval1.append('yes')
    assert cfg.od.dodval1.stval1 == ['yes', 'yes']
    cfg.od.dodval1.stval1.pop(0)
    assert cfg.od.dodval1.stval1 == ['yes']


def test_prop_dyndescription_context():
    val1 = StrOption('val1', '', ['val1', 'val2'], multi=True)
    st = StrOption('st', '', properties=('test',))
    dod = DynOptionDescription('dod', '', [st], callback=return_list, callback_params={'': ((val1, False),)})
    od = OptionDescription('od', '', [dod, val1])
    od2 = OptionDescription('od', '', [od])
    cfg = Config(od2)
    stval1 = cfg.unwrap_from_path('od.dodval1.stval1')
    stval2 = cfg.unwrap_from_path('od.dodval2.stval2')
    assert str(cfg.cfgimpl_get_settings()[stval1]) in [str(['test']), str([u'test'])]
    assert str(cfg.cfgimpl_get_settings()[stval2]) in [str(['test']), str([u'test'])]
    cfg.cfgimpl_get_settings()[stval2].append('test2')
    assert str(cfg.cfgimpl_get_settings()[stval1]) in [str(['test']), str([u'test'])]
    assert str(cfg.cfgimpl_get_settings()[stval2]) in [str(['test', 'test2']), str([u'test', 'test2']), str(['test2', 'test'])]
    cfg.cfgimpl_get_settings()[stval1].remove('test')
    assert str(cfg.cfgimpl_get_settings()[stval1]) == str([])


def test_callback_dyndescription_context():
    val1 = StrOption('val1', '', ['val1', 'val2'], multi=True)
    st = StrOption('st', '', callback=return_dynval)
    dod = DynOptionDescription('dod', '', [st], callback=return_list)
    od = OptionDescription('od', '', [dod, val1])
    od2 = OptionDescription('od', '', [od])
    cfg = Config(od2)
    owner = cfg.cfgimpl_get_settings().getowner()
    stval1 = cfg.unwrap_from_path('od.dodval1.stval1')
    stval2 = cfg.unwrap_from_path('od.dodval2.stval2')
    assert cfg.od.dodval1.stval1 == 'val'
    assert cfg.od.dodval2.stval2 == 'val'
    assert cfg.getowner(stval1) == owners.default
    assert cfg.getowner(stval2) == owners.default
    cfg.od.dodval1.stval1 = 'val2'
    assert cfg.od.dodval1.stval1 == 'val2'
    assert cfg.od.dodval2.stval2 == 'val'
    assert cfg.getowner(stval1) == owner
    assert cfg.getowner(stval2) == owners.default
    del(cfg.od.dodval1.stval1)
    assert cfg.od.dodval1.stval1 == 'val'
    assert cfg.od.dodval2.stval2 == 'val'
    assert cfg.getowner(stval1) == owners.default
    assert cfg.getowner(stval2) == owners.default


def test_mandatory_dyndescription_context():
    val1 = StrOption('val1', '', ['val1', 'val2'], multi=True)
    st = StrOption('st', '', properties=('mandatory',))
    dod = DynOptionDescription('dod', '', [st], callback=return_list, callback_params={'': ((val1, False),)})
    od = OptionDescription('od', '', [dod, val1])
    od2 = OptionDescription('od', '', [od])
    cfg = Config(od2)
    cfg.read_only()
    raises(PropertiesOptionError, "cfg.od.dodval1.stval1")
    raises(PropertiesOptionError, "cfg.od.dodval2.stval2")
    cfg.read_write()
    cfg.od.dodval1.stval1 = 'val'
    cfg.read_only()
    assert cfg.od.dodval1.stval1 == 'val'
    raises(PropertiesOptionError, "cfg.od.dodval2.stval2")
    cfg.read_write()
    del(cfg.od.dodval1.stval1)
    cfg.read_only()
    raises(PropertiesOptionError, "cfg.od.dodval1.stval1")
    assert list(cfg.cfgimpl_get_values().mandatory_warnings()) == ['od.dodval1.stval1', 'od.dodval2.stval2']


def test_increase_dyndescription_context():
    val1 = StrOption('val1', '', ['val1', 'val2'], multi=True)
    st = StrOption('st', '', properties=('mandatory',))
    dod = DynOptionDescription('dod', '', [st], callback=return_list, callback_params={'': ((val1, False),)})
    od = OptionDescription('od', '', [dod, val1])
    od2 = OptionDescription('od', '', [od])
    cfg = Config(od2)
    cfg.read_write()
    assert cfg.od.dodval1.stval1 is None
    assert cfg.od.dodval2.stval2 is None
    raises(AttributeError, "cfg.od.dodval3")
    cfg.od.val1 = ['val1', 'val2', 'val3']
    assert cfg.od.dodval1.stval1 is None
    assert cfg.od.dodval2.stval2 is None
    assert cfg.od.dodval3.stval3 is None


def test_decrease_dyndescription_context():
    val1 = StrOption('val1', '', ['val1', 'val2'], multi=True)
    st = StrOption('st', '', properties=('mandatory',))
    dod = DynOptionDescription('dod', '', [st], callback=return_list, callback_params={'': ((val1, False),)})
    od = OptionDescription('od', '', [dod, val1])
    od2 = OptionDescription('od', '', [od])
    cfg = Config(od2)
    owner = cfg.cfgimpl_get_settings().getowner()
    stval1 = cfg.unwrap_from_path('od.dodval1.stval1')
    stval2 = cfg.unwrap_from_path('od.dodval2.stval2')
    cfg.read_write()
    assert cfg.od.dodval1.stval1 is None
    assert cfg.od.dodval2.stval2 is None
    cfg.od.dodval2.stval2 = 'yes'
    assert cfg.od.dodval1.stval1 is None
    assert cfg.od.dodval2.stval2 == 'yes'
    assert cfg.getowner(stval1) == owners.default
    assert cfg.getowner(stval2) == owner
    raises(AttributeError, "cfg.od.dodval3")
    cfg.od.val1 = ['val1']
    assert cfg.od.dodval1.stval1 is None
    raises(AttributeError, "cfg.od.dodval2")
    raises(AttributeError, "cfg.od.dodval3")
    assert cfg.getowner(stval1) == owners.default
    #FIXME
#    raises(AttributeError, "cfg.getowner(stval2)")
    raises(AttributeError, "cfg.unwrap_from_path('od.dodval2.stval2')")
#
#
#def test_requires_dyndescription():
#    boolean = BoolOption('boolean', '', True)
#    st = StrOption('st', '', requires=[{'option': boolean, 'expected': False,
#                                        'action': 'disabled'}])
#    dod = DynOptionDescription('dod', '', [st], callback=return_list)
#    od = OptionDescription('od', '', [dod])
#    od2 = OptionDescription('od', '', [od, boolean])
#    cfg = Config(od2)
#    cfg.read_write()
#    assert cfg.od.dodval1.stval1 is None
#    assert cfg.od.dodval2.stval2 is None
#    #
#    cfg.boolean = False
#    props = []
#    try:
#        cfg.od.dodval1.stval1
#    except PropertiesOptionError as err:
#        props = err.proptype
#    assert props == ['disabled']
#    props = []
#    try:
#        cfg.od.dodval2.stval2
#    except PropertiesOptionError as err:
#        props = err.proptype
#    assert props == ['disabled']
#    #
#    cfg.boolean = True
#    assert cfg.od.dodval1.stval1 is None
#    assert cfg.od.dodval2.stval2 is None
#    #transitive
#    cfg.cfgimpl_get_settings()[boolean].append('disabled')
#    props = []
#    try:
#        cfg.od.dodval1.stval1
#    except PropertiesOptionError as err:
#        props = err.proptype
#    assert props == ['disabled']
#    props = []
#    try:
#        cfg.od.dodval2.stval2
#    except PropertiesOptionError as err:
#        props = err.proptype
#    assert props == ['disabled']


#def test_requires_dyndescription2():
#    boolean = BoolOption('boolean', '', True)
#    st = StrOption('st', '')
#    dod = DynOptionDescription('dod', '', [st], callback=return_list,
#                               requires=[{'option': boolean, 'expected': False,
#                                          'action': 'disabled'}])
#    od = OptionDescription('od', '', [dod])
#    od2 = OptionDescription('od', '', [od, boolean])
#    cfg = Config(od2)
#    cfg.read_write()
#    assert cfg.od.dodval1.stval1 is None
#    assert cfg.od.dodval2.stval2 is None
#    #
#    cfg.boolean = False
#    props = []
#    try:
#        cfg.od.dodval1.stval1
#    except PropertiesOptionError as err:
#        props = err.proptype
#    assert props == ['disabled']
#    props = []
#    try:
#        cfg.od.dodval2.stval2
#    except PropertiesOptionError as err:
#        props = err.proptype
#    assert props == ['disabled']
#    #
#    cfg.boolean = True
#    assert cfg.od.dodval1.stval1 is None
#    assert cfg.od.dodval2.stval2 is None
#    #transitive
#    cfg.cfgimpl_get_settings()[boolean].append('disabled')
#    props = []
#    try:
#        cfg.od.dodval1.stval1
#    except PropertiesOptionError as err:
#        props = err.proptype
#    assert props == ['disabled']
#    props = []
#    try:
#        cfg.od.dodval2.stval2
#    except PropertiesOptionError as err:
#        props = err.proptype
#    assert props == ['disabled']
#
#
def test_validator_dyndescription():
    val1 = StrOption('val1', '', ['val1', 'val2'], multi=True)
    st = StrOption('st', '', validator=return_true, validator_params={'': ('yes',)}, default='val')
    dod = DynOptionDescription('dod', '', [st], callback=return_list)
    od = OptionDescription('od', '', [dod, val1])
    od2 = OptionDescription('od', '', [od])
    cfg = Config(od2)
    assert cfg.od.dodval1.stval1 == 'val'
    raises(ValueError, "cfg.od.dodval1.stval1 = 'no'")
    cfg.od.dodval1.stval1 = 'val'


def test_makedict_dyndescription_context():
    val1 = StrOption('val1', '', ['val1', 'val2'], multi=True)
    st = StrOption('st', '')
    dod = DynOptionDescription('dod', '', [st], callback=return_list)
    od = OptionDescription('od', '', [dod, val1])
    od2 = OptionDescription('od', '', [od])
    cfg = Config(od2)
    cfg.od.dodval1.stval1 = 'yes'
    assert cfg.make_dict() == {'od.val1': ['val1', 'val2'], 'od.dodval1.stval1': 'yes', 'od.dodval2.stval2': None}
    assert cfg.make_dict(flatten=True) == {'val1': ['val1', 'val2'], 'stval1': 'yes', 'stval2': None}
    assert cfg.make_dict(withoption='stval1') == {'od.dodval1.stval1': 'yes'}
    assert cfg.od.make_dict(withoption='stval1') == {'dodval1.stval1': 'yes'}
    assert cfg.od.dodval1.make_dict(withoption='stval1') == {'stval1': 'yes'}


def test_find_dyndescription_context():
    val1 = StrOption('val1', '', ['val1', 'val2'], multi=True)
    st = StrOption('st', '')
    dod = DynOptionDescription('dod', '', [st], callback=return_list)
    od = OptionDescription('od', '', [dod, val1])
    od2 = OptionDescription('od', '', [od])
    cfg = Config(od2)
    cfg.od.dodval1.stval1 = 'yes'
    assert cfg.find_first(byname='stval1', type_='value') == "yes"
    assert isinstance(cfg.find_first(byname='stval1', type_='option'), DynSymLinkOption)
    assert cfg.find(bytype=StrOption, type_='path') == ['od.dodval1.stval1', 'od.dodval2.stval2', 'od.val1']
    opts = cfg.find(byvalue='yes')
    raises(AttributeError, "cfg.find(byname='strnotexists')")
    assert len(opts) == 1
    assert isinstance(opts[0], DynSymLinkOption)
    assert opts[0].impl_getname() == 'stval1'


def test_iter_all_dyndescription_context():
    val1 = StrOption('val1', '', ['val1', 'val2'], multi=True)
    st = StrOption('st', '')
    dod = DynOptionDescription('dod', '', [st], callback=return_list)
    od = OptionDescription('od', '', [dod, val1])
    od2 = OptionDescription('od', '', [od])
    cfg = Config(od2)
    for it in cfg.iter_all():
        assert it[0] == 'od'
        assert str(it[1]) == str(cfg.od)
    #
    list_od = []
    for it in cfg.od.iter_all():
        list_od.append(it[0])
    assert list_od == ['dodval1', 'dodval2', 'val1']
    #
    list_od = []
    for it in cfg.od.dodval1:
        list_od.append(it[0])
    assert list_od == ['stval1']


def test_information_dyndescription_context():
    val1 = StrOption('val1', '', ['val1', 'val2'], multi=True)
    st = StrOption('st', '')
    dod = DynOptionDescription('dod', '', [st], callback=return_list)
    od = OptionDescription('od', '', [dod, val1])
    od2 = OptionDescription('od', '', [od])
    dod.impl_set_information('testod', 'val1')
    st.impl_set_information('testst', 'val2')
    cfg = Config(od2)
    cfg.impl_set_information('testcfgod', 'val3')
    assert dod.impl_get_information('testod') == 'val1'
    assert st.impl_get_information('testst') == 'val2'
    assert cfg.impl_get_information('testcfgod') == 'val3'
#
#
#def test_consistency_dyndescription():
#    st = StrOption('st', '')
#    st2 = StrOption('st2', '')
#    dod = DynOptionDescription('dod', '', [st, st2], callback=return_list)
#    od = OptionDescription('od', '', [dod])
#    st.impl_add_consistency('not_equal', st2)
#    od2 = OptionDescription('od', '', [od])
#    cfg = Config(od2)
#    cfg.od.dodval1.stval1 = 'yes'
#    raises(ValueError, "cfg.od.dodval1.st2val1 = 'yes'")
#    cfg.od.dodval2.stval2 = 'yes'
#    raises(ValueError, "cfg.od.dodval2.st2val2 = 'yes'")
#    raises(ValueError, "cfg.od.dodval1.st2val1 = 'yes'")
#    del(cfg.od.dodval2.stval2)
#    raises(ValueError, "cfg.od.dodval1.st2val1 = 'yes'")
#    cfg.od.dodval2.st2val2 = 'yes'
#    raises(ValueError, "cfg.od.dodval2.stval2 = 'yes'")


def test_consistency_dyndescription_default():
    st = StrOption('st', '', 'yes')
    st2 = StrOption('st2', '')
    dod = DynOptionDescription('dod', '', [st, st2], callback=return_list)
    od = OptionDescription('od', '', [dod])
    st.impl_add_consistency('not_equal', st2)
    od2 = OptionDescription('od', '', [od])
    cfg = Config(od2)
    cfg
    raises(ValueError, "cfg.od.dodval1.st2val1 = 'yes'")
    raises(ValueError, "cfg.od.dodval2.st2val2 = 'yes'")


def test_consistency_dyndescription_default_multi2():
    st = StrOption('st', '', ['yes'], multi=True)
    st2 = StrOption('st2', '', ['yes'], multi=True)
    dod = DynOptionDescription('dod', '', [st, st2], callback=return_list)
    dod
    raises(ValueError, "st.impl_add_consistency('not_equal', st2)")


def test_consistency_only_one_dyndescription():
    st = StrOption('st', '')
    st
    st2 = StrOption('st2', '')
    DynOptionDescription('dod', '', [st2], callback=return_list)
    raises(ConfigError, "st.impl_add_consistency('not_equal', st2)")
    raises(ConfigError, "st2.impl_add_consistency('not_equal', st)")


def test_consistency_became_dyndescription():
    st = StrOption('st', '')
    st2 = StrOption('st2', '')
    st2.impl_add_consistency('not_equal', st)
    od = DynOptionDescription('dod', '', [st2], callback=return_list)
    od2 = OptionDescription('od', '', [od, st])
    od2
    raises(ConfigError, "c = Config(od2)")


def test_consistency_became_dyndescription2():
    st = StrOption('st', '')
    st2 = StrOption('st2', '')
    st.impl_add_consistency('not_equal', st2)
    od = DynOptionDescription('dod', '', [st2], callback=return_list)
    od2 = OptionDescription('od', '', [od, st])
    od2
    raises(ConfigError, "c = Config(od2)")


def test_consistency_external_dyndescription():
    st = StrOption('st', '')
    st1 = StrOption('st1', '')
    st2 = StrOption('st2', '')
    dod = DynOptionDescription('dod', '', [st1, st2], callback=return_list)
    od = OptionDescription('od', '', [dod, st])
    od
    raises(ConfigError, "st.impl_add_consistency('not_equal', st2)")


def test_consistency_notsame_dyndescription():
    st1 = StrOption('st1', '')
    st2 = StrOption('st2', '')
    dod = DynOptionDescription('dod', '', [st1, st2], callback=return_list)
    tst1 = StrOption('tst1', '')
    tst2 = StrOption('tst2', '')
    tdod = DynOptionDescription('tdod', '', [tst1, tst2], callback=return_list)
    od = OptionDescription('od', '', [dod, tdod])
    od
    raises(ConfigError, "st1.impl_add_consistency('not_equal', tst1)")


def test_all_dyndescription():
    st = StrOption('st', '')
    ip = IPOption('ip', '')
    network = NetworkOption('network', '')
    netmask = NetmaskOption('netmask', '')
    ch = ChoiceOption('ch', '', ('val1', 'val2', 'val3'))
    ch1 = ChoiceOption('ch1', '', return_list)
    boo = BoolOption('boo', '')
    intr = IntOption('intr', '')
    floa = FloatOption('floa', '')
    uni = UnicodeOption('uni', '')
    port = PortOption('port', '')
    broad = BroadcastOption('broad', '')
    domain = DomainnameOption('domain', '')
    email = EmailOption('email', '')
    url = URLOption('url', '')
    username = UsernameOption('username', '')
    filename = FilenameOption('filename', '')
    dod = DynOptionDescription('dod', '', [st, ip, network, netmask, ch, ch1,
                                           boo, intr, floa, uni, port, broad,
                                           domain, email, url, username,
                                           filename], callback=return_list)
    od = OptionDescription('od', '', [dod])
    cfg = Config(od)
    assert cfg.dodval1.stval1 is None
    assert cfg.dodval1.ipval1 is None
    assert cfg.dodval1.networkval1 is None
    assert cfg.dodval1.netmaskval1 is None
    assert cfg.dodval1.chval1 is None
    assert cfg.dodval1.ch1val1 is None
    assert cfg.dodval1.booval1 is None
    assert cfg.dodval1.intrval1 is None
    assert cfg.dodval1.floaval1 is None
    assert cfg.dodval1.unival1 is None
    assert cfg.dodval1.portval1 is None
    assert cfg.dodval1.broadval1 is None
    assert cfg.dodval1.domainval1 is None
    assert cfg.dodval1.emailval1 is None
    assert cfg.dodval1.urlval1 is None
    assert cfg.dodval1.usernameval1 is None
    assert cfg.dodval1.filenameval1 is None
    #
    cfg.dodval1.stval1 = "no"
    cfg.dodval1.ipval1 = "1.1.1.1"
    cfg.dodval1.networkval1 = "1.1.1.0"
    cfg.dodval1.netmaskval1 = "255.255.255.0"
    cfg.dodval1.chval1 = "val1"
    cfg.dodval1.ch1val1 = "val2"
    cfg.dodval1.booval1 = True
    cfg.dodval1.intrval1 = 1
    cfg.dodval1.floaval1 = 0.1
    cfg.dodval1.unival1 = u"no"
    cfg.dodval1.portval1 = 80
    cfg.dodval1.broadval1 = "1.1.1.255"
    cfg.dodval1.domainval1 = "test.com"
    cfg.dodval1.emailval1 = "test@test.com"
    cfg.dodval1.urlval1 = "http://test.com"
    cfg.dodval1.usernameval1 = "user1"
    cfg.dodval1.filenameval1 = "/tmp"
    assert cfg.dodval1.stval1 == "no"
    assert cfg.dodval1.ipval1 == "1.1.1.1"
    assert cfg.dodval1.networkval1 == "1.1.1.0"
    assert cfg.dodval1.netmaskval1 == "255.255.255.0"
    assert cfg.dodval1.chval1 == "val1"
    assert cfg.dodval1.ch1val1 == "val2"
    assert cfg.dodval1.booval1 is True
    assert cfg.dodval1.intrval1 == 1
    assert cfg.dodval1.floaval1 == 0.1
    assert cfg.dodval1.unival1 == u"no"
    assert cfg.dodval1.portval1 == 80
    assert cfg.dodval1.broadval1 == "1.1.1.255"
    assert cfg.dodval1.domainval1 == "test.com"
    assert cfg.dodval1.emailval1 == "test@test.com"
    assert cfg.dodval1.urlval1 == "http://test.com"
    assert cfg.dodval1.usernameval1 == "user1"
    assert cfg.dodval1.filenameval1 == "/tmp"
    #
    assert cfg.dodval2.stval2 is None
    assert cfg.dodval2.ipval2 is None
    assert cfg.dodval2.networkval2 is None
    assert cfg.dodval2.netmaskval2 is None
    assert cfg.dodval2.chval2 is None
    assert cfg.dodval2.ch1val2 is None
    assert cfg.dodval2.booval2 is None
    assert cfg.dodval2.intrval2 is None
    assert cfg.dodval2.floaval2 is None
    assert cfg.dodval2.unival2 is None
    assert cfg.dodval2.portval2 is None
    assert cfg.dodval2.broadval2 is None
    assert cfg.dodval2.domainval2 is None
    assert cfg.dodval2.emailval2 is None
    assert cfg.dodval2.urlval2 is None
    assert cfg.dodval2.usernameval2 is None
    assert cfg.dodval2.filenameval2 is None
#
#
#def test_consistency_ip_netmask_dyndescription():
#    a = IPOption('a', '')
#    b = NetmaskOption('b', '')
#    dod = DynOptionDescription('dod', '', [a, b], callback=return_list)
#    b.impl_add_consistency('ip_netmask', a)
#    od = OptionDescription('od', '', [dod])
#    c = Config(od)
#    c.dodval1.aval1 = '192.168.1.1'
#    c.dodval1.bval1 = '255.255.255.0'
#    c.dodval2.aval2 = '192.168.1.2'
#    c.dodval2.bval2 = '255.255.255.255'
##    c.dodval2.bval2 = '255.255.255.0'
#
#
#def test_consistency_ip_in_network_dyndescription():
#    a = NetworkOption('a', '')
#    b = NetmaskOption('b', '')
#    c = IPOption('c', '')
#    dod = DynOptionDescription('dod', '', [a, b, c], callback=return_list)
#    c.impl_add_consistency('in_network', a, b)
#    od = OptionDescription('od', '', [dod])
#    cfg = Config(od)
#    cfg.dodval1.aval1 = '192.168.1.0'
#    cfg.dodval1.bval1 = '255.255.255.0'
#    cfg.dodval1.cval1 = '192.168.1.1'


#def test_masterslaves_dyndescription():
#    st1 = StrOption('st1', "", multi=True)
#    st2 = StrOption('st2', "", multi=True)
#    stm = MasterSlaves('st1', '', [st1, st2])
#    #stm.impl_set_group_type(groups.master)
#    st = DynOptionDescription('st', '', [stm], callback=return_list)
#    od = OptionDescription('od', '', [st])
#    od2 = OptionDescription('od', '', [od])
#    cfg = Config(od2)
#    print('--------------- 1')
#    owner = cfg.cfgimpl_get_settings().getowner()
#    print('--------------- 2')
#    st1val1 = cfg.unwrap_from_path('od.stval1.st1val1.st1val1')
#    print('--------------- 3')
#    st2val1 = cfg.unwrap_from_path('od.stval1.st1val1.st2val1')
#    print('--------------- 4')
#    st1val2 = cfg.unwrap_from_path('od.stval2.st1val2.st1val2')
#    print('--------------- 5')
#    st2val2 = cfg.unwrap_from_path('od.stval2.st1val2.st2val2')
#    print('--------------- 6')
#    assert cfg.make_dict() == {'od.stval1.st1val1.st2val1': [], 'od.stval2.st1val2.st2val2': [], 'od.stval2.st1val2.st1val2': [], 'od.stval1.st1val1.st1val1': []}
#    print('--------------- 7')
#    assert cfg.od.stval1.st1val1.st1val1 == []
#    print('--------------- 8')
#    assert cfg.od.stval1.st1val1.st2val1 == []
#    print('--------------- 9')
#    assert cfg.od.stval2.st1val2.st1val2 == []
#    print('--------------- 10')
#    assert cfg.od.stval2.st1val2.st2val2 == []
#    print('--------------- 11')
#    assert cfg.getowner(st1val1) == owners.default
#    print('--------------- 12')
#    assert cfg.getowner(st1val2) == owners.default
#    print('--------------- 13')
#    assert cfg.getowner(st2val1) == owners.default
#    print('--------------- 14')
#    assert cfg.getowner(st2val2) == owners.default
#    print('--------------- 15')
#    #
#    cfg.od.stval1.st1val1.st1val1.append('yes')
#    print('--------------- 16')
#    assert cfg.make_dict() == {'od.stval1.st1val1.st2val1': [None], 'od.stval2.st1val2.st2val2': [], 'od.stval2.st1val2.st1val2': [], 'od.stval1.st1val1.st1val1': ['yes']}
#    print('--------------- 17')
#    assert cfg.od.stval1.st1val1.st1val1 == ['yes']
#    print('--------------- 18')
#    assert cfg.od.stval1.st1val1.st2val1 == [None]
#    print('--------------- 19')
#    assert cfg.od.stval2.st1val2.st1val2 == []
#    print('--------------- 20')
#    assert cfg.od.stval2.st1val2.st2val2 == []
#    print('--------------- 21')
#    assert cfg.getowner(st1val1) == owner
#    print('--------------- 22')
#    assert cfg.getowner(st1val2) == owners.default
#    print('--------------- 23')
#    assert cfg.getowner(st2val1) == owners.default
#    print('--------------- 24')
#    assert cfg.getowner(st2val2) == owners.default
#    print('--------------- 25')
#    #
#    cfg.od.stval1.st1val1.st1val1 = ['yes']
#    assert cfg.od.stval1.st1val1.st1val1 == ['yes']
#    assert cfg.od.stval1.st1val1.st2val1 == [None]
#    assert cfg.od.stval2.st1val2.st1val2 == []
#    assert cfg.od.stval2.st1val2.st2val2 == []
#    assert cfg.getowner(st1val1) == owner
#    assert cfg.getowner(st1val2) == owners.default
#    assert cfg.getowner(st2val1) == owners.default
#    assert cfg.getowner(st2val2) == owners.default
#    #
#    cfg.od.stval1.st1val1.st2val1 = ['no']
#    assert cfg.od.stval1.st1val1.st1val1 == ['yes']
#    assert cfg.od.stval1.st1val1.st2val1 == ['no']
#    assert cfg.od.stval2.st1val2.st1val2 == []
#    assert cfg.od.stval2.st1val2.st2val2 == []
#    assert cfg.getowner(st1val1) == owner
#    assert cfg.getowner(st1val2) == owners.default
#    assert cfg.getowner(st2val1, 0) == owner
##    assert cfg.getowner(st2val2) == owners.default
#    #
#    cfg.od.stval1.st1val1.st1val1.pop(0)
#    assert cfg.od.stval1.st1val1.st1val1 == []
#    assert cfg.od.stval1.st1val1.st2val1 == []
#    assert cfg.od.stval2.st1val2.st1val2 == []
#    assert cfg.od.stval2.st1val2.st2val2 == []
#    assert cfg.getowner(st1val1) == owner
#    assert cfg.getowner(st1val2) == owners.default
##    assert cfg.getowner(st2val1) == owner
##    assert cfg.getowner(st2val2) == owners.default
#    #
#    cfg.od.stval1.st1val1.st1val1 = ['yes']
#    cfg.od.stval1.st1val1.st2val1 = ['yes']
#    assert cfg.getowner(st1val1) == owner
#    assert cfg.getowner(st2val1, 0) == owner
#    del(cfg.od.stval1.st1val1.st2val1)
#    assert cfg.getowner(st1val1) == owner
#    assert cfg.getowner(st1val2) == owners.default
##    assert cfg.getowner(st2val1) == owners.default
##    assert cfg.getowner(st2val2) == owners.default
#    #
#    cfg.od.stval1.st1val1.st1val1 = ['yes']
#    cfg.od.stval1.st1val1.st2val1 = ['yes']
#    del(cfg.od.stval1.st1val1.st1val1)
#    assert cfg.od.stval1.st1val1.st1val1 == []
#    assert cfg.od.stval1.st1val1.st2val1 == []
#    assert cfg.od.stval2.st1val2.st1val2 == []
#    assert cfg.od.stval2.st1val2.st2val2 == []
#    assert cfg.getowner(st1val1) == owners.default
#    assert cfg.getowner(st1val2) == owners.default
#    assert cfg.getowner(st2val1) == owners.default
#    assert cfg.getowner(st2val2) == owners.default
#
#
#def test_masterslaves_default_multi_dyndescription():
#    st1 = StrOption('st1', "", multi=True)
#    st2 = StrOption('st2', "", multi=True, default_multi='no')
#    stm = MasterSlaves('st1', '', [st1, st2])
#    #stm.impl_set_group_type(groups.master)
#    st = DynOptionDescription('st', '', [stm], callback=return_list)
#    od = OptionDescription('od', '', [st])
#    od2 = OptionDescription('od', '', [od])
#    cfg = Config(od2)
#    owner = cfg.cfgimpl_get_settings().getowner()
#    st1val1 = cfg.unwrap_from_path('od.stval1.st1val1.st1val1')
#    st2val1 = cfg.unwrap_from_path('od.stval1.st1val1.st2val1')
#    st1val2 = cfg.unwrap_from_path('od.stval2.st1val2.st1val2')
#    st2val2 = cfg.unwrap_from_path('od.stval2.st1val2.st2val2')
#    assert cfg.od.stval1.st1val1.st1val1 == []
#    assert cfg.od.stval1.st1val1.st2val1 == []
#    assert cfg.od.stval2.st1val2.st1val2 == []
#    assert cfg.od.stval2.st1val2.st2val2 == []
#    assert cfg.getowner(st1val1) == owners.default
#    assert cfg.getowner(st1val2) == owners.default
#    assert cfg.getowner(st2val1) == owners.default
#    assert cfg.getowner(st2val2) == owners.default
#    cfg.od.stval1.st1val1.st1val1.append('yes')
#    assert cfg.od.stval1.st1val1.st1val1 == ['yes']
#    assert cfg.od.stval1.st1val1.st2val1 == ['no']
#    assert cfg.od.stval2.st1val2.st1val2 == []
#    assert cfg.od.stval2.st1val2.st2val2 == []
#    assert cfg.getowner(st1val1) == owner
#    assert cfg.getowner(st1val2) == owners.default
#    assert cfg.getowner(st2val1) == owners.default
#    assert cfg.getowner(st2val2) == owners.default
#
#
#def test_masterslaves_submulti_dyndescription():
#    st1 = StrOption('st1', "", multi=True)
#    st2 = StrOption('st2', "", multi=submulti)
#    stm = MasterSlaves('st1', '', [st1, st2])
#    #stm.impl_set_group_type(groups.master)
#    st = DynOptionDescription('st', '', [stm], callback=return_list)
#    od = OptionDescription('od', '', [st])
#    od2 = OptionDescription('od', '', [od])
#    cfg = Config(od2)
#    owner = cfg.cfgimpl_get_settings().getowner()
#    st1val1 = cfg.unwrap_from_path('od.stval1.st1val1.st1val1')
#    st2val1 = cfg.unwrap_from_path('od.stval1.st1val1.st2val1')
#    st1val2 = cfg.unwrap_from_path('od.stval2.st1val2.st1val2')
#    st2val2 = cfg.unwrap_from_path('od.stval2.st1val2.st2val2')
#    assert cfg.od.stval1.st1val1.st1val1 == []
#    assert cfg.od.stval1.st1val1.st2val1 == []
#    assert cfg.od.stval2.st1val2.st1val2 == []
#    assert cfg.od.stval2.st1val2.st2val2 == []
#    assert cfg.getowner(st1val1) == owners.default
#    assert cfg.getowner(st1val2) == owners.default
#    assert cfg.getowner(st2val1) == owners.default
#    assert cfg.getowner(st2val2) == owners.default
#    cfg.od.stval1.st1val1.st1val1.append('yes')
#    assert cfg.od.stval1.st1val1.st1val1 == ['yes']
#    assert cfg.od.stval1.st1val1.st2val1 == [[]]
#    assert cfg.od.stval2.st1val2.st1val2 == []
#    assert cfg.od.stval2.st1val2.st2val2 == []
#    assert cfg.getowner(st1val1) == owner
#    assert cfg.getowner(st1val2) == owners.default
#    assert cfg.getowner(st2val1) == owners.default
#    assert cfg.getowner(st2val2) == owners.default
#    #
#    cfg.od.stval1.st1val1.st2val1[0].append('no')
#    assert cfg.od.stval1.st1val1.st1val1 == ['yes']
#    assert cfg.od.stval1.st1val1.st2val1 == [['no']]
#    assert cfg.od.stval2.st1val2.st1val2 == []
#    assert cfg.od.stval2.st1val2.st2val2 == []
#    assert cfg.getowner(st1val1) == owner
#    assert cfg.getowner(st1val2) == owners.default
#    assert cfg.getowner(st2val1, 0) == owner
#    assert cfg.getowner(st2val2) == owners.default


#def test_masterslaves_consistency_ip_dyndescription():
#    a = NetworkOption('net', '', multi=True)
#    b = NetmaskOption('mask', '', multi=True)
#    c = BroadcastOption('broad', '', multi=True)
#    b.impl_add_consistency('network_netmask', a)
#    c.impl_add_consistency('broadcast', a, b)
#    dod = DynOptionDescription('net', '', [a, b, c], callback=return_list)
#    dod.impl_set_group_type(groups.master)
#    od = OptionDescription('od', '', [dod])
#    cfg = Config(od)
#    cfg.netval1.netval1 = ['192.168.1.0']
#    cfg.netval1.maskval1 = ['255.255.255.0']
#    cfg.netval1.broadval1 = ['192.168.1.255']
#
#    cfg.netval1.netval1 = ['192.168.1.0', '192.168.2.128']
#    cfg.netval1.maskval1 = ['255.255.255.0', '255.255.255.128']
#    cfg.netval1.broadval1 = ['192.168.1.255', '192.168.2.255']
#    cfg.netval1.broadval1[1] = '192.168.2.255'
#    #
#    assert cfg.netval1.netval1 == ['192.168.1.0', '192.168.2.128']
#    assert cfg.netval1.maskval1 == ['255.255.255.0', '255.255.255.128']
#    assert cfg.netval1.broadval1 == ['192.168.1.255', '192.168.2.255']
#    assert cfg.netval2.netval2 == []
#    assert cfg.netval2.maskval2 == []
#    assert cfg.netval2.broadval2 == []


#def test_masterslaves_consistency_ip_dyndescription_propertyerror():
#    a = NetworkOption('net', '', multi=True)
#    b = NetmaskOption('mask', '', multi=True, properties=('mandatory',))
#    c = BroadcastOption('broad', '', multi=True)
#    b.impl_add_consistency('network_netmask', a)
#    c.impl_add_consistency('broadcast', a, b)
#    dod = DynOptionDescription('net', '', [a, b, c], callback=return_list)
#    dod.impl_set_group_type(groups.master)
#    od = OptionDescription('od', '', [dod])
#    cfg = Config(od)
#    cfg.read_write()
#    cfg.netval1.netval1 = ['192.168.1.0']
#    cfg.read_only()
#    raises(PropertiesOptionError, "cfg.netval1.netval1")
#
#
#def test_masterslaves_callback_dyndescription():
#    st1 = StrOption('st1', "", multi=True)
#    st2 = StrOption('st2', "", multi=True, callback=return_dynval, callback_params={'value': ((st1, False),)})
#    stm = MasterSlaves('st1', '', [st1, st2])
#    #stm.impl_set_group_type(groups.master)
#    st = DynOptionDescription('st', '', [stm], callback=return_list)
#    od = OptionDescription('od', '', [st])
#    od2 = OptionDescription('od', '', [od])
#    cfg = Config(od2)
#    owner = cfg.cfgimpl_get_settings().getowner()
#    st1val1 = cfg.unwrap_from_path('od.stval1.st1val1.st1val1')
#    st2val1 = cfg.unwrap_from_path('od.stval1.st1val1.st2val1')
#    st1val2 = cfg.unwrap_from_path('od.stval2.st1val2.st1val2')
#    st2val2 = cfg.unwrap_from_path('od.stval2.st1val2.st2val2')
#    assert cfg.make_dict() == {'od.stval1.st1val1.st2val1': [], 'od.stval2.st1val2.st2val2': [], 'od.stval2.st1val2.st1val2': [], 'od.stval1.st1val1.st1val1': []}
#    assert cfg.od.stval1.st1val1.st1val1 == []
#    assert cfg.od.stval1.st1val1.st2val1 == []
#    assert cfg.od.stval2.st1val2.st1val2 == []
#    assert cfg.od.stval2.st1val2.st2val2 == []
#    assert cfg.getowner(st1val1) == owners.default
#    assert cfg.getowner(st1val2) == owners.default
#    assert cfg.getowner(st2val1) == owners.default
#    assert cfg.getowner(st2val2) == owners.default
#    #
#    cfg.od.stval1.st1val1.st1val1.append('yes')
#    assert cfg.make_dict() == {'od.stval1.st1val1.st2val1': ['yes'], 'od.stval2.st1val2.st2val2': [], 'od.stval2.st1val2.st1val2': [], 'od.stval1.st1val1.st1val1': ['yes']}
#    assert cfg.od.stval1.st1val1.st1val1 == ['yes']
#    assert cfg.od.stval1.st1val1.st2val1 == ['yes']
#    assert cfg.od.stval2.st1val2.st1val2 == []
#    assert cfg.od.stval2.st1val2.st2val2 == []
#    assert cfg.getowner(st1val1) == owner
#    assert cfg.getowner(st1val2) == owners.default
#    assert cfg.getowner(st2val1) == owners.default
#    assert cfg.getowner(st2val2) == owners.default
#    #
#    cfg.od.stval1.st1val1.st2val1 = ['no']
#    assert cfg.od.stval1.st1val1.st1val1 == ['yes']
#    assert cfg.od.stval1.st1val1.st2val1 == ['no']
#    assert cfg.od.stval2.st1val2.st1val2 == []
#    assert cfg.od.stval2.st1val2.st2val2 == []
#    assert cfg.getowner(st1val1) == owner
#    assert cfg.getowner(st1val2) == owners.default
#    assert cfg.getowner(st2val1, 0) == owner
##    assert cfg.getowner(st2val2) == owners.default
#    #
#    cfg.od.stval1.st1val1.st1val1.pop(0)
#    assert cfg.od.stval1.st1val1.st1val1 == []
#    assert cfg.od.stval1.st1val1.st2val1 == []
#    assert cfg.od.stval2.st1val2.st1val2 == []
#    assert cfg.od.stval2.st1val2.st2val2 == []
#    assert cfg.getowner(st1val1) == owner
#    assert cfg.getowner(st1val2) == owners.default
##    assert cfg.getowner(st2val1) == owner
##    assert cfg.getowner(st2val2) == owners.default
#    #
#    cfg.od.stval1.st1val1.st1val1 = ['yes']
#    cfg.od.stval1.st1val1.st2val1 = ['yes']
#    assert cfg.getowner(st1val1) == owner
#    assert cfg.getowner(st2val1, 0) == owner
#    del(cfg.od.stval1.st1val1.st2val1)
#    assert cfg.getowner(st1val1) == owner
#    assert cfg.getowner(st1val2) == owners.default
#    assert cfg.getowner(st2val1) == owners.default
#    assert cfg.getowner(st2val2) == owners.default
#    #
#    cfg.od.stval1.st1val1.st1val1 = ['yes']
#    cfg.od.stval1.st1val1.st2val1 = ['yes']
#    del(cfg.od.stval1.st1val1.st1val1)
#    assert cfg.od.stval1.st1val1.st1val1 == []
#    assert cfg.od.stval1.st1val1.st2val1 == []
#    assert cfg.od.stval2.st1val2.st1val2 == []
#    assert cfg.od.stval2.st1val2.st2val2 == []
#    assert cfg.getowner(st1val1) == owners.default
#    assert cfg.getowner(st1val2) == owners.default
#    assert cfg.getowner(st2val1) == owners.default
#    assert cfg.getowner(st2val2) == owners.default
#    #
#    cfg.od.stval1.st1val1.st2val1 = []
#    cfg.od.stval1.st1val1.st1val1 = ['yes']
#    assert cfg.od.stval1.st1val1.st2val1 == ['yes']
#
#
#def test_masterslaves_callback_value_dyndescription():
#    st1 = StrOption('st1', "", multi=True)
#    st2 = StrOption('st2', "", multi=True, callback=return_dynval, callback_params={'value': ('val',)})
#    stm = MasterSlaves('st1', '', [st1, st2])
#    #stm.impl_set_group_type(groups.master)
#    st = DynOptionDescription('st', '', [stm], callback=return_list)
#    od = OptionDescription('od', '', [st])
#    od2 = OptionDescription('od', '', [od])
#    cfg = Config(od2)
#    assert cfg.od.stval1.st1val1.st1val1 == []
#    assert cfg.od.stval1.st1val1.st2val1 == []
#    cfg.od.stval1.st1val1.st1val1.append('yes')
#    assert cfg.od.stval1.st1val1.st1val1 == ['yes']
#    assert cfg.od.stval1.st1val1.st2val1[0] == 'val'
#    assert cfg.od.stval1.st1val1.st2val1 == ['val']
#
#
#def test_masterslaves_callback_nomulti_dyndescription():
#    v1 = StrOption('v1', '', "val")
#    st1 = StrOption('st1', "", multi=True)
#    st2 = StrOption('st2', "", multi=True, callback=return_dynval, callback_params={'': ((v1, False),)})
#    stm = MasterSlaves('st1', '', [st1, st2])
#    #stm.impl_set_group_type(groups.master)
#    st = DynOptionDescription('st', '', [stm], callback=return_list)
#    od = OptionDescription('od', '', [st])
#    od2 = OptionDescription('od', '', [od, v1])
#    cfg = Config(od2)
#    assert cfg.od.stval1.st1val1.st1val1 == []
#    assert cfg.od.stval1.st1val1.st2val1 == []
#    cfg.od.stval1.st1val1.st1val1.append('yes')
#    assert cfg.od.stval1.st1val1.st1val1 == ['yes']
#    assert cfg.od.stval1.st1val1.st2val1 == ['val']
#
#
#def test_masterslaves_callback_samegroup_dyndescription():
#    st1 = StrOption('st1', "", multi=True)
#    st2 = StrOption('st2', "", multi=True)
#    st3 = StrOption('st3', "", multi=True, callback=return_dynval, callback_params={'': ((st2, False),)})
#    stm = MasterSlaves('st1', '', [st1, st2, st3])
#    #stm.impl_set_group_type(groups.master)
#    st = DynOptionDescription('st', '', [stm], callback=return_list)
#    od = OptionDescription('od', '', [st])
#    od2 = OptionDescription('od', '', [od])
#    cfg = Config(od2)
#    owner = cfg.cfgimpl_get_settings().getowner()
#    st1val1 = cfg.unwrap_from_path('od.stval1.st1val1.st1val1')
#    st2val1 = cfg.unwrap_from_path('od.stval1.st1val1.st2val1')
#    st3val1 = cfg.unwrap_from_path('od.stval1.st1val1.st3val1')
#    st1val2 = cfg.unwrap_from_path('od.stval2.st1val2.st1val2')
#    st2val2 = cfg.unwrap_from_path('od.stval2.st1val2.st2val2')
#    st3val2 = cfg.unwrap_from_path('od.stval2.st1val2.st3val2')
#    assert cfg.make_dict() == {'od.stval1.st1val1.st1val1': [],
#                               'od.stval1.st1val1.st2val1': [],
#                               'od.stval1.st1val1.st3val1': [],
#                               'od.stval2.st1val2.st1val2': [],
#                               'od.stval2.st1val2.st2val2': [],
#                               'od.stval2.st1val2.st3val2': []}
#    assert cfg.od.stval1.st1val1.st1val1 == []
#    assert cfg.od.stval1.st1val1.st2val1 == []
#    assert cfg.od.stval1.st1val1.st3val1 == []
#    assert cfg.od.stval2.st1val2.st1val2 == []
#    assert cfg.od.stval2.st1val2.st2val2 == []
#    assert cfg.od.stval2.st1val2.st3val2 == []
#    assert cfg.getowner(st1val1) == owners.default
#    assert cfg.getowner(st1val2) == owners.default
#    assert cfg.getowner(st2val1) == owners.default
#    assert cfg.getowner(st2val2) == owners.default
#    assert cfg.getowner(st3val1) == owners.default
#    assert cfg.getowner(st3val2) == owners.default
#    ##
#    cfg.od.stval1.st1val1.st1val1.append('yes')
#    assert cfg.make_dict() == {'od.stval1.st1val1.st1val1': ['yes'],
#                               'od.stval1.st1val1.st2val1': [None],
#                               'od.stval1.st1val1.st3val1': [None],
#                               'od.stval2.st1val2.st1val2': [],
#                               'od.stval2.st1val2.st2val2': [],
#                               'od.stval2.st1val2.st3val2': []}
#    assert cfg.getowner(st1val1) == owner
#    assert cfg.getowner(st1val2) == owners.default
#    assert cfg.getowner(st2val1) == owners.default
#    assert cfg.getowner(st2val2) == owners.default
#    assert cfg.getowner(st3val1) == owners.default
#    assert cfg.getowner(st3val2) == owners.default
#    #
#    cfg.od.stval1.st1val1.st2val1[0] = 'yes'
#    assert cfg.make_dict() == {'od.stval1.st1val1.st1val1': ['yes'],
#                               'od.stval1.st1val1.st2val1': ['yes'],
#                               'od.stval1.st1val1.st3val1': ['yes'],
#                               'od.stval2.st1val2.st1val2': [],
#                               'od.stval2.st1val2.st2val2': [],
#                               'od.stval2.st1val2.st3val2': []}
#    assert cfg.getowner(st1val1) == owner
#    assert cfg.getowner(st2val1, 0) == owner
#    assert cfg.getowner(st3val1, 0) == owners.default
#    assert cfg.getowner(st1val2) == owners.default
#    #assert cfg.getowner(st2val2) == owners.default
#    #assert cfg.getowner(st3val2) == owners.default


def test_invalid_conflict_dyndescription():
    st = StrOption('st', '')
    dod = DynOptionDescription('dod', '', [st], callback=return_list)
    dodinvalid = StrOption('dodinvalid', '')
    dod, dodinvalid
    raises(ConflictError, "OptionDescription('od', '', [dod, dodinvalid])")


def test_invalid_subod_dyndescription():
    st2 = StrOption('st2', '')
    od1 = OptionDescription('od1', '', [st2])
    od1
    raises(ConfigError, "DynOptionDescription('dod', '', [od1], callback=return_list)")


def test_invalid_subdynod_dyndescription():
    st2 = StrOption('st2', '')
    od1 = DynOptionDescription('od1', '', [st2], callback=return_list)
    od1
    raises(ConfigError, "DynOptionDescription('dod', '', [od1], callback=return_list)")


def test_invalid_symlink_dyndescription():
    st = StrOption('st', '')
    st2 = SymLinkOption('st2', st)
    st2
    raises(ConfigError, "DynOptionDescription('dod', '', [st, st2], callback=return_list)")


def test_nocallback_dyndescription():
    st = StrOption('st', '')
    st2 = StrOption('st2', '')
    st, st2
    raises(ConfigError, "DynOptionDescription('dod', '', [st, st2])")


def test_invalid_samevalue_dyndescription():
    st = StrOption('st', '')
    dod = DynOptionDescription('dod', '', [st], callback=return_same_list)
    od = OptionDescription('od', '', [dod])
    cfg = Config(od)
    cfg
    raises(ConfigError, "print(cfg)")


def test_invalid_name_dyndescription():
    st = StrOption('st', '')
    dod = DynOptionDescription('dod', '', [st], callback=return_wrong_list)
    od = OptionDescription('od', '', [dod])
    cfg = Config(od)
    cfg
    raises(ValueError, "print(cfg)")