diff --git a/.DS_Store b/.DS_Store new file mode 100644 index 000000000..0b9a44bd2 Binary files /dev/null and b/.DS_Store differ diff --git a/.coverage b/.coverage new file mode 100644 index 000000000..576a7b9c2 Binary files /dev/null and b/.coverage differ diff --git a/__pycache__/__init__.cpython-313.pyc b/__pycache__/__init__.cpython-313.pyc new file mode 100644 index 000000000..fa47d1ce3 Binary files /dev/null and b/__pycache__/__init__.cpython-313.pyc differ diff --git a/__init__.py b/praktikum/__init__.py similarity index 100% rename from __init__.py rename to praktikum/__init__.py diff --git a/praktikum/__pycache__/__init__.cpython-313.pyc b/praktikum/__pycache__/__init__.cpython-313.pyc new file mode 100644 index 000000000..6c0fba2f3 Binary files /dev/null and b/praktikum/__pycache__/__init__.cpython-313.pyc differ diff --git a/praktikum/__pycache__/bun.cpython-313.pyc b/praktikum/__pycache__/bun.cpython-313.pyc new file mode 100644 index 000000000..089e77f25 Binary files /dev/null and b/praktikum/__pycache__/bun.cpython-313.pyc differ diff --git a/praktikum/__pycache__/burger.cpython-313.pyc b/praktikum/__pycache__/burger.cpython-313.pyc new file mode 100644 index 000000000..2a5a65f8c Binary files /dev/null and b/praktikum/__pycache__/burger.cpython-313.pyc differ diff --git a/praktikum/__pycache__/database.cpython-313.pyc b/praktikum/__pycache__/database.cpython-313.pyc new file mode 100644 index 000000000..206bc519c Binary files /dev/null and b/praktikum/__pycache__/database.cpython-313.pyc differ diff --git a/praktikum/__pycache__/ingredient.cpython-313.pyc b/praktikum/__pycache__/ingredient.cpython-313.pyc new file mode 100644 index 000000000..6997f619d Binary files /dev/null and b/praktikum/__pycache__/ingredient.cpython-313.pyc differ diff --git a/praktikum/__pycache__/ingredient_types.cpython-313.pyc b/praktikum/__pycache__/ingredient_types.cpython-313.pyc new file mode 100644 index 000000000..5421e92c7 Binary files /dev/null and b/praktikum/__pycache__/ingredient_types.cpython-313.pyc differ diff --git a/bun.py b/praktikum/bun.py similarity index 100% rename from bun.py rename to praktikum/bun.py diff --git a/burger.py b/praktikum/burger.py similarity index 100% rename from burger.py rename to praktikum/burger.py diff --git a/database.py b/praktikum/database.py similarity index 100% rename from database.py rename to praktikum/database.py diff --git a/ingredient.py b/praktikum/ingredient.py similarity index 100% rename from ingredient.py rename to praktikum/ingredient.py diff --git a/ingredient_types.py b/praktikum/ingredient_types.py similarity index 100% rename from ingredient_types.py rename to praktikum/ingredient_types.py diff --git a/praktikum.py b/praktikum/praktikum.py similarity index 100% rename from praktikum.py rename to praktikum/praktikum.py diff --git a/requirements.txt b/requirements.txt new file mode 100644 index 000000000..0983bfd90 --- /dev/null +++ b/requirements.txt @@ -0,0 +1,35 @@ +allure-pytest==2.15.3 +allure-python-commons==2.15.3 +attrs==25.4.0 +certifi==2025.11.12 +charset-normalizer==3.4.4 +coverage==7.10.7 +execnet==2.1.2 +h11==0.16.0 +idna==3.11 +iniconfig==2.1.0 +Jinja2==3.1.6 +MarkupSafe==3.0.3 +outcome==1.3.0.post0 +packaging==25.0 +pluggy==1.6.0 +Pygments==2.19.2 +PySocks==1.7.1 +pytest==8.4.1 +pytest-cov==7.0.0 +pytest-html==4.1.1 +pytest-metadata==3.1.1 +pytest-xdist==3.8.0 +python-dotenv==1.2.1 +python-mock==0.0.3 +requests==2.32.5 +selenium==4.39.0 +sniffio==1.3.1 +sortedcontainers==2.4.0 +trio==0.32.0 +trio-websocket==0.12.2 +typing_extensions==4.15.0 +urllib3==2.6.1 +webdriver-manager==4.0.2 +websocket-client==1.9.0 +wsproto==1.3.2 diff --git a/tests/__init__.py b/tests/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/tests/__pycache__/__init__.cpython-313.pyc b/tests/__pycache__/__init__.cpython-313.pyc new file mode 100644 index 000000000..16d43006a Binary files /dev/null and b/tests/__pycache__/__init__.cpython-313.pyc differ diff --git a/tests/__pycache__/test_bun.cpython-313-pytest-8.4.1.pyc b/tests/__pycache__/test_bun.cpython-313-pytest-8.4.1.pyc new file mode 100644 index 000000000..60743242b Binary files /dev/null and b/tests/__pycache__/test_bun.cpython-313-pytest-8.4.1.pyc differ diff --git a/tests/__pycache__/test_burger.cpython-313-pytest-8.4.1.pyc b/tests/__pycache__/test_burger.cpython-313-pytest-8.4.1.pyc new file mode 100644 index 000000000..3bc0f8970 Binary files /dev/null and b/tests/__pycache__/test_burger.cpython-313-pytest-8.4.1.pyc differ diff --git a/tests/__pycache__/test_database.cpython-313-pytest-8.4.1.pyc b/tests/__pycache__/test_database.cpython-313-pytest-8.4.1.pyc new file mode 100644 index 000000000..ab2f5b80f Binary files /dev/null and b/tests/__pycache__/test_database.cpython-313-pytest-8.4.1.pyc differ diff --git a/tests/__pycache__/test_ingredient.cpython-313-pytest-8.4.1.pyc b/tests/__pycache__/test_ingredient.cpython-313-pytest-8.4.1.pyc new file mode 100644 index 000000000..04df9e6b2 Binary files /dev/null and b/tests/__pycache__/test_ingredient.cpython-313-pytest-8.4.1.pyc differ diff --git a/tests/test_bun.py b/tests/test_bun.py new file mode 100644 index 000000000..d2d4569ac --- /dev/null +++ b/tests/test_bun.py @@ -0,0 +1,43 @@ +import pytest +from praktikum.bun import Bun + +class TestBun: + + @pytest.mark.parametrize("name, price", [ + ("black bun", 100), + ("white bun", 200), + ("red bun", 300), + ("", 0), + ("Very long bun name with many characters", 999.99) + ]) + def test_bun_initialization(self, name, price): + #Проверка инициализации булочки с разными параметрами + bun = Bun(name, price) + assert bun.get_name() == name + assert bun.get_price() == price + + def test_bun_name_getter(self): + #Проверка получения имени булочки + bun = Bun("test bun", 150) + assert bun.get_name() == "test bun" + + def test_bun_price_getter(self): + #Проверка получения цены булочки + bun = Bun("test bun", 150) + assert bun.get_price() == 150 + + @pytest.mark.parametrize("name, price", [ + (None, 100), + (123, 100), + ("bun", None), + ("bun", "100"), + (None, None), + (123, "456") + ]) + def test_bun_accepts_any_types(self, name, price): + #Проверка, что класс принимает любые типы данных + bun = Bun(name, price) + + assert bun is not None + assert bun.get_name() == name + assert bun.get_price() == price \ No newline at end of file diff --git a/tests/test_burger.py b/tests/test_burger.py new file mode 100644 index 000000000..c54e85dd4 --- /dev/null +++ b/tests/test_burger.py @@ -0,0 +1,112 @@ +import pytest +from unittest.mock import Mock, patch +from praktikum.burger import Burger +from praktikum.burger import Burger +from praktikum.bun import Bun +from praktikum.ingredient import Ingredient +from praktikum.ingredient_types import INGREDIENT_TYPE_SAUCE, INGREDIENT_TYPE_FILLING + +class TestBurger: + + def setup_method(self): + #Подготовка данных перед каждым тестом + self.burger = Burger() + self.mock_bun = Mock(spec=Bun) + self.mock_bun.get_name.return_value = "mock bun" + self.mock_bun.get_price.return_value = 100 + + self.mock_sauce = Mock(spec=Ingredient) + self.mock_sauce.get_type.return_value = INGREDIENT_TYPE_SAUCE + self.mock_sauce.get_name.return_value = "mock sauce" + self.mock_sauce.get_price.return_value = 50 + + self.mock_filling = Mock(spec=Ingredient) + self.mock_filling.get_type.return_value = INGREDIENT_TYPE_FILLING + self.mock_filling.get_name.return_value = "mock filling" + self.mock_filling.get_price.return_value = 75 + + def test_burger_initialization(self): + #Проверка инициализации пустого бургера + assert self.burger.bun is None + assert len(self.burger.ingredients) == 0 + + def test_set_buns(self): + #Проверка установки булочек + self.burger.set_buns(self.mock_bun) + assert self.burger.bun == self.mock_bun + + def test_add_ingredient(self): + #Проверка добавления ингредиента + self.burger.add_ingredient(self.mock_sauce) + assert len(self.burger.ingredients) == 1 + assert self.burger.ingredients[0] == self.mock_sauce + + def test_remove_ingredient(self): + #Проверка удаления ингредиента + self.burger.add_ingredient(self.mock_sauce) + self.burger.add_ingredient(self.mock_filling) + self.burger.remove_ingredient(0) + + assert len(self.burger.ingredients) == 1 + assert self.burger.ingredients[0] == self.mock_filling + + def test_move_ingredient(self): + #Проверка перемещения ингредиента + self.burger.add_ingredient(self.mock_sauce) + self.burger.add_ingredient(self.mock_filling) + self.burger.move_ingredient(1, 0) + + assert self.burger.ingredients[0] == self.mock_filling + assert self.burger.ingredients[1] == self.mock_sauce + + def test_get_price_with_bun_only(self): + #Проверка расчета цены только с булочкой + self.burger.set_buns(self.mock_bun) + expected_price = self.mock_bun.get_price() * 2 + + assert self.burger.get_price() == expected_price + + def test_get_price_with_ingredients(self): + #Проверка расчета цены с ингредиентами + self.burger.set_buns(self.mock_bun) + self.burger.add_ingredient(self.mock_sauce) + self.burger.add_ingredient(self.mock_filling) + + expected_price = (self.mock_bun.get_price() * 2 + + self.mock_sauce.get_price() + + self.mock_filling.get_price()) + + assert self.burger.get_price() == expected_price + + def test_get_receipt_with_bun_only(self): + #Проверка формирования чека только с булочкой + self.burger.set_buns(self.mock_bun) + + receipt = self.burger.get_receipt() + expected_lines = [ + f"(==== {self.mock_bun.get_name()} ====)", + f"(==== {self.mock_bun.get_name()} ====)", + "", + f"Price: {self.burger.get_price()}" + ] + + assert receipt == "\n".join(expected_lines) + + def test_get_receipt_with_ingredients(self): + #Проверка формирования чека с ингредиентами + self.burger.set_buns(self.mock_bun) + self.burger.add_ingredient(self.mock_sauce) + self.burger.add_ingredient(self.mock_filling) + + receipt = self.burger.get_receipt() + + receipt_lines = [line for line in receipt.split('\n') if line != ""] + expected_order = [ + f"(==== {self.mock_bun.get_name()} ====)", + f"= sauce {self.mock_sauce.get_name()} =", + f"= filling {self.mock_filling.get_name()} =", + f"(==== {self.mock_bun.get_name()} ====)", + f"Price: {self.burger.get_price()}" + ] + assert receipt_lines == expected_order + \ No newline at end of file diff --git a/tests/test_database.py b/tests/test_database.py new file mode 100644 index 000000000..35ed02b16 --- /dev/null +++ b/tests/test_database.py @@ -0,0 +1,80 @@ +import pytest +from unittest.mock import Mock, patch, MagicMock +from praktikum.database import Database +from praktikum.bun import Bun +from praktikum.ingredient import Ingredient +from praktikum.ingredient_types import INGREDIENT_TYPE_SAUCE, INGREDIENT_TYPE_FILLING + +class TestDatabase: + + def setup_method(self): + #Подготовка данных перед каждым тестом + self.db = Database() + + def test_database_initialization(self): + #Проверка инициализации базы данных + assert hasattr(self.db, 'buns') + assert hasattr(self.db, 'ingredients') + assert len(self.db.buns) > 0 + assert len(self.db.ingredients) > 0 + + def test_available_buns(self): + #Проверка получения списка булочек + buns = self.db.available_buns() + assert isinstance(buns, list) + assert len(buns) == len(self.db.buns) + for bun in buns: + assert isinstance(bun, Bun) + + def test_available_ingredients(self): + #Проверка получения списка ингредиентов + ingredients = self.db.available_ingredients() + assert isinstance(ingredients, list) + assert len(ingredients) == len(self.db.ingredients) + for ingredient in ingredients: + assert isinstance(ingredient, Ingredient) + + def test_available_ingredients_invalid_type(self): + #Проверка получения всех ингредиентов (метод не фильтрует по типу) + ingredients = self.db.available_ingredients() + + # Проверяем, что возвращаются все ингредиенты + assert isinstance(ingredients, list) + assert len(ingredients) == len(self.db.ingredients) + + # Проверяем, что среди ингредиентов есть и соусы, и начинки + has_sauce = False + has_filling = False + + for ingredient in ingredients: + if ingredient.get_type() == INGREDIENT_TYPE_SAUCE: + has_sauce = True + elif ingredient.get_type() == INGREDIENT_TYPE_FILLING: + has_filling = True + + assert has_sauce and has_filling + + @patch('praktikum.database.Database.available_buns') + def test_database_methods_callable(self, mock_available_buns): + #Проверка, что методы базы данных вызываются корректно + mock_available_buns.return_value = ["mock_bun1", "mock_bun2"] + + result = self.db.available_buns() + + mock_available_buns.assert_called_once() + assert result == ["mock_bun1", "mock_bun2"] + + def test_database_data_integrity(self): + #Проверка целостности данных в базе + # Проверяем булочки + for bun in self.db.buns: + assert isinstance(bun.get_name(), str) + assert isinstance(bun.get_price(), (int, float)) + assert bun.get_price() > 0 + + # Проверяем ингредиенты + for ingredient in self.db.ingredients: + assert ingredient.get_type() in [INGREDIENT_TYPE_SAUCE, INGREDIENT_TYPE_FILLING] + assert isinstance(ingredient.get_name(), str) + assert isinstance(ingredient.get_price(), (int, float)) + assert ingredient.get_price() > 0 \ No newline at end of file diff --git a/tests/test_ingredient.py b/tests/test_ingredient.py new file mode 100644 index 000000000..76ff76816 --- /dev/null +++ b/tests/test_ingredient.py @@ -0,0 +1,55 @@ +import pytest +from praktikum.ingredient import Ingredient +from praktikum.ingredient_types import INGREDIENT_TYPE_SAUCE, INGREDIENT_TYPE_FILLING + +class TestIngredient: + + @pytest.mark.parametrize("ingredient_type, name, price", [ + (INGREDIENT_TYPE_SAUCE, "hot sauce", 100), + (INGREDIENT_TYPE_FILLING, "cutlet", 200), + (INGREDIENT_TYPE_SAUCE, "", 0), + (INGREDIENT_TYPE_FILLING, "Very long ingredient name", 999.99) + ]) + def test_ingredient_initialization(self, ingredient_type, name, price): + #Проверка инициализации ингредиента с разными параметрами + ingredient = Ingredient(ingredient_type, name, price) + assert ingredient.get_type() == ingredient_type + assert ingredient.get_name() == name + assert ingredient.get_price() == price + + def test_ingredient_price_getter(self): + #Проверка получения цены ингредиента + ingredient = Ingredient(INGREDIENT_TYPE_SAUCE, "sauce", 150) + assert ingredient.get_price() == 150 + + def test_ingredient_name_getter(self): + #Проверка получения названия ингредиента + ingredient = Ingredient(INGREDIENT_TYPE_FILLING, "cutlet", 200) + assert ingredient.get_name() == "cutlet" + + def test_ingredient_type_getter(self): + #Проверка получения типа ингредиента + ingredient = Ingredient(INGREDIENT_TYPE_SAUCE, "sauce", 150) + assert ingredient.get_type() == INGREDIENT_TYPE_SAUCE + + @pytest.mark.parametrize("ingredient_type, name, price", [ + ("invalid_type", "sauce", 100), + (None, "sauce", 100), + (INGREDIENT_TYPE_SAUCE, None, 100), + (INGREDIENT_TYPE_SAUCE, "sauce", None), + (INGREDIENT_TYPE_SAUCE, "sauce", "100"), + (123, "sauce", 100), + (INGREDIENT_TYPE_SAUCE, 456, 100), + (INGREDIENT_TYPE_SAUCE, "sauce", "not a number") + ]) + def test_ingredient_accepts_any_types(self, ingredient_type, name, price): + #Проверка, что класс принимает любые типы данных + ingredient = Ingredient(ingredient_type, name, price) + + # Проверяем, что объект создался + assert ingredient is not None + + # Проверяем, что значения сохранились + assert ingredient.get_type() == ingredient_type + assert ingredient.get_name() == name + assert ingredient.get_price() == price \ No newline at end of file