Browse Source

Merge branch 'feature/settings_validator' of 1ffy/sp-1 into master

1ffy 1 year ago
parent
commit
79e3f49f6e
3 changed files with 230 additions and 34 deletions
  1. 22 8
      src/settings.py
  2. 126 0
      src/settings_validator.py
  3. 82 26
      tests/test_settings.py

+ 22 - 8
src/settings.py

@@ -1,3 +1,4 @@
+from src.settings_validator import settings_validator
 
 
 class settings:
@@ -17,6 +18,13 @@ class settings:
     __property_type = ""
 
 
+    # Валидатор
+    __vtor = None
+
+    def __init__(self):
+        self.__vtor = settings_validator()
+
+
     def __validate(value, exp_type=None, length=None):
         """
             Валидация аргумента по типу и/или длине
@@ -53,10 +61,10 @@ class settings:
             value (str): Полное наименование
 
         Raises:
-            TypeError: Некорректный аргумента
+            TypeError: Некорректный аргумент
         """
 
-        settings.__validate(value, str)
+        self.__vtor.check_type(value, str)
         
         self.__first_name = value.strip()
 
@@ -76,7 +84,8 @@ class settings:
             ValueError: Некорректная длина аргумента
         """
 
-        settings.__validate(value, int, 12)
+        self.__vtor.check_type(value, int)
+        self.__vtor.check_length(value, 12)
 
         self.__tax_id = value
     
@@ -97,6 +106,8 @@ class settings:
         """
 
         settings.__validate(value, int, 9)
+        self.__vtor.check_type(value, int)
+        self.__vtor.check_length(value, 9)
 
         self.__bank_id = value
 
@@ -117,7 +128,8 @@ class settings:
             ValueError: Некорректная длина аргумента
         """
 
-        settings.__validate(value, int, 11)
+        self.__vtor.check_type(value, int)
+        self.__vtor.check_length(value, 11)
 
         self.__bank_account_id = value
         
@@ -138,7 +150,8 @@ class settings:
             ValueError: Некорректная длина аргумента
         """
 
-        settings.__validate(value, int, 11)
+        self.__vtor.check_type(value, int)
+        self.__vtor.check_length(value, 11)
 
         self.__corresp_account_id = value
 
@@ -158,7 +171,7 @@ class settings:
             TypeError: Некорректный тип аргумента
         """
 
-        settings.__validate(value, str) 
+        self.__vtor.check_type(value, str)
 
         self.__property_name = value
 
@@ -179,6 +192,7 @@ class settings:
             ValueError: Некорректная длина аргумента
         """
 
-        settings.__validate(value, str, 5)
+        self.__vtor.check_type(value, str)
+        self.__vtor.check_length(value, 5)
 
-        self.__property_type = value
+        self.__property_type = value

+ 126 - 0
src/settings_validator.py

@@ -0,0 +1,126 @@
+import re
+
+class settings_validator:
+    def check_type(self, value, exp_type):
+        """
+            Валидация аргумента по типу
+        Args:
+            value (any): Передаваемый аргумент
+            type(Type): Ожидаемый тип
+        Raises:
+            TypeError: Некорректный тип аргумента
+        """
+
+        if not isinstance(value, exp_type):
+            raise TypeError(f"Некорректный тип аргумента ({type(value)}, expected {exp_type})")
+
+        return True
+
+    def check_length(self, value, length: int):
+        """
+            Валидация аргумента по длине
+        Args:
+            value (any): Передаваемый аргумент
+            length (int): Ожидаемая длина
+        Raises:
+            ValueError: Несоответствующая длина аргумента
+        """
+
+        if isinstance(value, int):
+            value = str(value)
+
+        if len(value) != length:
+            raise ValueError(f"Несоответствующая длина аргумента ({len(value)}, expected {length})")
+
+        return True
+
+    def check_length_less(self, value, length: int, inclusive=True):
+        """
+            Валидация аргумента по максимальной длине
+        Args:
+            value (any): Передаваемый аргумент
+            length (int): Максимальная допустимая длина
+            inclusive (bool): Сравнивать включительно? default=True
+        Raises:
+            ValueError: Превышена длина аргумента
+        """
+
+        if value is int:
+            value = str(value)
+        
+        if (len(value) > length if inclusive \
+                else len(value) >= length):
+                    raise ValueError(f"Превышена длина аргумента ({len(value)}, max={length})")
+
+        return True
+
+    def check_length_greater(self, value, length: int, inclusive=True):
+        """
+            Валидация аргумента по минимальной длине
+        Args:
+            value (any): Передаваемый аргумент
+            length (int): Максимальная допустимая длина
+            inclusive (bool): Сравнивать включительно? default=True
+        Raises:
+            ValueError: Недостаточная длина аргумента
+        """
+
+        if value is int:
+            value = str(value)
+
+        if (len(value) < length if inclusive \
+                else len(value) <= length):
+            raise ValueError("Недостаточная длина аргумента ({len(value)}, min={length})")
+
+        return True
+
+    def check_length_bound(self, value, min_length: int, max_length: int, inclusive_min=True, inclusive_max=True):
+        """
+            Валидация аргумента по минимальной и максимальной длинам
+        Args:
+            value (any): Передаваемый аргумент
+            min_length (int): Минимальная длина
+            max_length (int): Максимальная длина
+            inclusive_min (bool): Сравнимать минимальную длину включительно? default=True
+            inclusive_max (bool): Сравнивать максимальную длину включительно? default=True
+        Raises:
+            ValueError: Недостаточная длина аргумента
+            ValueError: Превышена длина аргумента
+        """
+
+        self.check_length_less(value, max_length, inclusive_max)
+        self.check_length_greater(value, min_length, inclusive_min)
+
+        return True
+
+    def check_type_length(self, value, exp_type, length: int):
+        """
+            Валидация аргумента по типу и длине
+        Args:
+            value (any): Передаваемый аргумент
+            exp_type (Type): Ожидаемый тип
+            length (int): Ожидаемая длина
+        Raises:
+            TypeError: Несоответствие типа аргумента
+            ValueError: Несоответствие длины аргумента
+        """
+
+        self.check_type(value, exp_type)
+        self.check_length(value, length)
+
+        return True
+
+    def check_regex(self, value, expression: str):
+        """
+            Валидация аргумента по регулярному выражению
+        Args:
+            value (any): Передаваемый аргумент
+            expression (str): Регулярное выражение
+        Raises:
+            ValueError: Аргумент не соответствует регулярному выражению
+        """
+
+        if re.match(expression, value) is None:
+            raise ValueError(f"Аргумент не соответствует регулярному выражению ({str(value)}, regex: {expression})")
+
+        return True

+ 82 - 26
tests/test_settings.py

@@ -1,5 +1,6 @@
 from src.settings import settings
 from src.settings_manager import settings_manager
+from src.settings_validator import settings_validator
 import unittest, os, random
     
 
@@ -7,10 +8,8 @@ class test_settings(unittest.TestCase):
     projdir = os.path.dirname(__file__) + "/.."
     
     
-    #
-    # Провеиить корректность заполнения поля first_name
-    #
-    def test_check_first_name(self):
+    def first_name_setter(self):
+        """Проверить корректность заполнения поля first_name"""
         # Подготовка
         item = settings()
         
@@ -20,10 +19,8 @@ class test_settings(unittest.TestCase):
         # Проверка
         assert item.first_name == "a"
 
-    #
-    # Проверить, что settings_manager инстанциируется только один раз
-    #
-    def test_check_settings_manager_singleton(self):
+    def settings_manager_singleton(self):
+        """Проверить, что settings_manager имплементирует singleton"""
         # Подготовка
         man1 = settings_manager()
         man2 = settings_manager()
@@ -33,11 +30,8 @@ class test_settings(unittest.TestCase):
         # Проверка
         assert man1 is man2
 
-    
-    #
-    # Проверить корректность загрузки настроек
-    #
-    def test_check_open_settings(self):
+    def open_settings(self):
+        """Проверить корректность загрузки настроек"""
         # Подготовка
         man = settings_manager()
         
@@ -47,11 +41,8 @@ class test_settings(unittest.TestCase):
         # Проверка
         assert result == True
 
-
-    # 
-    # Проверить, что все поля настроек не пусты
-    #
-    def test_check_settings_fields_nonempty(self):
+    def settings_fields_nonempty(self):
+        """Проверить, что все поля настроек не пусты после считывания настроек"""
         # Подготовка
         man = settings_manager()
         settings = None
@@ -64,13 +55,9 @@ class test_settings(unittest.TestCase):
         # Проверка
         for key in dict.keys():
             assert len(str(dict[key])) != 0
-
-    
-    #
-    #   Проверить, что менеджер настроек может открыть файл
-    #       с любым названием и в любой папке
-    #
-    def test_settings_any_filename(self):
+            
+    def settings_any_filename(self):
+        """Проверить, что менеджер настроек может открыть файл с любым названием и в любой папке"""
         # Подготовка
         if not os.path.exists(f"{self.projdir}/.test_data"):
             os.mkdir(f"{self.projdir}/.test_data")
@@ -96,4 +83,73 @@ class test_settings(unittest.TestCase):
 
         # Очистка
         os.remove(filename)
-        os.removedirs(dirname)
+        os.removedirs(dirname)
+
+
+    def settings_validator_typeguard(self):
+        """Проверить работоспособность settings_validation.check_type()"""
+        # Подготовка
+        validator = settings_validator()
+
+        # Действие
+
+        # Проверка
+        assert validator.check_type("", str)
+        self.assertRaises(TypeError, lambda: validator.check_type("", int))
+
+    def settings_validator_len_exact(self):
+        """Проверить работоспособность settings_validator.check_length()"""
+        # Подготовка
+        validator = settings_validator()
+
+        # Действие
+
+        # Проверка
+        assert validator.check_length("aa", 2)
+        self.assertRaises(ValueError, lambda: validator.check_length("aa", 1))
+        self.assertRaises(ValueError, lambda: validator.check_length("aa", 3))
+
+    def settings_validator_len_int(self):
+        """Проверить работоспособность settings_validator.check_length() при передаче int"""
+        # Подготовка
+        validator = settings_validator()
+
+        # Действие
+
+        # Проверка
+        assert validator.check_length(10, 2)
+        self.assertRaises(ValueError, lambda: validator.check_length(10, 1))
+        self.assertRaises(ValueError, lambda: validator.check_length(10, 3))
+
+    def settings_validator_len_bound(self):
+        """Проверить работоспособность settings_validator.check_length_bound()"""
+        # Подготовка
+        validator = settings_validator()
+
+        # Действие
+
+        # Проверка
+
+        # Вхождение в минимум
+        assert validator.check_length_bound("abc", 3, 10)
+        # Вхождение в максимум
+        assert validator.check_length_bound("abc", 1, 3)
+        # Невхождение в максимум
+        self.assertRaises(ValueError, lambda: validator.check_length_bound("abc", 1, 2))
+        # Невхождение в минимум
+        self.assertRaises(ValueError, lambda: validator.check_length_bound("abc", 4, 5))
+        # Невхождение в исключительный минимум
+        self.assertRaises(ValueError, lambda: validator.check_length_bound("abc", 3, 5, inclusive_min=False))
+        # Невхождение в исключительный максимум
+        self.assertRaises(ValueError, lambda: validator.check_length_bound("abc", 1, 3, inclusive_max=False))
+
+    def settings_validator_regex(self):
+        """Проверить работоспособность settings_validator.check_regex()"""
+        # Подготовка
+        validator = settings_validator()
+
+        # Действие
+
+        # Проверка
+        assert validator.check_regex("abc", ".*b[c]+")
+        self.assertRaises(ValueError, lambda: validator.check_regex("abc", ".*b[c]+[a]+"))