123 lines
4.3 KiB
Python
123 lines
4.3 KiB
Python
|
|
"""Tests for mempalace.layers — focused on Layer0."""
|
||
|
|
|
||
|
|
import os
|
||
|
|
from unittest.mock import patch
|
||
|
|
|
||
|
|
from mempalace.layers import Layer0
|
||
|
|
|
||
|
|
|
||
|
|
# ── Layer0 — with identity file ─────────────────────────────────────────
|
||
|
|
|
||
|
|
|
||
|
|
def test_layer0_reads_identity_file(tmp_path):
|
||
|
|
identity_file = tmp_path / "identity.txt"
|
||
|
|
identity_file.write_text("I am Atlas, a personal AI assistant for Alice.")
|
||
|
|
layer = Layer0(identity_path=str(identity_file))
|
||
|
|
text = layer.render()
|
||
|
|
assert "Atlas" in text
|
||
|
|
assert "Alice" in text
|
||
|
|
|
||
|
|
|
||
|
|
def test_layer0_caches_text(tmp_path):
|
||
|
|
identity_file = tmp_path / "identity.txt"
|
||
|
|
identity_file.write_text("Hello world")
|
||
|
|
layer = Layer0(identity_path=str(identity_file))
|
||
|
|
first = layer.render()
|
||
|
|
# Modify file after first read
|
||
|
|
identity_file.write_text("Changed content")
|
||
|
|
second = layer.render()
|
||
|
|
# Should return cached version
|
||
|
|
assert first == second
|
||
|
|
assert second == "Hello world"
|
||
|
|
|
||
|
|
|
||
|
|
def test_layer0_missing_file_returns_default(tmp_path):
|
||
|
|
missing = str(tmp_path / "nonexistent.txt")
|
||
|
|
layer = Layer0(identity_path=missing)
|
||
|
|
text = layer.render()
|
||
|
|
assert "No identity configured" in text
|
||
|
|
assert "identity.txt" in text
|
||
|
|
|
||
|
|
|
||
|
|
def test_layer0_token_estimate(tmp_path):
|
||
|
|
identity_file = tmp_path / "identity.txt"
|
||
|
|
content = "A" * 400 # 400 chars ~ 100 tokens
|
||
|
|
identity_file.write_text(content)
|
||
|
|
layer = Layer0(identity_path=str(identity_file))
|
||
|
|
estimate = layer.token_estimate()
|
||
|
|
assert estimate == 100
|
||
|
|
|
||
|
|
|
||
|
|
def test_layer0_token_estimate_empty(tmp_path):
|
||
|
|
identity_file = tmp_path / "identity.txt"
|
||
|
|
identity_file.write_text("")
|
||
|
|
layer = Layer0(identity_path=str(identity_file))
|
||
|
|
assert layer.token_estimate() == 0
|
||
|
|
|
||
|
|
|
||
|
|
def test_layer0_strips_whitespace(tmp_path):
|
||
|
|
identity_file = tmp_path / "identity.txt"
|
||
|
|
identity_file.write_text(" Hello world \n\n")
|
||
|
|
layer = Layer0(identity_path=str(identity_file))
|
||
|
|
text = layer.render()
|
||
|
|
assert text == "Hello world"
|
||
|
|
|
||
|
|
|
||
|
|
def test_layer0_default_path():
|
||
|
|
layer = Layer0()
|
||
|
|
expected = os.path.expanduser("~/.mempalace/identity.txt")
|
||
|
|
assert layer.path == expected
|
||
|
|
|
||
|
|
|
||
|
|
# ── Layer1 — mocked chromadb ────────────────────────────────────────────
|
||
|
|
|
||
|
|
|
||
|
|
def test_layer1_no_palace():
|
||
|
|
"""Layer1 returns helpful message when no palace exists."""
|
||
|
|
with patch("mempalace.layers.MempalaceConfig") as mock_cfg:
|
||
|
|
mock_cfg.return_value.palace_path = "/nonexistent/palace"
|
||
|
|
from mempalace.layers import Layer1
|
||
|
|
|
||
|
|
layer = Layer1(palace_path="/nonexistent/palace")
|
||
|
|
result = layer.generate()
|
||
|
|
assert "No palace found" in result or "No memories" in result
|
||
|
|
|
||
|
|
|
||
|
|
# ── Layer2 — mocked chromadb ────────────────────────────────────────────
|
||
|
|
|
||
|
|
|
||
|
|
def test_layer2_no_palace():
|
||
|
|
"""Layer2 returns message when no palace exists."""
|
||
|
|
with patch("mempalace.layers.MempalaceConfig") as mock_cfg:
|
||
|
|
mock_cfg.return_value.palace_path = "/nonexistent/palace"
|
||
|
|
from mempalace.layers import Layer2
|
||
|
|
|
||
|
|
layer = Layer2(palace_path="/nonexistent/palace")
|
||
|
|
result = layer.retrieve(wing="test")
|
||
|
|
assert "No palace found" in result
|
||
|
|
|
||
|
|
|
||
|
|
# ── Layer3 — mocked chromadb ────────────────────────────────────────────
|
||
|
|
|
||
|
|
|
||
|
|
def test_layer3_no_palace():
|
||
|
|
"""Layer3 returns message when no palace exists."""
|
||
|
|
with patch("mempalace.layers.MempalaceConfig") as mock_cfg:
|
||
|
|
mock_cfg.return_value.palace_path = "/nonexistent/palace"
|
||
|
|
from mempalace.layers import Layer3
|
||
|
|
|
||
|
|
layer = Layer3(palace_path="/nonexistent/palace")
|
||
|
|
result = layer.search("test query")
|
||
|
|
assert "No palace found" in result
|
||
|
|
|
||
|
|
|
||
|
|
def test_layer3_search_raw_no_palace():
|
||
|
|
"""Layer3.search_raw returns empty list when no palace exists."""
|
||
|
|
with patch("mempalace.layers.MempalaceConfig") as mock_cfg:
|
||
|
|
mock_cfg.return_value.palace_path = "/nonexistent/palace"
|
||
|
|
from mempalace.layers import Layer3
|
||
|
|
|
||
|
|
layer = Layer3(palace_path="/nonexistent/palace")
|
||
|
|
result = layer.search_raw("test query")
|
||
|
|
assert result == []
|