Du kannst nicht mehr als 25 Themen auswählen Themen müssen entweder mit einem Buchstaben oder einer Ziffer beginnen. Sie können Bindestriche („-“) enthalten und bis zu 35 Zeichen lang sein.

99 Zeilen
3.4 KiB

  1. import os
  2. import tempfile
  3. import unittest
  4. from unittest.mock import patch, MagicMock
  5. from services.headlines import is_headline, prepare_headlines
  6. from services.normalization import canonicalize, get_excluded_phrases, is_excluded
  7. PHRASES = [
  8. "skip to content",
  9. "privacy choices",
  10. "terms of service",
  11. "privacy policy",
  12. ]
  13. class TestCanonicalize(unittest.TestCase):
  14. def test_lowercase_and_collapse(self):
  15. self.assertEqual(canonicalize(" Terms-of-Service. "), "terms of service")
  16. def test_empty(self):
  17. self.assertEqual(canonicalize(""), "")
  18. self.assertEqual(canonicalize(None), "")
  19. class TestIsExcluded(unittest.TestCase):
  20. def test_exact_match(self):
  21. self.assertTrue(is_excluded("Terms of Service", PHRASES))
  22. def test_sub_phrase_match(self):
  23. # "privacy choices" matches the longer "Your Privacy Choices".
  24. self.assertTrue(is_excluded("Your Privacy Choices", PHRASES))
  25. def test_case_and_punctuation_insensitive(self):
  26. self.assertTrue(is_excluded("SKIP-TO-CONTENT", PHRASES))
  27. def test_no_match(self):
  28. self.assertFalse(is_excluded("Federal Reserve holds rates steady", PHRASES))
  29. def test_no_phrases(self):
  30. self.assertFalse(is_excluded("anything here now", []))
  31. self.assertFalse(is_excluded("anything here now", None))
  32. class TestGetExcludedPhrases(unittest.TestCase):
  33. def test_loads_skipping_comments_and_blanks(self):
  34. path = None
  35. try:
  36. with tempfile.NamedTemporaryFile("w", suffix=".txt", delete=False) as f:
  37. f.write("# a comment\n\nskip to content\n\nprivacy choices\n# another\n")
  38. path = f.name
  39. self.assertEqual(get_excluded_phrases(path), ["skip to content", "privacy choices"])
  40. finally:
  41. if path:
  42. os.unlink(path)
  43. class TestIsHeadlineExcluded(unittest.TestCase):
  44. def setUp(self):
  45. self.stopwords = {"the", "a", "an", "in", "on", "and", "of", "to"}
  46. def test_boilerplate_rejected(self):
  47. for text in ["Your Privacy Choices", "Skip to Content", "Terms of Service"]:
  48. with self.subTest(text=text):
  49. self.assertFalse(is_headline(text, self.stopwords, PHRASES))
  50. def test_real_headline_kept(self):
  51. self.assertTrue(is_headline("Senate passes major infrastructure bill", self.stopwords, PHRASES))
  52. class TestPrepareHeadlinesExcluded(unittest.TestCase):
  53. def setUp(self):
  54. self.stopwords = {"the", "a", "an", "in", "on", "and", "of", "to"}
  55. @patch("services.headlines.requests.get")
  56. def test_boilerplate_links_are_filtered_out(self, mock_get):
  57. html = (
  58. "<html><body>"
  59. "<a href='/skip'>Skip to Content</a>"
  60. "<a href='/terms'>Terms of Service</a>"
  61. "<a href='/privacy'>Your Privacy Choices</a>"
  62. "<a href='/article'>Senate passes major infrastructure bill</a>"
  63. "</body></html>"
  64. )
  65. mock_response = MagicMock()
  66. mock_response.status_code = 200
  67. mock_response.content = html.encode("utf-8")
  68. mock_response.text = html
  69. mock_get.return_value = mock_response
  70. headlines = prepare_headlines(["https://example.com/news"], self.stopwords, excluded_phrases=PHRASES)
  71. texts = [h.display_text for h in headlines]
  72. self.assertEqual(texts, ["Senate passes major infrastructure bill"])
  73. if __name__ == "__main__":
  74. unittest.main()