"No","テストID","対象クラス","対象メソッド","テスト観点","テストケース名","前提条件","入力値","期待結果","優先度","備考"
"1","UT-EMC-001","Concerns::CaptainToolsHelpers","built_in_agent_tools","正常系","組み込みエージェントツール一覧が取得できること","tools.ymlに有効なツール設定が存在する","なし","ツール情報（id, title, description, icon）を含むハッシュ配列が返却される","高","クラスメソッド、メモ化あり"
"2","UT-EMC-002","Concerns::CaptainToolsHelpers","built_in_agent_tools","正常系","結果がメモ化されること","初回呼び出し完了済み","なし","2回目以降は同じインスタンスが返却される","中","@built_in_agent_toolsインスタンス変数"
"3","UT-EMC-003","Concerns::CaptainToolsHelpers","built_in_agent_tools","異常系","解決できないツールがフィルタリングされること","tools.ymlに存在しないクラスのツールが定義されている","なし","解決できないツールは除外され、警告ログが出力される","中","filter_mapによるnil除外"
"4","UT-EMC-004","Concerns::CaptainToolsHelpers","resolve_tool_class","正常系","スネークケースのIDからツールクラスが解決できること","Captain::Tools::SomeToolが存在する","tool_id=""some""","Captain::Tools::SomeToolクラスが返却される","高","classifyメソッドでPascalCase変換"
"5","UT-EMC-005","Concerns::CaptainToolsHelpers","resolve_tool_class","異常系","存在しないツールIDの場合nilが返却されること","対応するクラスが存在しない","tool_id=""nonexistent""","nilが返却される","高","safe_constantizeによる安全な解決"
"6","UT-EMC-006","Concerns::CaptainToolsHelpers","resolve_tool_class","正常系","アンダースコア区切りのIDが正しく解決されること","Captain::Tools::MyCustomToolが存在する","tool_id=""my_custom""","Captain::Tools::MyCustomToolクラスが返却される","中","複合語のID処理"
"7","UT-EMC-007","Concerns::CaptainToolsHelpers","built_in_tool_ids","正常系","組み込みツールIDの配列が取得できること","built_in_agent_toolsが正常に動作する","なし","ツールIDの文字列配列が返却される","中","クラスメソッド"
"8","UT-EMC-008","Concerns::CaptainToolsHelpers","built_in_tool_ids","正常系","結果がメモ化されること","初回呼び出し完了済み","なし","2回目以降は同じインスタンスが返却される","低","@built_in_tool_idsインスタンス変数"
"9","UT-EMC-009","Concerns::CaptainToolsHelpers","extract_tool_ids_from_text","正常系","テキストからツールIDが抽出できること","なし","text=""[Tool](tool://my_tool)""","[""my_tool""]が返却される","高","TOOL_REFERENCE_REGEX使用"
"10","UT-EMC-010","Concerns::CaptainToolsHelpers","extract_tool_ids_from_text","正常系","複数のツール参照が抽出できること","なし","text=""[A](tool://t1) [B](tool://t2)""","[""t1"", ""t2""]が返却される","高","複数マッチ処理"
"11","UT-EMC-011","Concerns::CaptainToolsHelpers","extract_tool_ids_from_text","正常系","重複するツールIDが一意化されること","なし","text=""[A](tool://t1) [B](tool://t1)""","[""t1""]が返却される","中","uniqメソッド"
"12","UT-EMC-012","Concerns::CaptainToolsHelpers","extract_tool_ids_from_text","境界値","空文字列の場合は空配列が返却されること","なし","text=""""","[]が返却される","中","blank?チェック"
"13","UT-EMC-013","Concerns::CaptainToolsHelpers","extract_tool_ids_from_text","境界値","nilの場合は空配列が返却されること","なし","text=nil","[]が返却される","中","blank?チェック"
"14","UT-EMC-014","Concerns::CaptainToolsHelpers","extract_tool_ids_from_text","正常系","ツール参照がないテキストの場合は空配列が返却されること","なし","text=""Hello World""","[]が返却される","中","マッチなしケース"
"15","UT-EMC-015","Concerns::SafeEndpointValidatable","validate_safe_endpoint_url","正常系","有効なHTTPS URLがバリデーションを通過すること","なし","endpoint_url=""https://example.com/api""","エラーなし","高","正常系バリデーション"
"16","UT-EMC-016","Concerns::SafeEndpointValidatable","validate_safe_endpoint_url","異常系","HTTP URLがバリデーションエラーになること","なし","endpoint_url=""http://example.com/api""","endpoint_url: must use HTTPS protocol","高","スキーム検証"
"17","UT-EMC-017","Concerns::SafeEndpointValidatable","validate_safe_endpoint_url","異常系","localhostがバリデーションエラーになること","なし","endpoint_url=""https://localhost/api""","endpoint_url: cannot use disallowed hostname","高","禁止ホスト検証"
"18","UT-EMC-018","Concerns::SafeEndpointValidatable","validate_safe_endpoint_url","異常系",".localドメインがバリデーションエラーになること","なし","endpoint_url=""https://server.local/api""","endpoint_url: cannot use disallowed hostname","高","正規表現パターン検証"
"19","UT-EMC-019","Concerns::SafeEndpointValidatable","validate_safe_endpoint_url","異常系","FRONTEND_URLと同じホストがバリデーションエラーになること","FRONTEND_URL=http://myapp.comが設定されている","endpoint_url=""https://myapp.com/api""","endpoint_url: cannot point to the application itself","高","自己参照防止"
"20","UT-EMC-020","Concerns::SafeEndpointValidatable","validate_safe_endpoint_url","異常系","IPv4アドレスがバリデーションエラーになること","なし","endpoint_url=""https://192.168.1.1/api""","endpoint_url: cannot be an IP address, must be a hostname","高","IPアドレス検証"
"21","UT-EMC-021","Concerns::SafeEndpointValidatable","validate_safe_endpoint_url","異常系","IPv6アドレスがバリデーションエラーになること","なし","endpoint_url=""https://[::1]/api""","endpoint_url: cannot be an IP address, must be a hostname","高","IPv6検証"
"22","UT-EMC-022","Concerns::SafeEndpointValidatable","validate_safe_endpoint_url","異常系","Unicodeホスト名がバリデーションエラーになること","なし","endpoint_url=""https://exаmple.com/api""（キリル文字のa）","endpoint_url: hostname cannot contain non-ASCII characters","高","ホモグリフ攻撃対策"
"23","UT-EMC-023","Concerns::SafeEndpointValidatable","validate_safe_endpoint_url","境界値","空のendpoint_urlはバリデーションをスキップすること","なし","endpoint_url=""""","エラーなし","中","blank?による早期リターン"
"24","UT-EMC-024","Concerns::SafeEndpointValidatable","validate_safe_endpoint_url","異常系","不正なURL形式がバリデーションエラーになること","なし","endpoint_url=""not-a-url""","endpoint_url: must be a valid URL","中","URI.parseエラー"
"25","UT-EMC-025","Concerns::SafeEndpointValidatable","parse_endpoint_uri","正常系","Liquid変数を含むURLが正しくパースされること","なし","endpoint_url=""https://api.com/{{id}}""","Liquid変数がplaceholderに置換されてパースされる","中","Liquidテンプレート対応"
"26","UT-EMC-026","Concerns::SafeEndpointValidatable","parse_endpoint_uri","異常系","不正なURLでnilが返却されること","なし","endpoint_url="":::invalid:::""","nilが返却される","中","URI::InvalidURIError処理"
"27","UT-EMC-027","Concerns::SafeEndpointValidatable","validate_endpoint_host","異常系","ホスト名がない場合エラーになること","なし","endpoint_url=""https:///path""","endpoint_url: must have a valid hostname","中","空ホスト検証"
"28","UT-EMC-028","Concerns::Agentable","agent","正常系","Agents::Agentインスタンスが正しく生成されること","agent_nameとprompt_contextが実装されている","なし","適切な設定でAgents::Agentが生成される","高","メインメソッド"
"29","UT-EMC-029","Concerns::Agentable","agent","正常系","temperatureが正しく設定されること","temperature=0.5が設定されている","なし","temperature: 0.5でAgentが生成される","中","to_f変換"
"30","UT-EMC-030","Concerns::Agentable","agent","正常系","temperatureが未設定の場合デフォルト値が使用されること","temperatureが未設定","なし","temperature: 0.7でAgentが生成される","中","デフォルト値フォールバック"
"31","UT-EMC-031","Concerns::Agentable","agent_instructions","正常系","コンテキストなしでプロンプトがレンダリングされること","prompt_contextが実装されている","context=nil","prompt_contextのみでレンダリングされる","高","基本レンダリング"
"32","UT-EMC-032","Concerns::Agentable","agent_instructions","正常系","コンテキストありでプロンプトがレンダリングされること","prompt_contextが実装されている","context=conversation/contactデータ付き","conversation/contactデータがマージされてレンダリングされる","高","拡張コンテキスト"
"33","UT-EMC-033","Concerns::Agentable","agent_name","異常系","未実装の場合NotImplementedErrorがスローされること","サブクラスで未実装","なし","NotImplementedErrorがスローされる","高","抽象メソッド"
"34","UT-EMC-034","Concerns::Agentable","template_name","正常系","クラス名からテンプレート名が生成されること","MyCustomAgentクラスに適用","なし","""my_custom_agent""が返却される","中","demodulize.underscore"
"35","UT-EMC-035","Concerns::Agentable","agent_tools","正常系","デフォルトで空配列が返却されること","オーバーライドなし","なし","[]が返却される","低","デフォルト実装"
"36","UT-EMC-036","Concerns::Agentable","agent_model","正常系","InstallationConfigからモデル名が取得されること","CAPTAIN_OPEN_AI_MODELが設定されている","なし","設定されたモデル名が返却される","中","設定値取得"
"37","UT-EMC-037","Concerns::Agentable","agent_model","正常系","設定がない場合デフォルトモデルが使用されること","CAPTAIN_OPEN_AI_MODELが未設定","なし","LlmConstants::DEFAULT_MODELが返却される","中","デフォルトフォールバック"
"38","UT-EMC-038","Concerns::Agentable","prompt_context","異常系","未実装の場合NotImplementedErrorがスローされること","サブクラスで未実装","なし","NotImplementedErrorがスローされる","高","抽象メソッド"
"39","UT-EMC-039","Concerns::Toolable","tool","正常系","動的にツールクラスが生成されること","slug, description, param_schemaが設定されている","assistant=有効なアシスタント","Captain::Tools::HttpToolを継承したクラスが生成される","高","動的クラス生成"
"40","UT-EMC-040","Concerns::Toolable","tool","正常系","パラメータスキーマが正しく設定されること","param_schema=[{name: ""query"", type: ""string"", ...}]","assistant=有効なアシスタント","queryパラメータが設定されたツールが生成される","高","paramメソッド呼び出し"
"41","UT-EMC-041","Concerns::Toolable","tool","正常系","既存の定数が更新されること","同じslugで2回目の呼び出し","assistant=有効なアシスタント","既存の定数が削除され、新しいクラスで置換される","中","remove_const処理"
"42","UT-EMC-042","Concerns::Toolable","build_request_url","正常系","Liquid変数がパラメータで置換されること","endpoint_url=""https://api.com/{{id}}""","params={id: ""123""}","https://api.com/123が返却される","高","テンプレートレンダリング"
"43","UT-EMC-043","Concerns::Toolable","build_request_url","正常系","変数がないURLはそのまま返却されること","endpoint_url=""https://api.com/static""","params={}","https://api.com/staticが返却される","中","早期リターン"
"44","UT-EMC-044","Concerns::Toolable","build_request_url","境界値","空のURLはそのまま返却されること","endpoint_url=""""","params={}","""""が返却される","低","blank?チェック"
"45","UT-EMC-045","Concerns::Toolable","build_request_body","正常系","リクエストテンプレートがレンダリングされること","request_template=""{\"\"query\"\": \"\"{{q}}\"\"}""","params={q: ""test""}","JSONボディが生成される","高","テンプレートレンダリング"
"46","UT-EMC-046","Concerns::Toolable","build_request_body","境界値","テンプレートが空の場合nilが返却されること","request_template=""""","params={}","nilが返却される","中","blank?チェック"
"47","UT-EMC-047","Concerns::Toolable","build_auth_headers","正常系","Bearer認証ヘッダーが生成されること","auth_type=""bearer"", auth_config={token: ""abc123""}","なし","{""Authorization"": ""Bearer abc123""}が返却される","高","Bearer認証"
"48","UT-EMC-048","Concerns::Toolable","build_auth_headers","正常系","APIキー（ヘッダー）認証が生成されること","auth_type=""api_key"", auth_config={location: ""header"", name: ""X-API-Key"", key: ""secret""}","なし","{""X-API-Key"": ""secret""}が返却される","高","APIキー認証"
"49","UT-EMC-049","Concerns::Toolable","build_auth_headers","正常系","認証なしの場合は空ハッシュが返却されること","auth_type=""none""またはauth_none?=true","なし","{}が返却される","中","認証なしケース"
"50","UT-EMC-050","Concerns::Toolable","build_auth_headers","正常系","APIキー（非ヘッダー）の場合は空ハッシュが返却されること","auth_type=""api_key"", auth_config={location: ""query""}","なし","{}が返却される","中","クエリパラメータ認証"
"51","UT-EMC-051","Concerns::Toolable","build_basic_auth_credentials","正常系","Basic認証情報が返却されること","auth_type=""basic"", auth_config={username: ""user"", password: ""pass""}","なし","[""user"", ""pass""]が返却される","高","Basic認証"
"52","UT-EMC-052","Concerns::Toolable","build_basic_auth_credentials","正常系","Basic認証以外の場合はnilが返却されること","auth_type=""bearer""","なし","nilが返却される","中","認証タイプチェック"
"53","UT-EMC-053","Concerns::Toolable","build_metadata_headers","正常系","基本メタデータヘッダーが生成されること","slug=""my-tool""","state={account_id: 1, assistant_id: 2}","X-Chatwoot-Account-Id, X-Chatwoot-Assistant-Id, X-Chatwoot-Tool-Slugが設定される","高","メタデータヘッダー"
"54","UT-EMC-054","Concerns::Toolable","build_metadata_headers","正常系","会話メタデータヘッダーが追加されること","なし","state={conversation: {id: 10, display_id: 20}}","X-Chatwoot-Conversation-Id, X-Chatwoot-Conversation-Display-Idが設定される","中","会話ヘッダー"
"55","UT-EMC-055","Concerns::Toolable","build_metadata_headers","正常系","連絡先メタデータヘッダーが追加されること","なし","state={contact: {id: 5, email: ""a@b.com"", phone_number: ""+1234""}}","X-Chatwoot-Contact-Id, X-Chatwoot-Contact-Email, X-Chatwoot-Contact-Phoneが設定される","中","連絡先ヘッダー"
"56","UT-EMC-056","Concerns::Toolable","format_response","正常系","レスポンステンプレートがレンダリングされること","response_template=""Result: {{response.data}}""","raw_response_body=""{\"\"data\"\": \"\"value\"\"}""","""Result: value""が返却される","高","レスポンスフォーマット"
"57","UT-EMC-057","Concerns::Toolable","format_response","正常系","テンプレートがない場合は生のレスポンスが返却されること","response_template=""""","raw_response_body=""raw data""","""raw data""が返却される","中","早期リターン"
"58","UT-EMC-058","Concerns::Toolable","render_template","異常系","Liquid構文エラーで例外がスローされること","なし","template=""{% invalid %}""","例外がスローされ、エラーログが出力される","高","Liquid::SyntaxError処理"
"59","UT-EMC-059","Concerns::Toolable","render_template","異常系","未定義変数で例外がスローされること","strict_variables=true","template=""{{undefined_var}}""","例外がスローされる","中","Liquid::UndefinedVariable処理"
"60","UT-EMC-060","Concerns::Toolable","parse_response_body","正常系","有効なJSONがパースされること","なし","body=""{\"\"key\"\": \"\"value\"\"}""","{""key"": ""value""}ハッシュが返却される","中","JSONパース"
"61","UT-EMC-061","Concerns::Toolable","parse_response_body","正常系","無効なJSONは文字列のまま返却されること","なし","body=""not json""","""not json""がそのまま返却される","中","JSON::ParserError処理"
