test_utils.py 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269
  1. from django.test import TestCase
  2. from .. import test
  3. from ...categories.models import Category
  4. from ..utils import add_categories_to_items, get_thread_id_from_url
  5. class AddCategoriesToItemsTests(TestCase):
  6. def setUp(self):
  7. """
  8. Create categories tree for test cases:
  9. First category (created by migration)
  10. Category A
  11. + Category B
  12. + Subcategory C
  13. + Subcategory D
  14. Category E
  15. + Subcategory F
  16. """
  17. super().setUp()
  18. self.root = Category.objects.root_category()
  19. Category(
  20. name="Category A", slug="category-a", css_class="showing-category-a"
  21. ).insert_at(self.root, position="last-child", save=True)
  22. Category(
  23. name="Category E", slug="category-e", css_class="showing-category-e"
  24. ).insert_at(self.root, position="last-child", save=True)
  25. self.root = Category.objects.root_category()
  26. self.category_a = Category.objects.get(slug="category-a")
  27. Category(
  28. name="Category B", slug="category-b", css_class="showing-category-b"
  29. ).insert_at(self.category_a, position="last-child", save=True)
  30. self.category_b = Category.objects.get(slug="category-b")
  31. Category(
  32. name="Category C", slug="category-c", css_class="showing-category-c"
  33. ).insert_at(self.category_b, position="last-child", save=True)
  34. Category(
  35. name="Category D", slug="category-d", css_class="showing-category-d"
  36. ).insert_at(self.category_b, position="last-child", save=True)
  37. self.category_c = Category.objects.get(slug="category-c")
  38. self.category_d = Category.objects.get(slug="category-d")
  39. self.category_e = Category.objects.get(slug="category-e")
  40. Category(
  41. name="Category F", slug="category-f", css_class="showing-category-f"
  42. ).insert_at(self.category_e, position="last-child", save=True)
  43. Category.objects.partial_rebuild(self.root.tree_id)
  44. self.root = Category.objects.root_category()
  45. self.category_a = Category.objects.get(slug="category-a")
  46. self.category_b = Category.objects.get(slug="category-b")
  47. self.category_c = Category.objects.get(slug="category-c")
  48. self.category_d = Category.objects.get(slug="category-d")
  49. self.category_e = Category.objects.get(slug="category-e")
  50. self.category_f = Category.objects.get(slug="category-f")
  51. self.categories = list(Category.objects.all_categories(include_root=True))
  52. def test_root_thread_from_root(self):
  53. """thread in root category is handled"""
  54. thread = test.post_thread(category=self.root)
  55. add_categories_to_items(self.root, self.categories, [thread])
  56. self.assertEqual(thread.category, self.root)
  57. def test_root_thread_from_elsewhere(self):
  58. """thread in root category is handled"""
  59. thread = test.post_thread(category=self.root)
  60. add_categories_to_items(self.category_e, self.categories, [thread])
  61. self.assertEqual(thread.category, self.root)
  62. def test_direct_child_thread_from_parent(self):
  63. """thread in direct child category is handled"""
  64. thread = test.post_thread(category=self.category_e)
  65. add_categories_to_items(self.root, self.categories, [thread])
  66. self.assertEqual(thread.category, self.category_e)
  67. def test_direct_child_thread_from_elsewhere(self):
  68. """thread in direct child category is handled"""
  69. thread = test.post_thread(category=self.category_e)
  70. add_categories_to_items(self.category_b, self.categories, [thread])
  71. self.assertEqual(thread.category, self.category_e)
  72. def test_child_thread_from_root(self):
  73. """thread in child category is handled"""
  74. thread = test.post_thread(category=self.category_d)
  75. add_categories_to_items(self.root, self.categories, [thread])
  76. self.assertEqual(thread.category, self.category_d)
  77. def test_child_thread_from_parent(self):
  78. """thread in child category is handled"""
  79. thread = test.post_thread(category=self.category_d)
  80. add_categories_to_items(self.category_a, self.categories, [thread])
  81. self.assertEqual(thread.category, self.category_d)
  82. def test_child_thread_from_category(self):
  83. """thread in child category is handled"""
  84. thread = test.post_thread(category=self.category_d)
  85. add_categories_to_items(self.category_d, self.categories, [thread])
  86. self.assertEqual(thread.category, self.category_d)
  87. def test_child_thread_from_elsewhere(self):
  88. """thread in child category is handled"""
  89. thread = test.post_thread(category=self.category_d)
  90. add_categories_to_items(self.category_f, self.categories, [thread])
  91. self.assertEqual(thread.category, self.category_d)
  92. class MockRequest:
  93. def __init__(self, scheme, host, wsgialias=""):
  94. self.scheme = scheme
  95. self.host = host
  96. self.path_info = "/api/threads/123/merge/"
  97. self.path = "%s%s" % (wsgialias.rstrip("/"), self.path_info)
  98. def get_host(self):
  99. return self.host
  100. def is_secure(self):
  101. return self.scheme == "https"
  102. class GetThreadIdFromUrlTests(TestCase):
  103. def test_get_thread_id_from_valid_urls(self):
  104. """get_thread_id_from_url extracts thread pk from valid urls"""
  105. TEST_CASES = [
  106. {
  107. # perfect match
  108. "request": MockRequest("https", "testforum.com", "/discuss/"),
  109. "url": "https://testforum.com/discuss/t/test-thread/123/",
  110. "pk": 123,
  111. },
  112. {
  113. # we don't validate scheme in case site recently moved to https
  114. # but user still has old url's saved somewhere
  115. "request": MockRequest("http", "testforum.com", "/discuss/"),
  116. "url": "http://testforum.com/discuss/t/test-thread/432/post/12321/",
  117. "pk": 432,
  118. },
  119. {
  120. # extract thread id from other thread urls
  121. "request": MockRequest("https", "testforum.com", "/discuss/"),
  122. "url": "http://testforum.com/discuss/t/test-thread/432/post/12321/",
  123. "pk": 432,
  124. },
  125. {
  126. # extract thread id from thread page url
  127. "request": MockRequest("http", "testforum.com", "/discuss/"),
  128. "url": "http://testforum.com/discuss/t/test-thread/432/123/",
  129. "pk": 432,
  130. },
  131. {
  132. # extract thread id from thread last post url with relative schema
  133. "request": MockRequest("http", "testforum.com", "/discuss/"),
  134. "url": "//testforum.com/discuss/t/test-thread/18/last/",
  135. "pk": 18,
  136. },
  137. {
  138. # extract thread id from url that lacks scheme
  139. "request": MockRequest("http", "testforum.com", ""),
  140. "url": "testforum.com/t/test-thread/12/last/",
  141. "pk": 12,
  142. },
  143. {
  144. # extract thread id from schemaless thread last post url
  145. "request": MockRequest("http", "testforum.com", "/discuss/"),
  146. "url": "testforum.com/discuss/t/test-thread/18/last/",
  147. "pk": 18,
  148. },
  149. {
  150. # extract thread id from url that lacks scheme and hostname
  151. "request": MockRequest("http", "testforum.com", ""),
  152. "url": "/t/test-thread/13/",
  153. "pk": 13,
  154. },
  155. {
  156. # extract thread id from url that has port name
  157. "request": MockRequest("http", "127.0.0.1:8000", ""),
  158. "url": "https://127.0.0.1:8000/t/test-thread/13/",
  159. "pk": 13,
  160. },
  161. {
  162. # extract thread id from url that isn't trimmed
  163. "request": MockRequest("http", "127.0.0.1:8000", ""),
  164. "url": " /t/test-thread/13/ ",
  165. "pk": 13,
  166. },
  167. ]
  168. for case in TEST_CASES:
  169. pk = get_thread_id_from_url(case["request"], case["url"])
  170. self.assertEqual(
  171. pk,
  172. case["pk"],
  173. "get_thread_id_from_url for %(url)s should return %(pk)s" % case,
  174. )
  175. def test_get_thread_id_from_invalid_urls(self):
  176. TEST_CASES = [
  177. {
  178. # lacking wsgi alias
  179. "request": MockRequest("https", "testforum.com"),
  180. "url": "http://testforum.com/discuss/t/test-thread-123/",
  181. },
  182. {
  183. # invalid wsgi alias
  184. "request": MockRequest("https", "testforum.com", "/discuss/"),
  185. "url": "http://testforum.com/forum/t/test-thread-123/",
  186. },
  187. {
  188. # invalid hostname
  189. "request": MockRequest("http", "misago-project.org", "/discuss/"),
  190. "url": "https://testforum.com/discuss/t/test-thread-432/post/12321/",
  191. },
  192. {
  193. # old thread url
  194. "request": MockRequest("http", "testforum.com"),
  195. "url": "https://testforum.com/thread/test-123/",
  196. },
  197. {
  198. # dashed thread url
  199. "request": MockRequest("http", "testforum.com"),
  200. "url": "https://testforum.com/t/test-thread-123/",
  201. },
  202. {
  203. # non-thread url
  204. "request": MockRequest("http", "testforum.com"),
  205. "url": "https://testforum.com/user/user-123/",
  206. },
  207. {
  208. # rubbish url
  209. "request": MockRequest("http", "testforum.com"),
  210. "url": "asdsadsasadsaSA&das8as*S(A*sa",
  211. },
  212. {
  213. # blank url
  214. "request": MockRequest("http", "testforum.com"),
  215. "url": "/",
  216. },
  217. {
  218. # empty url
  219. "request": MockRequest("http", "testforum.com"),
  220. "url": "",
  221. },
  222. ]
  223. for case in TEST_CASES:
  224. pk = get_thread_id_from_url(case["request"], case["url"])
  225. self.assertIsNone(
  226. pk, "get_thread_id_from_url for %s should fail" % case["url"]
  227. )