diff --git a/tests/timmy/test_memory_system.py b/tests/timmy/test_memory_system.py index 80ff2334..40590341 100644 --- a/tests/timmy/test_memory_system.py +++ b/tests/timmy/test_memory_system.py @@ -7,6 +7,8 @@ import pytest from timmy.memory_system import ( HotMemory, MemorySystem, + jot_note, + log_decision, reset_memory_system, store_last_reflection, ) @@ -246,3 +248,81 @@ class TestStoreLastReflection: result = recall_last_reflection() assert result is None + + +class TestJotNote: + """Tests for jot_note() artifact tool.""" + + def test_saves_note_file(self, tmp_path): + """jot_note creates a markdown file with title and body.""" + notes_dir = tmp_path / "notes" + with patch("timmy.memory_system.NOTES_DIR", notes_dir): + result = jot_note("My Title", "Some body text") + + assert "Note saved:" in result + files = list(notes_dir.glob("*.md")) + assert len(files) == 1 + content = files[0].read_text() + assert "# My Title" in content + assert "Some body text" in content + assert "Created:" in content + + def test_slug_in_filename(self, tmp_path): + """Filename contains a slug derived from the title.""" + notes_dir = tmp_path / "notes" + with patch("timmy.memory_system.NOTES_DIR", notes_dir): + jot_note("Hello World!", "body") + + files = list(notes_dir.glob("*.md")) + assert "hello-world" in files[0].name + + def test_rejects_empty_title(self): + """jot_note rejects empty title.""" + assert "title is empty" in jot_note("", "body") + assert "title is empty" in jot_note(" ", "body") + + def test_rejects_empty_body(self): + """jot_note rejects empty body.""" + assert "body is empty" in jot_note("title", "") + assert "body is empty" in jot_note("title", " ") + + +class TestLogDecision: + """Tests for log_decision() artifact tool.""" + + def test_creates_decision_log(self, tmp_path): + """log_decision creates the log file and appends an entry.""" + log_file = tmp_path / "decisions.md" + with patch("timmy.memory_system.DECISION_LOG", log_file): + result = log_decision("Use SQLite for storage") + + assert "Decision logged:" in result + content = log_file.read_text() + assert "# Decision Log" in content + assert "Use SQLite for storage" in content + + def test_appends_multiple_decisions(self, tmp_path): + """Multiple decisions are appended to the same file.""" + log_file = tmp_path / "decisions.md" + with patch("timmy.memory_system.DECISION_LOG", log_file): + log_decision("First decision") + log_decision("Second decision") + + content = log_file.read_text() + assert "First decision" in content + assert "Second decision" in content + + def test_includes_rationale(self, tmp_path): + """Rationale is included when provided.""" + log_file = tmp_path / "decisions.md" + with patch("timmy.memory_system.DECISION_LOG", log_file): + log_decision("Use Redis", "Fast in-memory cache") + + content = log_file.read_text() + assert "Use Redis" in content + assert "Fast in-memory cache" in content + + def test_rejects_empty_decision(self): + """log_decision rejects empty decision string.""" + assert "decision is empty" in log_decision("") + assert "decision is empty" in log_decision(" ")