import hashlib
import pytest

from ...helpers.datastruct import StableDict, Buffer
from ...helpers import msgpack


def test_stable_dict():
    d = StableDict(foo=1, bar=2, boo=3, baz=4)
    assert list(d.items()) == [("bar", 2), ("baz", 4), ("boo", 3), ("foo", 1)]
    assert hashlib.md5(msgpack.packb(d)).hexdigest() == "fc78df42cd60691b3ac3dd2a2b39903f"


class TestBuffer:
    def test_type(self):
        buffer = Buffer(bytearray)
        assert isinstance(buffer.get(), bytearray)
        buffer = Buffer(bytes)  # Do not do that in practice.
        assert isinstance(buffer.get(), bytes)

    def test_len(self):
        buffer = Buffer(bytearray, size=0)
        b = buffer.get()
        assert len(buffer) == len(b) == 0
        buffer = Buffer(bytearray, size=1234)
        b = buffer.get()
        assert len(buffer) == len(b) == 1234

    def test_resize(self):
        buffer = Buffer(bytearray, size=100)
        assert len(buffer) == 100
        b1 = buffer.get()
        buffer.resize(200)
        assert len(buffer) == 200
        b2 = buffer.get()
        assert b2 is not b1  # New, bigger buffer.
        buffer.resize(100)
        assert len(buffer) >= 100
        b3 = buffer.get()
        assert b3 is b2  # Still the same buffer (200).
        buffer.resize(100, init=True)
        assert len(buffer) == 100  # Except on init.
        b4 = buffer.get()
        assert b4 is not b3  # New, smaller buffer.

    def test_limit(self):
        buffer = Buffer(bytearray, size=100, limit=200)
        buffer.resize(200)
        assert len(buffer) == 200
        with pytest.raises(Buffer.MemoryLimitExceeded):
            buffer.resize(201)
        assert len(buffer) == 200

    def test_get(self):
        buffer = Buffer(bytearray, size=100, limit=200)
        b1 = buffer.get(50)
        assert len(b1) >= 50  # == 100
        b2 = buffer.get(100)
        assert len(b2) >= 100  # == 100
        assert b2 is b1  # Did not need resizing yet.
        b3 = buffer.get(200)
        assert len(b3) == 200
        assert b3 is not b2  # New, resized buffer.
        with pytest.raises(Buffer.MemoryLimitExceeded):
            buffer.get(201)  # Beyond limit.
        assert len(buffer) == 200
