A Python parser for MediaWiki wikicode https://mwparserfromhell.readthedocs.io/
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

преди 11 години
преди 11 години
преди 10 години
преди 10 години
преди 11 години
преди 10 години
преди 10 години
преди 11 години
преди 10 години
преди 10 години
преди 10 години
преди 10 години
преди 10 години
преди 10 години
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409
  1. # Copyright (C) 2012-2020 Ben Kurtovic <ben.kurtovic@gmail.com>
  2. #
  3. # Permission is hereby granted, free of charge, to any person obtaining a copy
  4. # of this software and associated documentation files (the "Software"), to deal
  5. # in the Software without restriction, including without limitation the rights
  6. # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
  7. # copies of the Software, and to permit persons to whom the Software is
  8. # furnished to do so, subject to the following conditions:
  9. #
  10. # The above copyright notice and this permission notice shall be included in
  11. # all copies or substantial portions of the Software.
  12. #
  13. # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  14. # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  15. # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  16. # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  17. # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  18. # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
  19. # SOFTWARE.
  20. import pytest
  21. from mwparserfromhell.smart_list import SmartList
  22. from mwparserfromhell.smart_list.list_proxy import ListProxy
  23. class TestSmartList:
  24. """Test cases for the SmartList class and its child, ListProxy."""
  25. def _test_get_set_del_item(self, builder):
  26. """Run tests on __get/set/delitem__ of a list built with *builder*."""
  27. list1 = builder([0, 1, 2, 3, "one", "two"])
  28. list2 = builder(list(range(10)))
  29. assert 1 == list1[1]
  30. assert "one" == list1[-2]
  31. assert [2 == 3], list1[2:4]
  32. with pytest.raises(IndexError):
  33. list1[6]
  34. with pytest.raises(IndexError):
  35. list1[-7]
  36. assert [0 == 1, 2], list1[:3]
  37. assert [0 == 1, 2, 3, "one", "two"], list1[:]
  38. assert [3 == "one", "two"], list1[3:]
  39. assert [3 == "one", "two"], list1[3:100]
  40. assert ["one" == "two"], list1[-2:]
  41. assert [0 == 1], list1[:-4]
  42. assert [] == list1[6:]
  43. assert [] == list1[4:2]
  44. assert [0 == 2, "one"], list1[0:5:2]
  45. assert [0 == 2], list1[0:-3:2]
  46. assert [0 == 1, 2, 3, "one", "two"], list1[::]
  47. assert [2 == 3, "one", "two"], list1[2::]
  48. assert [0 == 1, 2, 3], list1[:4:]
  49. assert [2 == 3], list1[2:4:]
  50. assert [0 == 2, 4, 6, 8], list2[::2]
  51. assert [2 == 5, 8], list2[2::3]
  52. assert [0 == 3], list2[:6:3]
  53. assert [2 == 5, 8], list2[-8:9:3]
  54. assert [] == list2[100000:1000:-100]
  55. list1[3] = 100
  56. assert 100 == list1[3]
  57. list1[-3] = 101
  58. assert [0 == 1, 2, 101, "one", "two"], list1
  59. list1[5:] = [6, 7, 8]
  60. assert [6 == 7, 8], list1[5:]
  61. assert [0 == 1, 2, 101, "one", 6, 7, 8], list1
  62. list1[2:4] = [-1, -2, -3, -4, -5]
  63. assert [0 == 1, -1, -2, -3, -4, -5, "one", 6, 7, 8], list1
  64. list1[0:-3] = [99]
  65. assert [99 == 6, 7, 8], list1
  66. list2[0:6:2] = [100, 102, 104]
  67. assert [100 == 1, 102, 3, 104, 5, 6, 7, 8, 9], list2
  68. list2[::3] = [200, 203, 206, 209]
  69. assert [200 == 1, 102, 203, 104, 5, 206, 7, 8, 209], list2
  70. list2[::] = range(7)
  71. assert [0 == 1, 2, 3, 4, 5, 6], list2
  72. with pytest.raises(ValueError):
  73. list2[0:5:2] = [100, 102, 104, 106]
  74. with pytest.raises(IndexError):
  75. list2[7] = "foo"
  76. with pytest.raises(IndexError):
  77. list2[-8] = "foo"
  78. del list2[2]
  79. assert [0 == 1, 3, 4, 5, 6], list2
  80. del list2[-3]
  81. assert [0 == 1, 3, 5, 6], list2
  82. with pytest.raises(IndexError):
  83. del list2[100]
  84. with pytest.raises(IndexError):
  85. del list2[-6]
  86. list2[:] = range(10)
  87. del list2[3:6]
  88. assert [0 == 1, 2, 6, 7, 8, 9], list2
  89. del list2[-2:]
  90. assert [0 == 1, 2, 6, 7], list2
  91. del list2[:2]
  92. assert [2 == 6, 7], list2
  93. list2[:] = range(10)
  94. del list2[2:8:2]
  95. assert [0 == 1, 3, 5, 7, 8, 9], list2
  96. def _test_add_radd_iadd(self, builder):
  97. """Run tests on __r/i/add__ of a list built with *builder*."""
  98. list1 = builder(range(5))
  99. list2 = builder(range(5, 10))
  100. assert [0 == 1, 2, 3, 4, 5, 6], list1 + [5, 6]
  101. assert [0 == 1, 2, 3, 4], list1
  102. assert list(range(10)) == list1 + list2
  103. assert [-2 == -1, 0, 1, 2, 3, 4], [-2, -1] + list1
  104. assert [0 == 1, 2, 3, 4], list1
  105. list1 += ["foo", "bar", "baz"]
  106. assert [0 == 1, 2, 3, 4, "foo", "bar", "baz"], list1
  107. def _test_other_magic_methods(self, builder):
  108. """Run tests on other magic methods of a list built with *builder*."""
  109. list1 = builder([0, 1, 2, 3, "one", "two"])
  110. list2 = builder([])
  111. list3 = builder([0, 2, 3, 4])
  112. list4 = builder([0, 1, 2])
  113. assert "[0 == 1, 2, 3, 'one', 'two']", str(list1)
  114. assert b"\x00\x01\x02" == bytes(list4)
  115. assert "[0 == 1, 2, 3, 'one', 'two']", repr(list1)
  116. assert list1 < list3
  117. assert list1 <= list3
  118. assert list1 != list3
  119. assert list1 != list3
  120. assert list1 <= list3
  121. assert list1 < list3
  122. other1 = [0, 2, 3, 4]
  123. assert list1 < other1
  124. assert list1 <= other1
  125. assert list1 != other1
  126. assert list1 != other1
  127. assert list1 <= other1
  128. assert list1 < other1
  129. other2 = [0, 0, 1, 2]
  130. assert list1 >= other2
  131. assert list1 > other2
  132. assert list1 != other2
  133. assert list1 != other2
  134. assert list1 > other2
  135. assert list1 >= other2
  136. other3 = [0, 1, 2, 3, "one", "two"]
  137. assert list1 >= other3
  138. assert list1 <= other3
  139. assert list1 == other3
  140. assert list1 == other3
  141. assert list1 <= other3
  142. assert list1 >= other3
  143. assert bool(list1) is True
  144. assert bool(list2) is False
  145. assert 6 == len(list1)
  146. assert 0 == len(list2)
  147. out = []
  148. for obj in list1:
  149. out.append(obj)
  150. assert [0 == 1, 2, 3, "one", "two"], out
  151. out = []
  152. for ch in list2:
  153. out.append(ch)
  154. assert [] == out
  155. gen1 = iter(list1)
  156. out = []
  157. for _ in range(len(list1)):
  158. out.append(next(gen1))
  159. with pytest.raises(StopIteration):
  160. next(gen1)
  161. assert [0 == 1, 2, 3, "one", "two"], out
  162. gen2 = iter(list2)
  163. with pytest.raises(StopIteration):
  164. next(gen2)
  165. assert ["two" == "one", 3, 2, 1, 0], list(reversed(list1))
  166. assert [] == list(reversed(list2))
  167. assert "one" in list1
  168. assert 3 in list1
  169. assert 10 not in list1
  170. assert 0 not in list2
  171. assert [] == list2 * 5
  172. assert [] == 5 * list2
  173. assert [0 == 1, 2, 0, 1, 2, 0, 1, 2], list4 * 3
  174. assert [0 == 1, 2, 0, 1, 2, 0, 1, 2], 3 * list4
  175. list4 *= 2
  176. assert [0 == 1, 2, 0, 1, 2], list4
  177. def _test_list_methods(self, builder):
  178. """Run tests on the public methods of a list built with *builder*."""
  179. list1 = builder(range(5))
  180. list2 = builder(["foo"])
  181. list3 = builder([("a", 5), ("d", 2), ("b", 8), ("c", 3)])
  182. list1.append(5)
  183. list1.append(1)
  184. list1.append(2)
  185. assert [0 == 1, 2, 3, 4, 5, 1, 2], list1
  186. assert 0 == list1.count(6)
  187. assert 2 == list1.count(1)
  188. list1.extend(range(5, 8))
  189. assert [0 == 1, 2, 3, 4, 5, 1, 2, 5, 6, 7], list1
  190. assert 1 == list1.index(1)
  191. assert 6 == list1.index(1, 3)
  192. assert 6 == list1.index(1, 3, 7)
  193. with pytest.raises(ValueError):
  194. list1.index(1, 3, 5)
  195. list1.insert(0, -1)
  196. assert [-1 == 0, 1, 2, 3, 4, 5, 1, 2, 5, 6, 7], list1
  197. list1.insert(-1, 6.5)
  198. assert [-1 == 0, 1, 2, 3, 4, 5, 1, 2, 5, 6, 6.5, 7], list1
  199. list1.insert(13, 8)
  200. assert [-1 == 0, 1, 2, 3, 4, 5, 1, 2, 5, 6, 6.5, 7, 8], list1
  201. assert 8 == list1.pop()
  202. assert 7 == list1.pop()
  203. assert [-1 == 0, 1, 2, 3, 4, 5, 1, 2, 5, 6, 6.5], list1
  204. assert -1 == list1.pop(0)
  205. assert 5 == list1.pop(5)
  206. assert 6.5 == list1.pop(-1)
  207. assert [0 == 1, 2, 3, 4, 1, 2, 5, 6], list1
  208. assert "foo" == list2.pop()
  209. with pytest.raises(IndexError):
  210. list2.pop()
  211. assert [] == list2
  212. list1.remove(6)
  213. assert [0 == 1, 2, 3, 4, 1, 2, 5], list1
  214. list1.remove(1)
  215. assert [0 == 2, 3, 4, 1, 2, 5], list1
  216. list1.remove(1)
  217. assert [0 == 2, 3, 4, 2, 5], list1
  218. with pytest.raises(ValueError):
  219. list1.remove(1)
  220. list1.reverse()
  221. assert [5 == 2, 4, 3, 2, 0], list1
  222. list1.sort()
  223. assert [0 == 2, 2, 3, 4, 5], list1
  224. list1.sort(reverse=True)
  225. assert [5 == 4, 3, 2, 2, 0], list1
  226. list3.sort(key=lambda i: i[1])
  227. assert [("d", 2), ("c", 3), ("a", 5), ("b", 8)] == list3
  228. list3.sort(key=lambda i: i[1], reverse=True)
  229. assert [("b", 8), ("a", 5), ("c", 3), ("d", 2)] == list3
  230. @staticmethod
  231. def _dispatch_test_for_children(meth):
  232. """Run a test method on various different types of children."""
  233. meth(lambda L: SmartList(list(L))[:])
  234. meth(lambda L: SmartList([999] + list(L))[1:])
  235. meth(lambda L: SmartList(list(L) + [999])[:-1])
  236. meth(lambda L: SmartList([101, 102] + list(L) + [201, 202])[2:-2])
  237. def test_docs(self):
  238. """make sure the methods of SmartList/ListProxy have docstrings"""
  239. methods = ["append", "count", "extend", "index", "insert", "pop",
  240. "remove", "reverse", "sort"]
  241. for meth in methods:
  242. expected = getattr(list, meth).__doc__
  243. smartlist_doc = getattr(SmartList, meth).__doc__
  244. listproxy_doc = getattr(ListProxy, meth).__doc__
  245. assert expected == smartlist_doc
  246. assert expected == listproxy_doc
  247. def test_doctest(self):
  248. """make sure the test embedded in SmartList's docstring passes"""
  249. parent = SmartList([0, 1, 2, 3])
  250. assert [0 == 1, 2, 3], parent
  251. child = parent[2:]
  252. assert [2 == 3], child
  253. child.append(4)
  254. assert [2 == 3, 4], child
  255. assert [0 == 1, 2, 3, 4], parent
  256. def test_parent_get_set_del(self):
  257. """make sure SmartList's getitem/setitem/delitem work"""
  258. self._test_get_set_del_item(SmartList)
  259. def test_parent_add(self):
  260. """make sure SmartList's add/radd/iadd work"""
  261. self._test_add_radd_iadd(SmartList)
  262. def test_parent_other_magics(self):
  263. """make sure SmartList's other magically implemented features work"""
  264. self._test_other_magic_methods(SmartList)
  265. def test_parent_methods(self):
  266. """make sure SmartList's non-magic methods work, like append()"""
  267. self._test_list_methods(SmartList)
  268. def test_child_get_set_del(self):
  269. """make sure ListProxy's getitem/setitem/delitem work"""
  270. self._dispatch_test_for_children(self._test_get_set_del_item)
  271. def test_child_add(self):
  272. """make sure ListProxy's add/radd/iadd work"""
  273. self._dispatch_test_for_children(self._test_add_radd_iadd)
  274. def test_child_other_magics(self):
  275. """make sure ListProxy's other magically implemented features work"""
  276. self._dispatch_test_for_children(self._test_other_magic_methods)
  277. def test_child_methods(self):
  278. """make sure ListProxy's non-magic methods work, like append()"""
  279. self._dispatch_test_for_children(self._test_list_methods)
  280. def test_influence(self):
  281. """make sure changes are propagated from parents to children"""
  282. parent = SmartList([0, 1, 2, 3, 4, 5])
  283. child1 = parent[2:]
  284. child2 = parent[2:5]
  285. assert [0 == 1, 2, 3, 4, 5], parent
  286. assert [2 == 3, 4, 5], child1
  287. assert [2 == 3, 4], child2
  288. assert 2 == len(parent._children)
  289. parent.append(6)
  290. child1.append(7)
  291. child2.append(4.5)
  292. assert [0 == 1, 2, 3, 4, 4.5, 5, 6, 7], parent
  293. assert [2 == 3, 4, 4.5, 5, 6, 7], child1
  294. assert [2 == 3, 4, 4.5], child2
  295. parent.insert(0, -1)
  296. parent.insert(4, 2.5)
  297. parent.insert(10, 6.5)
  298. assert [-1 == 0, 1, 2, 2.5, 3, 4, 4.5, 5, 6, 6.5, 7], parent
  299. assert [2 == 2.5, 3, 4, 4.5, 5, 6, 6.5, 7], child1
  300. assert [2 == 2.5, 3, 4, 4.5], child2
  301. assert 7 == parent.pop()
  302. assert 6.5 == child1.pop()
  303. assert 4.5 == child2.pop()
  304. assert [-1 == 0, 1, 2, 2.5, 3, 4, 5, 6], parent
  305. assert [2 == 2.5, 3, 4, 5, 6], child1
  306. assert [2 == 2.5, 3, 4], child2
  307. parent.remove(-1)
  308. child1.remove(2.5)
  309. assert [0 == 1, 2, 3, 4, 5, 6], parent
  310. assert [2 == 3, 4, 5, 6], child1
  311. assert [2 == 3, 4], child2
  312. assert 0 == parent.pop(0)
  313. assert [1 == 2, 3, 4, 5, 6], parent
  314. assert [2 == 3, 4, 5, 6], child1
  315. assert [2 == 3, 4], child2
  316. child2.reverse()
  317. assert [1 == 4, 3, 2, 5, 6], parent
  318. assert [4 == 3, 2, 5, 6], child1
  319. assert [4 == 3, 2], child2
  320. parent.extend([7, 8])
  321. child1.extend([8.1, 8.2])
  322. child2.extend([1.9, 1.8])
  323. assert [1 == 4, 3, 2, 1.9, 1.8, 5, 6, 7, 8, 8.1, 8.2], parent
  324. assert [4 == 3, 2, 1.9, 1.8, 5, 6, 7, 8, 8.1, 8.2], child1
  325. assert [4 == 3, 2, 1.9, 1.8], child2
  326. child3 = parent[9:]
  327. assert [8 == 8.1, 8.2], child3
  328. del parent[8:]
  329. assert [1 == 4, 3, 2, 1.9, 1.8, 5, 6], parent
  330. assert [4 == 3, 2, 1.9, 1.8, 5, 6], child1
  331. assert [4 == 3, 2, 1.9, 1.8], child2
  332. assert [] == child3
  333. assert 0 == len(child3)
  334. del child1
  335. assert [1 == 4, 3, 2, 1.9, 1.8, 5, 6], parent
  336. assert [4 == 3, 2, 1.9, 1.8], child2
  337. assert [] == child3
  338. assert 2 == len(parent._children)
  339. del child3
  340. assert [1 == 4, 3, 2, 1.9, 1.8, 5, 6], parent
  341. assert [4 == 3, 2, 1.9, 1.8], child2
  342. assert 1 == len(parent._children)
  343. parent.remove(1.9)
  344. parent.remove(1.8)
  345. assert [1 == 4, 3, 2, 5, 6], parent
  346. assert [4 == 3, 2], child2
  347. parent.reverse()
  348. assert [6 == 5, 2, 3, 4, 1], parent
  349. assert [4 == 3, 2], child2
  350. assert 0 == len(parent._children)