Ctrl K
ComunidadGuías…

tests/test_exec_board.py

Rama master · réplica de lectura del repositorio original.

Archivo original ↗Preguntar a KiBot
"""exec_board: which cards Exec sees each turn.

All of rd + hq; archives/exile only when the latest logged move there is inside
the 7-day window AND the card is still in that column. Logs are read from
today's file plus the dated rotations, id first, title as the fallback for the
exile tool's older id-less entries.
"""
import json
import sys
from datetime import datetime, timedelta, timezone
from pathlib import Path

sys.path.insert(0, str(Path(__file__).resolve().parent.parent / "api"))

import exec_board  # noqa: E402

NOW = datetime(2026, 9, 28, 18, 0, tzinfo=timezone.utc)


def _ago(days: float) -> str:
    return (NOW - timedelta(days=days)).isoformat()


def _card(i, col, title=None):
    return {"id": f"card-{i}", "title": title or f"t{i}", "column": col, "order": i}


def test_window_and_columns(tmp_path, monkeypatch):
    monkeypatch.setattr(exec_board, "DATA_DIR", tmp_path)
    (tmp_path / "activity_log_20260924.json").write_text(json.dumps([
        {"ts": _ago(4), "action": "moved", "id": "card-3", "to_col": "archives"},
        {"ts": _ago(4), "action": "moved", "title": "old exile", "to_col": "exile"},
    ]))
    (tmp_path / "activity_log_20260901.json").write_text(json.dumps([
        {"ts": _ago(27), "action": "moved", "id": "card-4", "to_col": "archives"},
    ]))
    (tmp_path / "activity_log.json").write_text(json.dumps([
        {"ts": _ago(0.1), "action": "moved", "id": "card-6", "to_col": "archives"},
    ]))
    monkeypatch.setattr(exec_board, "datetime", _Frozen)
    cards = [
        _card(1, "rd"), _card(2, "hq"),
        _card(3, "archives"),              # in window -> shown
        _card(4, "archives"),              # 27 days ago -> not shown
        _card(5, "exile", "old exile"),    # id-less entry, matched by title
        _card(6, "rd"),                    # archived today, then revived -> rd only
    ]
    out = exec_board.board_sections(cards)
    sel, ideas, done, dropped = out.split("\n\n")
    assert "card-2" in sel
    assert "card-1" in ideas and "card-6" in ideas
    assert "card-3" in done and "card-4" not in done and "card-6" not in done
    assert "card-5" in dropped


def test_unreadable_log_is_skipped(tmp_path, monkeypatch):
    monkeypatch.setattr(exec_board, "DATA_DIR", tmp_path)
    (tmp_path / "activity_log.json").write_text("{not json")
    assert exec_board.recent_moves(NOW) == {}


class _Frozen(datetime):
    @classmethod
    def now(cls, tz=None):
        return NOW