class TestRandomAccessMemory:

    """Test case for RAM."""

    ram = None

    def setup(self):
        """Init state."""
        self.ram = RandomAccessMemory(WORD_SIZE, 512, endianess='big')
        assert self.ram.word_size == WORD_SIZE
        assert self.ram.memory_size == 512
        assert len(self.ram) == 512
        assert self.ram.is_protected is True

    def test_check_address(self):
        """It a second part of information protection."""
        for i in range(len(self.ram)):
            self.ram.check_address(i)
        for i in range(len(self.ram), 2 * len(self.ram)):
            with raises(KeyError):
                self.ram.check_address(i)
        with raises(TypeError):
            self.ram.check_address('R1')

    def test_setitem(self):
        """Address should be checked."""
        for i in range(len(self.ram)):
            self.ram[i] = len(self.ram) + i
            assert i in self.ram
        for i in range(len(self.ram), 2 * len(self.ram)):
            with raises(KeyError):
                self.ram[i] = i
            assert i not in self.ram
        with raises(TypeError):
            self.ram['R1'] = 10
        assert 'R1' not in self.ram
        with raises(ValueError):
            self.ram[2] = 2 ** WORD_SIZE

    def test_getitem(self):
        """Address should be checked."""
        for i in range(2 * len(self.ram)):
            with raises(KeyError):
                self.ram.__getitem__(i)
        with raises(TypeError):
            self.ram.__getitem__('R1')

        for i in range(len(self.ram) // 2):
            self.ram[i] = i
            assert self.ram[i] == i

    def test_not_protected_getitem(self):
        """Test if programmer can shut in his leg."""
        self.ram = RandomAccessMemory(WORD_SIZE, 512, 'big', is_protected=False)
        for i in range(len(self.ram)):
            assert self.ram[i] == 0
        for i in range(len(self.ram), 2 * len(self.ram)):
            with raises(KeyError):
                self.ram.__getitem__(i)

    def test_fetch(self):
        """Fetch is basic operation of transfer data."""
        for i in range(5, 9):
            self.ram[i] = i
            assert self.ram.fetch(i, WORD_SIZE) == i
        assert (self.ram.fetch(5, 4 * WORD_SIZE) ==
                0x00000005000000060000000700000008)
        assert (self.ram.fetch(5, 4 * WORD_SIZE) ==
                big_endian_decode([5, 6, 7, 8], WORD_SIZE))

        self.ram[5] = 0
        assert (self.ram.fetch(5, 4 * WORD_SIZE) ==
                big_endian_decode([0, 6, 7, 8], WORD_SIZE))
        assert (self.ram.fetch(5, 4 * WORD_SIZE) ==
                0x00000000000000060000000700000008)

        with raises(KeyError):
            self.ram.fetch(5, 4 * WORD_SIZE - 1)
        with raises(KeyError):
            self.ram.fetch(4, 4 * WORD_SIZE)

        self.ram = RandomAccessMemory(WORD_SIZE, 512, endianess="little")
        for i in range(5, 9):
            self.ram[i] = i
            assert self.ram.fetch(i, WORD_SIZE) == i
        assert (self.ram.fetch(5, 4 * WORD_SIZE) ==
                0x00000008000000070000000600000005)
        assert (self.ram.fetch(5, 4 * WORD_SIZE) ==
                little_endian_decode([5, 6, 7, 8], WORD_SIZE))

    def test_put(self):
        """Test put operation."""
        value_list = [0, 6, 7, 0]
        value = big_endian_decode(value_list, WORD_SIZE)
        self.ram.put(5, value, 4 * WORD_SIZE)
        with raises(ValueError):
            self.ram.put(5, 2 ** WORD_SIZE, WORD_SIZE)
        self.ram.put(4, 4, WORD_SIZE)
        for i in range(5, 9):
            assert self.ram[i] == value_list[i - 5]

        self.ram = RandomAccessMemory(WORD_SIZE, 512, endianess="little")
        value = little_endian_decode(value_list, WORD_SIZE)
        self.ram.put(5, value, 4 * WORD_SIZE)
        for i in range(5, 9):
            assert self.ram[i] == value_list[i - 5]