Skip to content

Commit 747c36f

Browse files
committed
fix move_note tests
Signed-off-by: phernandez <paul@basicmachines.co>
2 parents 0c357ec + cd062de commit 747c36f

2 files changed

Lines changed: 102 additions & 0 deletions

File tree

src/basic_memory/mcp/tools/move_note.py

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -463,6 +463,41 @@ async def move_note(
463463
All examples in Basic Memory expect file extensions to be explicitly provided.
464464
""").strip()
465465

466+
# Get the source entity to check its file extension
467+
try:
468+
# Fetch source entity information
469+
url = f"{project_url}/knowledge/entities/{identifier}"
470+
response = await call_get(client, url)
471+
source_entity = EntityResponse.model_validate(response.json())
472+
473+
# Extract file extensions
474+
source_ext = source_entity.file_path.split(".")[-1] if "." in source_entity.file_path else ""
475+
dest_ext = destination_path.split(".")[-1] if "." in destination_path else ""
476+
477+
# Check if extensions match
478+
if source_ext and dest_ext and source_ext.lower() != dest_ext.lower():
479+
logger.warning(f"Move failed - file extension mismatch: source={source_ext}, dest={dest_ext}")
480+
return dedent(f"""
481+
# Move Failed - File Extension Mismatch
482+
483+
The destination file extension '.{dest_ext}' does not match the source file extension '.{source_ext}'.
484+
485+
To preserve file type consistency, the destination must have the same extension as the source.
486+
487+
## Source file:
488+
- Path: `{source_entity.file_path}`
489+
- Extension: `.{source_ext}`
490+
491+
## Try again with matching extension:
492+
```
493+
move_note("{identifier}", "{destination_path.rsplit('.', 1)[0]}.{source_ext}")
494+
```
495+
""").strip()
496+
except Exception as e:
497+
# If we can't fetch the source entity, log it but continue
498+
# This might happen if the identifier is not yet resolved
499+
logger.debug(f"Could not fetch source entity for extension check: {e}")
500+
466501
try:
467502
# Prepare move request
468503
move_data = {

tests/mcp/test_tool_move_note.py

Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -247,6 +247,73 @@ async def test_move_note_missing_file_extension(client, test_project):
247247
assert "Testing extension validation" in content
248248

249249

250+
@pytest.mark.asyncio
251+
async def test_move_note_file_extension_mismatch(client, test_project):
252+
"""Test that moving note with different extension is blocked."""
253+
# Create initial note with .md extension
254+
await write_note.fn(
255+
project=test_project.name,
256+
title="MarkdownNote",
257+
folder="source",
258+
content="# Markdown Note\nThis is a markdown file.",
259+
)
260+
261+
# Try to move with .txt extension
262+
result = await move_note.fn(
263+
project=test_project.name,
264+
identifier="source/markdown-note",
265+
destination_path="target/renamed-note.txt",
266+
)
267+
268+
# Should return error about extension mismatch
269+
assert isinstance(result, str)
270+
assert "# Move Failed - File Extension Mismatch" in result
271+
assert "does not match the source file extension" in result
272+
assert ".md" in result
273+
assert ".txt" in result
274+
assert "renamed-note.md" in result # Should suggest correct extension
275+
276+
# Test that note still exists at original location with original extension
277+
content = await read_note.fn("source/markdown-note", project=test_project.name)
278+
assert "# Markdown Note" in content
279+
assert "This is a markdown file" in content
280+
281+
282+
@pytest.mark.asyncio
283+
async def test_move_note_preserves_file_extension(client, test_project):
284+
"""Test that moving note with matching extension succeeds."""
285+
# Create initial note with .md extension
286+
await write_note.fn(
287+
project=test_project.name,
288+
title="PreserveExtension",
289+
folder="source",
290+
content="# Preserve Extension\nTesting that extension is preserved.",
291+
)
292+
293+
# Move with same .md extension
294+
result = await move_note.fn(
295+
project=test_project.name,
296+
identifier="source/preserve-extension",
297+
destination_path="target/preserved-note.md",
298+
)
299+
300+
# Should succeed
301+
assert isinstance(result, str)
302+
assert "✅ Note moved successfully" in result
303+
304+
# Verify note exists at new location with same extension
305+
content = await read_note.fn("target/preserved-note", project=test_project.name)
306+
assert "# Preserve Extension" in content
307+
assert "Testing that extension is preserved" in content
308+
309+
# Verify old location no longer exists
310+
try:
311+
await read_note.fn("source/preserve-extension")
312+
assert False, "Original note should not exist after move"
313+
except Exception:
314+
pass # Expected
315+
316+
250317
@pytest.mark.asyncio
251318
async def test_move_note_destination_exists(client, test_project):
252319
"""Test moving note to existing destination."""

0 commit comments

Comments
 (0)