Update projektu
This commit is contained in:
98
skills/note/tests/test_note_capture.py
Normal file
98
skills/note/tests/test_note_capture.py
Normal file
@@ -0,0 +1,98 @@
|
||||
"""Tests for note_capture.py — dumb capture into notes/inbox/ + audit log."""
|
||||
|
||||
import re
|
||||
import sys
|
||||
from pathlib import Path
|
||||
|
||||
import pytest
|
||||
|
||||
sys.path.insert(0, str(Path(__file__).resolve().parent.parent / "scripts"))
|
||||
import note_capture # noqa: E402
|
||||
|
||||
FILENAME_RE = re.compile(r"^\d{4}-\d{2}-\d{2}_\d{2}_\d{2}_\d{2}_\d{6}-[a-z0-9-]+\.md$")
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def workspace(tmp_path, monkeypatch):
|
||||
inbox = tmp_path / "notes" / "inbox"
|
||||
log = tmp_path / "log" / "note.log"
|
||||
monkeypatch.setattr(note_capture, "INBOX", inbox)
|
||||
monkeypatch.setattr(note_capture, "LOG", log)
|
||||
return tmp_path
|
||||
|
||||
|
||||
def _run(text=None, argv_extra=None):
|
||||
argv = ["note_capture.py"]
|
||||
if text is not None:
|
||||
argv += ["--text", text]
|
||||
if argv_extra:
|
||||
argv += argv_extra
|
||||
return argv
|
||||
|
||||
|
||||
def test_slugify_from_words():
|
||||
assert note_capture._slugify("Mazání starých images") == "mazani-starych-images"
|
||||
|
||||
|
||||
def test_slugify_caps_word_count():
|
||||
assert note_capture._slugify("one two three four five six") == "one-two-three-four"
|
||||
|
||||
|
||||
def test_slugify_bare_url_uses_domain():
|
||||
assert (
|
||||
note_capture._slugify("https://www.darkove-sklo.com/x/y") == "darkove-sklo-com"
|
||||
)
|
||||
|
||||
|
||||
def test_slugify_empty_falls_back():
|
||||
assert note_capture._slugify("!!!") == "note"
|
||||
|
||||
|
||||
def test_capture_writes_inbox_file_and_log(workspace, monkeypatch):
|
||||
monkeypatch.setattr(
|
||||
sys,
|
||||
"argv",
|
||||
_run("koupit kanistr na vodu", ["--channel", "telegram", "--chat-id", "42"]),
|
||||
)
|
||||
assert note_capture.main() == 0
|
||||
|
||||
files = list((workspace / "notes" / "inbox").glob("*.md"))
|
||||
assert len(files) == 1
|
||||
name = files[0].name
|
||||
assert FILENAME_RE.match(name), name
|
||||
|
||||
content = files[0].read_text(encoding="utf-8")
|
||||
assert content.startswith("---\n")
|
||||
assert "channel: telegram" in content
|
||||
assert 'chat_id: "42"' in content
|
||||
assert "koupit kanistr na vodu" in content
|
||||
|
||||
log_lines = (
|
||||
(workspace / "log" / "note.log").read_text(encoding="utf-8").splitlines()
|
||||
)
|
||||
assert len(log_lines) == 1
|
||||
assert "CAPTURE" in log_lines[0]
|
||||
assert name in log_lines[0]
|
||||
|
||||
|
||||
def test_capture_no_leftover_tmp_files(workspace, monkeypatch):
|
||||
monkeypatch.setattr(sys, "argv", _run("neco"))
|
||||
assert note_capture.main() == 0
|
||||
tmp_files = list((workspace / "notes" / "inbox").glob(".*"))
|
||||
assert tmp_files == []
|
||||
|
||||
|
||||
def test_capture_omits_absent_provenance(workspace, monkeypatch):
|
||||
monkeypatch.setattr(sys, "argv", _run("bez kanalu"))
|
||||
assert note_capture.main() == 0
|
||||
content = next((workspace / "notes" / "inbox").glob("*.md")).read_text(
|
||||
encoding="utf-8"
|
||||
)
|
||||
assert "channel:" not in content
|
||||
assert "chat_id:" not in content
|
||||
|
||||
|
||||
def test_capture_empty_input_fails(workspace, monkeypatch):
|
||||
monkeypatch.setattr(sys, "argv", _run(" "))
|
||||
assert note_capture.main() == 1
|
||||
assert list((workspace / "notes" / "inbox").glob("*.md")) == []
|
||||
117
skills/note/tests/test_note_compile.py
Normal file
117
skills/note/tests/test_note_compile.py
Normal file
@@ -0,0 +1,117 @@
|
||||
"""Tests for note_compile.py — the thin drain launcher (pre-check + lock).
|
||||
|
||||
The nanobot import is deferred inside run_compile, so importing the module and testing
|
||||
pending_sources / the lock needs no nanobot-ai install.
|
||||
"""
|
||||
|
||||
import subprocess
|
||||
import sys
|
||||
from pathlib import Path
|
||||
|
||||
import pytest
|
||||
|
||||
sys.path.insert(0, str(Path(__file__).resolve().parent.parent / "scripts"))
|
||||
import note_compile # noqa: E402
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def workspace(tmp_path, monkeypatch):
|
||||
notes = tmp_path / "notes"
|
||||
inbox = notes / "inbox"
|
||||
inbox.mkdir(parents=True)
|
||||
monkeypatch.setattr(note_compile, "NOTES", notes)
|
||||
monkeypatch.setattr(note_compile, "INBOX", inbox)
|
||||
monkeypatch.setattr(note_compile, "LOCK", notes / ".compile.lock")
|
||||
monkeypatch.setattr(note_compile, "LOG", tmp_path / "log" / "note_compile_cron.log")
|
||||
monkeypatch.setattr(note_compile, "WORKSPACE", tmp_path)
|
||||
return tmp_path
|
||||
|
||||
|
||||
def _git(workspace, *args) -> str:
|
||||
result = subprocess.run(
|
||||
["git", "-C", str(workspace), *args], check=True, capture_output=True, text=True
|
||||
)
|
||||
return result.stdout
|
||||
|
||||
|
||||
def _init_repo(workspace) -> None:
|
||||
_git(workspace, "init", "-q")
|
||||
_git(workspace, "config", "user.email", "test@example.com")
|
||||
_git(workspace, "config", "user.name", "test")
|
||||
|
||||
|
||||
def test_pending_sources_empty(workspace):
|
||||
assert note_compile.pending_sources() == []
|
||||
|
||||
|
||||
def test_pending_sources_ignores_hidden(workspace):
|
||||
inbox = workspace / "notes" / "inbox"
|
||||
(inbox / "2026-07-01_10_00_00_000000-a.md").write_text("x")
|
||||
(inbox / ".hidden.tmp").write_text("x")
|
||||
names = [p.name for p in note_compile.pending_sources()]
|
||||
assert names == ["2026-07-01_10_00_00_000000-a.md"]
|
||||
|
||||
|
||||
def test_pending_sources_sorted(workspace):
|
||||
inbox = workspace / "notes" / "inbox"
|
||||
for stem in ("2026-07-01_10_00_02_000000-c", "2026-07-01_10_00_01_000000-b"):
|
||||
(inbox / f"{stem}.md").write_text("x")
|
||||
names = [p.name for p in note_compile.pending_sources()]
|
||||
assert names == sorted(names)
|
||||
|
||||
|
||||
def test_lock_acquire_then_blocked(workspace):
|
||||
assert note_compile.acquire_lock() is True
|
||||
assert note_compile.acquire_lock() is False # live lock held by this pid
|
||||
|
||||
|
||||
def test_lock_reclaims_dead_pid(workspace):
|
||||
lock = workspace / "notes" / ".compile.lock"
|
||||
lock.write_text('{"pid": 999999, "started": "2999-01-01T00:00:00+00:00"}')
|
||||
assert note_compile.acquire_lock() is True # dead pid -> reclaimed
|
||||
|
||||
|
||||
def test_lock_reclaims_unparseable(workspace):
|
||||
(workspace / "notes" / ".compile.lock").write_text("garbage")
|
||||
assert note_compile.acquire_lock() is True
|
||||
|
||||
|
||||
def test_main_empty_inbox_returns_zero_without_lock(workspace):
|
||||
# No pending work -> exit before acquire_lock / nanobot import.
|
||||
assert note_compile.main() == 0
|
||||
assert not (workspace / "notes" / ".compile.lock").exists()
|
||||
|
||||
|
||||
def test_main_dry_run_releases_lock(workspace, monkeypatch):
|
||||
(workspace / "notes" / "inbox" / "2026-07-01_10_00_00_000000-a.md").write_text("x")
|
||||
monkeypatch.setattr(sys, "argv", ["note_compile.py", "--dry-run"])
|
||||
assert note_compile.main() == 0
|
||||
assert not (workspace / "notes" / ".compile.lock").exists()
|
||||
|
||||
|
||||
def test_commit_notes_creates_commit(workspace):
|
||||
_init_repo(workspace)
|
||||
(workspace / "notes" / "notes.md").write_text("# Notes\n\n## X\n\n- a fact\n")
|
||||
note_compile.commit_notes(2)
|
||||
assert "note: cron drain (2 captures)" in _git(workspace, "log", "--oneline")
|
||||
assert "notes/notes.md" in _git(workspace, "ls-files", "notes/")
|
||||
|
||||
|
||||
def test_commit_notes_noop_when_clean(workspace):
|
||||
_init_repo(workspace)
|
||||
(workspace / "notes" / "notes.md").write_text("# Notes\n")
|
||||
note_compile.commit_notes(1)
|
||||
before = _git(workspace, "rev-list", "--count", "HEAD").strip()
|
||||
note_compile.commit_notes(1) # nothing changed since last commit
|
||||
assert _git(workspace, "rev-list", "--count", "HEAD").strip() == before
|
||||
|
||||
|
||||
def test_commit_notes_skips_gitignored_lock(workspace):
|
||||
_init_repo(workspace)
|
||||
(workspace / ".gitignore").write_text("notes/.compile.lock\n")
|
||||
(workspace / "notes" / ".compile.lock").write_text('{"pid": 1}')
|
||||
(workspace / "notes" / "notes.md").write_text("# Notes\n")
|
||||
note_compile.commit_notes(1)
|
||||
tracked = _git(workspace, "ls-files", "notes/")
|
||||
assert "notes/notes.md" in tracked
|
||||
assert ".compile.lock" not in tracked
|
||||
Reference in New Issue
Block a user