import unittest
import sys
import os

from utils import execute, kill, run_file, run_barebone

def extend_commands(commands):
    # Initially we communicate with the compilation_manager to add the bytecodes
    pre =   [
                3,
                "upload",
                "test.o",
                "MD5_HASH",
                True,     # use NEW interface for constructors
                "funcdef", "main", 0, # Main function
            ]
    # We only have to define "main" for now
    post =  [
                True,
                "main",
                True,
                False,
            ]
    return pre + commands + post

class TestConstructorsActionLanguageLinkable(unittest.TestCase):
    def test_constructors_simple(self):
        commands = [
                        "output",
                            "const", True,
                            True,
                        "return",
                            True,
                            "const", True,
                        False,
                    ]
        commands = extend_commands(commands)
        self.assertTrue(run_barebone(commands, [True], None, link=["test.o"]))

    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",
                        False,
                ]
        commands = extend_commands(commands)
        self.assertTrue(run_barebone(commands, [True], None, link=["test.o"]))

    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",
                        False,
                ]
        commands = extend_commands(commands)
        self.assertTrue(run_barebone(commands, [False], None, link=["test.o"]))

    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",
                    False,
                ]
        commands = extend_commands(commands)
        self.assertTrue(run_barebone(commands, [True], None, link=["test.o"]))

    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",
                        False,
                ]
        commands = extend_commands(commands)
        self.assertTrue(run_barebone(commands, [None], None, timeout=True, link=["test.o"]))

    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",
                        False,
                ]
        commands = extend_commands(commands)
        self.assertTrue(run_barebone(commands, [False], None, link=["test.o"]))

    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",
                        False,
                ]
        commands = extend_commands(commands)
        self.assertTrue(run_barebone(commands, [True, True, True, True], None, link=["test.o"]))

    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",
                    False,
                ]
        commands = extend_commands(commands)
        self.assertTrue(run_barebone(commands, [5], None, link=["test.o"]))

    def test_constructors_output_input(self):
        commands = [
                     "output",
                        "input",
                        True,
                    "return",
                        True,
                        "const", "true",
                    False,
                ]
        commands = extend_commands(commands)
        self.assertTrue(run_barebone(commands, [123456], None, link=["test.o"], inputs=["123456"]))

    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,
                    False
                ]
        commands = extend_commands(commands)
        self.assertTrue(run_barebone(commands, [1, 1, 1, 1, 1], None, link=["test.o"]))

    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,
                    False
                ]
        commands = extend_commands(commands)
        self.assertTrue(run_barebone(commands, [1, 3], None, link=["test.o"]))
