Skip to content

Commit af51588

Browse files
committed
�[38;5;8m 1�[0m �[37mtest: add unit tests for reasoning_content extraction helpers�[0m
�[38;5;8m 2�[0m �[38;5;8m 3�[0m �[37mCover both SDK path (_extract_content) and HTTP dict path�[0m �[38;5;8m 4�[0m �[37m(_extract_content_from_dict) with 11 test cases:�[0m �[38;5;8m 5�[0m �[37m- normal content, reasoning fallback, empty string fallback,�[0m �[38;5;8m 6�[0m �[37m both missing, content preferred over reasoning.�[0m �[38;5;8m 7�[0m �[38;5;8m 8�[0m �[37mCo-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>�[0m
1 parent 8b02267 commit af51588

File tree

1 file changed

+87
-0
lines changed

1 file changed

+87
-0
lines changed

tests/llm/test_extract_content.py

Lines changed: 87 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,87 @@
1+
"""Tests for reasoning_content fallback in content extraction helpers."""
2+
3+
from __future__ import annotations
4+
5+
from types import SimpleNamespace
6+
from unittest.mock import MagicMock
7+
8+
from memu.llm.backends.base import _extract_content_from_dict
9+
from memu.llm.openai_sdk import _extract_content
10+
11+
12+
# -- _extract_content (SDK path, ChatCompletion objects) --
13+
14+
15+
def _fake_completion(content=None, reasoning_content=None):
16+
"""Build a minimal ChatCompletion-like object."""
17+
msg = MagicMock()
18+
msg.content = content
19+
# reasoning_content is an extra attr on some providers
20+
if reasoning_content is not None:
21+
msg.reasoning_content = reasoning_content
22+
else:
23+
# simulate the attr not existing at all
24+
del msg.reasoning_content
25+
choice = SimpleNamespace(message=msg)
26+
return SimpleNamespace(choices=[choice])
27+
28+
29+
class TestExtractContent:
30+
def test_normal_content(self):
31+
resp = _fake_completion(content="hello world")
32+
assert _extract_content(resp) == "hello world"
33+
34+
def test_reasoning_content_fallback(self):
35+
resp = _fake_completion(content=None, reasoning_content="thought result")
36+
assert _extract_content(resp) == "thought result"
37+
38+
def test_empty_string_content_falls_back(self):
39+
resp = _fake_completion(content="", reasoning_content="fallback")
40+
assert _extract_content(resp) == "fallback"
41+
42+
def test_both_none_returns_empty(self):
43+
resp = _fake_completion(content=None)
44+
assert _extract_content(resp) == ""
45+
46+
def test_content_preferred_over_reasoning(self):
47+
resp = _fake_completion(content="real answer", reasoning_content="thinking")
48+
assert _extract_content(resp) == "real answer"
49+
50+
51+
# -- _extract_content_from_dict (HTTP path, raw dicts) --
52+
53+
54+
def _fake_dict_response(content=None, reasoning_content=None):
55+
"""Build a minimal raw API response dict."""
56+
msg = {}
57+
if content is not None:
58+
msg["content"] = content
59+
if reasoning_content is not None:
60+
msg["reasoning_content"] = reasoning_content
61+
return {"choices": [{"message": msg}]}
62+
63+
64+
class TestExtractContentFromDict:
65+
def test_normal_content(self):
66+
data = _fake_dict_response(content="hello")
67+
assert _extract_content_from_dict(data) == "hello"
68+
69+
def test_reasoning_content_fallback(self):
70+
data = _fake_dict_response(reasoning_content="thought")
71+
assert _extract_content_from_dict(data) == "thought"
72+
73+
def test_empty_string_content_falls_back(self):
74+
data = _fake_dict_response(content="", reasoning_content="fb")
75+
assert _extract_content_from_dict(data) == "fb"
76+
77+
def test_both_missing_returns_empty(self):
78+
data = _fake_dict_response()
79+
assert _extract_content_from_dict(data) == ""
80+
81+
def test_content_preferred_over_reasoning(self):
82+
data = _fake_dict_response(content="answer", reasoning_content="thinking")
83+
assert _extract_content_from_dict(data) == "answer"
84+
85+
def test_none_content_with_reasoning(self):
86+
data = _fake_dict_response(content=None, reasoning_content="result")
87+
assert _extract_content_from_dict(data) == "result"

0 commit comments

Comments
 (0)