#  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.

"""Tests the Transformer building blocks to prove validity w.r.t. these tests.

See Also:
    :mod:`pypdevsbbl.generic.transformers` and :mod`pypdevsbbl.extra.packaging`
"""

import unittest

from pypdevsbbl.generic.collectors import TableCollector
from pypdevsbbl.generic.generators import FunctionGenerator, SingleFire
from pypdevsbbl.generic.transformers import Transformer, Pack, Unpack, LookupTable
from pypdevsbbl.extra.packaging import SizedPackage
from test.generic import Model, simulate


class TestTransformers(unittest.TestCase):
    def test_transformer(self):
        """Tests the :class:`pypdevsbbl.generic.transformers.Transformer`."""
        gen = FunctionGenerator("Counter")
        trans = Transformer("Transformer", lambda i, e, t: i**2)
        coll1 = TableCollector("OCollector")
        coll2 = TableCollector("TCollector")
        model = Model([gen, trans, coll1, coll2], [
            (gen.output, trans.input), (trans.original, coll1.input), (trans.transformed, coll2.input)
        ])
        simulate(model, 10.0)

        assert [(x, x) for x in list(range(11))] == model.nodes[2].table()
        assert [(x, x**2) for x in list(range(11))] == model.nodes[3].table()

    def test_lookup(self):
        """Tests the :class:`pypdevsbbl.generic.transformers.LookupTable`."""
        table = {x: x ** 3 for x in range(5)}
        gen = FunctionGenerator("Counter")
        trans = LookupTable("Lookup", table, 666)
        coll1 = TableCollector("OCollector")
        coll2 = TableCollector("TCollector")
        model = Model([gen, trans, coll1, coll2], [
            (gen.output, trans.input), (trans.original, coll1.input), (trans.transformed, coll2.input)
        ])
        simulate(model, 10.0)

        assert [(x, x) for x in list(range(11))] == model.nodes[2].table()
        assert [(x, x**3) if x in range(5) else (x, 666) for x in list(range(11))] == model.nodes[3].table()

    def test_pack(self):
        """Tests the :class:`pypdevsbbl.generic.transformers.Pack`."""
        gen = FunctionGenerator("Counter")
        pack = Pack("Pack")
        rel = SingleFire("Release", True, 10.0)
        coll = TableCollector("Collector")
        model = Model([gen, pack, coll, rel], [
            (gen.output, pack.input), (pack.output, coll.input), (rel.output, pack.release)
        ])
        simulate(model, 15.0)

        assert list(range(11)) == model.nodes[2].table()[0][1].contents

    def test_pack_automatic(self):
        """Tests the :class:`pypdevsbbl.generic.transformers.Pack` with automatic release."""
        gen = FunctionGenerator("Counter")
        pack = Pack("Pack", SizedPackage, 10)
        coll = TableCollector("Collector")
        model = Model([gen, pack, coll], [
            (gen.output, pack.input), (pack.output, coll.input)
        ])
        simulate(model, 15.0)

        assert list(range(10)) == model.nodes[2].table()[0][1].contents

    def test_unpack(self):
        """Tests the :class:`pypdevsbbl.generic.transformers.Unpack`."""
        gen = FunctionGenerator("Counter")
        pack = Pack("Pack", SizedPackage, 10)
        unpack = Unpack("Unpack")
        coll = TableCollector("Collector")
        model = Model([gen, pack, unpack, coll], [
            (gen.output, pack.input), (pack.output, unpack.input), (unpack.output, coll.input)
        ])
        simulate(model, 15.0)

        assert list(range(10)) == model.nodes[3].table()[0][1]


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