Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Empty file added praktikum/__init__.py
Empty file.
15 changes: 15 additions & 0 deletions praktikum/bun.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
class Bun:
"""
Модель булочки для бургера.
Булочке можно дать название и назначить цену.
"""

def __init__(self, name: str, price: float):
self.name = name
self.price = price

def get_name(self) -> str:
return self.name

def get_price(self) -> float:
return self.price
48 changes: 48 additions & 0 deletions praktikum/burger.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
from typing import List

from praktikum.bun import Bun
from praktikum.ingredient import Ingredient


class Burger:
"""
Модель бургера.
Бургер состоит из булочек и ингредиентов (начинка или соус).
Ингредиенты можно перемещать и удалять.
Можно распечать чек с информацией о бургере.
"""

def __init__(self):
self.bun = None
self.ingredients: List[Ingredient] = []

def set_buns(self, bun: Bun):
self.bun = bun

def add_ingredient(self, ingredient: Ingredient):
self.ingredients.append(ingredient)

def remove_ingredient(self, index: int):
del self.ingredients[index]

def move_ingredient(self, index: int, new_index: int):
self.ingredients.insert(new_index, self.ingredients.pop(index))

def get_price(self) -> float:
price = self.bun.get_price() * 2

for ingredient in self.ingredients:
price += ingredient.get_price()

return price

def get_receipt(self) -> str:
receipt: List[str] = [f'(==== {self.bun.get_name()} ====)']

for ingredient in self.ingredients:
receipt.append(f'= {str(ingredient.get_type()).lower()} {ingredient.get_name()} =')

receipt.append(f'(==== {self.bun.get_name()} ====)\n')
receipt.append(f'Price: {self.get_price()}')

return '\n'.join(receipt)
33 changes: 33 additions & 0 deletions praktikum/database.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
from typing import List

from praktikum.bun import Bun
from praktikum.ingredient import Ingredient
from praktikum.ingredient_types import INGREDIENT_TYPE_SAUCE, INGREDIENT_TYPE_FILLING


class Database:
"""
Класс с методами по работе с базой данных.
"""

def __init__(self):
self.buns: List[Bun] = []
self.ingredients: List[Ingredient] = []

self.buns.append(Bun("black bun", 100))
self.buns.append(Bun("white bun", 200))
self.buns.append(Bun("red bun", 300))

self.ingredients.append(Ingredient(INGREDIENT_TYPE_SAUCE, "hot sauce", 100))
self.ingredients.append(Ingredient(INGREDIENT_TYPE_SAUCE, "sour cream", 200))
self.ingredients.append(Ingredient(INGREDIENT_TYPE_SAUCE, "chili sauce", 300))

self.ingredients.append(Ingredient(INGREDIENT_TYPE_FILLING, "cutlet", 100))
self.ingredients.append(Ingredient(INGREDIENT_TYPE_FILLING, "dinosaur", 200))
self.ingredients.append(Ingredient(INGREDIENT_TYPE_FILLING, "sausage", 300))

def available_buns(self) -> List[Bun]:
return self.buns

def available_ingredients(self) -> List[Ingredient]:
return self.ingredients
20 changes: 20 additions & 0 deletions praktikum/ingredient.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
class Ingredient:
"""
Модель ингредиента.
Ингредиент: начинка или соус.
У ингредиента есть тип (начинка или соус), название и цена.
"""

def __init__(self, ingredient_type: str, name: str, price: float):
self.type = ingredient_type
self.name = name
self.price = price

def get_price(self) -> float:
return self.price

def get_name(self) -> str:
return self.name

def get_type(self) -> str:
return self.type
7 changes: 7 additions & 0 deletions praktikum/ingredient_types.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
"""
Перечисление с типами ингредиентов.
SAUCE – соус
FILLING – начинка
"""
INGREDIENT_TYPE_SAUCE = 'SAUCE'
INGREDIENT_TYPE_FILLING = 'FILLING'
41 changes: 41 additions & 0 deletions praktikum/praktikum.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
from typing import List

from praktikum.bun import Bun
from praktikum.burger import Burger
from praktikum.database import Database
from praktikum.ingredient import Ingredient


def main():
# Инициализируем базу данных
database: Database = Database()

# Создадим новый бургер
burger: Burger = Burger()

# Считаем список доступных булок из базы данных
buns: List[Bun] = database.available_buns()

# Считаем список доступных ингредиентов из базы данных
ingredients: List[Ingredient] = database.available_ingredients()

# Соберём бургер
burger.set_buns(buns[0])

burger.add_ingredient(ingredients[1])
burger.add_ingredient(ingredients[4])
burger.add_ingredient(ingredients[3])
burger.add_ingredient(ingredients[5])

# Переместим слой с ингредиентом
burger.move_ingredient(2, 1)

# Удалим ингредиент
burger.remove_ingredient(3)

# Распечатаем рецепт бургера
print(burger.get_receipt())


if __name__ == "__main__":
main()
3 changes: 3 additions & 0 deletions requirements.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
pytest==7.4.3
pytest-cov==7.0.0
allure-pytest==2.13.2
Empty file added tests/__init__.py
Empty file.
131 changes: 131 additions & 0 deletions tests/burger_test.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,131 @@
import pytest
import sys
from pathlib import Path

sys.path.insert(0, str(Path(__file__).parent))
sys.path.insert(0, str(Path(__file__).parent.parent))

from helpers import (
create_mock_ingredient,
create_mock_bun,
add_multiple_ingredients_to_burger,
calculate_burger_price,
create_ingredients_list
)
from praktikum.ingredient_types import INGREDIENT_TYPE_SAUCE, INGREDIENT_TYPE_FILLING


class TestBurger:

def test_set_bun_success(self, burger, white_bun):
burger.set_buns(white_bun)
assert burger.bun == white_bun

def test_set_bun_replace_existing(self, burger, white_bun, black_bun):
burger.set_buns(white_bun)
burger.set_buns(black_bun)
assert burger.bun == black_bun

def test_add_ingredient_one(self, burger, sauce_ingredient):
burger.add_ingredient(sauce_ingredient)
assert len(burger.ingredients) == 1

def test_add_ingredient_first_element(self, burger, sauce_ingredient):
burger.add_ingredient(sauce_ingredient)
assert burger.ingredients[0] == sauce_ingredient

def test_add_ingredient_multiple(self, burger, ingredient_count):
ingredients = create_ingredients_list(ingredient_count, INGREDIENT_TYPE_SAUCE, 50.0)
burger = add_multiple_ingredients_to_burger(burger, ingredients)
assert len(burger.ingredients) == ingredient_count

def test_add_ingredient_keeps_order_first(self, burger, sauce_ingredient, filling_ingredient):
burger.add_ingredient(sauce_ingredient)
burger.add_ingredient(filling_ingredient)
assert burger.ingredients[0] == sauce_ingredient

def test_add_ingredient_keeps_order_second(self, burger, sauce_ingredient, filling_ingredient):
burger.add_ingredient(sauce_ingredient)
burger.add_ingredient(filling_ingredient)
assert burger.ingredients[1] == filling_ingredient


def test_remove_ingredient_decreases_count(self, burger):
ing1 = create_mock_ingredient("First", INGREDIENT_TYPE_SAUCE, 50.0)
ing2 = create_mock_ingredient("Second", INGREDIENT_TYPE_FILLING, 100.0)
burger = add_multiple_ingredients_to_burger(burger, [ing1, ing2])
burger.remove_ingredient(0)
assert len(burger.ingredients) == 1

def test_remove_ingredient_first_leaves_second(self, burger):
ing1 = create_mock_ingredient("First", INGREDIENT_TYPE_SAUCE, 50.0)
ing2 = create_mock_ingredient("Second", INGREDIENT_TYPE_FILLING, 100.0)
burger = add_multiple_ingredients_to_burger(burger, [ing1, ing2])
burger.remove_ingredient(0)
assert burger.ingredients[0] == ing2

def test_remove_ingredient_middle(self, burger):
ing1 = create_mock_ingredient("First", INGREDIENT_TYPE_SAUCE, 50.0)
ing2 = create_mock_ingredient("Middle", INGREDIENT_TYPE_FILLING, 100.0)
ing3 = create_mock_ingredient("Last", INGREDIENT_TYPE_SAUCE, 75.0)
burger = add_multiple_ingredients_to_burger(burger, [ing1, ing2, ing3])
burger.remove_ingredient(1)
assert burger.ingredients[1] == ing3

def test_remove_ingredient_at_index(self, burger):
ingredients = create_ingredients_list(3, INGREDIENT_TYPE_SAUCE, 50.0)
burger = add_multiple_ingredients_to_burger(burger, ingredients)
burger.remove_ingredient(0)
assert len(burger.ingredients) == 2

def test_move_ingredient_forward(self, burger):
ing1 = create_mock_ingredient("First", INGREDIENT_TYPE_SAUCE, 50.0)
ing2 = create_mock_ingredient("Second", INGREDIENT_TYPE_FILLING, 100.0)
ing3 = create_mock_ingredient("Third", INGREDIENT_TYPE_SAUCE, 75.0)
burger = add_multiple_ingredients_to_burger(burger, [ing1, ing2, ing3])
burger.move_ingredient(0, 2)
assert burger.ingredients[2] == ing1

def test_move_ingredient_changes_first_position(self, burger):
ing1 = create_mock_ingredient("First", INGREDIENT_TYPE_SAUCE, 50.0)
ing2 = create_mock_ingredient("Second", INGREDIENT_TYPE_FILLING, 100.0)
ing3 = create_mock_ingredient("Third", INGREDIENT_TYPE_SAUCE, 75.0)
burger = add_multiple_ingredients_to_burger(burger, [ing1, ing2, ing3])
burger.move_ingredient(0, 2)
assert burger.ingredients[0] == ing2

def test_move_ingredient_backward(self, burger):
ing1 = create_mock_ingredient("First", INGREDIENT_TYPE_SAUCE, 50.0)
ing2 = create_mock_ingredient("Second", INGREDIENT_TYPE_FILLING, 100.0)
ing3 = create_mock_ingredient("Third", INGREDIENT_TYPE_SAUCE, 75.0)
burger = add_multiple_ingredients_to_burger(burger, [ing1, ing2, ing3])
burger.move_ingredient(2, 0)
assert burger.ingredients[0] == ing3

def test_move_ingredient_preserves_count(self, burger):

ingredients = create_ingredients_list(3, INGREDIENT_TYPE_SAUCE, 50.0)
burger = add_multiple_ingredients_to_burger(burger, ingredients)
burger.move_ingredient(0, 2)
assert len(burger.ingredients) == 3


@pytest.mark.parametrize("bun_price,ingredient_prices,expected_price", [
(100.0, [50.0], 250.0),
(150.0, [50.0, 75.0], 425.0),
(200.0, [100.0, 100.0, 100.0], 700.0),
])
def test_price_calculation(self, burger, bun_price, ingredient_prices, expected_price):
calculated_price = calculate_burger_price(bun_price, ingredient_prices)
assert calculated_price == expected_price


@pytest.mark.parametrize("from_pos,to_pos", [
(0, 1), (1, 0), (0, 2), (2, 0)
])
def test_move_ingredient_parametrized(self, burger, from_pos, to_pos):
ingredients = create_ingredients_list(3, INGREDIENT_TYPE_SAUCE, 50.0)
burger = add_multiple_ingredients_to_burger(burger, ingredients)
original_ingredient = burger.ingredients[from_pos]
burger.move_ingredient(from_pos, to_pos)
assert burger.ingredients[to_pos] == original_ingredient
34 changes: 34 additions & 0 deletions tests/conftest.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
import pytest
import sys
from pathlib import Path

sys.path.insert(0, str(Path(__file__).parent))
sys.path.insert(0, str(Path(__file__).parent.parent))

from helpers import create_mock_ingredient, create_mock_bun
from praktikum.burger import Burger
from praktikum.ingredient_types import INGREDIENT_TYPE_SAUCE, INGREDIENT_TYPE_FILLING

@pytest.fixture
def burger():
return Burger()

@pytest.fixture
def white_bun():
return create_mock_bun("White Bun", 100.0)

@pytest.fixture
def black_bun():
return create_mock_bun("Black Bun", 150.0)

@pytest.fixture
def sauce_ingredient():
return create_mock_ingredient("spicy sauce", INGREDIENT_TYPE_SAUCE, 90.0)

@pytest.fixture
def filling_ingredient():
return create_mock_ingredient("Cutlet", INGREDIENT_TYPE_FILLING, 100.0)

@pytest.fixture(params=[1, 3, 5, 10])
def ingredient_count(request):
return request.param
52 changes: 52 additions & 0 deletions tests/helpers.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
from unittest.mock import Mock
from praktikum.ingredient_types import INGREDIENT_TYPE_SAUCE, INGREDIENT_TYPE_FILLING


def create_mock_ingredient(name: str, ingredient_type: str, price: float) -> Mock:
ingredient = Mock()
ingredient.get_name = Mock(return_value=name)
ingredient.get_type = Mock(return_value=ingredient_type)
ingredient.get_price = Mock(return_value=price)
return ingredient


def create_mock_bun(name: str, price: float) -> Mock:
bun = Mock()
bun.get_name = Mock(return_value=name)
bun.get_price = Mock(return_value=price)
return bun


def setup_burger_with_bun_and_ingredients(burger, bun, *ingredients):
burger.set_buns(bun)
for ingredient in ingredients:
burger.add_ingredient(ingredient)
return burger


def add_multiple_ingredients_to_burger(burger, ingredient_list):
for ingredient in ingredient_list:
burger.add_ingredient(ingredient)
return burger


def calculate_burger_price(bun_price: float, ingredient_prices: list) -> float:
return (bun_price * 2) + sum(ingredient_prices)


def extract_price_from_receipt(receipt: str) -> float:
price_line = [line for line in receipt.split('\n') if line.startswith('Price:')]
if price_line:
return float(price_line[0].replace('Price: ', ''))
return 0.0


def verify_ingredients_in_receipt(receipt: str, ingredient_names: list) -> bool:
return all(name in receipt for name in ingredient_names)


def create_ingredients_list(count: int, ingredient_type: str, price: float) -> list:
return [
create_mock_ingredient(f"Ingredient_{i}", ingredient_type, price)
for i in range(count)
]