Add unit test suite with pytest configuration

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-04-04 08:48:45 -04:00
parent cfa77a1779
commit c8306e6702
13 changed files with 1286 additions and 1 deletions

View File

@@ -0,0 +1,259 @@
"""Tests for ObsidianService markdown parsing and file operations."""
import os
from datetime import datetime
from pathlib import Path
from unittest.mock import patch
import pytest
# Set vault path before importing so __init__ validation passes
_test_vault_dir = None
@pytest.fixture(autouse=True)
def vault_dir(tmp_path):
"""Create a temporary vault directory with a sample .md file."""
global _test_vault_dir
_test_vault_dir = tmp_path
# Create a sample markdown file so vault validation passes
sample = tmp_path / "sample.md"
sample.write_text("# Sample\nHello world")
with patch.dict(os.environ, {"OBSIDIAN_VAULT_PATH": str(tmp_path)}):
yield tmp_path
@pytest.fixture
def service(vault_dir):
from utils.obsidian_service import ObsidianService
return ObsidianService()
class TestParseMarkdown:
def test_extracts_frontmatter(self, service):
content = "---\ntitle: Test Note\ntags: [cat, vet]\n---\n\nBody content"
result = service.parse_markdown(content)
assert result["metadata"]["title"] == "Test Note"
assert result["metadata"]["tags"] == ["cat", "vet"]
def test_no_frontmatter(self, service):
content = "Just body content with no frontmatter"
result = service.parse_markdown(content)
assert result["metadata"] == {}
assert "Just body content" in result["content"]
def test_invalid_yaml_frontmatter(self, service):
content = "---\n: invalid: yaml: [[\n---\n\nBody"
result = service.parse_markdown(content)
assert result["metadata"] == {}
def test_extracts_tags(self, service):
content = "Some text with #tag1 and #tag2 here"
result = service.parse_markdown(content)
assert "tag1" in result["tags"]
assert "tag2" in result["tags"]
def test_extracts_wikilinks(self, service):
content = "Link to [[Other Note]] and [[Another Page]]"
result = service.parse_markdown(content)
assert "Other Note" in result["wikilinks"]
assert "Another Page" in result["wikilinks"]
def test_extracts_embeds(self, service):
content = "An embed [[!my_embed]] here"
result = service.parse_markdown(content)
assert "my_embed" in result["embeds"]
def test_cleans_wikilinks_from_content(self, service):
content = "Text with [[link]] included"
result = service.parse_markdown(content)
assert "[[" not in result["content"]
assert "]]" not in result["content"]
def test_filepath_passed_through(self, service):
result = service.parse_markdown("text", filepath=Path("/vault/note.md"))
assert result["filepath"] == "/vault/note.md"
def test_filepath_none_by_default(self, service):
result = service.parse_markdown("text")
assert result["filepath"] is None
def test_empty_content(self, service):
result = service.parse_markdown("")
assert result["metadata"] == {}
assert result["tags"] == []
assert result["wikilinks"] == []
assert result["embeds"] == []
class TestGetDailyNotePath:
def test_formats_path_correctly(self, service):
date = datetime(2026, 3, 15)
path = service.get_daily_note_path(date)
assert path == "journal/2026/2026-03-15.md"
def test_defaults_to_today(self, service):
path = service.get_daily_note_path()
today = datetime.now()
assert today.strftime("%Y-%m-%d") in path
assert path.startswith(f"journal/{today.strftime('%Y')}/")
class TestWalkVault:
def test_finds_markdown_files(self, service, vault_dir):
(vault_dir / "note1.md").write_text("# Note 1")
(vault_dir / "subdir").mkdir()
(vault_dir / "subdir" / "note2.md").write_text("# Note 2")
files = service.walk_vault()
filenames = [f.name for f in files]
assert "sample.md" in filenames
assert "note1.md" in filenames
assert "note2.md" in filenames
def test_excludes_obsidian_dir(self, service, vault_dir):
obsidian_dir = vault_dir / ".obsidian"
obsidian_dir.mkdir()
(obsidian_dir / "config.md").write_text("config")
files = service.walk_vault()
filenames = [f.name for f in files]
assert "config.md" not in filenames
def test_ignores_non_md_files(self, service, vault_dir):
(vault_dir / "image.png").write_bytes(b"\x89PNG")
files = service.walk_vault()
filenames = [f.name for f in files]
assert "image.png" not in filenames
class TestCreateNote:
def test_creates_file(self, service, vault_dir):
path = service.create_note("My Test Note", "Body content")
full_path = vault_dir / path
assert full_path.exists()
def test_sanitizes_title(self, service, vault_dir):
path = service.create_note("Hello World! @#$", "Body")
assert "hello-world" in path
assert "@" not in path
assert "#" not in path
def test_includes_frontmatter(self, service, vault_dir):
path = service.create_note("Test", "Body", tags=["cat", "vet"])
full_path = vault_dir / path
content = full_path.read_text()
assert "---" in content
assert "created_by: simbarag" in content
assert "cat" in content
assert "vet" in content
def test_custom_folder(self, service, vault_dir):
path = service.create_note("Test", "Body", folder="custom/subfolder")
assert path.startswith("custom/subfolder/")
assert (vault_dir / path).exists()
class TestDailyNoteTasks:
def test_get_tasks_from_daily_note(self, service, vault_dir):
# Create a daily note with tasks
date = datetime(2026, 1, 15)
rel_path = service.get_daily_note_path(date)
note_path = vault_dir / rel_path
note_path.parent.mkdir(parents=True, exist_ok=True)
note_path.write_text(
"---\nmodified: 2026-01-15\n---\n"
"### tasks\n\n"
"- [ ] Feed the cat\n"
"- [x] Clean litter box\n"
"- [ ] Buy cat food\n\n"
"### log\n"
)
result = service.get_daily_tasks(date)
assert result["found"] is True
assert len(result["tasks"]) == 3
assert result["tasks"][0] == {"text": "Feed the cat", "done": False}
assert result["tasks"][1] == {"text": "Clean litter box", "done": True}
assert result["tasks"][2] == {"text": "Buy cat food", "done": False}
def test_get_tasks_no_note(self, service):
date = datetime(2099, 12, 31)
result = service.get_daily_tasks(date)
assert result["found"] is False
assert result["tasks"] == []
def test_add_task_creates_note(self, service, vault_dir):
date = datetime(2026, 6, 1)
result = service.add_task_to_daily_note("Walk the cat", date)
assert result["success"] is True
assert result["created_note"] is True
# Verify file was created with the task
note_path = vault_dir / result["path"]
content = note_path.read_text()
assert "- [ ] Walk the cat" in content
def test_add_task_to_existing_note(self, service, vault_dir):
date = datetime(2026, 6, 2)
rel_path = service.get_daily_note_path(date)
note_path = vault_dir / rel_path
note_path.parent.mkdir(parents=True, exist_ok=True)
note_path.write_text(
"---\nmodified: 2026-06-02\n---\n"
"### tasks\n\n"
"- [ ] Existing task\n\n"
"### log\n"
)
result = service.add_task_to_daily_note("New task", date)
assert result["success"] is True
assert result["created_note"] is False
content = note_path.read_text()
assert "- [ ] Existing task" in content
assert "- [ ] New task" in content
def test_complete_task_exact_match(self, service, vault_dir):
date = datetime(2026, 6, 3)
rel_path = service.get_daily_note_path(date)
note_path = vault_dir / rel_path
note_path.parent.mkdir(parents=True, exist_ok=True)
note_path.write_text("### tasks\n\n" "- [ ] Feed the cat\n" "- [ ] Buy food\n")
result = service.complete_task_in_daily_note("Feed the cat", date)
assert result["success"] is True
content = note_path.read_text()
assert "- [x] Feed the cat" in content
assert "- [ ] Buy food" in content # Other task unchanged
def test_complete_task_partial_match(self, service, vault_dir):
date = datetime(2026, 6, 4)
rel_path = service.get_daily_note_path(date)
note_path = vault_dir / rel_path
note_path.parent.mkdir(parents=True, exist_ok=True)
note_path.write_text("### tasks\n\n- [ ] Feed the cat at 5pm\n")
result = service.complete_task_in_daily_note("Feed the cat", date)
assert result["success"] is True
def test_complete_task_not_found(self, service, vault_dir):
date = datetime(2026, 6, 5)
rel_path = service.get_daily_note_path(date)
note_path = vault_dir / rel_path
note_path.parent.mkdir(parents=True, exist_ok=True)
note_path.write_text("### tasks\n\n- [ ] Feed the cat\n")
result = service.complete_task_in_daily_note("Walk the dog", date)
assert result["success"] is False
assert "not found" in result["error"]
def test_complete_task_no_note(self, service):
date = datetime(2099, 12, 31)
result = service.complete_task_in_daily_note("Something", date)
assert result["success"] is False