from __future__ import absolute_import
# Copyright (c) 2010-2015 openpyxl

import pytest

from .. import Strict

class TestDescriptor:

    from ..base import Descriptor

    class Dummy:
        pass

    def test_ctor(self):
        d = self.Descriptor('key', size=1)
        assert d.name == 'key'
        assert d.size == 1

    def test_setter(self):
        d = self.Descriptor('key')
        client = self.Dummy()
        d.__set__(client, 42)
        assert client.key == 42


@pytest.fixture
def boolean():

    from ..base import Bool

    class Dummy(Strict):

        value = Bool()

    return Dummy()


class TestBool:

    def test_valid(self, boolean):
        boolean.value = True
        assert boolean.value

    @pytest.mark.parametrize("value, expected",
                             [
                                 (1, True,),
                                 (0, False),
                                 ('true', True),
                                 ('false', False),
                                 ('0', False),
                                 ('f', False),
                                 ('', False),
                                 ([], False)
                             ]
                              )
    def test_cast(self, boolean, value, expected):
        boolean.value = value
        assert boolean.value == expected


def test_nested():
    from ..base import Bool

    class DummyNested(Strict):

        value = Bool(nested=True)

    dummy = DummyNested()
    dummy.value = True
    assert dummy.__class__.value.nested == True


@pytest.fixture
def integer():

    from ..base import Integer

    class Dummy(Strict):

        value = Integer()

    return Dummy()


class TestInt:

    def test_valid(self, integer):
        integer.value = 4
        assert integer.value == 4

    @pytest.mark.parametrize("value", ['a', '4.5', None])
    def test_invalid(self, integer, value):
        with pytest.raises(TypeError):
            integer.value = value

    @pytest.mark.parametrize("value, expected",
                             [
                                 ('4', 4),
                                 (4.5, 4),
                             ])
    def test_cast(self, integer, value, expected):
        integer.value = value
        assert integer.value == expected


@pytest.fixture
def float():

    from ..base import Float

    class Dummy(Strict):

        value = Float()

    return Dummy()


class TestFloat:

    def test_valid(self, float):
        float.value = 4
        assert float.value == 4

    @pytest.mark.parametrize("value", ['a', None])
    def test_invalid(self, float, value):
        with pytest.raises(TypeError):
            float.value = value

    @pytest.mark.parametrize("value, expected",
                             [
                                 ('4.5', 4.5),
                                 (4.5, 4.5),
                                 (4, 4.0),
                             ])
    def test_cast(self, float, value, expected):
        float.value = value
        assert float.value == expected


@pytest.fixture
def allow_none():

    from ..base import Float

    class Dummy(Strict):

        value = Float(allow_none=True)

    return Dummy()


class TestAllowNone:

    def test_valid(self, allow_none):
        allow_none.value = None
        assert allow_none.value is None


@pytest.fixture
def maximum():
    from ..base import Max

    class Dummy(Strict):

        value = Max(max=5)

    return Dummy()


class TestMax:

    def test_ctor(self):
        from ..base import Max

        with pytest.raises(TypeError):
            class Dummy(Strict):
                value = Max()

    def test_valid(self, maximum):
        maximum.value = 4
        assert maximum.value == 4

    def test_invalid(self, maximum):
        with pytest.raises(ValueError):
            maximum.value = 6


@pytest.fixture
def minimum():
    from ..base import Min