-
Notifications
You must be signed in to change notification settings - Fork 6.2k
Expand file tree
/
Copy pathtest_memory_utils.py
More file actions
90 lines (77 loc) · 3.87 KB
/
test_memory_utils.py
File metadata and controls
90 lines (77 loc) · 3.87 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
import pytest
from mem0.memory.utils import parse_vision_messages, remove_spaces_from_entities, sanitize_relationship_for_cypher
class TestRemoveSpacesFromEntities:
"""
Covers behavior used by Neo4j, Memgraph (sanitize_relationship=True),
Kuzu, and Neptune (sanitize_relationship=False). All backends delegate here.
"""
@pytest.mark.parametrize(
"sanitize",
[True, False],
ids=["cypher_sanitized", "plain"],
)
def test_filters_empty_and_incomplete_dicts(self, sanitize):
mixed = [
{},
{"source": "a"},
{"source": "a", "relationship": "r"},
{"source": "x", "relationship": "rel", "destination": "y"},
]
out = remove_spaces_from_entities(mixed, sanitize_relationship=sanitize)
assert len(out) == 1
assert out[0]["source"] == "x"
assert out[0]["destination"] == "y"
@pytest.mark.parametrize("sanitize", [True, False])
def test_all_empty_returns_empty(self, sanitize):
assert remove_spaces_from_entities([{}, {}, {}], sanitize_relationship=sanitize) == []
def test_skips_non_dict_entries(self):
assert remove_spaces_from_entities([None, "not-a-dict", 123, {"source": "a", "relationship": "r", "destination": "b"}]) == [
{"source": "a", "relationship": "r", "destination": "b"}
]
def test_sanitize_true_relationship_uses_sanitizer(self):
"""Neo4j / Memgraph path: special characters mapped via sanitize_relationship_for_cypher."""
entities = [{"source": "A", "relationship": "x/y", "destination": "B"}]
out = remove_spaces_from_entities(entities, sanitize_relationship=True)
assert out[0]["relationship"] == sanitize_relationship_for_cypher("x/y".lower().replace(" ", "_"))
def test_sanitize_false_relationship_plain_only(self):
"""Kuzu / Neptune path: only lowercase and spaces to underscores."""
entities = [{"source": "A", "relationship": "Works At", "destination": "B Co"}]
out = remove_spaces_from_entities(entities, sanitize_relationship=False)
assert out[0]["relationship"] == "works_at"
assert out[0]["source"] == "a"
assert out[0]["destination"] == "b_co"
def test_sanitize_true_vs_false_slash_in_relationship(self):
"""Slash is rewritten when sanitizing (Cypher path); kept as-is for plain path."""
base = {"source": "s", "relationship": "a/b", "destination": "d"}
t = remove_spaces_from_entities([dict(base)], sanitize_relationship=True)[0]["relationship"]
f = remove_spaces_from_entities([dict(base)], sanitize_relationship=False)[0]["relationship"]
assert t == sanitize_relationship_for_cypher("a/b")
assert f == "a/b"
class TestParseVisionMessages:
def test_flattens_openai_text_parts_without_vision_llm(self):
messages = [
{"role": "user", "content": "你好"},
{
"role": "user",
"content": [
{"type": "text", "text": "For context:"},
{"type": "text", "text": "xxxxxxx"},
],
},
]
assert parse_vision_messages(messages) == [
{"role": "user", "content": "你好"},
{"role": "user", "content": "For context:\nxxxxxxx"},
]
def test_uses_llm_for_list_content_when_vision_enabled(self, mocker):
mock_llm = mocker.Mock()
mock_llm.generate_response.return_value = "image description"
message = {
"role": "user",
"content": [
{"type": "text", "text": "Describe this"},
{"type": "image_url", "image_url": {"url": "data:image/png;base64,abc"}},
],
}
assert parse_vision_messages([message], llm=mock_llm) == [{"role": "user", "content": "image description"}]
mock_llm.generate_response.assert_called_once()