from enum import IntEnum

from pya2l.utils import (
    Bunch,
    NotAvailable,
    SingletonBase,
    Tristate,
    align_as,
    cygpathToWin,
    enum_from_str,
    ffs,
    fold_equal,
    nfc_equal,
    padding,
    slicer,
)


def test_slicer():
    assert list(slicer([1, 2, 3, 4, 5], 2, converter=lambda *x: list(x))) == [[1, 2], [3, 4], [5]]
    assert list(slicer([1, 2, 3, 4, 5], 3, converter=lambda *x: list(x))) == [[1, 2, 3], [4, 5]]
    assert list(slicer([1, 2, 3, 4, 5], 3, converter=lambda *x: tuple(x))) == [(1, 2, 3), (4, 5)]


def test_cygpathToWin():
    assert cygpathToWin("/cygdrive/c/temp") == "c:\\temp"
    assert cygpathToWin("/usr/bin") == "/usr/bin"


def test_tristate():
    t = Tristate(True)
    assert t == True
    assert str(t) == "True"
    assert repr(t) == "Tristate(True)"

    f = Tristate(False)
    assert f == False

    n = Tristate(None)
    assert n != True
    assert n != False


def test_ffs():
    assert ffs(1) == 0
    assert ffs(2) == 1
    assert ffs(4) == 2
    assert ffs(8) == 3


def test_bunch():
    b = Bunch(a=1, b=2)
    assert b.a == 1
    assert b["b"] == 2


def test_nfc_equal():
    assert nfc_equal("a", "a")
    assert not nfc_equal("a", "b")


def test_fold_equal():
    assert fold_equal("A", "a")
    assert not fold_equal("A", "B")


class MyEnum(IntEnum):
    VAL1 = 1
    VAL2 = 2


def test_enum_from_str():
    assert enum_from_str(MyEnum, "VAL1") == MyEnum.VAL1
    assert enum_from_str(MyEnum, "VAL3") is None


def test_singleton():
    class S(SingletonBase):
        pass

    s1 = S()
    s2 = S()
    assert s1 is s2


def test_not_available():
    na = NotAvailable()
    assert na == NotAvailable()
    assert str(na) == "n/a"
    # Just check that it doesn't crash and returns a boolean or something
    assert isinstance(na < 1, bool)
    assert isinstance(na > 1, bool)


def test_alignment_1():
    assert align_as(0, 1) == 0
    assert align_as(1, 1) == 1
    assert align_as(2, 1) == 2
    assert align_as(3, 1) == 3
    assert align_as(4, 1) == 4
    assert align_as(5, 1) == 5
    assert align_as(6, 1) == 6
    assert align_as(7, 1) == 7
    assert align_as(8, 1) == 8
    assert align_as(9, 1) == 9
    assert align_as(10, 1) == 10
    assert align_as(11, 1) == 11
    assert align_as(12, 1) == 12
    assert align_as(13, 1) == 13
    assert align_as(14, 1) == 14
    assert align_as(15, 1) == 15
    assert align_as(16, 1) == 16
    assert align_as(17, 1) == 17
    assert align_as(18, 1) == 18
    assert align_as(19, 1) == 19
    assert align_as(20, 1) == 20
    assert align_as(21, 1) == 21
    assert align_as(22, 1) == 22
    assert align_as(23, 1) == 23
    assert align_as(24, 1) == 24
    assert align_as(25, 1) == 25
    assert align_as(26, 1) == 26
    assert align_as(27, 1) == 27
    assert align_as(28, 1) == 28
    assert align_as(29, 1) == 29
    assert align_as(30, 1) == 30
    assert align_as(31, 1) == 31


def test_alignment_2():
    assert align_as(0, 2) == 0
    assert align_as(1, 2) == 2
    assert align_as(2, 2) == 2
    assert align_as(3, 2) == 4
    assert align_as(4, 2) == 4
    assert align_as(5, 2) == 6
    assert align_as(6, 2) == 6
    assert align_as(7, 2) == 8
    assert align_as(8, 2) == 8
    assert align_as(9, 2) == 10
    assert align_as(10, 2) == 10
    assert align_as(11, 2) == 12
    assert align_as(12, 2) == 12
    assert align_as(13, 2) == 14
    assert align_as(14, 2) == 14
    assert align_as(15, 2) == 16
    assert align_as(16, 2) == 16
    assert align_as(17, 2) == 18
    assert align_as(18, 2) == 18
    assert align_as(19, 2) == 20
    assert align_as(20, 2) == 20
    assert align_as(21, 2) == 22
    assert align_as(22, 2) == 22
    assert align_as(23, 2) == 24
    assert align_as(24, 2) == 24
    assert align_as(25, 2) == 26
    assert align_as(26, 2) == 26
    assert align_as(27, 2) == 28
    assert align_as(28, 2) == 28
    assert align_as(29, 2) == 30
    assert align_as(30, 2) == 30
    assert align_as(31, 2) == 32


def test_alignment_4():
    assert align_as(0, 4) == 0
    assert align_as(1, 4) == 4
    assert align_as(2, 4) == 4
    assert align_as(3, 4) == 4
    assert align_as(4, 4) == 4
    assert align_as(5, 4) == 8
    assert align_as(6, 4) == 8
    assert align_as(7, 4) == 8
    assert align_as(8, 4) == 8
    assert align_as(9, 4) == 12
    assert align_as(10, 4) == 12
    assert align_as(11, 4) == 12
    assert align_as(12, 4) == 12
    assert align_as(13, 4) == 16
    assert align_as(14, 4) == 16
    assert align_as(15, 4) == 16
    assert align_as(16, 4) == 16
    assert align_as(17, 4) == 20
    assert align_as(18, 4) == 20
    assert align_as(19, 4) == 20
    assert align_as(20, 4) == 20
    assert align_as(21, 4) == 24
    assert align_as(22, 4) == 24
    assert align_as(23, 4) == 24
    assert align_as(24, 4) == 24
    assert align_as(25, 4) == 28
    assert align_as(26, 4) == 28
    assert align_as(27, 4) == 28
    assert align_as(28, 4) == 28
    assert align_as(29, 4) == 32
    assert align_as(30, 4) == 32
    assert align_as(31, 4) == 32


def test_alignment_8():
    assert align_as(0, 8) == 0
    assert align_as(1, 8) == 8
    assert align_as(2, 8) == 8
    assert align_as(3, 8) == 8
    assert align_as(4, 8) == 8
    assert align_as(5, 8) == 8
    assert align_as(6, 8) == 8
    assert align_as(7, 8) == 8
    assert align_as(8, 8) == 8
    assert align_as(9, 8) == 16
    assert align_as(10, 8) == 16
    assert align_as(11, 8) == 16
    assert align_as(12, 8) == 16
    assert align_as(13, 8) == 16
    assert align_as(14, 8) == 16
    assert align_as(15, 8) == 16
    assert align_as(16, 8) == 16
    assert align_as(17, 8) == 24
    assert align_as(18, 8) == 24
    assert align_as(19, 8) == 24
    assert align_as(20, 8) == 24
    assert align_as(21, 8) == 24
    assert align_as(22, 8) == 24
    assert align_as(23, 8) == 24
    assert align_as(24, 8) == 24
    assert align_as(25, 8) == 32
    assert align_as(26, 8) == 32
    assert align_as(27, 8) == 32
    assert align_as(28, 8) == 32
    assert align_as(29, 8) == 32
    assert align_as(30, 8) == 32
    assert align_as(31, 8) == 32


def test_padding_1():
    assert padding(0, 1) == 0
    assert padding(1, 1) == 0
    assert padding(2, 1) == 0
    assert padding(3, 1) == 0
    assert padding(4, 1) == 0
    assert padding(5, 1) == 0
    assert padding(6, 1) == 0
    assert padding(7, 1) == 0
    assert padding(8, 1) == 0
    assert padding(9, 1) == 0
    assert padding(10, 1) == 0
    assert padding(11, 1) == 0
    assert padding(12, 1) == 0
    assert padding(13, 1) == 0
    assert padding(14, 1) == 0
    assert padding(15, 1) == 0
    assert padding(16, 1) == 0
    assert padding(17, 1) == 0
    assert padding(18, 1) == 0
    assert padding(19, 1) == 0
    assert padding(20, 1) == 0
    assert padding(21, 1) == 0
    assert padding(22, 1) == 0
    assert padding(23, 1) == 0
    assert padding(24, 1) == 0
    assert padding(25, 1) == 0
    assert padding(26, 1) == 0
    assert padding(27, 1) == 0
    assert padding(28, 1) == 0
    assert padding(29, 1) == 0
    assert padding(30, 1) == 0
    assert padding(31, 1) == 0


def test_padding_2():
    assert padding(0, 2) == 0
    assert padding(1, 2) == 1
    assert padding(2, 2) == 0
    assert padding(3, 2) == 1
    assert padding(4, 2) == 0
    assert padding(5, 2) == 1
    assert padding(6, 2) == 0
    assert padding(7, 2) == 1
    assert padding(8, 2) == 0
    assert padding(9, 2) == 1
    assert padding(10, 2) == 0
    assert padding(11, 2) == 1
    assert padding(12, 2) == 0
    assert padding(13, 2) == 1
    assert padding(14, 2) == 0
    assert padding(15, 2) == 1
    assert padding(16, 2) == 0
    assert padding(17, 2) == 1
    assert padding(18, 2) == 0
    assert padding(19, 2) == 1
    assert padding(20, 2) == 0
    assert padding(21, 2) == 1
    assert padding(22, 2) == 0
    assert padding(23, 2) == 1
    assert padding(24, 2) == 0
    assert padding(25, 2) == 1
    assert padding(26, 2) == 0
    assert padding(27, 2) == 1
    assert padding(28, 2) == 0
    assert padding(29, 2) == 1
    assert padding(30, 2) == 0
    assert padding(31, 2) == 1


def test_padding_4():
    assert padding(0, 4) == 0
    assert padding(1, 4) == 3
    assert padding(2, 4) == 2
    assert padding(3, 4) == 1
    assert padding(4, 4) == 0
    assert padding(5, 4) == 3
    assert padding(6, 4) == 2
    assert padding(7, 4) == 1
    assert padding(8, 4) == 0
    assert padding(9, 4) == 3
    assert padding(10, 4) == 2
    assert padding(11, 4) == 1
    assert padding(12, 4) == 0
    assert padding(13, 4) == 3
    assert padding(14, 4) == 2
    assert padding(15, 4) == 1
    assert padding(16, 4) == 0
    assert padding(17, 4) == 3
    assert padding(18, 4) == 2
    assert padding(19, 4) == 1
    assert padding(20, 4) == 0
    assert padding(21, 4) == 3
    assert padding(22, 4) == 2
    assert padding(23, 4) == 1
    assert padding(24, 4) == 0
    assert padding(25, 4) == 3
    assert padding(26, 4) == 2
    assert padding(27, 4) == 1
    assert padding(28, 4) == 0
    assert padding(29, 4) == 3
    assert padding(30, 4) == 2
    assert padding(31, 4) == 1


def test_padding_8():
    assert padding(0, 8) == 0
    assert padding(1, 8) == 7
    assert padding(2, 8) == 6
    assert padding(3, 8) == 5
    assert padding(4, 8) == 4
    assert padding(5, 8) == 3
    assert padding(6, 8) == 2
    assert padding(7, 8) == 1
    assert padding(8, 8) == 0
    assert padding(9, 8) == 7
    assert padding(10, 8) == 6
    assert padding(11, 8) == 5
    assert padding(12, 8) == 4
    assert padding(13, 8) == 3
    assert padding(14, 8) == 2
    assert padding(15, 8) == 1
    assert padding(16, 8) == 0
    assert padding(17, 8) == 7
    assert padding(18, 8) == 6
    assert padding(19, 8) == 5
    assert padding(20, 8) == 4
    assert padding(21, 8) == 3
    assert padding(22, 8) == 2
    assert padding(23, 8) == 1
    assert padding(24, 8) == 0
    assert padding(25, 8) == 7
    assert padding(26, 8) == 6
    assert padding(27, 8) == 5
    assert padding(28, 8) == 4
    assert padding(29, 8) == 3
    assert padding(30, 8) == 2
    assert padding(31, 8) == 1
