"config.set() or config.setoption() or option.setoption()"
from .autopath import do_autopath
do_autopath()
from .config import config_type, get_config

from py.test import raises

from tiramisu.i18n import _
from tiramisu.error import display_list, ConfigError
from tiramisu.setting import owners, groups
from tiramisu import ChoiceOption, BoolOption, IntOption, FloatOption, \
    StrOption, OptionDescription, Leadership, Config, undefined, \
    Calculation, Params, ParamOption, ParamValue, ParamIndex, \
    calc_value, calc_value_property_help
from tiramisu.error import PropertiesOptionError
from tiramisu.storage import list_sessions
import warnings


def teardown_function(function):
    assert list_sessions() == [], 'session list is not empty when leaving "{}"'.format(function.__name__)


def make_description():
    gcoption = ChoiceOption('name', 'GC name', ('ref', 'framework'), 'ref')
    gcdummy = BoolOption('dummy', 'dummy', default=False)
    objspaceoption = ChoiceOption('objspace', 'Object space',
                                  ('std', 'thunk'), 'std')
    booloption = BoolOption('bool', 'Test boolean option', default=True)
    intoption = IntOption('int', 'Test int option', default=0)
    floatoption = FloatOption('float', 'Test float option', default=2.3)
    stroption = StrOption('str', 'Test string option', default="abc")
    boolop = BoolOption('boolop', 'Test boolean option op', default=True)
    wantref_option = BoolOption('wantref', 'Test requires', default=False)
    wantframework_option = BoolOption('wantframework', 'Test requires',
                                      default=False)
    gcgroup = OptionDescription('gc', '', [gcoption, gcdummy, floatoption])
    descr = OptionDescription('tiramisu', '', [gcgroup, booloption, objspaceoption,
                                               wantref_option, stroption,
                                               wantframework_option,
                                               intoption, boolop])
    return descr


#____________________________________________________________
# change with __setattr__
def test_attribute_access(config_type):
    "Once set, option values can't be changed again by attribute access"
    s = StrOption("string", "", default="string")
    descr = OptionDescription("options", "", [s])
    cfg = Config(descr)
    cfg = get_config(cfg, config_type)
    # let's try to change it again
    cfg.option('string').value.set('foo')
    assert cfg.option('string').value.get() == 'foo'


def test_mod_read_only_write():
    "default with multi is a list"
    s = StrOption("string", "", default=[], default_multi="string", multi=True)
    descr = OptionDescription("options", "", [s])
    config = Config(descr)
    config2 = Config(descr)
    assert config.property.getdefault() == {'cache', 'validator', 'warnings'}
    assert config.property.getdefault('read_only', 'append') == {'frozen',
                                                                 'disabled',
                                                                 'validator',
                                                                 'everything_frozen',
                                                                 'mandatory',
                                                                 'empty',
                                                                 'force_store_value'}
    assert config.property.getdefault('read_only', 'remove') == {'permissive',
                                                                 'hidden'}
    assert config.property.getdefault('read_write', 'append') == {'frozen',
                                                                  'disabled',
                                                                  'validator',
                                                                  'hidden',
                                                                  'force_store_value'}
    assert config.property.getdefault('read_write', 'remove') == {'permissive',
                                                                  'everything_frozen',
                                                                  'mandatory',
                                                                  'empty'}
    #
    config.property.setdefault(frozenset(['cache']))
    config.property.setdefault(type='read_only', when='append', properties=frozenset(['disabled']))
    config.property.setdefault(type='read_only', when='remove', properties=frozenset(['hidden']))
    config.property.setdefault(type='read_write', when='append', properties=frozenset(['disabled', 'hidden']))
    config.property.setdefault(type='read_write', when='remove', properties=frozenset([]))
    raises(ValueError, "config.property.setdefault(type='unknown', when='append', properties=frozenset(['disabled']))")
    raises(ValueError, "config.property.setdefault(type='read_only', when='unknown', properties=frozenset(['disabled']))")
    raises(TypeError, "config.property.setdefault(type='read_only', when='append', properties=['disabled'])")

    assert config.property.getdefault() == {'cache'}
    assert config.property.getdefault('read_only', 'append') == {'disabled'}
    assert config.property.getdefault('read_only', 'remove') == {'hidden'}
    assert config.property.getdefault('read_write', 'append') == {'disabled',
                                                                  'hidden'}
    assert config.property.getdefault('read_write', 'remove') == set([])
    #
    config.property.read_only()
    assert config.property.get() == {'cache', 'disabled'}
    config.property.read_write()
    assert config.property.get() == {'cache', 'disabled', 'hidden'}
    config.property.read_only()
    assert config.property.get() == {'cache', 'disabled'}
    #
    assert config2.property.getdefault() == {'cache', 'validator', 'warnings'}
    assert config2.property.getdefault('read_only', 'append') == {'frozen',
                                                                  'disabled',
                                                                  'validator',
                                                                  'everything_frozen',
                                                                  'mandatory',
                                                                  'empty',
                                                                  'force_store_value'}
    assert config2.property.getdefault('read_only', 'remove') == {'permissive',
                                                                  'hidden'}
    assert config2.property.getdefault('read_write', 'append') == {'frozen',
                                                                   'disabled',
                                                                   'validator',
                                                                   'hidden',
                                                                   'force_store_value'}
    assert config2.property.getdefault('read_write', 'remove') == {'permissive',
                                                                   'everything_frozen',
                                                                   'mandatory',
                                                                   'empty'}
    raises(ValueError, "config2.property.getdefault('unknown', 'remove')")
    raises(ValueError, "config2.property.getdefault('read_write', 'unknown')")


def test_setitem(config_type):
    s = StrOption("string", "", default=["string", "sdfsdf"], default_multi="prout", multi=True)
    descr = OptionDescription("options", "", [s])
    cfg = Config(descr)
    cfg = get_config(cfg, config_type)
    cfg.option('string').value.set([undefined, 'foo'])
    assert cfg.option('string').value.get() == ['string', 'foo']


def test_reset(config_type):
    "if value is None, resets to default owner"
    s = StrOption("string", "", default="string")
    descr = OptionDescription("options", "", [s])
    cfg = Config(descr)
    cfg = get_config(cfg, config_type)
    cfg.option('string').value.set('foo')
    assert cfg.option('string').value.get() == "foo"
    assert cfg.option('string').owner.get() ==owners.user
    cfg.option('string').value.reset()
    assert cfg.option('string').value.get() == 'string'
    assert cfg.option('string').owner.get() ==owners.default


def test_reset_with_multi(config_type):
    s = StrOption("string", "", default=["string"], default_multi="string", multi=True)
    descr = OptionDescription("options", "", [s])
    cfg = Config(descr)
    cfg = get_config(cfg, config_type)
#    cfg.option('string').value.set([])
    cfg.option('string').value.reset()
    assert cfg.option('string').value.get() == ["string"]
    assert cfg.option('string').owner.get() =='default'
    cfg.option('string').value.set(["eggs", "spam", "foo"])
    assert cfg.option('string').owner.get() =='user'
    cfg.option('string').value.set([])
    cfg.option('string').value.reset()
#    assert cfg.option('string').value.get() == ["string"]
    assert cfg.option('string').owner.get() =='default'
    raises(ValueError, "cfg.option('string').value.set(None)")


def test_property_only_raises():
    s = StrOption("string", "", default=["string"], default_multi="string", multi=True)
    intoption = IntOption('int', 'Test int option', default=0)
    hidden_property = Calculation(calc_value,
                                  Params(ParamValue('hidden'),
                                         kwargs={'condition': ParamOption(intoption),
                                                 'expected': ParamValue(1)}))
    stroption = StrOption('str', 'Test string option', default=["abc"], default_multi="abc", properties=(hidden_property,), multi=True)
    descr = OptionDescription("options", "", [s, intoption, stroption])
    cfg = Config(descr)
    cfg.property.read_write()
    assert cfg.option('str').property.get() == {'empty'}
    assert cfg.option('str').property.get(only_raises=True) == set()


def test_default_with_multi():
    "default with multi is a list"
    s = StrOption("string", "", default=[], default_multi="string", multi=True)
    descr = OptionDescription("options", "", [s])
    cfg = Config(descr)
    assert cfg.option('string').value.get() == []
    s = StrOption("string", "", default=None, default_multi="string", multi=True)
    descr = OptionDescription("options", "", [s])
    cfg = Config(descr)
    assert cfg.option('string').value.get() == []


def test_idontexist():
    descr = make_description()
    cfg = Config(descr)
    cfg.value.dict()
    raises(AttributeError, "cfg.option('idontexist').value.get()")


# ____________________________________________________________
def test_attribute_access_with_multi(config_type):
    s = StrOption("string", "", default=["string"], default_multi="string", multi=True)
    descr = OptionDescription("options", "", [s])
    cfg = Config(descr)
    cfg = get_config(cfg, config_type)
    cfg.option('string').value.set(["foo", "bar"])
    assert cfg.option('string').value.get() == ["foo", "bar"]


def test_item_access_with_multi(config_type):
    s = StrOption("string", "", default=["string"], multi=True)
    descr = OptionDescription("options", "", [s])
    cfg = Config(descr)
    cfg = get_config(cfg, config_type)
    cfg.option('string').value.set(["foo", "bar"])
    assert cfg.option('string').value.get() == ["foo", "bar"]
    cfg.option('string').value.set(["changetest", "bar"])
    assert cfg.option('string').value.get() == ["changetest", "bar"]


def test_access_with_multi_default(config_type):
    s = StrOption("string", "", default=["string"], multi=True)
    descr = OptionDescription("options", "", [s])
    cfg = Config(descr)
    cfg = get_config(cfg, config_type)
    assert cfg.option('string').owner.get() =='default'
    cfg.option('string').value.set(["foo", "bar"])
    assert cfg.option('string').value.get() == ["foo", "bar"]
    assert cfg.option('string').owner.get() =='user'


def test_multi_with_requires():
    s = StrOption("string", "", default=["string"], default_multi="string", multi=True)
    intoption = IntOption('int', 'Test int option', default=0)
    hidden_property = Calculation(calc_value,
                                  Params(ParamValue('hidden'),
                                         kwargs={'condition': ParamOption(intoption),
                                                 'expected': ParamValue(1)}))
    stroption = StrOption('str', 'Test string option', default=["abc"], default_multi="abc", properties=(hidden_property,), multi=True)
    descr = OptionDescription("options", "", [s, intoption, stroption])
    cfg = Config(descr)
    cfg.property.read_write()
    assert not 'hidden' in cfg.option('str').property.get()
    cfg.option('int').value.set(1)
    raises(PropertiesOptionError, "cfg.option('str').value.set(['a', 'b'])")
    assert 'hidden' in cfg.forcepermissive.option('str').property.get()


def test_requires_with_inverted():
    s = StrOption("string", "", default=["string"], multi=True)
    intoption = IntOption('int', 'Test int option', default=0)
    hide_property = Calculation(calc_value,
                                Params(ParamValue('hide'),
                                       kwargs={'condition': ParamOption(intoption),
                                               'expected': ParamValue(1),
                                               'inverse_condition': ParamValue(True)}))
    stroption = StrOption('str', 'Test string option', default=["abc"], default_multi="abc", properties=(hide_property,), multi=True)
    descr = OptionDescription("options", "", [s, intoption, stroption])
    cfg = Config(descr)
    assert not 'hidden' in cfg.option('str').property.get()
    assert 'hide' in cfg.option('str').property.get()
    cfg.option('int').value.set(1)
    assert not 'hidden' in cfg.option('str').property.get()
    assert not 'hide' in cfg.option('str').property.get()


def test_multi_with_requires_in_another_group():
    s = StrOption("string", "", default=["string"], multi=True)
    intoption = IntOption('int', 'Test int option', default=0)
    hidden_property = Calculation(calc_value,
                                  Params(ParamValue('hidden'),
                                         kwargs={'condition': ParamOption(intoption),
                                                 'expected': ParamValue(1)}))
    stroption = StrOption('str', 'Test string option', default=["abc"], properties=(hidden_property,), multi=True)
    descr = OptionDescription("opt", "", [stroption])
    descr2 = OptionDescription("opt2", "", [intoption, s, descr])
    cfg = Config(descr2)
    cfg.property.read_write()
    assert not 'hidden' in cfg.option('opt.str').property.get()
    cfg.option('int').value.set(1)
    raises(PropertiesOptionError,  "cfg.option('opt.str').value.set(['a', 'b'])")
    assert 'hidden' in cfg.forcepermissive.option('opt.str').property.get()


def test_multi_with_requires_in_another_group_inverse():
    s = StrOption("string", "", default=["string"], multi=True)
    intoption = IntOption('int', 'Test int option', default=0)
    hidden_property = Calculation(calc_value,
                                  Params(ParamValue('hidden'),
                                         kwargs={'condition': ParamOption(intoption),
                                                 'expected': ParamValue(1)}))
#                          requires=[{'option': intoption, 'expected': 1, 'action': 'hidden'}], multi=True)
    stroption = StrOption('str', 'Test string option', default=["abc"], properties=(hidden_property,), multi=True)
    descr = OptionDescription("opt", "", [stroption])
    descr2 = OptionDescription("opt2", "", [intoption, s, descr])
    cfg = Config(descr2)
    cfg.property.read_write()
    assert not 'hidden' in cfg.option('opt.str').property.get()
    cfg.option('int').value.set(1)
    raises(PropertiesOptionError,  "cfg.option('opt.str').value.set(['a', 'b'])")
    assert 'hidden' in cfg.forcepermissive.option('opt.str').property.get()


def test_apply_requires_from_config():
    s = StrOption("string", "", default=["string"], multi=True)
    intoption = IntOption('int', 'Test int option', default=0)
    hidden_property = Calculation(calc_value,
                                  Params(ParamValue('hidden'),
                                         kwargs={'condition': ParamOption(intoption),
                                                 'expected': ParamValue(1)}))
    stroption = StrOption('str', 'Test string option', default=["abc"], properties=(hidden_property,), multi=True)
    descr = OptionDescription("opt", "", [stroption])
    descr2 = OptionDescription("opt2", "", [intoption, s, descr])
    cfg = Config(descr2)
    cfg.property.read_write()
    assert not 'hidden' in cfg.option('opt.str').property.get()
    cfg.option('int').value.set(1)
    raises(PropertiesOptionError, "cfg.option('opt.str').value.get()")
    assert 'hidden' in cfg.forcepermissive.option('opt.str').property.get()
    assert 'hidden' not in cfg.forcepermissive.option('opt.str').option.properties()
    assert 'hidden' not in cfg.forcepermissive.option('opt.str').option.properties(only_raises=True)


def test_apply_requires_with_disabled():
    s = StrOption("string", "", default=["string"], multi=True)
    intoption = IntOption('int', 'Test int option', default=0)
    disabled_property = Calculation(calc_value,
                                    Params(ParamValue('disabled'),
                                           kwargs={'condition': ParamOption(intoption),
                                                   'expected': ParamValue(1)}))
    stroption = StrOption('str', 'Test string option', default=["abc"], properties=(disabled_property,), multi=True)
    descr = OptionDescription("opt", "", [stroption])
    descr2 = OptionDescription("opt2", "", [intoption, s, descr])
    cfg = Config(descr2)
    cfg.property.read_write()
    assert not 'disabled' in cfg.option('opt.str').property.get()
    cfg.option('int').value.set(1)
    raises(PropertiesOptionError, "cfg.option('opt.str').value.get()")
    assert 'disabled' not in cfg.unrestraint.option('opt.str').option.properties()
    assert 'disabled' not in cfg.unrestraint.option('opt.str').option.properties(only_raises=True)
    assert 'disabled' in cfg.unrestraint.option('opt.str').property.get()


def test_multi_with_requires_with_disabled_in_another_group():
    s = StrOption("string", "", default=["string"], multi=True)
    intoption = IntOption('int', 'Test int option', default=0)
    disabled_property = Calculation(calc_value,
                                    Params(ParamValue('disabled'),
                                           kwargs={'condition': ParamOption(intoption),
                                                   'expected': ParamValue(1)}))
    stroption = StrOption('str', 'Test string option', default=["abc"], properties=(disabled_property,), multi=True)
    descr = OptionDescription("opt", "", [stroption])
    descr2 = OptionDescription("opt2", "", [intoption, s, descr])
    cfg = Config(descr2)
    cfg.property.read_write()
    assert not 'disabled' in cfg.option('opt.str').property.get()
    cfg.option('int').value.set(1)
    raises(PropertiesOptionError,  "cfg.option('opt.str').value.set(['a', 'b'])")
    assert 'disabled' in cfg.unrestraint.option('opt.str').property.get()
#
#
#def test_multi_with_requires_that_is_multi():
#    b = IntOption('int', 'Test int option', default=[0], multi=True)
#    hidden_property = Calculation(calc_value,
#                                  Params(ParamValue('hidden'),
#                                         kwargs={'condition': ParamOption(b),
#                                                 'expected': ParamValue(1)}))
#    c = StrOption('str', 'Test string option', default=['abc'], properties=(hidden_property,), multi=True)
#    descr = OptionDescription("opt", "", [b, c])
#    descr
#    # FIXME: ValueError: requirement mal formés pour l'option "int" ne doit pas être une valeur multiple pour "str"
#    raises(ValueError, "Config(descr)")
#
#
#def test_multi_with_requires_that_is_multi_inverse():
#    b = IntOption('int', 'Test int option', default=[0], multi=True)
#    c = StrOption('str', 'Test string option', default=['abc'], requires=[{'option': b, 'expected': 0, 'action': 'hidden', 'inverse': True}], multi=True)
#    descr = OptionDescription("opt", "", [b, c])
#    descr
#    Config(descr)
#    # FIXME: ValueError: requirement mal formés pour l'option "int" ne doit pas être une valeur multiple pour "str"
#    raises(ValueError, "Config(descr)")
#
#
#def test_multi_with_requires_that_is_leadership():
#    b = IntOption('int', 'Test int option', default=[0], multi=True)
#    c = StrOption('str', 'Test string option', requires=[{'option': b, 'expected': 1, 'action': 'hidden'}], multi=True)
#    descr = Leadership("int", "", [b, c])
#    od = OptionDescription('root', '', [descr])
#    Config(od)
#
#
#def test_multi_with_requires_that_is_leadership_leader():
#    b = IntOption('int', 'Test int option', multi=True)
#    c = StrOption('str', 'Test string option', requires=[{'option': b, 'expected': 1, 'action': 'hidden'}], multi=True)
#    raises(ValueError, "Leadership('str', '', [c, b])")


def test_multi_with_requires_that_is_leadership_follower():
    b = IntOption('int', 'Test int option', default=[0], multi=True)
    c = StrOption('str', 'Test string option', multi=True)
    hidden_property = Calculation(calc_value,
                                  Params(ParamValue('hidden'),
                                         kwargs={'condition': ParamOption(c),
                                                 'index': ParamIndex(),
                                                 'expected': ParamValue('1')}))
    d = StrOption('str1', 'Test string option', properties=(hidden_property,), multi=True)
    descr = Leadership("int", "", [b, c, d])
    descr2 = OptionDescription('od', '', [descr])
    cfg = Config(descr2)
    cfg.property.read_write()
    assert cfg.option('int.int').value.get() == [0]
    assert cfg.option('int.str', 0).value.get() == None
    assert cfg.option('int.str1', 0).value.get() == None
    cfg.option('int.int').value.set([0, 1])
    assert cfg.option('int.int').value.get() == [0, 1]
    assert cfg.option('int.str', 0).value.get() == None
    assert cfg.option('int.str', 1).value.get() == None
    assert cfg.option('int.str1', 0).value.get() == None
    assert cfg.option('int.str1', 1).value.get() == None
    cfg.option('int.str', 1).value.set('1')
    cfg.property.read_only()
    assert cfg.option('int.str1', 0).value.get() == None
    assert cfg.option('int.str1', 1).value.get() == None
    cfg.property.read_write()
    assert cfg.option('int.str1', 0).value.get() == None
    raises(PropertiesOptionError, "cfg.option('int.str1', 1).value.get()")


def test_multi_with_requires_that_is_leadership_follower_inverse():
    b = IntOption('int', 'Test int option', default=[0], multi=True)
    c = StrOption('str', 'Test string option', multi=True)
    hidden_property = Calculation(calc_value,
                                  Params(ParamValue('hidden'),
                                         kwargs={'condition': ParamOption(c),
                                                 'index': ParamIndex(),
                                                 'inverse_condition': ParamValue(True),
                                                 'expected': ParamValue(None)}))
    d = StrOption('str1', 'Test string option', properties=(hidden_property,), multi=True)
    descr = Leadership("int", "", [b, c, d])
    descr2 = OptionDescription('od', '', [descr])
    cfg = Config(descr2)
    cfg.property.read_write()
    assert cfg.option('int.int').value.get() == [0]
    assert cfg.option('int.str', 0).value.get() is None
    assert cfg.option('int.str1', 0).value.get() is None
    cfg.option('int.int').value.set([0, 1])
    assert cfg.option('int.int').value.get() == [0, 1]
    assert cfg.option('int.str', 0).value.get() is None
    assert cfg.option('int.str', 1).value.get() is None
    assert cfg.option('int.str1', 0).value.get() is None
    assert cfg.option('int.str1', 1).value.get() is None
    cfg.option('int.str', 1).value.set('1')
    cfg.property.read_only()
    assert cfg.option('int.str1', 0).value.get() is None
    assert cfg.option('int.str1', 1).value.get() is None
    cfg.property.read_write()
    assert cfg.option('int.str1', 0).value.get() is None
    raises(PropertiesOptionError, "cfg.option('int.str1', 1).value.get()")


#def test_multi_with_requires_that_is_not_same_leadership():
#    b = IntOption('int', 'Test int option', default=[0], multi=True)
#    hidden_property = Calculation(calc_value,
#                                  Params(ParamValue('hidden'),
#                                         kwargs={'condition': ParamOption(b),
#                                                 'index': ParamIndex(),
#                                                 'expected': ParamValue(1)}))
#    c = StrOption('str', 'Test string option', properties=(hidden_property,), multi=True)
#    #c = StrOption('str', 'Test string option', requires=[{'option': b, 'expected': 1, 'action': 'hidden'}], multi=True)
#    descr1 = Leadership("int", "", [b, c])
#    d = IntOption('int1', 'Test int option', default=[0], multi=True)
#    e = StrOption('str', 'Test string option', requires=[{'option': b, 'expected': 1, 'action': 'hidden'}], multi=True)
#    descr2 = Leadership("int1", "", [d, e])
#    descr3 = OptionDescription('val', '', [descr1, descr2])
#    descr3
#    raises(ValueError, "Config(descr3)")


def test_multi_with_bool():
    s = BoolOption("bool", "", default=[False], multi=True)
    descr = OptionDescription("options", "", [s])
    cfg = Config(descr)
    cfg.option('bool').value.set([True, False])
    assert cfg.option('bool').value.get() == [True, False]


def test_choice_access_with_multi():
    ch = ChoiceOption("t1", "", ("a", "b"), default=["a"], multi=True)
    descr = OptionDescription("options", "", [ch])
    cfg = Config(descr)
    cfg.option('t1').value.set(["a", "b", "a", "b"]) 
    assert cfg.option('t1').value.get() == ["a", "b", "a", "b"]


#____________________________________________________________
def test_accepts_multiple_changes_from_option():
    s = StrOption("string", "", default="string")
    descr = OptionDescription("options", "", [s])
    cfg = Config(descr)
    cfg.option('string').value.set("egg")
    assert cfg.option('string').option.default() == "string"
    assert cfg.option('string').value.get() == "egg"
    cfg.option('string').value.set('blah')
    assert cfg.option('string').option.default() == "string"
    assert cfg.option('string').value.get() == "blah"
    cfg.option('string').value.set('bol')
    assert cfg.option('string').value.get() == 'bol'


def test_allow_multiple_changes_from_config():
    """
    a `setoption` from the config object is much like the attribute access,
    except the fact that value owner can bet set
    """
    s = StrOption("string", "", default="string")
    s2 = StrOption("string2", "", default="string")
    suboption = OptionDescription("bip", "", [s2])
    descr = OptionDescription("options", "", [s, suboption])
    cfg = Config(descr)
    cfg.option('string').value.set("oh")
    assert cfg.option('string').value.get() == "oh"
    cfg.option('string').value.set("blah")
    assert cfg.option('string').value.get() == "blah"


# ____________________________________________________________
# accessing a value by the get method
def test_access_by_get():
    descr = make_description()
    cfg = Config(descr)
    raises(AttributeError, "list(cfg.option.find('idontexist'))")
    assert cfg.option.find('wantref', first=True).value.get() is False
    assert cfg.option.find('dummy', first=True).value.get() is False


def test_access_by_get_whith_hide():
    b1 = BoolOption("b1", "", properties=(('hidden'),))
    descr = OptionDescription("opt", "",
                              [OptionDescription("sub", "",
                                                 [b1, ChoiceOption("c1", "", ('a', 'b', 'c'), 'a'),
                                                  BoolOption("d1", "")]),
                               BoolOption("b2", ""),
                               BoolOption("d1", "")])
    cfg = Config(descr)
    cfg.property.read_write()
    raises(AttributeError, "cfg.option.find('b1').value.get()")


def test_append_properties():
    descr = make_description()
    cfg = Config(descr)
    assert cfg.option('gc.dummy').property.get() == set()
    cfg.option('gc.dummy').property.add('test')
    assert cfg.option('gc.dummy').property.get() == {'test'}
    raises(ConfigError, "cfg.option('gc.dummy').property.add('force_store_value')")
    assert cfg.option('gc.dummy').property.get() == {'test'}


def test_reset_properties():
    descr = make_description()
    cfg = Config(descr)
    assert cfg.option('gc.dummy').property.get() == set()
    cfg.option('gc.dummy').property.add('frozen')
    assert cfg.option('gc.dummy').property.get() == {'frozen'}
    cfg.option('gc.dummy').property.reset()
    assert cfg.option('gc.dummy').property.get() == set()


def test_properties_cached():
    b1 = BoolOption("b1", "", properties=('test',))
    descr = OptionDescription("opt", "", [OptionDescription("sub", "", [b1])])
    cfg = Config(descr)
    cfg.property.read_write()
    assert cfg.option('sub.b1').property.get() == {'test'}


def test_append_properties_force_store_value():
    gcdummy = BoolOption('dummy', 'dummy', default=False, properties=('force_store_value',))
    gcgroup = OptionDescription('gc', '', [gcdummy])
    descr = OptionDescription('tiramisu', '', [gcgroup])
    cfg = Config(descr)
    assert cfg.option('gc.dummy').property.get() == {'force_store_value'}
    cfg.option('gc.dummy').property.add('test')
    assert cfg.option('gc.dummy').property.get() == {'force_store_value', 'test'}


def test_reset_properties_force_store_value():
    gcdummy = BoolOption('dummy', 'dummy', default=False, properties=('force_store_value',))
    gcgroup = OptionDescription('gc', '', [gcdummy])
    descr = OptionDescription('tiramisu', '', [gcgroup])
    cfg = Config(descr)
    assert cfg.property.exportation() == {}
    cfg.property.add('frozen')
    assert cfg.property.exportation() == \
            {None: set(('frozen', 'cache', 'validator', 'warnings'))}
    cfg.property.reset()
    assert cfg.property.exportation() == {}
    cfg.option('gc.dummy').property.add('test')
    assert cfg.property.exportation() == {'gc.dummy': set(('test', 'force_store_value'))}
    cfg.property.reset()
    assert cfg.property.exportation() == {'gc.dummy': set(('test', 'force_store_value'))}
    cfg.property.add('frozen')
    assert cfg.property.exportation() == \
            {None: set(('frozen', 'validator', 'cache', 'warnings')),
             'gc.dummy': set(('test', 'force_store_value'))}
    cfg.property.add('frozen')
    assert cfg.property.exportation() == \
            {None: set(('frozen', 'validator', 'cache', 'warnings')),
             'gc.dummy': set(('test', 'force_store_value'))}
    cfg.option('gc.dummy').property.add('test')
    assert cfg.property.exportation() == \
            {None: set(('frozen', 'validator', 'cache', 'warnings')),
             'gc.dummy': set(('test', 'force_store_value'))}


def test_importation_force_store_value():
    gcdummy = BoolOption('dummy', 'dummy', default=False,
                         properties=('force_store_value',))
    gcgroup = OptionDescription('gc', '', [gcdummy])
    descr = OptionDescription('tiramisu', '', [gcgroup])
    config1 = Config(descr)
    assert config1.value.exportation() == [[], [], [], []]
    config1.property.add('frozen')
    assert config1.value.exportation() == [[], [], [], []]
    config1.property.add('force_store_value')
    assert config1.value.exportation() == [['gc.dummy'], [None], [False], ['forced']]
    exportation = config1.property.exportation()
    config2 = Config(descr)
    assert config2.value.exportation() == [[], [], [], []]
    config2.property.importation(exportation)
    assert config2.value.exportation() == [['gc.dummy'], [None], [False], ['forced']]
    config2.property.importation(exportation)
    assert config2.value.exportation() == [['gc.dummy'], [None], [False], ['forced']]


def test_set_modified_value():
    gcdummy = BoolOption('dummy', 'dummy', default=False, properties=('force_store_value',))
    gcgroup = OptionDescription('gc', '', [gcdummy])
    descr = OptionDescription('tiramisu', '', [gcgroup])
    cfg = Config(descr)
    assert cfg.property.exportation() == {}
    cfg.property.importation({None: set(('frozen', 'cache', 'validator', 'warnings'))})
    assert cfg.property.exportation() == \
            {None: set(('frozen', 'cache', 'validator', 'warnings'))}


def test_pprint():
    msg_error = _("cannot access to {0} \"{1}\" because has {2} {3}")
    msg_is_not = _('the value of "{0}" is not {1}')
    msg_is = _('the value of "{0}" is {1}')
    properties = _('properties')
    prop = _('property')

    s = StrOption("string", "", default=["string"], default_multi="string", multi=True, properties=('hidden', 'disabled'))
    s2 = StrOption("string2", "", default="string")
    s3 = StrOption("string3", "", default=["string"], default_multi="string", multi=True, properties=('hidden',))
    intoption = IntOption('int', 'Test int option', default=0)
    hidden_property = Calculation(calc_value,
                                  Params(ParamValue('hidden'),
                                         kwargs={'condition': ParamOption(intoption, todict=True),
                                                 'expected_0': ParamValue(2),
                                                 'expected_1': ParamValue(3),
                                                 'expected_2': ParamValue(4),
                                                 'inverse_condition': ParamValue(True)}),
                                  calc_value_property_help)
    disabled_property = Calculation(calc_value,
                                    Params(ParamValue('disabled'),
                                           kwargs={'condition_0': ParamOption(intoption, todict=True),
                                                   'expected_0': ParamValue(1),
                                                   'condition_1': ParamOption(s2, todict=True),
                                                   'expected_1': ParamValue('string')}),
                                    calc_value_property_help)
    stroption = StrOption('str', 'Test string option', default="abc", properties=(hidden_property, disabled_property))
#                          requires=[{'option': intoption, 'expected': 2, 'action': 'hidden', 'inverse': True},
#                                    {'option': intoption, 'expected': 3, 'action': 'hidden', 'inverse': True},
#                                    {'option': intoption, 'expected': 4, 'action': 'hidden', 'inverse': True},
#                                    {'option': intoption, 'expected': 1, 'action': 'disabled'},
#                                    {'option': s2, 'expected': 'string', 'action': 'disabled'}])

    val2 = StrOption('val2', "")
    hidden_property = Calculation(calc_value,
                                  Params(ParamValue('hidden'),
                                         kwargs={'condition': ParamOption(intoption, todict=True),
                                                 'expected': ParamValue(1)}),
                                  calc_value_property_help)
    descr2 = OptionDescription("options", "", [val2], properties=(hidden_property,))
    #descr2 = OptionDescription("options", "", [val2], requires=[{'option': intoption, 'expected': 1, 'action': 'hidden'}])

    hidden_property = Calculation(calc_value,
                                  Params(ParamValue('hidden'),
                                         kwargs={'condition': ParamOption(stroption, todict=True),
                                                 'expected': ParamValue('2'),
                                                 'inverse_condition': ParamValue(True)}),
                                  calc_value_property_help)
    val3 = StrOption('val3', "", properties=(hidden_property,))
    #val3 = StrOption('val3', "", requires=[{'option': stroption, 'expected': '2', 'action': 'hidden', 'inverse': True}])

    descr = OptionDescription("options", "", [s, s2, s3, intoption, stroption, descr2, val3])
    cfg = Config(descr)
    cfg.property.read_write()
    cfg.option('int').value.set(1)
    err = None
    try:
        cfg.option('str').value.get()
    except PropertiesOptionError as error:
        err = error

    list_disabled = '"disabled" (' + display_list([msg_is.format('Test int option', '"1"'), msg_is.format('string2', '"string"')], add_quote=False) + ')'
    list_hidden = '"hidden" (' + msg_is_not.format('Test int option', display_list([2, 3, 4], 'or', add_quote=True)) + ')'
    assert str(err) == _(msg_error.format('option', 'Test string option', properties, display_list([list_disabled, list_hidden], add_quote=False)))
    del err

    err = None
    try:
        cfg.option('options.val2').value.get()
    except PropertiesOptionError as error:
        err = error

    assert str(err) == msg_error.format('optiondescription', 'options', prop, '"hidden" (' + msg_is.format('Test int option', '"1"') + ')')

    #err = None
    #try:
    #    cfg.option('val3').value.get()
    #except PropertiesOptionError as error:
    #    err = error

    #msg_1 = msg_is.format('string2', 'string')
    #msg_2 = msg_is.format('Test int option', 1)
    #msg_3 = msg_is_not.format('Test int option', display_list([2, 3, 4], 'or', add_quote=True))
    #list_hidden = '"hidden" (' + display_list([msg_2, msg_3, msg_1]) + ')'

    #assert str(err) == msg_error.format('option', 'val3', prop, list_hidden)

    err = None
    try:
        cfg.option('string').value.get()
    except Exception as error:
        err = error

    assert str(err) == msg_error.format('option', 'string', properties, display_list(['disabled', 'hidden'], add_quote=True))
    del err

    err = None
    try:
        cfg.option('string3').value.get()
    except Exception as error:
        err = error

    assert str(err) == msg_error.format('option', 'string3', prop, '"hidden"')
    del err