#  Copyright 2020 Modelling, Simulation and Design Lab (MSDL) at
#  McGill University and the University of Antwerp (http://msdl.cs.mcgill.ca/)
#
#  Licensed under the Apache License, Version 2.0 (the "License");
#  you may not use this file except in compliance with the License.
#  You may obtain a copy of the License at
#
#     http://www.apache.org/licenses/LICENSE-2.0
#
#  Unless required by applicable law or agreed to in writing, software
#  distributed under the License is distributed on an "AS IS" BASIS,
#  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
#  See the License for the specific language governing permissions and
#  limitations under the License.

"""Test that the heap implementation works as required.

See Also:
    :mod:`pypdevsbbl.extra.heap`
"""

import unittest
import random as rnd
from pypdevsbbl.extra.heap import heap, MIN_HEAP

class TestHeap(unittest.TestCase):
    def setUp(self):
        """Sets up all tests.

        Creates two heaps (a min-heap and a max-heap) and
        fills them with 10,000 random integers.
        """
        N = 10000
        lst = [rnd.randint(1, N) for _ in range(N)]
        self.sn = sorted(lst)
        self.sr = sorted(lst, reverse=True)
        self.hn = heap(MIN_HEAP)
        self.hr = heap()

        assert self.hn.empty()
        assert self.hr.empty()
        assert self.hn.peek() is None
        assert self.hr.peek() is None

        for i in lst:
            self.hn.insert(i)
            self.hr.insert(i)

        assert not self.hn.empty()
        assert not self.hr.empty()
        assert self.hn.peek() is not None
        assert self.hr.peek() is not None

    def test_insert(self):
        """Tests the insertion in the heap."""
        assert len(self.hn.items()) == len(self.hr.items()) == len(self.sn)
        assert sorted(self.hn.items()) == sorted(self.hr.items()) == self.sn

    def test_pop(self):
        """Tests the pop of the max/min item in the heap."""
        n = []
        while not self.hn.empty():
            n.append(self.hn.pop())

        r = []
        while not self.hr.empty():
            r.append(self.hr.pop())

        assert self.hn.empty()
        assert self.hr.empty()

        assert len(self.sn) == len(n) == len(self.sr)
        for i in range(len(n)):
            assert self.sn[i] == n[i]
        for i in range(len(r)):
            assert self.sr[i] == r[i]

    def test_peek(self):
        """Tests peeking of items (and regaining their indexes) of the heap."""
        for i in self.hn.data:
            idx = self.hn.indexOf(i)
            assert self.hn.peek(idx) == i

        for i in self.hr.data:
            idx = self.hr.indexOf(i)
            assert self.hr.peek(idx) == i


if __name__ == '__main__':
    unittest.main()

