A Python parser for MediaWiki wikicode https://mwparserfromhell.readthedocs.io/
Nelze vybrat více než 25 témat Téma musí začínat písmenem nebo číslem, může obsahovat pomlčky („-“) a může být dlouhé až 35 znaků.
 
 
 
 

433 řádky
14 KiB

  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. """
  21. Test cases for the Tag node.
  22. """
  23. import pytest
  24. from mwparserfromhell.nodes import Tag, Template, Text
  25. from mwparserfromhell.nodes.extras import Attribute
  26. from .conftest import assert_wikicode_equal, wrap, wraptext
  27. def agen(name, value):
  28. return Attribute(wraptext(name), wraptext(value))
  29. def agennv(name):
  30. return Attribute(wraptext(name))
  31. def agennq(name, value):
  32. return Attribute(wraptext(name), wraptext(value), None)
  33. def agenp(name, v, a, b, c):
  34. return Attribute(wraptext(name), v, '"', a, b, c)
  35. def agenpnv(name, a, b, c):
  36. return Attribute(wraptext(name), None, '"', a, b, c)
  37. def test_str():
  38. """test Tag.__str__()"""
  39. node1 = Tag(wraptext("ref"))
  40. node2 = Tag(wraptext("span"), wraptext("foo"), [agen("style", "color: red;")])
  41. node3 = Tag(
  42. wraptext("ref"),
  43. attrs=[agennq("name", "foo"), agenpnv("some_attr", " ", "", "")],
  44. self_closing=True,
  45. )
  46. node4 = Tag(wraptext("br"), self_closing=True, padding=" ")
  47. node5 = Tag(wraptext("br"), self_closing=True, implicit=True)
  48. node6 = Tag(wraptext("br"), self_closing=True, invalid=True, implicit=True)
  49. node7 = Tag(wraptext("br"), self_closing=True, invalid=True, padding=" ")
  50. node8 = Tag(wraptext("hr"), wiki_markup="----", self_closing=True)
  51. node9 = Tag(wraptext("i"), wraptext("italics!"), wiki_markup="''")
  52. assert "<ref></ref>" == str(node1)
  53. assert '<span style="color: red;">foo</span>' == str(node2)
  54. assert "<ref name=foo some_attr/>" == str(node3)
  55. assert "<br />" == str(node4)
  56. assert "<br>" == str(node5)
  57. assert "</br>" == str(node6)
  58. assert "</br />" == str(node7)
  59. assert "----" == str(node8)
  60. assert "''italics!''" == str(node9)
  61. def test_children():
  62. """test Tag.__children__()"""
  63. # <ref>foobar</ref>
  64. node1 = Tag(wraptext("ref"), wraptext("foobar"))
  65. # '''bold text'''
  66. node2 = Tag(wraptext("b"), wraptext("bold text"), wiki_markup="'''")
  67. # <img id="foo" class="bar" selected />
  68. node3 = Tag(
  69. wraptext("img"),
  70. attrs=[agen("id", "foo"), agen("class", "bar"), agennv("selected")],
  71. self_closing=True,
  72. padding=" ",
  73. )
  74. gen1 = node1.__children__()
  75. gen2 = node2.__children__()
  76. gen3 = node3.__children__()
  77. assert node1.tag == next(gen1)
  78. assert node3.tag == next(gen3)
  79. assert node3.attributes[0].name == next(gen3)
  80. assert node3.attributes[0].value == next(gen3)
  81. assert node3.attributes[1].name == next(gen3)
  82. assert node3.attributes[1].value == next(gen3)
  83. assert node3.attributes[2].name == next(gen3)
  84. assert node1.contents == next(gen1)
  85. assert node2.contents == next(gen2)
  86. assert node1.closing_tag == next(gen1)
  87. with pytest.raises(StopIteration):
  88. next(gen1)
  89. with pytest.raises(StopIteration):
  90. next(gen2)
  91. with pytest.raises(StopIteration):
  92. next(gen3)
  93. def test_strip():
  94. """test Tag.__strip__()"""
  95. node1 = Tag(wraptext("i"), wraptext("foobar"))
  96. node2 = Tag(wraptext("math"), wraptext("foobar"))
  97. node3 = Tag(wraptext("br"), self_closing=True)
  98. assert "foobar" == node1.__strip__()
  99. assert node2.__strip__() is None
  100. assert node3.__strip__() is None
  101. def test_showtree():
  102. """test Tag.__showtree__()"""
  103. output = []
  104. getter, marker = object(), object()
  105. def get(code):
  106. return output.append((getter, code))
  107. def mark():
  108. return output.append(marker)
  109. node1 = Tag(
  110. wraptext("ref"), wraptext("text"), [agen("name", "foo"), agennv("selected")]
  111. )
  112. node2 = Tag(wraptext("br"), self_closing=True, padding=" ")
  113. node3 = Tag(
  114. wraptext("br"), self_closing=True, invalid=True, implicit=True, padding=" "
  115. )
  116. node1.__showtree__(output.append, get, mark)
  117. node2.__showtree__(output.append, get, mark)
  118. node3.__showtree__(output.append, get, mark)
  119. valid = [
  120. "<",
  121. (getter, node1.tag),
  122. (getter, node1.attributes[0].name),
  123. " = ",
  124. marker,
  125. (getter, node1.attributes[0].value),
  126. (getter, node1.attributes[1].name),
  127. ">",
  128. (getter, node1.contents),
  129. "</",
  130. (getter, node1.closing_tag),
  131. ">",
  132. "<",
  133. (getter, node2.tag),
  134. "/>",
  135. "</",
  136. (getter, node3.tag),
  137. ">",
  138. ]
  139. assert valid == output
  140. def test_tag():
  141. """test getter/setter for the tag attribute"""
  142. tag = wraptext("ref")
  143. node = Tag(tag, wraptext("text"))
  144. assert tag is node.tag
  145. assert tag is node.closing_tag
  146. node.tag = "span"
  147. assert_wikicode_equal(wraptext("span"), node.tag)
  148. assert_wikicode_equal(wraptext("span"), node.closing_tag)
  149. assert "<span>text</span>" == node
  150. def test_contents():
  151. """test getter/setter for the contents attribute"""
  152. contents = wraptext("text")
  153. node = Tag(wraptext("ref"), contents)
  154. assert contents is node.contents
  155. node.contents = "text and a {{template}}"
  156. parsed = wrap([Text("text and a "), Template(wraptext("template"))])
  157. assert_wikicode_equal(parsed, node.contents)
  158. assert "<ref>text and a {{template}}</ref>" == node
  159. def test_attributes():
  160. """test getter for the attributes attribute"""
  161. attrs = [agen("name", "bar")]
  162. node1 = Tag(wraptext("ref"), wraptext("foo"))
  163. node2 = Tag(wraptext("ref"), wraptext("foo"), attrs)
  164. assert [] == node1.attributes
  165. assert attrs is node2.attributes
  166. def test_wiki_markup():
  167. """test getter/setter for the wiki_markup attribute"""
  168. node = Tag(wraptext("i"), wraptext("italic text"))
  169. assert None is node.wiki_markup
  170. node.wiki_markup = "''"
  171. assert "''" == node.wiki_markup
  172. assert "''italic text''" == node
  173. node.wiki_markup = False
  174. assert node.wiki_markup is None
  175. assert "<i>italic text</i>" == node
  176. def test_self_closing():
  177. """test getter/setter for the self_closing attribute"""
  178. node = Tag(wraptext("ref"), wraptext("foobar"))
  179. assert node.self_closing is False
  180. node.self_closing = True
  181. assert node.self_closing is True
  182. assert "<ref/>" == node
  183. node.self_closing = 0
  184. assert node.self_closing is False
  185. assert "<ref>foobar</ref>" == node
  186. def test_invalid():
  187. """test getter/setter for the invalid attribute"""
  188. node = Tag(wraptext("br"), self_closing=True, implicit=True)
  189. assert node.invalid is False
  190. node.invalid = True
  191. assert node.invalid is True
  192. assert "</br>" == node
  193. node.invalid = 0
  194. assert node.invalid is False
  195. assert "<br>" == node
  196. def test_implicit():
  197. """test getter/setter for the implicit attribute"""
  198. node = Tag(wraptext("br"), self_closing=True)
  199. assert node.implicit is False
  200. node.implicit = True
  201. assert node.implicit is True
  202. assert "<br>" == node
  203. node.implicit = 0
  204. assert node.implicit is False
  205. assert "<br/>" == node
  206. def test_padding():
  207. """test getter/setter for the padding attribute"""
  208. node = Tag(wraptext("ref"), wraptext("foobar"))
  209. assert "" == node.padding
  210. node.padding = " "
  211. assert " " == node.padding
  212. assert "<ref >foobar</ref>" == node
  213. node.padding = None
  214. assert "" == node.padding
  215. assert "<ref>foobar</ref>" == node
  216. with pytest.raises(ValueError):
  217. node.__setattr__("padding", True)
  218. def test_closing_tag():
  219. """test getter/setter for the closing_tag attribute"""
  220. tag = wraptext("ref")
  221. node = Tag(tag, wraptext("foobar"))
  222. assert tag is node.closing_tag
  223. node.closing_tag = "ref {{ignore me}}"
  224. parsed = wrap([Text("ref "), Template(wraptext("ignore me"))])
  225. assert_wikicode_equal(parsed, node.closing_tag)
  226. assert "<ref>foobar</ref {{ignore me}}>" == node
  227. def test_wiki_style_separator():
  228. """test getter/setter for wiki_style_separator attribute"""
  229. node = Tag(wraptext("table"), wraptext("\n"))
  230. assert None is node.wiki_style_separator
  231. node.wiki_style_separator = "|"
  232. assert "|" == node.wiki_style_separator
  233. node.wiki_markup = "{"
  234. assert "{|\n{" == node
  235. node2 = Tag(wraptext("table"), wraptext("\n"), wiki_style_separator="|")
  236. assert "|" == node2.wiki_style_separator
  237. def test_closing_wiki_markup():
  238. """test getter/setter for closing_wiki_markup attribute"""
  239. node = Tag(wraptext("table"), wraptext("\n"))
  240. assert None is node.closing_wiki_markup
  241. node.wiki_markup = "{|"
  242. assert "{|" == node.closing_wiki_markup
  243. node.closing_wiki_markup = "|}"
  244. assert "|}" == node.closing_wiki_markup
  245. assert "{|\n|}" == node
  246. node.wiki_markup = "!!"
  247. assert "|}" == node.closing_wiki_markup
  248. assert "!!\n|}" == node
  249. node.wiki_markup = False
  250. assert node.closing_wiki_markup is None
  251. assert "<table>\n</table>" == node
  252. node2 = Tag(
  253. wraptext("table"),
  254. wraptext("\n"),
  255. attrs=[agen("id", "foo")],
  256. wiki_markup="{|",
  257. closing_wiki_markup="|}",
  258. )
  259. assert "|}" == node2.closing_wiki_markup
  260. assert '{| id="foo"\n|}' == node2
  261. def test_has():
  262. """test Tag.has()"""
  263. node = Tag(wraptext("ref"), wraptext("cite"), [agen("name", "foo")])
  264. assert node.has("name") is True
  265. assert node.has(" name ") is True
  266. assert node.has(wraptext("name")) is True
  267. assert node.has("Name") is False
  268. assert node.has("foo") is False
  269. attrs = [
  270. agen("id", "foo"),
  271. agenp("class", "bar", " ", "\n", "\n"),
  272. agen("foo", "bar"),
  273. agenpnv("foo", " ", " \n ", " \t"),
  274. ]
  275. node2 = Tag(wraptext("div"), attrs=attrs, self_closing=True)
  276. assert node2.has("id") is True
  277. assert node2.has("class") is True
  278. assert (
  279. node2.has(attrs[1].pad_first + str(attrs[1].name) + attrs[1].pad_before_eq)
  280. is True
  281. )
  282. assert node2.has(attrs[3]) is True
  283. assert node2.has(str(attrs[3])) is True
  284. assert node2.has("idclass") is False
  285. assert node2.has("id class") is False
  286. assert node2.has("id=foo") is False
  287. def test_get():
  288. """test Tag.get()"""
  289. attrs = [agen("name", "foo")]
  290. node = Tag(wraptext("ref"), wraptext("cite"), attrs)
  291. assert attrs[0] is node.get("name")
  292. assert attrs[0] is node.get(" name ")
  293. assert attrs[0] is node.get(wraptext("name"))
  294. with pytest.raises(ValueError):
  295. node.get("Name")
  296. with pytest.raises(ValueError):
  297. node.get("foo")
  298. attrs = [
  299. agen("id", "foo"),
  300. agenp("class", "bar", " ", "\n", "\n"),
  301. agen("foo", "bar"),
  302. agenpnv("foo", " ", " \n ", " \t"),
  303. ]
  304. node2 = Tag(wraptext("div"), attrs=attrs, self_closing=True)
  305. assert attrs[0] is node2.get("id")
  306. assert attrs[1] is node2.get("class")
  307. assert attrs[1] is node2.get(
  308. attrs[1].pad_first + str(attrs[1].name) + attrs[1].pad_before_eq
  309. )
  310. assert attrs[3] is node2.get(attrs[3])
  311. assert attrs[3] is node2.get(str(attrs[3]))
  312. assert attrs[3] is node2.get(" foo")
  313. with pytest.raises(ValueError):
  314. node2.get("idclass")
  315. with pytest.raises(ValueError):
  316. node2.get("id class")
  317. with pytest.raises(ValueError):
  318. node2.get("id=foo")
  319. def test_add():
  320. """test Tag.add()"""
  321. node = Tag(wraptext("ref"), wraptext("cite"))
  322. node.add("name", "value")
  323. node.add("name", "value", quotes=None)
  324. node.add("name", "value", quotes="'")
  325. node.add("name")
  326. node.add(1, False)
  327. node.add("style", "{{foobar}}")
  328. node.add("name", "value", '"', "\n", " ", " ")
  329. attr1 = ' name="value"'
  330. attr2 = " name=value"
  331. attr3 = " name='value'"
  332. attr4 = " name"
  333. attr5 = ' 1="False"'
  334. attr6 = ' style="{{foobar}}"'
  335. attr7 = '\nname = "value"'
  336. assert attr1 == node.attributes[0]
  337. assert attr2 == node.attributes[1]
  338. assert attr3 == node.attributes[2]
  339. assert attr4 == node.attributes[3]
  340. assert attr5 == node.attributes[4]
  341. assert attr6 == node.attributes[5]
  342. assert attr7 == node.attributes[6]
  343. assert attr7 == node.get("name")
  344. assert_wikicode_equal(
  345. wrap([Template(wraptext("foobar"))]), node.attributes[5].value
  346. )
  347. assert (
  348. "".join(
  349. ("<ref", attr1, attr2, attr3, attr4, attr5, attr6, attr7, ">cite</ref>")
  350. )
  351. == node
  352. )
  353. with pytest.raises(ValueError):
  354. node.add("name", "foo", quotes="bar")
  355. with pytest.raises(ValueError):
  356. node.add("name", "a bc d", quotes=None)
  357. def test_remove():
  358. """test Tag.remove()"""
  359. attrs = [
  360. agen("id", "foo"),
  361. agenp("class", "bar", " ", "\n", "\n"),
  362. agen("foo", "bar"),
  363. agenpnv("foo", " ", " \n ", " \t"),
  364. ]
  365. node = Tag(wraptext("div"), attrs=attrs, self_closing=True)
  366. node.remove("class")
  367. assert '<div id="foo" foo="bar" foo \n />' == node
  368. node.remove("foo")
  369. assert '<div id="foo"/>' == node
  370. with pytest.raises(ValueError):
  371. node.remove("foo")
  372. node.remove("id")
  373. assert "<div/>" == node