import unittest
import sys
import os

from utils import execute, kill, run_file, run_barebone

def flatten(lst):
    new_lst = []
    for f in lst:
        if isinstance(f, (list, tuple)):
            new_lst.extend(flatten(f))
        else:
            new_lst.append(f)
    return new_lst

class TestConstructorsActionLanguage(unittest.TestCase):
    def test_constructors_simple(self):
        commands = [('"output"',                    # Output
                        ('"const"', 'true'),
                        'true',                     # (has next)
                        ('"return"',                # Return
                            'true',                 # (has value)
                            ('"const"', 'true'),
                        ),
                    )
                ]
        self.assertTrue(run_barebone(flatten(commands), ["True"], 1))

    def test_constructors_if_else_true(self):
        commands = [('"if"',                    # If
                        ('"const"', 'true'),    # Condition
                        ('"output"',            # True-part
                            ('"const"', 'true'),
                            'false',            # Has next
                        ),
                        'true',                 # Has else
                        ('"output"',            # False-part
                            ('"const"', 'false'),
                            'false',            # Has next
                        ),
                        'true',                 # Has next
                        ('"return"',            # Return
                            'true',             # Has value
                            ('"const"', "true"),
                        ),

                    )
                ]
        self.assertTrue(run_barebone(flatten(commands), ["True"], 1))

    def test_constructors_if_else_false(self):
        commands = [('"if"',                    # If
                        ('"const"', 'false'),   # Condition
                        ('"output"',            # True-part
                            ('"const"', 'true'),
                            'false',            # Has next
                        ),
                        'true',                 # Has else
                        ('"output"',            # False-part
                            ('"const"', 'false'),
                            'false',            # Has next
                        ),
                        'true',                 # Has next
                        ('"return"',            # Return
                            'true',             # Has value
                            ('"const"', "true"),
                        ),

                    )
                ]
        self.assertTrue(run_barebone(flatten(commands), ["False"], 1))

    def test_constructors_if_true(self):
        commands = [('"if"',                    # If
                        ('"const"', 'true'),    # Condition
                        ('"output"',            # True-part
                            ('"const"', 'true'),
                            'false',            # Has next
                        ),
                        'false',                # Has else
                        'true',                 # Has next
                        ('"return"',            # Return
                            'true',             # Has value
                            ('"const"', "true"),
                        ),

                    )
                ]
        self.assertTrue(run_barebone(flatten(commands), ["True"], 1))

    def test_constructors_if_false(self):
        commands = [('"if"',                    # If
                        ('"const"', 'false'),   # Condition
                        ('"output"',            # True-part
                            ('"const"', 'true'),
                            'false',            # Has next
                        ),
                        'false',                # Has else
                        'true',                 # Has next
                        ('"return"',            # Return
                            'true',             # Has value
                            ('"const"', "true"),
                        ),

                    )
                ]
        self.assertTrue(run_barebone(flatten(commands), [None], 1, timeout=True))

    def test_constructors_addition(self):
        commands = [('"output"',
                        ('"call"',
                            ('"deref"', '"primitives/integer_addition"'),
                            '2',
                            ('"const"', '1'),
                            ('"const"', '5'),
                            'false',
                        ),
                        'true',
                        ('"return"', 'true', '"const"', 'true'),
                    )
                ]
        self.assertTrue(run_barebone(flatten(commands), ["6"], 1))

    def test_constructors_while_false(self):
        commands = [('"while"',                 # While
                        ('"const"', 'false'),   # Condition
                        ('"output"',            # True-part
                            ('"const"', 'true'),
                            'false',            # Has next
                        ),
                        'true',                 # Has next
                        ('"output"',            # Output false
                            ('"const"', 'false'),
                            'true',             # Has next
                            ('"return"',        # Return
                                'true',         # Has value
                                ('"const"', "true"),
                            ),
                        ),

                    )
                ]
        self.assertTrue(run_barebone(flatten(commands), ["False"], 1))

    def test_constructors_while_true(self):
        commands = ['"while"',                 # While
                        '"const"', 'true',    # Condition
                        '"output"',            # True-part
                            '"const"', 'true',
                            'false',            # Has next
                        'true',                 # Has next
                        '"output"',            # False-part
                            '"const"', 'false',
                            'true',            # Has next
                        '"return"',            # Return
                            'true',             # Has value
                            '"const"', "true",
                ]
        self.assertTrue(run_barebone(flatten(commands), ["True", "True", "True", "True"], 1))

    def test_constructors_declare_and_assign(self):
        commands = ['"declare"',
                        '"1"',
                        'true',
                    '"assign"',
                        '"resolve"', '"1"',
                        '"const"', '5',
                        'true',
                    '"output"',
                        '"access"', '"resolve"', '"1"',
                        'true',
                    '"return"',
                        'true',
                        '"const"', "true",
                ]
        self.assertTrue(run_barebone(flatten(commands), ["5"], 1))

    def test_constructors_output_input(self):
        commands = ['"output"',
                        '"input"',
                        'true',
                    '"return"',
                        'true',
                        '"const"', "true",
                ]
        self.assertTrue(run_barebone(flatten(commands) + ['123456'], ["123456"], 1))

    def test_constructors_continue(self):
        commands = ['"while"',
                        '"const"', 'true',
                        '"output"', '"const"', '1',
                            'true',
                            '"if"',
                                '"const"', 'true',
                                '"continue"',
                                'false',
                                'true',
                            '"output"', '"const"', '2',
                                'false',
                        'true',
                    '"output"', '"const"', '3',
                        'true',
                    '"return"', 'true',
                        '"const"', 'true',
                ]
        self.assertTrue(run_barebone(flatten(commands), ['1', '1', '1', '1', '1'], 1))

    def test_constructors_break(self):
        commands = ['"while"',
                        '"const"', 'true',
                        '"output"', '"const"', '1',
                            'true',
                            '"if"',
                                '"const"', 'true',
                                '"break"',
                                'false',
                                'true',
                            '"output"', '"const"', '2',
                                'false',
                        'true',
                    '"output"', '"const"', '3',
                        'true',
                    '"return"', 'true',
                        '"const"', 'true',
                ]
        self.assertTrue(run_barebone(flatten(commands), ['1', '3'], 1))
