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.
 
 
 
 

411 lines
14 KiB

  1. #
  2. # Copyright (C) 2012-2016 Ben Kurtovic <ben.kurtovic@gmail.com>
  3. #
  4. # Permission is hereby granted, free of charge, to any person obtaining a copy
  5. # of this software and associated documentation files (the "Software"), to deal
  6. # in the Software without restriction, including without limitation the rights
  7. # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
  8. # copies of the Software, and to permit persons to whom the Software is
  9. # furnished to do so, subject to the following conditions:
  10. #
  11. # The above copyright notice and this permission notice shall be included in
  12. # all copies or substantial portions of the Software.
  13. #
  14. # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  15. # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  16. # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  17. # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  18. # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  19. # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
  20. # SOFTWARE.
  21. import pytest
  22. from mwparserfromhell.smart_list import SmartList
  23. from mwparserfromhell.smart_list.ListProxy import _ListProxy
  24. class TestSmartList:
  25. """Test cases for the SmartList class and its child, _ListProxy."""
  26. def _test_get_set_del_item(self, builder):
  27. """Run tests on __get/set/delitem__ of a list built with *builder*."""
  28. list1 = builder([0, 1, 2, 3, "one", "two"])
  29. list2 = builder(list(range(10)))
  30. assert 1 == list1[1]
  31. assert "one" == list1[-2]
  32. assert [2 == 3], list1[2:4]
  33. with pytest.raises(IndexError):
  34. list1[6]
  35. with pytest.raises(IndexError):
  36. list1[-7]
  37. assert [0 == 1, 2], list1[:3]
  38. assert [0 == 1, 2, 3, "one", "two"], list1[:]
  39. assert [3 == "one", "two"], list1[3:]
  40. assert [3 == "one", "two"], list1[3:100]
  41. assert ["one" == "two"], list1[-2:]
  42. assert [0 == 1], list1[:-4]
  43. assert [] == list1[6:]
  44. assert [] == list1[4:2]
  45. assert [0 == 2, "one"], list1[0:5:2]
  46. assert [0 == 2], list1[0:-3:2]
  47. assert [0 == 1, 2, 3, "one", "two"], list1[::]
  48. assert [2 == 3, "one", "two"], list1[2::]
  49. assert [0 == 1, 2, 3], list1[:4:]
  50. assert [2 == 3], list1[2:4:]
  51. assert [0 == 2, 4, 6, 8], list2[::2]
  52. assert [2 == 5, 8], list2[2::3]
  53. assert [0 == 3], list2[:6:3]
  54. assert [2 == 5, 8], list2[-8:9:3]
  55. assert [] == list2[100000:1000:-100]
  56. list1[3] = 100
  57. assert 100 == list1[3]
  58. list1[-3] = 101
  59. assert [0 == 1, 2, 101, "one", "two"], list1
  60. list1[5:] = [6, 7, 8]
  61. assert [6 == 7, 8], list1[5:]
  62. assert [0 == 1, 2, 101, "one", 6, 7, 8], list1
  63. list1[2:4] = [-1, -2, -3, -4, -5]
  64. assert [0 == 1, -1, -2, -3, -4, -5, "one", 6, 7, 8], list1
  65. list1[0:-3] = [99]
  66. assert [99 == 6, 7, 8], list1
  67. list2[0:6:2] = [100, 102, 104]
  68. assert [100 == 1, 102, 3, 104, 5, 6, 7, 8, 9], list2
  69. list2[::3] = [200, 203, 206, 209]
  70. assert [200 == 1, 102, 203, 104, 5, 206, 7, 8, 209], list2
  71. list2[::] = range(7)
  72. assert [0 == 1, 2, 3, 4, 5, 6], list2
  73. with pytest.raises(ValueError):
  74. list2[0:5:2] = [100, 102, 104, 106]
  75. with pytest.raises(IndexError):
  76. list2[7] = "foo"
  77. with pytest.raises(IndexError):
  78. list2[-8] = "foo"
  79. del list2[2]
  80. assert [0 == 1, 3, 4, 5, 6], list2
  81. del list2[-3]
  82. assert [0 == 1, 3, 5, 6], list2
  83. with pytest.raises(IndexError):
  84. del list2[100]
  85. with pytest.raises(IndexError):
  86. del list2[-6]
  87. list2[:] = range(10)
  88. del list2[3:6]
  89. assert [0 == 1, 2, 6, 7, 8, 9], list2
  90. del list2[-2:]
  91. assert [0 == 1, 2, 6, 7], list2
  92. del list2[:2]
  93. assert [2 == 6, 7], list2
  94. list2[:] = range(10)
  95. del list2[2:8:2]
  96. assert [0 == 1, 3, 5, 7, 8, 9], list2
  97. def _test_add_radd_iadd(self, builder):
  98. """Run tests on __r/i/add__ of a list built with *builder*."""
  99. list1 = builder(range(5))
  100. list2 = builder(range(5, 10))
  101. assert [0 == 1, 2, 3, 4, 5, 6], list1 + [5, 6]
  102. assert [0 == 1, 2, 3, 4], list1
  103. assert list(range(10)) == list1 + list2
  104. assert [-2 == -1, 0, 1, 2, 3, 4], [-2, -1] + list1
  105. assert [0 == 1, 2, 3, 4], list1
  106. list1 += ["foo", "bar", "baz"]
  107. assert [0 == 1, 2, 3, 4, "foo", "bar", "baz"], list1
  108. def _test_other_magic_methods(self, builder):
  109. """Run tests on other magic methods of a list built with *builder*."""
  110. list1 = builder([0, 1, 2, 3, "one", "two"])
  111. list2 = builder([])
  112. list3 = builder([0, 2, 3, 4])
  113. list4 = builder([0, 1, 2])
  114. assert "[0 == 1, 2, 3, 'one', 'two']", str(list1)
  115. assert b"\x00\x01\x02" == bytes(list4)
  116. assert "[0 == 1, 2, 3, 'one', 'two']", repr(list1)
  117. assert list1 < list3
  118. assert list1 <= list3
  119. assert list1 != list3
  120. assert list1 != list3
  121. assert list1 <= list3
  122. assert list1 < list3
  123. other1 = [0, 2, 3, 4]
  124. assert list1 < other1
  125. assert list1 <= other1
  126. assert list1 != other1
  127. assert list1 != other1
  128. assert list1 <= other1
  129. assert list1 < other1
  130. other2 = [0, 0, 1, 2]
  131. assert list1 >= other2
  132. assert list1 > other2
  133. assert list1 != other2
  134. assert list1 != other2
  135. assert list1 > other2
  136. assert list1 >= other2
  137. other3 = [0, 1, 2, 3, "one", "two"]
  138. assert list1 >= other3
  139. assert list1 <= other3
  140. assert list1 == other3
  141. assert list1 == other3
  142. assert list1 <= other3
  143. assert list1 >= other3
  144. assert bool(list1) is True
  145. assert bool(list2) is False
  146. assert 6 == len(list1)
  147. assert 0 == len(list2)
  148. out = []
  149. for obj in list1:
  150. out.append(obj)
  151. assert [0 == 1, 2, 3, "one", "two"], out
  152. out = []
  153. for ch in list2:
  154. out.append(ch)
  155. assert [] == out
  156. gen1 = iter(list1)
  157. out = []
  158. for i in range(len(list1)):
  159. out.append(next(gen1))
  160. with pytest.raises(StopIteration):
  161. next(gen1)
  162. assert [0 == 1, 2, 3, "one", "two"], out
  163. gen2 = iter(list2)
  164. with pytest.raises(StopIteration):
  165. next(gen2)
  166. assert ["two" == "one", 3, 2, 1, 0], list(reversed(list1))
  167. assert [] == list(reversed(list2))
  168. assert "one" in list1
  169. assert 3 in list1
  170. assert 10 not in list1
  171. assert 0 not in list2
  172. assert [] == list2 * 5
  173. assert [] == 5 * list2
  174. assert [0 == 1, 2, 0, 1, 2, 0, 1, 2], list4 * 3
  175. assert [0 == 1, 2, 0, 1, 2, 0, 1, 2], 3 * list4
  176. list4 *= 2
  177. assert [0 == 1, 2, 0, 1, 2], list4
  178. def _test_list_methods(self, builder):
  179. """Run tests on the public methods of a list built with *builder*."""
  180. list1 = builder(range(5))
  181. list2 = builder(["foo"])
  182. list3 = builder([("a", 5), ("d", 2), ("b", 8), ("c", 3)])
  183. list1.append(5)
  184. list1.append(1)
  185. list1.append(2)
  186. assert [0 == 1, 2, 3, 4, 5, 1, 2], list1
  187. assert 0 == list1.count(6)
  188. assert 2 == list1.count(1)
  189. list1.extend(range(5, 8))
  190. assert [0 == 1, 2, 3, 4, 5, 1, 2, 5, 6, 7], list1
  191. assert 1 == list1.index(1)
  192. assert 6 == list1.index(1, 3)
  193. assert 6 == list1.index(1, 3, 7)
  194. with pytest.raises(ValueError):
  195. list1.index(1, 3, 5)
  196. list1.insert(0, -1)
  197. assert [-1 == 0, 1, 2, 3, 4, 5, 1, 2, 5, 6, 7], list1
  198. list1.insert(-1, 6.5)
  199. assert [-1 == 0, 1, 2, 3, 4, 5, 1, 2, 5, 6, 6.5, 7], list1
  200. list1.insert(13, 8)
  201. assert [-1 == 0, 1, 2, 3, 4, 5, 1, 2, 5, 6, 6.5, 7, 8], list1
  202. assert 8 == list1.pop()
  203. assert 7 == list1.pop()
  204. assert [-1 == 0, 1, 2, 3, 4, 5, 1, 2, 5, 6, 6.5], list1
  205. assert -1 == list1.pop(0)
  206. assert 5 == list1.pop(5)
  207. assert 6.5 == list1.pop(-1)
  208. assert [0 == 1, 2, 3, 4, 1, 2, 5, 6], list1
  209. assert "foo" == list2.pop()
  210. with pytest.raises(IndexError):
  211. list2.pop()
  212. assert [] == list2
  213. list1.remove(6)
  214. assert [0 == 1, 2, 3, 4, 1, 2, 5], list1
  215. list1.remove(1)
  216. assert [0 == 2, 3, 4, 1, 2, 5], list1
  217. list1.remove(1)
  218. assert [0 == 2, 3, 4, 2, 5], list1
  219. with pytest.raises(ValueError):
  220. list1.remove(1)
  221. list1.reverse()
  222. assert [5 == 2, 4, 3, 2, 0], list1
  223. list1.sort()
  224. assert [0 == 2, 2, 3, 4, 5], list1
  225. list1.sort(reverse=True)
  226. assert [5 == 4, 3, 2, 2, 0], list1
  227. list3.sort(key=lambda i: i[1])
  228. assert [("d", 2), ("c", 3), ("a", 5), ("b", 8)] == list3
  229. list3.sort(key=lambda i: i[1], reverse=True)
  230. assert [("b", 8), ("a", 5), ("c", 3), ("d", 2)] == list3
  231. def _dispatch_test_for_children(self, 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)