import os

import string

import sys

import unittest

import errno

from unittest.mock import patch



from ascend_deployer.utils import Validator

from ascend_deployer.utils import get_validated_env



PATH_WHITE_LIST_LIN = string.digits + string.ascii_letters + '~-+_./ '

MAX_PATH_LEN = 4096





class TestGetValidatedEnv(unittest.TestCase):



    @patch('os.getenv')

    def test_env_not_set(self, mock_getenv):

        mock_getenv.return_value = None

        with self.assertRaises(ValueError) as context:

            get_validated_env('TEST_ENV')

        self.assertEqual(str(context.exception), "Environment variable TEST_ENV is not set")



    @patch('os.getenv')

    def test_env_value_not_in_whitelist(self, mock_getenv):

        mock_getenv.return_value = 'invalid_value('

        with self.assertRaises(ValueError) as context:

            get_validated_env('TEST_ENV')

        self.assertEqual(str(context.exception), "The path is invalid. The path can contain only char in '{}'".format(PATH_WHITE_LIST_LIN))



    @patch('os.getenv')

    def test_env_value_too_short(self, mock_getenv):

        mock_getenv.return_value = 'a'

        with self.assertRaises(ValueError) as context:

            get_validated_env('TEST_ENV', min_length=2)

        self.assertEqual(str(context.exception), "Value for TEST_ENV is too short. Minimum length: 2, actual: 1")



    @patch('os.getenv')

    def test_env_value_too_long(self, mock_getenv):

        mock_getenv.return_value = 'a' * (MAX_PATH_LEN + 1)

        with self.assertRaises(ValueError) as context:

            get_validated_env('TEST_ENV', max_length=MAX_PATH_LEN)

        self.assertEqual(str(context.exception), "Value for TEST_ENV is too long. Maximum length: {}, actual: {}".format(MAX_PATH_LEN, MAX_PATH_LEN + 1))



    @patch('os.getenv')

    @patch('os.path.lexists')

    @patch('os.path.islink')

    def test_env_value_is_symlink(self, mock_islink, mock_lexists, mock_getenv):

        mock_getenv.return_value = '/path/to/symlink'

        mock_lexists.return_value = True

        mock_islink.return_value = True

        with self.assertRaises(ValueError) as context:

            get_validated_env('TEST_ENV', check_symlink=True)

        self.assertEqual(str(context.exception), "Path for TEST_ENV is a symlink: /path/to/symlink. Symlinks are not allowed for security reasons.")



    @patch('os.getenv')

    @patch('os.path.lexists')

    @patch('os.path.islink')

    def test_env_value_is_not_symlink(self, mock_islink, mock_lexists, mock_getenv):

        mock_getenv.return_value = '/path/to/file'

        mock_lexists.return_value = True

        mock_islink.return_value = False

        self.assertEqual(get_validated_env('TEST_ENV', check_symlink=True), '/path/to/file')



    @patch('os.getenv')

    @patch('os.path.lexists')

    def test_env_value_lexists_error(self, mock_lexists, mock_getenv):

        mock_getenv.return_value = '/path/to/file'

        mock_lexists.side_effect = OSError(errno.ENOENT, 'No such file or directory')

        self.assertEqual(get_validated_env('TEST_ENV', check_symlink=True), '/path/to/file')



    @patch('os.getenv')

    @patch('os.path.lexists')

    def test_env_value_lexists_io_error(self, mock_lexists, mock_getenv):

        mock_getenv.return_value = '/path/to/file'

        mock_lexists.side_effect = IOError(errno.ENOENT, 'No such file or directory')

        self.assertEqual(get_validated_env('TEST_ENV', check_symlink=True), '/path/to/file')





class TestValidator(unittest.TestCase):



    def test_valid_ip(self):

        validator = Validator()

        self.assertEqual(True, validator.is_valid_ip("192.168.0.1"))

        self.assertEqual(True, validator.is_valid_ip("0.0.0.0"))

        self.assertEqual(True, validator.is_valid_ip("2001:0db8:85a3::8a2e:0370:7334"))

        self.assertEqual(True, validator.is_valid_ip("::1"))

        self.assertEqual(False, validator.is_valid_ip(" "))

        self.assertEqual(False, validator.is_valid_ip("11111111111"))

        self.assertEqual(True, validator.is_valid_ip("localhost"))

        self.assertEqual(True, validator.is_valid_ip("LOCALHOST"))

        



if __name__ == '__main__':

    unittest.main()