"config.set() or config.setoption() or option.setoption()"
import autopath
from py.test import raises

from tiramisu.setting import owners
from tiramisu.config import Config
from tiramisu.option import ChoiceOption, BoolOption, IntOption, FloatOption, \
    StrOption, OptionDescription
from tiramisu.error import PropertiesOptionError


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():
    "Once set, option values can't be changed again by attribute access"
    s = StrOption("string", "", default="string")
    descr = OptionDescription("options", "", [s])
    config = Config(descr)
    # let's try to change it again
    config.string = "foo"
    assert config.string == "foo"


def test_setitem():
    s = StrOption("string", "", default=["string", "sdfsdf"], default_multi="prout", multi=True)
    descr = OptionDescription("options", "", [s])
    config = Config(descr)
    config.string[1] = "titi"


def test_reset():
    "if value is None, resets to default owner"
    s = StrOption("string", "", default="string")
    descr = OptionDescription("options", "", [s])
    config = Config(descr)
    config.string = "foo"
    assert config.string == "foo"
    assert config.getowner(s) == owners.user
    del(config.string)
    assert config.string == 'string'
    assert config.getowner(s) == owners.default


def test_reset_with_multi():
    s = StrOption("string", "", default=["string"], default_multi="string", multi=True)
    descr = OptionDescription("options", "", [s])
    config = Config(descr)
#    config.string = []
    del(config.string)
    assert config.string == ["string"]
    assert config.getowner(s) == 'default'
    config.string = ["eggs", "spam", "foo"]
    assert config.getowner(s) == 'user'
    config.string = []
    del(config.string)
#    assert config.string == ["string"]
    assert config.getowner(s) == 'default'
    raises(ValueError, "config.string = None")


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


def test_idontexist():
    descr = make_description()
    cfg = Config(descr)
    raises(AttributeError, "cfg.idontexist")


# ____________________________________________________________
def test_attribute_access_with_multi():
    s = StrOption("string", "", default=["string"], default_multi="string", multi=True)
    descr = OptionDescription("options", "", [s])
    config = Config(descr)
    config.string = ["foo", "bar"]
    assert config.string == ["foo", "bar"]


def test_item_access_with_multi():
    s = StrOption("string", "", default=["string"], multi=True)
    descr = OptionDescription("options", "", [s])
    config = Config(descr)
    config.string = ["foo", "bar"]
    assert config.string == ["foo", "bar"]
    assert config.string[0] == "foo"
    config.string[0] = 'changetest'
    assert config.string[0] == 'changetest'


def test_access_with_multi_default():
    s = StrOption("string", "", default=["string"], multi=True)
    descr = OptionDescription("options", "", [s])
    config = Config(descr)
    assert config.getowner(s) == 'default'
    config.string = ["foo", "bar"]
    assert config.string == ["foo", "bar"]
    assert config.getowner(s) == 'user'


def test_multi_with_requires():
    s = StrOption("string", "", default=["string"], default_multi="string", multi=True)
    intoption = IntOption('int', 'Test int option', default=0)
    stroption = StrOption('str', 'Test string option', default=["abc"], default_multi="abc",
                          requires=[{'option': intoption, 'expected': 1, 'action': 'hidden'}], multi=True)
    descr = OptionDescription("options", "", [s, intoption, stroption])
    config = Config(descr)
    setting = config.cfgimpl_get_settings()
    config.read_write()
    assert not 'hidden' in setting[stroption]
    config.int = 1
    raises(PropertiesOptionError, "config.str = ['a', 'b']")
    assert 'hidden' in setting[stroption]


def test__requires_with_inverted():
    s = StrOption("string", "", default=["string"], multi=True)
    intoption = IntOption('int', 'Test int option', default=0)
    stroption = StrOption('str', 'Test string option', default=["abc"], default_multi="abc",
                          requires=[{'option': intoption, 'expected': 1, 'action': 'hide', 'inverse': True}], multi=True)
    descr = OptionDescription("options", "", [s, intoption, stroption])
    config = Config(descr)
    setting = config.cfgimpl_get_settings()
    assert not 'hidden' in setting[stroption]
    config.int = 1
    assert not 'hidden' in setting[stroption]


def test_multi_with_requires_in_another_group():
    s = StrOption("string", "", default=["string"], multi=True)
    intoption = IntOption('int', 'Test int option', default=0)
    descr = OptionDescription("options", "", [intoption])
    stroption = StrOption('str', 'Test string option', default=["abc"],
                          requires=[{'option': intoption, 'expected': 1, 'action': 'hidden'}], multi=True)
    descr = OptionDescription("opt", "", [stroption])
    descr2 = OptionDescription("opt2", "", [intoption, s, descr])
    config = Config(descr2)
    setting = config.cfgimpl_get_settings()
    config.read_write()
    assert not 'hidden' in setting[stroption]
    config.int = 1
    raises(PropertiesOptionError,  "config.opt.str = ['a', 'b']")
    assert 'hidden' in setting[stroption]


def test_apply_requires_from_config():
    s = StrOption("string", "", default=["string"], multi=True)
    intoption = IntOption('int', 'Test int option', default=0)
    descr = OptionDescription("options", "", [intoption])
    stroption = StrOption('str', 'Test string option', default=["abc"],
                          requires=[{'option': intoption, 'expected': 1, 'action': 'hidden'}], multi=True)
    descr = OptionDescription("opt", "", [stroption])
    descr2 = OptionDescription("opt2", "", [intoption, s, descr])
    config = Config(descr2)
    setting = config.cfgimpl_get_settings()
    config.read_write()
    assert not 'hidden' in setting[stroption]
    config.int = 1
    raises(PropertiesOptionError, 'config.opt.str')
    assert 'hidden' in setting[stroption]


def test_apply_requires_with_disabled():
    s = StrOption("string", "", default=["string"], multi=True)
    intoption = IntOption('int', 'Test int option', default=0)
    descr = OptionDescription("options", "", [intoption])
    stroption = StrOption('str', 'Test string option', default=["abc"],
                          requires=[{'option': intoption, 'expected': 1, 'action': 'disabled'}], multi=True)
    descr = OptionDescription("opt", "", [stroption])
    descr2 = OptionDescription("opt2", "", [intoption, s, descr])
    config = Config(descr2)
    setting = config.cfgimpl_get_settings()
    config.read_write()
    assert not 'disabled' in setting[stroption]
    config.int = 1
    raises(PropertiesOptionError, 'config.opt.str')
    assert 'disabled' in setting[stroption]


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)
    descr = OptionDescription("options", "", [intoption])
    stroption = StrOption('str', 'Test string option', default=["abc"],
                          requires=[{'option': intoption, 'expected': 1, 'action': 'disabled'}], multi=True)
    descr = OptionDescription("opt", "", [stroption])
    descr2 = OptionDescription("opt2", "", [intoption, s, descr])
    config = Config(descr2)
    setting = config.cfgimpl_get_settings()
    config.read_write()
    assert not 'disabled' in setting[stroption]
    config.int = 1
    raises(PropertiesOptionError,  "config.opt.str = ['a', 'b']")
    assert 'disabled' in setting[stroption]


def test_multi_with_requires_that_is_multi():
    s = StrOption("string", "", default=["string"], multi=True)
    intoption = IntOption('int', 'Test int option', default=[0], multi=True)
    raises(ValueError, "StrOption('str', 'Test string option', default=['abc'], requires=[{'option': intoption, 'expected': 1, 'action': 'hidden'}], multi=True)")


def test_multi_with_bool():
    s = BoolOption("bool", "", default=[False], multi=True)
    descr = OptionDescription("options", "", [s])
    config = Config(descr)
    assert descr.bool.impl_is_multi() is True
    config.bool = [True, False]
    assert config.cfgimpl_get_values()[s] == [True, False]
    assert config.bool == [True, False]


def test_multi_with_bool_two():
    s = BoolOption("bool", "", default=[False], multi=True)
    descr = OptionDescription("options", "", [s])
    config = Config(descr)
    assert descr.bool.impl_is_multi() is True
    raises(ValueError, "config.bool = True")


def test_choice_access_with_multi():
    ch = ChoiceOption("t1", "", ("a", "b"), default=["a"], multi=True)
    descr = OptionDescription("options", "", [ch])
    config = Config(descr)
    config.t1 = ["a", "b", "a", "b"]
    assert config.t1 == ["a", "b", "a", "b"]


#____________________________________________________________
def test_accepts_multiple_changes_from_option():
    s = StrOption("string", "", default="string")
    descr = OptionDescription("options", "", [s])
    config = Config(descr)
    config.string = "egg"
    assert s.impl_getdefault() == "string"
    assert config.string == "egg"
    config.string = 'blah'
    assert s.impl_getdefault() == "string"
    assert config.string == "blah"
    config.string = 'bol'
    assert config.string == '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])
    config = Config(descr)
    config.string = "oh"
    assert config.string == "oh"
    config.string = "blah"
    assert config.string == "blah"


# ____________________________________________________________
# accessing a value by the get method
def test_access_by_get():
    descr = make_description()
    cfg = Config(descr)
    raises(AttributeError, "cfg.find(byname='idontexist')")
    assert cfg.find_first(byname='wantref', type_='value') is False
    assert cfg.gc.dummy is False
    assert cfg.find_first(byname='dummy', type_='value') 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", "")])
    c = Config(descr)
    c.read_write()
    raises(AttributeError, "c.find(byname='b1')")


def test_extend_config_properties():
    descr = make_description()
    cfg = Config(descr)
    setting = cfg.cfgimpl_get_settings()
    assert str(setting) == str(['cache', 'expire', 'validator'])
    setting.extend(['test', 'test2'])
    assert str(setting) == str(['test', 'cache', 'test2', 'expire', 'validator'])


def test_append_properties():
    descr = make_description()
    cfg = Config(descr)
    setting = cfg.cfgimpl_get_settings()
    option = cfg.cfgimpl_get_description().gc.dummy
    assert option._properties == tuple()
    assert not 'test' in setting[option]
    setting[option].append('test')
    assert option._properties == tuple()
    assert 'test' in setting[option]


def test_reset_properties():
    descr = make_description()
    cfg = Config(descr)
    setting = cfg.cfgimpl_get_settings()
    option = cfg.cfgimpl_get_description().gc.dummy
    assert setting._p_.get_modified_properties() == {}
    setting.append('frozen')
    assert setting._p_.get_modified_properties() == {None: set(('frozen', 'expire', 'cache', 'validator'))}
    setting.reset()
    assert setting._p_.get_modified_properties() == {}
    setting[option].append('test')
    assert setting._p_.get_modified_properties() == {'gc.dummy': set(('test',))}
    setting.reset()
    assert setting._p_.get_modified_properties() == {'gc.dummy': set(('test',))}
    setting.append('frozen')
    assert setting._p_.get_modified_properties() == {None: set(('frozen', 'expire', 'validator', 'cache')), 'gc.dummy': set(('test',))}
    setting.reset(option)
    assert setting._p_.get_modified_properties() == {None: set(('frozen', 'expire', 'validator', 'cache'))}
    setting[option].append('test')
    assert setting._p_.get_modified_properties() == {None: set(('frozen', 'expire', 'validator', 'cache')), 'gc.dummy': set(('test',))}
    setting.reset(all_properties=True)
    assert setting._p_.get_modified_properties() == {}
    raises(ValueError, 'setting.reset(all_properties=True, opt=option)')
    a = descr.wantref
    setting[a].append('test')
    setting[a].reset()


def test_reset_multiple():
    descr = make_description()
    cfg = Config(descr)
    setting = cfg.cfgimpl_get_settings()
    option = cfg.cfgimpl_get_description().gc.dummy
    setting.append('frozen')
    setting[option].append('test')
    setting.reset()
    setting.reset()
    setting.append('frozen')
    setting[option].append('test')
    setting.reset(option)
    setting.reset(option)
    setting.append('frozen')
    setting[option].append('test')
    setting.reset(all_properties=True)
    setting.reset(all_properties=True)


def test_properties_cached():
    b1 = BoolOption("b1", "", properties=('test',))
    descr = OptionDescription("opt", "", [OptionDescription("sub", "", [b1])])
    c = Config(descr)
    c.read_write()
    setting = c.cfgimpl_get_settings()
    option = c.cfgimpl_get_description().sub.b1
    c._setattr('sub.b1', True, force_permissive=True)
    assert str(setting[b1]) == "['test']"