import datetime as dt import pandas as pd import pytest from app.screener.nodes.ai_news import AiNewsSentiment class FakeCtx: def __init__(self, df=None): self.news_sentiment = df self.asof = dt.date(2026, 5, 13) def test_compute_empty_context(): out = AiNewsSentiment().compute(FakeCtx(None), {"min_news_count": 1}) assert out.empty def test_compute_with_data_percentile_ranks(): df = pd.DataFrame([ {"ticker": "A", "score_raw": -5.0, "news_count": 3}, {"ticker": "B", "score_raw": 0.0, "news_count": 3}, {"ticker": "C", "score_raw": 8.0, "news_count": 3}, ]) out = AiNewsSentiment().compute(FakeCtx(df), {"min_news_count": 1}) assert len(out) == 3 # percentile rank: A (lowest) < B < C (highest) assert out.loc["A"] < out.loc["B"] < out.loc["C"] # all within [0, 100] assert (out >= 0).all() and (out <= 100).all() def test_compute_filters_by_min_news_count(): df = pd.DataFrame([ {"ticker": "A", "score_raw": -5.0, "news_count": 0}, # 필터됨 {"ticker": "B", "score_raw": 0.0, "news_count": 2}, {"ticker": "C", "score_raw": 8.0, "news_count": 5}, ]) out = AiNewsSentiment().compute(FakeCtx(df), {"min_news_count": 1}) assert "A" not in out.index assert "B" in out.index assert "C" in out.index def test_compute_all_filtered_returns_empty(): df = pd.DataFrame([ {"ticker": "A", "score_raw": 5.0, "news_count": 0}, ]) out = AiNewsSentiment().compute(FakeCtx(df), {"min_news_count": 1}) assert out.empty def test_metadata(): n = AiNewsSentiment() assert n.name == "ai_news" assert "AI" in n.label or "뉴스" in n.label assert n.default_params == {"min_news_count": 1} assert "min_news_count" in n.param_schema["properties"]