Files

170 lines
5.8 KiB
Python

from __future__ import annotations
import json
from pathlib import Path
import pytest
from standard_products.db import (
Product,
add_product,
connect,
count_products,
delete_product,
export_json,
get_product,
import_json,
init_db,
list_products,
search_products,
update_product,
upsert_product,
)
@pytest.fixture()
def connection(tmp_path: Path):
db_path = init_db(tmp_path / "catalog.db")
with connect(db_path) as conn:
yield conn
def make_product(**overrides: object) -> Product:
data: dict[str, object] = {
"designation": "Болт M10x50 ГОСТ 7798-70",
"name": "Болт с шестигранной головкой",
"standard": "ГОСТ 7798-70",
"category": "Крепёж",
"material": "Сталь 20",
"mass_kg": 0.045,
"attributes": {"резьба": "M10", "покрытие": "цинк"},
}
data.update(overrides)
return Product(**data) # type: ignore[arg-type]
def test_init_db_creates_file(tmp_path: Path) -> None:
db_path = init_db(tmp_path / "nested" / "catalog.db")
assert db_path.exists()
with connect(db_path) as conn:
assert count_products(conn) == 0
def test_add_and_get_product(connection) -> None:
product_id = add_product(connection, make_product())
assert product_id > 0
stored = get_product(connection, "Болт M10x50 ГОСТ 7798-70")
assert stored is not None
assert stored.name == "Болт с шестигранной головкой"
assert stored.attributes == {"резьба": "M10", "покрытие": "цинк"}
assert stored.mass_kg == pytest.approx(0.045)
def test_duplicate_designation_is_rejected(connection) -> None:
add_product(connection, make_product())
with pytest.raises(ValueError, match="уже существует"):
add_product(connection, make_product(name="Другой болт"))
def test_upsert_updates_existing_row(connection) -> None:
product_id = add_product(connection, make_product())
updated_id = upsert_product(connection, make_product(name="Болт обновлённый"))
assert updated_id == product_id
stored = get_product(connection, "Болт M10x50 ГОСТ 7798-70")
assert stored is not None
assert stored.name == "Болт обновлённый"
assert count_products(connection) == 1
def test_validation(connection) -> None:
with pytest.raises(ValueError, match="designation"):
add_product(connection, make_product(designation=" "))
with pytest.raises(ValueError, match="name"):
add_product(connection, make_product(name=""))
with pytest.raises(ValueError, match="mass_kg"):
add_product(connection, make_product(mass_kg=-1))
def test_search_by_query_and_filters(connection) -> None:
add_product(connection, make_product())
add_product(
connection,
make_product(
designation="Гайка M10 ГОСТ 5915-70",
name="Гайка шестигранная",
standard="ГОСТ 5915-70",
material="Сталь 10",
attributes={},
),
)
by_text = search_products(connection, "гайка")
assert [p.designation for p in by_text] == ["Гайка M10 ГОСТ 5915-70"]
by_attribute = search_products(connection, "цинк")
assert [p.designation for p in by_attribute] == ["Болт M10x50 ГОСТ 7798-70"]
by_standard = search_products(connection, standard="ГОСТ 5915-70")
assert len(by_standard) == 1
by_category = search_products(connection, category="Крепёж", limit=1)
assert len(by_category) == 1
def test_update_product(connection) -> None:
add_product(connection, make_product())
assert update_product(connection, "Болт M10x50 ГОСТ 7798-70", material="Сталь 35")
stored = get_product(connection, "Болт M10x50 ГОСТ 7798-70")
assert stored is not None
assert stored.material == "Сталь 35"
assert update_product(connection, "нет такого", name="x") is False
def test_update_rejects_unknown_fields(connection) -> None:
add_product(connection, make_product())
with pytest.raises(ValueError, match="Неизвестные поля"):
update_product(connection, "Болт M10x50 ГОСТ 7798-70", diameter=10)
def test_delete_product(connection) -> None:
add_product(connection, make_product())
assert delete_product(connection, "Болт M10x50 ГОСТ 7798-70") is True
assert delete_product(connection, "Болт M10x50 ГОСТ 7798-70") is False
assert count_products(connection) == 0
def test_list_with_limit(connection) -> None:
for index in range(3):
add_product(connection, make_product(designation=f"Изделие-{index}"))
assert len(list_products(connection, limit=2)) == 2
assert len(list_products(connection)) == 3
def test_import_export_roundtrip(connection, tmp_path: Path) -> None:
add_product(connection, make_product())
add_product(connection, make_product(designation="Шайба 10 ГОСТ 11371-78", name="Шайба"))
exported_path = tmp_path / "export.json"
assert export_json(connection, exported_path) == 2
payload = json.loads(exported_path.read_text(encoding="utf-8"))
assert len(payload["products"]) == 2
init_db(tmp_path / "other.db")
with connect(tmp_path / "other.db") as other:
assert import_json(other, exported_path) == 2
assert count_products(other) == 2
assert get_product(other, "Шайба 10 ГОСТ 11371-78") is not None
def test_import_accepts_inline_list(connection) -> None:
imported = import_json(
connection,
[{"designation": "Подшипник 6205", "name": "Подшипник шариковый"}],
)
assert imported == 1
assert count_products(connection) == 1