1+ """Integration tests for Obsidian-compatible YAML formatting in write_note tool."""
2+
3+ import pytest
4+ from pathlib import Path
5+
6+ from basic_memory .mcp .tools import write_note
7+
8+
9+ @pytest .mark .asyncio
10+ async def test_write_note_tags_yaml_format (app , project_config ):
11+ """Test that write_note creates files with proper YAML list format for tags."""
12+ # Create a note with tags using write_note
13+ result = await write_note .fn (
14+ title = "YAML Format Test" ,
15+ folder = "test" ,
16+ content = "Testing YAML tag formatting" ,
17+ tags = ["system" , "overview" , "reference" ]
18+ )
19+
20+ # Verify the note was created successfully
21+ assert "Created note" in result
22+ assert "file_path: test/YAML Format Test.md" in result
23+
24+ # Read the file directly to check YAML formatting
25+ file_path = project_config .home / "test" / "YAML Format Test.md"
26+ content = file_path .read_text (encoding = "utf-8" )
27+
28+ # Should use YAML list format
29+ assert "tags:" in content
30+ assert "- system" in content
31+ assert "- overview" in content
32+ assert "- reference" in content
33+
34+ # Should NOT use JSON array format
35+ assert '["system"' not in content
36+ assert '"overview"' not in content
37+ assert '"reference"]' not in content
38+
39+
40+ @pytest .mark .asyncio
41+ async def test_write_note_stringified_json_tags (app , project_config ):
42+ """Test that stringified JSON arrays are handled correctly."""
43+ # This simulates the issue where AI assistants pass tags as stringified JSON
44+ result = await write_note .fn (
45+ title = "Stringified JSON Test" ,
46+ folder = "test" ,
47+ content = "Testing stringified JSON tag input" ,
48+ tags = '["python", "testing", "json"]' # Stringified JSON array
49+ )
50+
51+ # Verify the note was created successfully
52+ assert "Created note" in result
53+
54+ # Read the file to check formatting
55+ file_path = project_config .home / "test" / "Stringified JSON Test.md"
56+ content = file_path .read_text (encoding = "utf-8" )
57+
58+ # Should properly parse the JSON and format as YAML list
59+ assert "tags:" in content
60+ assert "- python" in content
61+ assert "- testing" in content
62+ assert "- json" in content
63+
64+ # Should NOT have the original stringified format issues
65+ assert '["python"' not in content
66+ assert '"testing"' not in content
67+ assert '"json"]' not in content
68+
69+
70+ @pytest .mark .asyncio
71+ async def test_write_note_single_tag_yaml_format (app , project_config ):
72+ """Test that single tags are still formatted as YAML lists."""
73+ result = await write_note .fn (
74+ title = "Single Tag Test" ,
75+ folder = "test" ,
76+ content = "Testing single tag formatting" ,
77+ tags = ["solo-tag" ]
78+ )
79+
80+ file_path = project_config .home / "test" / "Single Tag Test.md"
81+ content = file_path .read_text (encoding = "utf-8" )
82+
83+ # Single tag should still use list format
84+ assert "tags:" in content
85+ assert "- solo-tag" in content
86+
87+
88+ @pytest .mark .asyncio
89+ async def test_write_note_no_tags (app , project_config ):
90+ """Test that notes without tags work normally."""
91+ result = await write_note .fn (
92+ title = "No Tags Test" ,
93+ folder = "test" ,
94+ content = "Testing note without tags" ,
95+ tags = None
96+ )
97+
98+ file_path = project_config .home / "test" / "No Tags Test.md"
99+ content = file_path .read_text (encoding = "utf-8" )
100+
101+ # Should not have tags field in frontmatter
102+ assert "tags:" not in content
103+ assert "title: No Tags Test" in content
104+
105+
106+ @pytest .mark .asyncio
107+ async def test_write_note_empty_tags_list (app , project_config ):
108+ """Test that empty tag lists are handled properly."""
109+ result = await write_note .fn (
110+ title = "Empty Tags Test" ,
111+ folder = "test" ,
112+ content = "Testing empty tag list" ,
113+ tags = []
114+ )
115+
116+ file_path = project_config .home / "test" / "Empty Tags Test.md"
117+ content = file_path .read_text (encoding = "utf-8" )
118+
119+ # Should not add tags field to frontmatter for empty lists
120+ assert "tags:" not in content
121+
122+
123+ @pytest .mark .asyncio
124+ async def test_write_note_update_preserves_yaml_format (app , project_config ):
125+ """Test that updating a note preserves the YAML list format."""
126+ # First, create the note
127+ await write_note .fn (
128+ title = "Update Format Test" ,
129+ folder = "test" ,
130+ content = "Initial content" ,
131+ tags = ["initial" , "tag" ]
132+ )
133+
134+ # Then update it with new tags
135+ result = await write_note .fn (
136+ title = "Update Format Test" ,
137+ folder = "test" ,
138+ content = "Updated content" ,
139+ tags = ["updated" , "new-tag" , "format" ]
140+ )
141+
142+ # Should be an update, not a new creation
143+ assert "Updated note" in result
144+
145+ # Check the file format
146+ file_path = project_config .home / "test" / "Update Format Test.md"
147+ content = file_path .read_text (encoding = "utf-8" )
148+
149+ # Should have proper YAML formatting for updated tags
150+ assert "tags:" in content
151+ assert "- updated" in content
152+ assert "- new-tag" in content
153+ assert "- format" in content
154+
155+ # Old tags should be gone
156+ assert "- initial" not in content
157+ assert "- tag" not in content
158+
159+ # Content should be updated
160+ assert "Updated content" in content
161+ assert "Initial content" not in content
162+
163+
164+ @pytest .mark .asyncio
165+ async def test_complex_tags_yaml_format (app , project_config ):
166+ """Test that complex tags with special characters format correctly."""
167+ result = await write_note .fn (
168+ title = "Complex Tags Test" ,
169+ folder = "test" ,
170+ content = "Testing complex tag formats" ,
171+ tags = ["python-3.9" , "api_integration" , "v2.0" , "nested/category" , "under_score" ]
172+ )
173+
174+ file_path = project_config .home / "test" / "Complex Tags Test.md"
175+ content = file_path .read_text (encoding = "utf-8" )
176+
177+ # All complex tags should format correctly
178+ assert "- python-3.9" in content
179+ assert "- api_integration" in content
180+ assert "- v2.0" in content
181+ assert "- nested/category" in content
182+ assert "- under_score" in content
0 commit comments