80 lines
2.6 KiB
Python
80 lines
2.6 KiB
Python
|
|
"""Tests for memory_store — port of long_term_memory tests in rust."""
|
||
|
|
|
||
|
|
import json
|
||
|
|
import os
|
||
|
|
import pytest
|
||
|
|
|
||
|
|
|
||
|
|
def test_remember_recall_round_trip(isolated_state):
|
||
|
|
m = isolated_state('memory_store', ['_PATH'])
|
||
|
|
m.remember("любимый чай", "улун")
|
||
|
|
assert m.recall("любимый чай") == "улун"
|
||
|
|
assert m.recall("Любимый Чай") == "улун" # case-insensitive
|
||
|
|
|
||
|
|
|
||
|
|
def test_recall_returns_none_for_missing(isolated_state):
|
||
|
|
m = isolated_state('memory_store', ['_PATH'])
|
||
|
|
assert m.recall("nonexistent") is None
|
||
|
|
|
||
|
|
|
||
|
|
def test_forget_removes(isolated_state):
|
||
|
|
m = isolated_state('memory_store', ['_PATH'])
|
||
|
|
m.remember("foo", "bar")
|
||
|
|
assert m.forget("foo") is True
|
||
|
|
assert m.recall("foo") is None
|
||
|
|
assert m.forget("foo") is False # idempotent
|
||
|
|
|
||
|
|
|
||
|
|
def test_search_by_key_and_value(isolated_state):
|
||
|
|
m = isolated_state('memory_store', ['_PATH'])
|
||
|
|
m.remember("любимый чай", "улун")
|
||
|
|
m.remember("любимый кофе", "арабика")
|
||
|
|
m.remember("питомец", "собака бася")
|
||
|
|
|
||
|
|
hits = m.search("чай", 5)
|
||
|
|
assert len(hits) == 1
|
||
|
|
assert hits[0]['key'] == "любимый чай"
|
||
|
|
|
||
|
|
hits = m.search("бася", 5)
|
||
|
|
assert len(hits) == 1
|
||
|
|
assert hits[0]['key'] == "питомец"
|
||
|
|
|
||
|
|
|
||
|
|
def test_search_respects_limit(isolated_state):
|
||
|
|
m = isolated_state('memory_store', ['_PATH'])
|
||
|
|
for i in range(10):
|
||
|
|
m.remember(f"key{i}", "value")
|
||
|
|
hits = m.search("value", 3)
|
||
|
|
assert len(hits) == 3
|
||
|
|
|
||
|
|
|
||
|
|
def test_search_empty_query_returns_nothing(isolated_state):
|
||
|
|
m = isolated_state('memory_store', ['_PATH'])
|
||
|
|
m.remember("foo", "bar")
|
||
|
|
assert m.search("", 5) == []
|
||
|
|
assert m.search(" ", 5) == []
|
||
|
|
|
||
|
|
|
||
|
|
def test_persists_across_module_reload(isolated_state, tmp_path):
|
||
|
|
m = isolated_state('memory_store', ['_PATH'])
|
||
|
|
m.remember("persistent", "yes")
|
||
|
|
json_file = m._PATH
|
||
|
|
assert os.path.isfile(json_file)
|
||
|
|
with open(json_file, encoding='utf-8') as f:
|
||
|
|
data = json.load(f)
|
||
|
|
assert data['entries']['persistent']['value'] == 'yes'
|
||
|
|
|
||
|
|
|
||
|
|
def test_build_llm_context_format(isolated_state):
|
||
|
|
m = isolated_state('memory_store', ['_PATH'])
|
||
|
|
m.remember("любимый чай", "улун")
|
||
|
|
# Query "чай" is substring of key "любимый чай" → matches.
|
||
|
|
ctx = m.build_llm_context("чай", 5)
|
||
|
|
assert "любимый чай = улун" in ctx
|
||
|
|
assert ctx.startswith("Известные факты")
|
||
|
|
|
||
|
|
|
||
|
|
def test_build_llm_context_empty(isolated_state):
|
||
|
|
m = isolated_state('memory_store', ['_PATH'])
|
||
|
|
assert m.build_llm_context("anything", 5) == ""
|