import unittest

import modelflow.elementarynodes
import modelflow.exceptions
import modelflow.node


class TestElementaryUnits(unittest.TestCase):
    def test_minus_pre_set(self):
        minus = modelflow.elementarynodes.Minus()
        minus['plus'] = 7
        minus['minus'] = 3
        self.assertEqual(7-3, minus())

    def test_minus_invalid_argument_error(self):
        minus = modelflow.elementarynodes.Minus()
        with self.assertRaises(modelflow.exceptions.InvalidInputChannelException):
            minus({"invalid_argument": 42})

    def test_minus_call(self):
        minus = modelflow.elementarynodes.Minus()
        self.assertEqual(7-3, minus({'plus': 7, 'minus': 3}))

    def test_division_pre_set(self):
        div = modelflow.elementarynodes.Division()
        div['denominator'] = 3
        div['enumerator'] = 7
        self.assertEqual(7/3, div())

    def test_plus_set_parameters_in_init(self):
        plus = modelflow.elementarynodes.Plus(arg1=1, arg2=2)
        self.assertEqual(3, plus())

    def test_division_call(self):
        div = modelflow.elementarynodes.Division()
        self.assertEqual(7/3, div({'enumerator': 7, 'denominator': 3}))

    def test_plus_plus_partially_pre_set(self):
        plus = modelflow.elementarynodes.Plus()
        plus['arg1'] = 3
        self.assertEqual(7+3, plus(arg2=7))

    def test_plus_plus_wrong_argument(self):
        plus = modelflow.elementarynodes.Plus()
        with self.assertRaises(modelflow.exceptions.InvalidInputChannelException):
            plus['arg1_typo'] = 3

    def test_division_call(self):
        div = modelflow.elementarynodes.Division()
        self.assertEqual(7/3, div({'enumerator': 7, 'denominator': 3}))

    def test_identity(self):
        identity = modelflow.elementarynodes.Identity()
        identity['value'] = 42
        self.assertEqual(42, identity())

    def test_get_input(self):
        plus = modelflow.elementarynodes.Plus()
        plus['arg1'] = 2
        self.assertEqual(2, plus['arg1'])

    def test_run_not_implemented_abc_meta_exception(self):
        class TestNode(modelflow.node.Node):
            pass
        with self.assertRaises(TypeError):
            TestNode()

    def test_node_invalid_input_at_construction(self):
        class TestNode(modelflow.Node):
            def run(self):
                return 42

        with self.assertRaises(modelflow.exceptions.InvalidInputChannelException):
            TestNode(a=1)

    def test_node_invalid_input_at_run(self):
        class TestNode(modelflow.Node):
            def run(self):
                return 42

        with self.assertRaises(modelflow.exceptions.InvalidInputChannelException):
            TestNode()(a=1)


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