Skip to content

Commit dfb4554

Browse files
web-flowclaude
andcommitted
fix: StructuredLogger.info()をlog_info()に修正
StructuredLogger.info()がlog_debug()を呼び出していたため、 テストのcaplogでログがキャプチャされない問題を修正。 info()メソッドは論理的にINFOレベルで出力するべきなので、 log_info()を使用するように変更。 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
1 parent a019667 commit dfb4554

4 files changed

Lines changed: 657 additions & 6 deletions

File tree

EpisodicRAG/docs/user/QUICKSTART.en.md

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -86,14 +86,14 @@ Created files:
8686

8787
Create a file with the following content:
8888

89-
**Filename**: `Loop0001_TestConversation.txt`
89+
**Filename**: `L00001_TestConversation.txt`
9090

9191
**Location**: `~/.claude/plugins/EpisodicRAG-Plugin@Plugins-Weave/data/Loops/`
9292

9393
**Content** (copy-paste ready):
9494

9595
```text
96-
# Loop0001: Test Conversation
96+
# L00001: Test Conversation
9797
9898
User: Hello, this is a test for EpisodicRAG.
9999
Assistant: Hello! This is a test for EpisodicRAG. How can I help you?
@@ -114,7 +114,7 @@ Assistant: EpisodicRAG is an 8-layer long-term memory system. It saves conversat
114114
```text
115115
Unprocessed Loop files detected: 1
116116
117-
- Loop0001_TestConversation.txt
117+
- L00001_TestConversation.txt
118118
119119
Starting analysis with DigestAnalyzer...
120120

EpisodicRAG/scripts/infrastructure/structured_logging.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@
2323
LOG_PREFIX_STATE,
2424
LOG_PREFIX_VALIDATE,
2525
)
26-
from infrastructure.logging_config import log_debug
26+
from infrastructure.logging_config import log_debug, log_info
2727

2828

2929
class StructuredLoggerProtocol(Protocol):
@@ -111,9 +111,9 @@ def info(self, message: str) -> None:
111111
112112
Example:
113113
logger.info("Processing started")
114-
# -> [DEBUG] Processing started
114+
# -> [INFO] Processing started
115115
"""
116-
log_debug(message)
116+
log_info(message)
117117

118118
def state(self, message: str, **context: Any) -> None:
119119
"""
Lines changed: 306 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,306 @@
1+
#!/usr/bin/env python3
2+
"""
3+
error_messages ユニットテスト
4+
=============================
5+
6+
config/error_messages.py のユニットテスト。
7+
各エラーメッセージ生成関数の動作を検証:
8+
- invalid_level_message
9+
- unknown_level_message
10+
- config_key_missing_message
11+
- config_invalid_value_message
12+
- config_section_missing_message
13+
- initialization_failed_message
14+
- file_not_found_message
15+
- invalid_json_message
16+
- directory_not_found_message
17+
"""
18+
19+
from pathlib import Path
20+
21+
import pytest
22+
23+
from config.error_messages import (
24+
config_invalid_value_message,
25+
config_key_missing_message,
26+
config_section_missing_message,
27+
directory_not_found_message,
28+
file_not_found_message,
29+
initialization_failed_message,
30+
invalid_json_message,
31+
invalid_level_message,
32+
unknown_level_message,
33+
)
34+
35+
36+
# =============================================================================
37+
# TestInvalidLevelMessage
38+
# =============================================================================
39+
40+
41+
class TestInvalidLevelMessage:
42+
"""invalid_level_messageのテスト"""
43+
44+
@pytest.mark.unit
45+
def test_without_valid_levels(self):
46+
"""有効レベルなしのメッセージ"""
47+
result = invalid_level_message("invalid_level")
48+
assert result == "Invalid level: 'invalid_level'"
49+
50+
@pytest.mark.unit
51+
def test_with_valid_levels(self):
52+
"""有効レベルありのメッセージ"""
53+
valid = ["weekly", "monthly", "annual"]
54+
result = invalid_level_message("bad", valid)
55+
assert "Invalid level: 'bad'" in result
56+
assert "weekly" in result
57+
assert "monthly" in result
58+
assert "annual" in result
59+
60+
@pytest.mark.unit
61+
def test_with_single_valid_level(self):
62+
"""単一の有効レベル"""
63+
result = invalid_level_message("bad", ["weekly"])
64+
assert "Invalid level: 'bad'" in result
65+
assert "weekly" in result
66+
67+
@pytest.mark.unit
68+
def test_with_empty_valid_levels(self):
69+
"""空の有効レベルリスト"""
70+
result = invalid_level_message("bad", [])
71+
# 空リストはFalsyなので、valid_levelsなしと同じ扱い
72+
assert result == "Invalid level: 'bad'"
73+
74+
@pytest.mark.unit
75+
def test_with_none_valid_levels(self):
76+
"""None の有効レベル"""
77+
result = invalid_level_message("bad", None)
78+
assert result == "Invalid level: 'bad'"
79+
80+
@pytest.mark.unit
81+
def test_special_characters_in_level(self):
82+
"""特殊文字を含むレベル名"""
83+
result = invalid_level_message("level<script>")
84+
assert "level<script>" in result
85+
86+
87+
# =============================================================================
88+
# TestUnknownLevelMessage
89+
# =============================================================================
90+
91+
92+
class TestUnknownLevelMessage:
93+
"""unknown_level_messageのテスト"""
94+
95+
@pytest.mark.unit
96+
def test_basic_message(self):
97+
"""基本的なメッセージ"""
98+
result = unknown_level_message("unknown")
99+
assert result == "Unknown level: 'unknown'"
100+
101+
@pytest.mark.unit
102+
def test_empty_level(self):
103+
"""空のレベル名"""
104+
result = unknown_level_message("")
105+
assert result == "Unknown level: ''"
106+
107+
@pytest.mark.unit
108+
def test_level_with_spaces(self):
109+
"""スペースを含むレベル名"""
110+
result = unknown_level_message("weekly level")
111+
assert "weekly level" in result
112+
113+
114+
# =============================================================================
115+
# TestConfigKeyMissingMessage
116+
# =============================================================================
117+
118+
119+
class TestConfigKeyMissingMessage:
120+
"""config_key_missing_messageのテスト"""
121+
122+
@pytest.mark.unit
123+
def test_basic_message(self):
124+
"""基本的なメッセージ"""
125+
result = config_key_missing_message("loops_path")
126+
assert result == "Required configuration key missing: 'loops_path'"
127+
128+
@pytest.mark.unit
129+
def test_nested_key(self):
130+
"""ネストされたキー名"""
131+
result = config_key_missing_message("paths.loops_dir")
132+
assert "paths.loops_dir" in result
133+
134+
135+
# =============================================================================
136+
# TestConfigInvalidValueMessage
137+
# =============================================================================
138+
139+
140+
class TestConfigInvalidValueMessage:
141+
"""config_invalid_value_messageのテスト"""
142+
143+
@pytest.mark.unit
144+
def test_with_string_value(self):
145+
"""文字列値の場合"""
146+
result = config_invalid_value_message("threshold", "int", "five")
147+
assert "threshold" in result
148+
assert "expected int" in result
149+
assert "str" in result
150+
151+
@pytest.mark.unit
152+
def test_with_int_value(self):
153+
"""整数値の場合"""
154+
result = config_invalid_value_message("path", "str", 123)
155+
assert "path" in result
156+
assert "expected str" in result
157+
assert "int" in result
158+
159+
@pytest.mark.unit
160+
def test_with_list_value(self):
161+
"""リスト値の場合"""
162+
result = config_invalid_value_message("count", "int", [1, 2, 3])
163+
assert "count" in result
164+
assert "list" in result
165+
166+
@pytest.mark.unit
167+
def test_with_none_value(self):
168+
"""None値の場合"""
169+
result = config_invalid_value_message("required", "str", None)
170+
assert "required" in result
171+
assert "NoneType" in result
172+
173+
174+
# =============================================================================
175+
# TestConfigSectionMissingMessage
176+
# =============================================================================
177+
178+
179+
class TestConfigSectionMissingMessage:
180+
"""config_section_missing_messageのテスト"""
181+
182+
@pytest.mark.unit
183+
def test_basic_message(self):
184+
"""基本的なメッセージ"""
185+
result = config_section_missing_message("paths")
186+
assert result == "'paths' section missing in config.json"
187+
188+
@pytest.mark.unit
189+
def test_levels_section(self):
190+
"""levelsセクション"""
191+
result = config_section_missing_message("levels")
192+
assert "'levels' section missing" in result
193+
194+
195+
# =============================================================================
196+
# TestInitializationFailedMessage
197+
# =============================================================================
198+
199+
200+
class TestInitializationFailedMessage:
201+
"""initialization_failed_messageのテスト"""
202+
203+
@pytest.mark.unit
204+
def test_with_value_error(self):
205+
"""ValueError の場合"""
206+
error = ValueError("invalid value")
207+
result = initialization_failed_message("ConfigLoader", error)
208+
assert "Failed to initialize ConfigLoader" in result
209+
assert "invalid value" in result
210+
211+
@pytest.mark.unit
212+
def test_with_file_not_found_error(self):
213+
"""FileNotFoundError の場合"""
214+
error = FileNotFoundError("config.json not found")
215+
result = initialization_failed_message("DigestConfig", error)
216+
assert "Failed to initialize DigestConfig" in result
217+
assert "config.json not found" in result
218+
219+
@pytest.mark.unit
220+
def test_with_generic_exception(self):
221+
"""一般的なException"""
222+
error = Exception("unknown error")
223+
result = initialization_failed_message("Component", error)
224+
assert "Failed to initialize Component" in result
225+
226+
227+
# =============================================================================
228+
# TestFileNotFoundMessage
229+
# =============================================================================
230+
231+
232+
class TestFileNotFoundMessage:
233+
"""file_not_found_messageのテスト"""
234+
235+
@pytest.mark.unit
236+
def test_with_path_object(self):
237+
"""Pathオブジェクトの場合"""
238+
path = Path("/tmp/missing.json")
239+
result = file_not_found_message(path)
240+
assert "File not found:" in result
241+
assert "missing.json" in result
242+
243+
@pytest.mark.unit
244+
def test_with_relative_path(self):
245+
"""相対パスの場合"""
246+
path = Path("config/config.json")
247+
result = file_not_found_message(path)
248+
assert "config.json" in result
249+
250+
@pytest.mark.unit
251+
def test_with_windows_path(self):
252+
"""Windowsパスの場合"""
253+
path = Path("C:/Users/test/file.json")
254+
result = file_not_found_message(path)
255+
assert "file.json" in result
256+
257+
258+
# =============================================================================
259+
# TestInvalidJsonMessage
260+
# =============================================================================
261+
262+
263+
class TestInvalidJsonMessage:
264+
"""invalid_json_messageのテスト"""
265+
266+
@pytest.mark.unit
267+
def test_with_decode_error(self):
268+
"""デコードエラーの場合"""
269+
path = Path("/tmp/bad.json")
270+
error = ValueError("Expecting property name enclosed in double quotes")
271+
result = invalid_json_message(path, error)
272+
assert "Invalid JSON" in result
273+
assert "bad.json" in result
274+
assert "double quotes" in result
275+
276+
@pytest.mark.unit
277+
def test_path_included_in_message(self):
278+
"""パスがメッセージに含まれる"""
279+
path = Path("/data/config.json")
280+
error = Exception("parse error")
281+
result = invalid_json_message(path, error)
282+
assert "config.json" in result
283+
284+
285+
# =============================================================================
286+
# TestDirectoryNotFoundMessage
287+
# =============================================================================
288+
289+
290+
class TestDirectoryNotFoundMessage:
291+
"""directory_not_found_messageのテスト"""
292+
293+
@pytest.mark.unit
294+
def test_basic_message(self):
295+
"""基本的なメッセージ"""
296+
path = Path("/tmp/missing_dir")
297+
result = directory_not_found_message(path)
298+
assert "Directory not found:" in result
299+
assert "missing_dir" in result
300+
301+
@pytest.mark.unit
302+
def test_with_nested_path(self):
303+
"""ネストされたパス"""
304+
path = Path("/data/Digests/1_Weekly")
305+
result = directory_not_found_message(path)
306+
assert "1_Weekly" in result

0 commit comments

Comments
 (0)