Ви не можете вибрати більше 25 тем Теми мають розпочинатися з літери або цифри, можуть містити дефіси (-) і не повинні перевищувати 35 символів.

109 рядки
4.0 KiB

  1. import os
  2. import tempfile
  3. import unittest
  4. from services.normalization import get_aliases, normalize_headline, replace_aliases
  5. ALIASES = {
  6. "federal reserve": "fed",
  7. "united states": "us",
  8. "united states of america": "us",
  9. "president of the united states": "potus",
  10. "united nations": "unitednations",
  11. "inflation rate": "inflation",
  12. }
  13. class TestGetAliases(unittest.TestCase):
  14. def test_loads_toml_with_key_normalization(self):
  15. path = None
  16. try:
  17. with tempfile.NamedTemporaryFile("wb", suffix=".toml", delete=False) as f:
  18. f.write(
  19. b"[aliases]\n"
  20. b"\"Federal Reserve\" = \"Fed\"\n"
  21. b"\"people's republic of china\" = \"china\"\n"
  22. )
  23. path = f.name
  24. aliases = get_aliases(path)
  25. self.assertEqual(aliases["federal reserve"], "fed")
  26. # apostrophe is stripped so keys match punctuation-removed text
  27. self.assertEqual(aliases["peoples republic of china"], "china")
  28. finally:
  29. if path:
  30. os.unlink(path)
  31. def test_missing_file_raises(self):
  32. with self.assertRaises(FileNotFoundError):
  33. get_aliases("/no/such/aliases.toml")
  34. class TestReplaceAliases(unittest.TestCase):
  35. def test_whole_word_only(self):
  36. # "united states" must not match inside "united statesman".
  37. self.assertEqual(
  38. replace_aliases("united statesman wins award", ALIASES),
  39. "united statesman wins award",
  40. )
  41. def test_longest_phrase_first(self):
  42. # "president of the united states" -> "potus", not "president of the us".
  43. self.assertEqual(
  44. replace_aliases("president of the united states speaks", ALIASES),
  45. "potus speaks",
  46. )
  47. def test_no_aliases_returns_text(self):
  48. self.assertEqual(replace_aliases("plain text here", None), "plain text here")
  49. self.assertEqual(replace_aliases("plain text here", {}), "plain text here")
  50. class TestNormalizeHeadlineAliases(unittest.TestCase):
  51. def setUp(self):
  52. self.stopwords = {"the", "a", "an", "in", "on", "and", "of", "to", "for"}
  53. def test_full_name_and_acronym_cluster(self):
  54. # "Federal Reserve" and "the Fed" normalize to the same first token.
  55. full = normalize_headline("Federal Reserve raises rates", self.stopwords, ALIASES)
  56. short = normalize_headline("the Fed raises rates", self.stopwords, ALIASES)
  57. self.assertEqual(full, ["fed", "raises", "rates"])
  58. self.assertEqual(short, ["fed", "raises", "rates"])
  59. def test_united_nations_not_dropped(self):
  60. # Regression guard: the canonical must survive stopword removal.
  61. self.assertEqual(
  62. normalize_headline("United Nations meets", self.stopwords, ALIASES),
  63. ["unitednations", "meets"],
  64. )
  65. def test_inflation_rates_not_mangled(self):
  66. # "inflation rate" must not fire inside "inflation rates".
  67. self.assertEqual(
  68. normalize_headline("inflation rates fall", self.stopwords, ALIASES),
  69. ["inflation", "rates", "fall"],
  70. )
  71. class TestAliasesFileIntegrity(unittest.TestCase):
  72. """Guard against an alias canonical colliding with a stopword, which would
  73. get silently stripped during normalization (the original 'united nations'
  74. -> 'un' bug)."""
  75. def test_no_canonical_is_a_stopword(self):
  76. base = os.path.join(os.path.dirname(__file__), "..", "resources")
  77. aliases = get_aliases(os.path.join(base, "aliases.toml"))
  78. with open(os.path.join(base, "stopwords.txt"), encoding="utf-8-sig") as f:
  79. stopwords = set(f.read().splitlines())
  80. self.assertTrue(aliases)
  81. for phrase, canonical in aliases.items():
  82. for token in canonical.split():
  83. self.assertNotIn(
  84. token,
  85. stopwords,
  86. "alias %r canonical token %r is a stopword" % (phrase, token),
  87. )
  88. if __name__ == "__main__":
  89. unittest.main()