# encoding: utf-8

"""
.. codeauthor:: Tsuyoshi Hombashi <tsuyoshi.hombashi@gmail.com>
"""

from __future__ import absolute_import, unicode_literals

import itertools
import string

import pytest
from pathvalidate import (
    InvalidCharError, InvalidReservedNameError, NullNameError, sanitize_python_var_name,
    validate_python_var_name)

from ._common import INVALID_PYTHON_VAR_CHARS


RESERVED_KEYWORDS = [
    "and", "del", "from", "not", "while",
    "as", "elif", "global", "or", "with",
    "assert", "else", "if", "pass", "yield",
    "break", "except", "import", "print",
    "class", "exec", "in", "raise",
    "continue", "finally", "is", "return",
    "def", "for", "lambda", "try",
    "False", "True", "None", "NotImplemented", "Ellipsis",
]


class Test_validate_python_var_name(object):
    VALID_CHAR_LIST = [
        c for c in string.digits + string.ascii_letters + "_"
    ]
    INVALID_CHAR_LIST = INVALID_PYTHON_VAR_CHARS

    @pytest.mark.parametrize(["value"], [
        ["abc" + valid_char + "hoge123"] for valid_char in VALID_CHAR_LIST
    ])
    def test_normal(self, value):
        validate_python_var_name(value)

    @pytest.mark.parametrize(["value"], [
        ["abc" + invalid_char + "hoge123"] for invalid_char in INVALID_CHAR_LIST
    ])
    def test_exception_invalid_char(self, value):
        with pytest.raises(InvalidCharError):
            validate_python_var_name(value)

    @pytest.mark.parametrize(["value"], [
        [invalid_char + "hoge123"] for invalid_char in string.digits + "_"
    ])
    def test_exception_invalid_first_char(self, value):
        with pytest.raises(InvalidCharError):
            validate_python_var_name(value)

    @pytest.mark.parametrize(["value", "expected"], [
        [None, ValueError],
        ["", NullNameError],
        ["123", ValueError],
        [1, TypeError],
        [True, TypeError],
    ])
    def test_exception_type(self, value, expected):
        with pytest.raises(expected):
            validate_python_var_name(value)

    @pytest.mark.parametrize(["value", "expected"], [
        [reserved_keyword, InvalidReservedNameError]
        for reserved_keyword in RESERVED_KEYWORDS + ["__debug__"]
    ])
    def test_exception_reserved(self, value, expected):
        with pytest.raises(expected):
            validate_python_var_name(value)


class Test_sanitize_python_var_name(object):
    SANITIZE_CHAR_LIST = INVALID_PYTHON_VAR_CHARS
    NOT_SANITIZE_CHAR_LIST = ["_"]
    REPLACE_TEXT_LIST = ["", "_"]

    @pytest.mark.parametrize(
        ["value", "replace_text", "expected"],
        [
            ["A" + c + "B", rep, "A" + rep + "B"]
            for c, rep in itertools.product(SANITIZE_CHAR_LIST, REPLACE_TEXT_LIST)
        ] + [
            ["A" + c + "B", rep, "A" + c + "B"]
            for c, rep in itertools.product(NOT_SANITIZE_CHAR_LIST, REPLACE_TEXT_LIST)
        ])
    def test_normal(self, value, replace_text, expected):
        sanitized_name = sanitize_python_var_name(value, replace_text)
        assert sanitized_name == expected
        validate_python_var_name(sanitized_name)

    @pytest.mark.parametrize(
        ["value", "replace_text", "expected"],
        [
            [invalid_char + "hoge_123", "_", "hoge_123"] for invalid_char in string.digits + "_"
        ] + [
            [invalid_char + "hoge_123", "a", "ahoge_123"] for invalid_char in string.digits + "_"
        ])
    def test_normal_invalid_first_char_x1(self, value, replace_text, expected):
        sanitized_name = sanitize_python_var_name(value, replace_text)
        assert sanitized_name == expected
        validate_python_var_name(sanitized_name)

    @pytest.mark.parametrize(
        ["value", "replace_text", "expected"],
        [
            [invalid_char * 2 + "hoge_123", "_", "hoge_123"]
            for invalid_char in string.digits + "_"
        ] + [
            [invalid_char * 2 + "hoge_123", "a", "aahoge_123"]
            for invalid_char in string.digits + "_"
        ])
    def test_normal_invalid_first_char_x2(self, value, replace_text, expected):
        sanitized_name = sanitize_python_var_name(value, replace_text)
        assert sanitized_name == expected
        validate_python_var_name(sanitized_name)

    @pytest.mark.parametrize(["value", "expected"], [
        [reserved_keyword, reserved_keyword + "_"] for reserved_keyword in RESERVED_KEYWORDS
    ])
    def test_normal_reserved(self, value, expected):
        assert sanitize_python_var_name(value) == expected

    @pytest.mark.parametrize(["value", "expected"], [
        [None, ValueError],
        [1, TypeError],
        [True, TypeError],
    ])
    def test_exception_type(self, value, expected):
        with pytest.raises(expected):
            sanitize_python_var_name(value)

@@ -1003,27 +1003,24 @@
 c%22 + valid_c
-har
  + %22hoge123%22
@@ -1028,27 +1028,24 @@
  for valid_c
-har
  in VALID_CH
@@ -1194,35 +1194,32 @@
 abc%22 + invalid_c
-har
  + %22hoge123%22%5D fo
@@ -1225,27 +1225,24 @@
 or invalid_c
-har
  in INVALID_
@@ -1451,35 +1451,32 @@
       %5Binvalid_c
-har
  + %22hoge123%22%5D fo
@@ -1478,35 +1478,32 @@
 %22%5D for invalid_c
-har
  in string.digit
@@ -3184,35 +3184,32 @@
       %5Binvalid_c
-har
  + %22hoge_123%22, %22
@@ -3229,35 +3229,32 @@
 %22%5D for invalid_c
-har
  in string.digit
@@ -3297,19 +3297,16 @@
 nvalid_c
-har
  + %22hoge
@@ -3335,35 +3335,32 @@
 %22%5D for invalid_c
-har
  in string.digit
@@ -3722,35 +3722,32 @@
       %5Binvalid_c
-har
  * 2 + %22hoge_123
@@ -3761,36 +3761,24 @@
  %22hoge_123%22%5D
-%0A           
  for invalid
@@ -3771,35 +3771,32 @@
 %22%5D for invalid_c
-har
  in string.digit
@@ -3839,19 +3839,16 @@
 nvalid_c
-har
  * 2 + %22
@@ -3876,28 +3876,16 @@
 ge_123%22%5D
-%0A           
  for inv
@@ -3890,19 +3890,16 @@
 nvalid_c
-har
  in stri

Rename variables