import json import pytest from unittest.mock import AsyncMock, MagicMock from app.screener.ai_news import analyzer def _mk_llm(content_text: str, in_tokens: int = 100, out_tokens: int = 20): llm = AsyncMock() resp = MagicMock() block = MagicMock() block.text = content_text resp.content = [block] resp.usage = MagicMock(input_tokens=in_tokens, output_tokens=out_tokens) llm.messages = MagicMock() llm.messages.create = AsyncMock(return_value=resp) return llm NEWS = [ {"title": "삼성전자, HBM 양산", "summary": "1분기 영업이익 사상 최대", "pub_date": "2026-05-14"}, {"title": "메모리 가격 반등", "summary": "", "pub_date": "2026-05-14"}, ] @pytest.mark.asyncio async def test_score_sentiment_success_parses_json(): llm = _mk_llm(json.dumps({"score": 7.5, "reason": "HBM 호재"})) out = await analyzer.score_sentiment(llm, "005930", NEWS, name="삼성전자") assert out["ticker"] == "005930" assert out["score_raw"] == 7.5 assert out["reason"] == "HBM 호재" assert out["news_count"] == 2 assert out["tokens_input"] == 100 assert out["tokens_output"] == 20 @pytest.mark.asyncio async def test_score_sentiment_json_parse_fail_returns_zero(): llm = _mk_llm("not valid json") out = await analyzer.score_sentiment(llm, "005930", NEWS) assert out["score_raw"] == 0.0 assert "parse fail" in out["reason"] assert out["tokens_input"] == 100 # 호출은 발생했음 @pytest.mark.asyncio async def test_score_sentiment_clamps_out_of_range(): llm = _mk_llm(json.dumps({"score": 15.0, "reason": "초강세"})) out = await analyzer.score_sentiment(llm, "005930", NEWS) assert out["score_raw"] == 10.0 # +10 클램프 @pytest.mark.asyncio async def test_score_sentiment_clamps_negative_out_of_range(): llm = _mk_llm(json.dumps({"score": -42.0, "reason": "초악재"})) out = await analyzer.score_sentiment(llm, "005930", NEWS) assert out["score_raw"] == -10.0 @pytest.mark.asyncio async def test_score_sentiment_includes_summary_in_prompt(): """summary 가 있으면 prompt 에 포함, 없으면 title 만.""" llm = _mk_llm(json.dumps({"score": 5.0, "reason": "ok"})) await analyzer.score_sentiment(llm, "005930", NEWS, name="삼성전자") call = llm.messages.create.call_args user_msg = call.kwargs["messages"][0]["content"] assert "1분기 영업이익 사상 최대" in user_msg # summary 포함 assert "삼성전자, HBM 양산" in user_msg # title 포함 assert "2026-05-14" in user_msg # pub_date 포함