"""Tests para fetch_hackernews_search. El parser (_parse_hits) se testea con un fixture offline. La funcion completa fetch_hackernews_search hace red real; aqui solo validamos el shape del parser para no depender de conectividad en CI. """ import sys import os sys.path.insert(0, os.path.dirname(__file__)) from fetch_hackernews_search import _parse_hits _FIXTURE_HITS = [ { "objectID": "39000000", "title": "Show HN: a tool to dedupe CSVs", "story_text": "I wish there was a better way", "url": "https://example.com/tool", "author": "hnuser", "created_at_i": 1700000000, "points": 120, }, { "objectID": "39000001", "title": "Ask HN: alternative to X?", "comment_text": "Looking for a tool that does Y", "url": None, "author": "asker", "created_at_i": 1700001234, "points": None, }, ] _EXPECTED_KEYS = { "source", "platform_id", "title", "body", "url", "author", "channel", "created_utc", "platform_score", "query", } def test_parser_normaliza_hits_al_shape_exacto(): rows = _parse_hits(_FIXTURE_HITS, "csv dedupe") assert len(rows) == 2 r = rows[0] assert set(r.keys()) == _EXPECTED_KEYS assert r["source"] == "hackernews" assert r["platform_id"] == "39000000" assert r["title"] == "Show HN: a tool to dedupe CSVs" assert r["body"] == "I wish there was a better way" assert r["url"] == "https://example.com/tool" assert r["author"] == "hnuser" assert r["channel"] == "hn" assert r["created_utc"] == 1700000000.0 assert isinstance(r["created_utc"], float) assert r["platform_score"] == 120 assert isinstance(r["platform_score"], int) assert r["query"] == "csv dedupe" def test_hit_sin_url_externa_cae_a_news_ycombinator_item_link(): rows = _parse_hits(_FIXTURE_HITS, "q") assert rows[1]["url"] == "https://news.ycombinator.com/item?id=39000001" # body cae a comment_text cuando no hay story_text assert rows[1]["body"] == "Looking for a tool that does Y" def test_points_none_se_mapea_a_0(): rows = _parse_hits(_FIXTURE_HITS, "q") assert rows[1]["platform_score"] == 0 def test_hits_vacio_devuelve_lista_vacia(): assert _parse_hits([], "q") == [] if __name__ == "__main__": test_parser_normaliza_hits_al_shape_exacto() test_hit_sin_url_externa_cae_a_news_ycombinator_item_link() test_points_none_se_mapea_a_0() test_hits_vacio_devuelve_lista_vacia() print("All tests passed.")