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"]))
