kin: KIN-013 Настройки в GUI: страница Settings с конфигурацией проектов. Путь к Obsidian vault для синхронизации decisions/tasks/kanban. Двусторонний sync: decisions → Obsidian .md, Obsidian чекбоксы → tasks.
This commit is contained in:
parent
6b328d7f2d
commit
4fd825dc58
2 changed files with 241 additions and 0 deletions
|
|
@ -15,6 +15,18 @@ from core.obsidian_sync import (
|
|||
from core import models
|
||||
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# 0. Migration — obsidian_vault_path column must exist after init_db
|
||||
# ---------------------------------------------------------------------------
|
||||
|
||||
def test_migration_obsidian_vault_path_column_exists():
|
||||
"""init_db создаёт или мигрирует колонку obsidian_vault_path в таблице projects."""
|
||||
conn = init_db(db_path=":memory:")
|
||||
cols = {r[1] for r in conn.execute("PRAGMA table_info(projects)").fetchall()}
|
||||
conn.close()
|
||||
assert "obsidian_vault_path" in cols
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def tmp_vault(tmp_path):
|
||||
"""Returns a temporary vault root directory."""
|
||||
|
|
@ -184,3 +196,64 @@ def test_sync_no_vault_path(db):
|
|||
# project exists but obsidian_vault_path is NULL
|
||||
with pytest.raises(ValueError, match="obsidian_vault_path not set"):
|
||||
sync_obsidian(db, "proj1")
|
||||
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# 8. export — frontmatter обёрнут в разделители ---
|
||||
# ---------------------------------------------------------------------------
|
||||
|
||||
def test_export_frontmatter_has_yaml_delimiters(tmp_vault):
|
||||
"""Экспортированный файл начинается с '---' и содержит закрывающий '---'."""
|
||||
decisions = [
|
||||
{
|
||||
"id": 99,
|
||||
"project_id": "p",
|
||||
"type": "decision",
|
||||
"category": None,
|
||||
"title": "YAML Delimiter Test",
|
||||
"description": "Verifying frontmatter delimiters.",
|
||||
"tags": [],
|
||||
"created_at": "2026-01-01",
|
||||
}
|
||||
]
|
||||
tmp_vault.mkdir(parents=True)
|
||||
created = export_decisions_to_md("p", decisions, tmp_vault)
|
||||
content = created[0].read_text(encoding="utf-8")
|
||||
|
||||
assert content.startswith("---\n"), "Frontmatter должен начинаться с '---\\n'"
|
||||
# первые --- открывают, вторые --- закрывают frontmatter
|
||||
parts = content.split("---\n")
|
||||
assert len(parts) >= 3, "Должно быть минимум два разделителя '---'"
|
||||
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# 9. sync_obsidian — несуществующий vault_path → ошибка в errors, не исключение
|
||||
# ---------------------------------------------------------------------------
|
||||
|
||||
def test_sync_nonexistent_vault_records_error(db, tmp_path):
|
||||
"""Если vault_path не существует, sync возвращает ошибку в errors без raise."""
|
||||
nonexistent = tmp_path / "ghost_vault"
|
||||
models.update_project(db, "proj1", obsidian_vault_path=str(nonexistent))
|
||||
|
||||
result = sync_obsidian(db, "proj1")
|
||||
|
||||
assert len(result["errors"]) > 0
|
||||
assert "does not exist" in result["errors"][0].lower() or "not exist" in result["errors"][0].lower()
|
||||
assert result["exported_decisions"] == 0
|
||||
assert result["tasks_updated"] == 0
|
||||
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# 10. sync_obsidian — пустой vault → 0 экспортов, 0 обновлений, нет ошибок
|
||||
# ---------------------------------------------------------------------------
|
||||
|
||||
def test_sync_empty_vault_no_errors(db, tmp_vault):
|
||||
"""Пустой vault (нет decisions, нет task-файлов) → exported=0, updated=0, errors=[]."""
|
||||
tmp_vault.mkdir(parents=True)
|
||||
models.update_project(db, "proj1", obsidian_vault_path=str(tmp_vault))
|
||||
|
||||
result = sync_obsidian(db, "proj1")
|
||||
|
||||
assert result["exported_decisions"] == 0
|
||||
assert result["tasks_updated"] == 0
|
||||
assert result["errors"] == []
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue