| 1 | """Tests for reddit_enrich.py — comment enrichment and parsing.""" |
| 2 | |
| 3 | import json |
| 4 | import unittest |
| 5 | from pathlib import Path |
| 6 | |
| 7 | # Add lib to path |
| 8 | |
| 9 | from lib import reddit_enrich |
| 10 | |
| 11 | FIXTURES_DIR = Path(__file__).parent.parent / "fixtures" |
| 12 | |
| 13 | |
| 14 | def _load_fixture(name): |
| 15 | with open(FIXTURES_DIR / name) as f: |
| 16 | return json.load(f) |
| 17 | |
| 18 | |
| 19 | class TestExtractRedditPath(unittest.TestCase): |
| 20 | """Tests for extract_reddit_path().""" |
| 21 | |
| 22 | def test_valid_url(self): |
| 23 | url = "https://www.reddit.com/r/ClaudeAI/comments/abc123/post_title/" |
| 24 | path = reddit_enrich.extract_reddit_path(url) |
| 25 | self.assertEqual(path, "/r/ClaudeAI/comments/abc123/post_title/") |
| 26 | |
| 27 | def test_non_reddit_url(self): |
| 28 | self.assertIsNone(reddit_enrich.extract_reddit_path("https://example.com/foo")) |
| 29 | |
| 30 | def test_empty_string(self): |
| 31 | self.assertIsNone(reddit_enrich.extract_reddit_path("")) |
| 32 | |
| 33 | def test_old_reddit(self): |
| 34 | url = "https://old.reddit.com/r/test/comments/xyz/" |
| 35 | self.assertIsNotNone(reddit_enrich.extract_reddit_path(url)) |
| 36 | |
| 37 | |
| 38 | class TestParseThreadData(unittest.TestCase): |
| 39 | """Tests for parse_thread_data() using fixture.""" |
| 40 | |
| 41 | def test_parses_submission(self): |
| 42 | data = _load_fixture("reddit_thread_sample.json") |
| 43 | result = reddit_enrich.parse_thread_data(data) |
| 44 | self.assertIsNotNone(result["submission"]) |
| 45 | self.assertEqual(result["submission"]["score"], 847) |
| 46 | self.assertEqual(result["submission"]["num_comments"], 156) |
| 47 | |
| 48 | def test_parses_comments(self): |
| 49 | data = _load_fixture("reddit_thread_sample.json") |
| 50 | result = reddit_enrich.parse_thread_data(data) |
| 51 | self.assertEqual(len(result["comments"]), 8) |
| 52 | self.assertEqual(result["comments"][0]["author"], "skill_expert") |
| 53 | |
| 54 | def test_empty_input(self): |
| 55 | result = reddit_enrich.parse_thread_data([]) |
| 56 | self.assertIsNone(result["submission"]) |
| 57 | self.assertEqual(result["comments"], []) |
| 58 | |
| 59 | def test_malformed_input(self): |
| 60 | result = reddit_enrich.parse_thread_data("not a list") |
| 61 | self.assertIsNone(result["submission"]) |
| 62 | |
| 63 | def test_none_input(self): |
| 64 | result = reddit_enrich.parse_thread_data(None) |
| 65 | self.assertIsNone(result["submission"]) |
| 66 | |
| 67 | |
| 68 | class TestGetTopComments(unittest.TestCase): |
| 69 | """Tests for get_top_comments().""" |
| 70 | |
| 71 | def test_sorted_by_score(self): |
| 72 | comments = [ |
| 73 | {"score": 10, "author": "a"}, |
| 74 | {"score": 100, "author": "b"}, |
| 75 | {"score": 50, "author": "c"}, |
| 76 | ] |
| 77 | top = reddit_enrich.get_top_comments(comments, limit=3) |
| 78 | self.assertEqual(top[0]["score"], 100) |
| 79 | self.assertEqual(top[1]["score"], 50) |
| 80 | |
| 81 | def test_filters_deleted(self): |
| 82 | comments = [ |
| 83 | {"score": 100, "author": "[deleted]"}, |
| 84 | {"score": 50, "author": "[removed]"}, |
| 85 | {"score": 10, "author": "real_user"}, |
| 86 | ] |
| 87 | top = reddit_enrich.get_top_comments(comments) |
| 88 | self.assertEqual(len(top), 1) |
| 89 | self.assertEqual(top[0]["author"], "real_user") |
| 90 | |
| 91 | def test_respects_limit(self): |
| 92 | comments = [{"score": i, "author": f"u{i}"} for i in range(20)] |
| 93 | top = reddit_enrich.get_top_comments(comments, limit=5) |
| 94 | self.assertEqual(len(top), 5) |
| 95 | |
| 96 | def test_empty_list(self): |
| 97 | self.assertEqual(reddit_enrich.get_top_comments([]), []) |
| 98 | |
| 99 | |
| 100 | class TestExtractCommentInsights(unittest.TestCase): |
| 101 | """Tests for extract_comment_insights().""" |
| 102 | |
| 103 | def test_filters_short_comments(self): |
| 104 | comments = [ |
| 105 | {"body": "yes"}, |
| 106 | {"body": "A" * 50 + " this is a substantive comment about the topic."}, |
| 107 | ] |
| 108 | insights = reddit_enrich.extract_comment_insights(comments) |
| 109 | self.assertEqual(len(insights), 1) |
| 110 | |
| 111 | def test_filters_low_value_patterns(self): |
| 112 | comments = [ |
| 113 | {"body": "This."}, |
| 114 | {"body": "lol that's hilarious"}, |
| 115 | {"body": "A" * 50 + " Here's a real insight about how to approach this problem."}, |
| 116 | ] |
| 117 | insights = reddit_enrich.extract_comment_insights(comments) |
| 118 | self.assertEqual(len(insights), 1) |
| 119 | |
| 120 | def test_respects_limit(self): |
| 121 | comments = [{"body": f"Comment number {i} " + "x" * 50} for i in range(20)] |
| 122 | insights = reddit_enrich.extract_comment_insights(comments, limit=3) |
| 123 | self.assertLessEqual(len(insights), 3) |
| 124 | |
| 125 | if __name__ == "__main__": |
| 126 | unittest.main() |
| 127 |