返回 last30days-skill
test_reddit_dedicated.py
根目录 / tests / test_reddit_dedicated.py
1 """Tests for the dedicated-subreddit lane in reddit_keyless (U1).
2
3 A dedicated subreddit (the entity's home, e.g. r/Kanye for "Kanye West") is
4 wholly on-topic: pulled in full via top+hot+new listings and exempt from the
5 relevance floor, so an on-topic post whose title lacks the entity name is kept.
6 """
7
8 from unittest import mock
9
10 from lib import reddit_keyless
11
12
13 def _post(i, date="2026-05-20", rel=0.0):
14 url = f"https://www.reddit.com/r/test/comments/{i:06d}/post_{i}/"
15 return {
16 "id": "", "title": f"Post {i}", "url": url, "score": 0, "num_comments": 0,
17 "subreddit": "test", "created_utc": None, "author": "u", "selftext": "",
18 "date": date, "engagement": {"score": 0, "num_comments": 0, "upvote_ratio": None},
19 "relevance": rel, "why_relevant": "Reddit RSS", "metadata": {},
20 }
21
22
23 def _listing_post(i, score, title, rel=0.0):
24 p = _post(i, rel=rel)
25 p["title"] = title
26 p["score"] = score
27 p["engagement"]["score"] = score
28 p["why_relevant"] = "Reddit listing"
29 p["metadata"] = {"post_id": f"{i:06d}"}
30 return p
31
32
33 def _no_enrich():
34 return mock.patch.object(
35 reddit_keyless.reddit_shreddit, "fetch_comments",
36 return_value={"top_comments": [], "comment_insights": [], "num_comments": None},
37 )
38
39
40 class TestDedicatedLane:
41 def test_dedicated_listings_pulled_with_top_hot_new_and_marked(self):
42 ded = _listing_post(1, 2643, "What the actual fuck is this ye?")
43 captured = {}
44
45 def fake_fetch(subs, depth="default", query="", sorts=None):
46 if sorts == reddit_keyless.DEDICATED_SORTS:
47 captured["sorts"] = sorts
48 captured["subs"] = subs
49 return [ded]
50 return []
51
52 with mock.patch.object(reddit_keyless.reddit_listing, "fetch_listings",
53 side_effect=fake_fetch), \
54 mock.patch.object(reddit_keyless.reddit_rss, "search_rss", return_value=[]):
55 out = reddit_keyless._discover("Kanye West", "default", None,
56 dedicated_subreddits=["Kanye"])
57 assert captured["sorts"] == ["top", "hot", "new"]
58 assert captured["subs"] == ["Kanye"]
59 assert len(out) == 1
60 assert out[0]["dedicated"] is True
61
62 def test_dedicated_post_survives_floor_without_entity_name(self):
63 # On-topic dedicated post whose title lacks "Kanye" (relevance 0) must be
64 # kept; off-topic non-dedicated posts (relevance 0) are floored out.
65 ded = _listing_post(1, 2284, "There's 2 types of people", rel=0.0)
66 ded["dedicated"] = True
67 offtopic = [_post(10 + i, rel=0.0) for i in range(5)]
68 with mock.patch.object(reddit_keyless, "_discover", return_value=[ded] + offtopic), \
69 _no_enrich():
70 out = reddit_keyless.search_and_enrich("Kanye West", "2026-05-01", "2026-05-31")
71 urls = {p["url"] for p in out}
72 assert ded["url"] in urls # dedicated kept despite relevance 0
73 assert all(o["url"] not in urls for o in offtopic) # off-topic floored
74
75 def test_dedicated_dedup_keeps_floor_exempt_status(self):
76 # A thread present in both the dedicated lane and a broad listing keeps
77 # its dedicated (floor-exempt) flag — dedicated is merged first.
78 shared_ded = _listing_post(1, 500, "fresh thread", rel=0.0)
79 shared_broad = _listing_post(1, 500, "fresh thread", rel=0.0) # same url/id
80
81 def fake_fetch(subs, depth="default", query="", sorts=None):
82 return [shared_ded] if sorts == reddit_keyless.DEDICATED_SORTS else [shared_broad]
83
84 with mock.patch.object(reddit_keyless.reddit_listing, "fetch_listings",
85 side_effect=fake_fetch), \
86 mock.patch.object(reddit_keyless.reddit_rss, "search_rss", return_value=[]):
87 out = reddit_keyless._discover("Kanye West", "default", ["hiphopheads"],
88 dedicated_subreddits=["Kanye"])
89 same = [p for p in out if p["url"] == shared_ded["url"]]
90 assert len(same) == 1
91 assert same[0].get("dedicated") is True
92
93 def test_no_dedicated_subs_is_noop(self):
94 with mock.patch.object(reddit_keyless.reddit_rss, "search_rss",
95 return_value=[_post(1)]), \
96 mock.patch.object(reddit_keyless.reddit_listing, "fetch_listings",
97 return_value=[]):
98 out = reddit_keyless._discover("topic", "default", ["test"])
99 assert all(not p.get("dedicated") for p in out)
100
100 lines PYTHON