109 lines
5 KiB
Python
109 lines
5 KiB
Python
|
|
"""Regression tests for KIN-126 — фильтр по дате выполнения задач.
|
|||
|
|
|
|||
|
|
Проверяет backend-поведение:
|
|||
|
|
1. Колонка completed_at добавляется в таблицу tasks при инициализации БД
|
|||
|
|
2. Новая задача имеет completed_at=None по умолчанию
|
|||
|
|
3. update_task(status='done') устанавливает completed_at как ISO-строку
|
|||
|
|
4. update_task(status='done') — completed_at является валидной ISO-строкой
|
|||
|
|
5. update_task(status='in_progress') не устанавливает completed_at
|
|||
|
|
6. update_task(status='cancelled') не устанавливает completed_at
|
|||
|
|
7. Обновление полей без смены статуса на done не трогает completed_at
|
|||
|
|
8. update_task(status='blocked') не устанавливает completed_at
|
|||
|
|
"""
|
|||
|
|
|
|||
|
|
import pytest
|
|||
|
|
from datetime import datetime
|
|||
|
|
from core.db import init_db
|
|||
|
|
from core import models
|
|||
|
|
|
|||
|
|
|
|||
|
|
@pytest.fixture
|
|||
|
|
def conn():
|
|||
|
|
"""Fresh in-memory DB for each test."""
|
|||
|
|
c = init_db(db_path=":memory:")
|
|||
|
|
yield c
|
|||
|
|
c.close()
|
|||
|
|
|
|||
|
|
|
|||
|
|
# ---------------------------------------------------------------------------
|
|||
|
|
# Schema
|
|||
|
|
# ---------------------------------------------------------------------------
|
|||
|
|
|
|||
|
|
def test_schema_tasks_has_completed_at_column(conn):
|
|||
|
|
"""KIN-126: таблица tasks содержит колонку completed_at после инициализации БД."""
|
|||
|
|
cols = {r[1] for r in conn.execute("PRAGMA table_info(tasks)").fetchall()}
|
|||
|
|
assert "completed_at" in cols, "KIN-126: колонка completed_at должна быть в таблице tasks"
|
|||
|
|
|
|||
|
|
|
|||
|
|
# ---------------------------------------------------------------------------
|
|||
|
|
# Default value
|
|||
|
|
# ---------------------------------------------------------------------------
|
|||
|
|
|
|||
|
|
def test_new_task_completed_at_is_null(conn):
|
|||
|
|
"""KIN-126: новая задача имеет completed_at=None по умолчанию."""
|
|||
|
|
models.create_project(conn, "p1", "P1", "/p1")
|
|||
|
|
t = models.create_task(conn, "P1-001", "p1", "Task")
|
|||
|
|
assert t["completed_at"] is None
|
|||
|
|
|
|||
|
|
|
|||
|
|
# ---------------------------------------------------------------------------
|
|||
|
|
# Setting completed_at on status='done'
|
|||
|
|
# ---------------------------------------------------------------------------
|
|||
|
|
|
|||
|
|
def test_update_task_to_done_sets_completed_at(conn):
|
|||
|
|
"""KIN-126: update_task(status='done') устанавливает completed_at."""
|
|||
|
|
models.create_project(conn, "p1", "P1", "/p1")
|
|||
|
|
models.create_task(conn, "P1-001", "p1", "Task")
|
|||
|
|
updated = models.update_task(conn, "P1-001", status="done")
|
|||
|
|
assert updated["completed_at"] is not None
|
|||
|
|
|
|||
|
|
|
|||
|
|
def test_update_task_to_done_completed_at_is_valid_iso(conn):
|
|||
|
|
"""KIN-126: completed_at при status='done' — валидная ISO-строка datetime."""
|
|||
|
|
models.create_project(conn, "p1", "P1", "/p1")
|
|||
|
|
models.create_task(conn, "P1-001", "p1", "Task")
|
|||
|
|
updated = models.update_task(conn, "P1-001", status="done")
|
|||
|
|
# Must parse without exception
|
|||
|
|
parsed = datetime.fromisoformat(updated["completed_at"])
|
|||
|
|
assert parsed is not None
|
|||
|
|
|
|||
|
|
|
|||
|
|
# ---------------------------------------------------------------------------
|
|||
|
|
# Non-done statuses do NOT set completed_at
|
|||
|
|
# ---------------------------------------------------------------------------
|
|||
|
|
|
|||
|
|
def test_update_task_to_in_progress_does_not_set_completed_at(conn):
|
|||
|
|
"""KIN-126: update_task(status='in_progress') не устанавливает completed_at."""
|
|||
|
|
models.create_project(conn, "p1", "P1", "/p1")
|
|||
|
|
models.create_task(conn, "P1-001", "p1", "Task")
|
|||
|
|
updated = models.update_task(conn, "P1-001", status="in_progress")
|
|||
|
|
assert updated["completed_at"] is None
|
|||
|
|
|
|||
|
|
|
|||
|
|
def test_update_task_to_cancelled_does_not_set_completed_at(conn):
|
|||
|
|
"""KIN-126: update_task(status='cancelled') не устанавливает completed_at."""
|
|||
|
|
models.create_project(conn, "p1", "P1", "/p1")
|
|||
|
|
models.create_task(conn, "P1-001", "p1", "Task")
|
|||
|
|
updated = models.update_task(conn, "P1-001", status="cancelled")
|
|||
|
|
assert updated["completed_at"] is None
|
|||
|
|
|
|||
|
|
|
|||
|
|
def test_update_task_to_blocked_does_not_set_completed_at(conn):
|
|||
|
|
"""KIN-126: update_task(status='blocked') не устанавливает completed_at."""
|
|||
|
|
models.create_project(conn, "p1", "P1", "/p1")
|
|||
|
|
models.create_task(conn, "P1-001", "p1", "Task")
|
|||
|
|
updated = models.update_task(conn, "P1-001", status="blocked")
|
|||
|
|
assert updated["completed_at"] is None
|
|||
|
|
|
|||
|
|
|
|||
|
|
# ---------------------------------------------------------------------------
|
|||
|
|
# Non-status updates do NOT touch completed_at
|
|||
|
|
# ---------------------------------------------------------------------------
|
|||
|
|
|
|||
|
|
def test_update_task_priority_only_does_not_set_completed_at(conn):
|
|||
|
|
"""KIN-126: update_task с изменением только priority не трогает completed_at."""
|
|||
|
|
models.create_project(conn, "p1", "P1", "/p1")
|
|||
|
|
models.create_task(conn, "P1-001", "p1", "Task")
|
|||
|
|
updated = models.update_task(conn, "P1-001", priority=1)
|
|||
|
|
assert updated["completed_at"] is None
|