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.
 
 
 
 

802 lines
26 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 Template node.
  22. """
  23. from difflib import unified_diff
  24. import pytest
  25. from mwparserfromhell.nodes import HTMLEntity, Template, Text
  26. from mwparserfromhell.nodes.extras import Parameter
  27. from mwparserfromhell import parse
  28. from .conftest import assert_wikicode_equal, wrap, wraptext
  29. pgens = lambda k, v: Parameter(wraptext(k), wraptext(v), showkey=True)
  30. pgenh = lambda k, v: Parameter(wraptext(k), wraptext(v), showkey=False)
  31. def test_str():
  32. """test Template.__str__()"""
  33. node = Template(wraptext("foobar"))
  34. assert "{{foobar}}" == str(node)
  35. node2 = Template(wraptext("foo"), [pgenh("1", "bar"), pgens("abc", "def")])
  36. assert "{{foo|bar|abc=def}}" == str(node2)
  37. def test_children():
  38. """test Template.__children__()"""
  39. node2p1 = Parameter(wraptext("1"), wraptext("bar"), showkey=False)
  40. node2p2 = Parameter(wraptext("abc"), wrap([Text("def"), Text("ghi")]), showkey=True)
  41. node1 = Template(wraptext("foobar"))
  42. node2 = Template(wraptext("foo"), [node2p1, node2p2])
  43. gen1 = node1.__children__()
  44. gen2 = node2.__children__()
  45. assert node1.name == next(gen1)
  46. assert node2.name == next(gen2)
  47. assert node2.params[0].value == next(gen2)
  48. assert node2.params[1].name == next(gen2)
  49. assert node2.params[1].value == next(gen2)
  50. with pytest.raises(StopIteration):
  51. next(gen1)
  52. with pytest.raises(StopIteration):
  53. next(gen2)
  54. def test_strip():
  55. """test Template.__strip__()"""
  56. node1 = Template(wraptext("foobar"))
  57. node2 = Template(
  58. wraptext("foo"), [pgenh("1", "bar"), pgens("foo", ""), pgens("abc", "def")]
  59. )
  60. node3 = Template(
  61. wraptext("foo"),
  62. [
  63. pgenh("1", "foo"),
  64. Parameter(
  65. wraptext("2"), wrap([Template(wraptext("hello"))]), showkey=False
  66. ),
  67. pgenh("3", "bar"),
  68. ],
  69. )
  70. assert node1.__strip__(keep_template_params=False) is None
  71. assert node2.__strip__(keep_template_params=False) is None
  72. assert "" == node1.__strip__(keep_template_params=True)
  73. assert "bar def" == node2.__strip__(keep_template_params=True)
  74. assert "foo bar" == node3.__strip__(keep_template_params=True)
  75. def test_showtree():
  76. """test Template.__showtree__()"""
  77. output = []
  78. getter, marker = object(), object()
  79. get = lambda code: output.append((getter, code))
  80. mark = lambda: output.append(marker)
  81. node1 = Template(wraptext("foobar"))
  82. node2 = Template(wraptext("foo"), [pgenh("1", "bar"), pgens("abc", "def")])
  83. node1.__showtree__(output.append, get, mark)
  84. node2.__showtree__(output.append, get, mark)
  85. valid = [
  86. "{{",
  87. (getter, node1.name),
  88. "}}",
  89. "{{",
  90. (getter, node2.name),
  91. " | ",
  92. marker,
  93. (getter, node2.params[0].name),
  94. " = ",
  95. marker,
  96. (getter, node2.params[0].value),
  97. " | ",
  98. marker,
  99. (getter, node2.params[1].name),
  100. " = ",
  101. marker,
  102. (getter, node2.params[1].value),
  103. "}}",
  104. ]
  105. assert valid == output
  106. def test_name():
  107. """test getter/setter for the name attribute"""
  108. name = wraptext("foobar")
  109. node1 = Template(name)
  110. node2 = Template(name, [pgenh("1", "bar")])
  111. assert name is node1.name
  112. assert name is node2.name
  113. node1.name = "asdf"
  114. node2.name = "téstïng"
  115. assert_wikicode_equal(wraptext("asdf"), node1.name)
  116. assert_wikicode_equal(wraptext("téstïng"), node2.name)
  117. def test_params():
  118. """test getter for the params attribute"""
  119. node1 = Template(wraptext("foobar"))
  120. plist = [pgenh("1", "bar"), pgens("abc", "def")]
  121. node2 = Template(wraptext("foo"), plist)
  122. assert [] == node1.params
  123. assert plist is node2.params
  124. def test_has():
  125. """test Template.has()"""
  126. node1 = Template(wraptext("foobar"))
  127. node2 = Template(wraptext("foo"), [pgenh("1", "bar"), pgens("\nabc ", "def")])
  128. node3 = Template(
  129. wraptext("foo"), [pgenh("1", "a"), pgens("b", "c"), pgens("1", "d")]
  130. )
  131. node4 = Template(wraptext("foo"), [pgenh("1", "a"), pgens("b", " ")])
  132. assert node1.has("foobar", False) is False
  133. assert node2.has(1, False) is True
  134. assert node2.has("abc", False) is True
  135. assert node2.has("def", False) is False
  136. assert node3.has("1", False) is True
  137. assert node3.has(" b ", False) is True
  138. assert node4.has("b", False) is True
  139. assert node3.has("b", True) is True
  140. assert node4.has("b", True) is False
  141. assert node1.has_param("foobar", False) is False
  142. assert node2.has_param(1, False) is True
  143. def test_get():
  144. """test Template.get()"""
  145. node1 = Template(wraptext("foobar"))
  146. node2p1 = pgenh("1", "bar")
  147. node2p2 = pgens("abc", "def")
  148. node2 = Template(wraptext("foo"), [node2p1, node2p2])
  149. node3p1 = pgens("b", "c")
  150. node3p2 = pgens("1", "d")
  151. node3 = Template(wraptext("foo"), [pgenh("1", "a"), node3p1, node3p2])
  152. node4p1 = pgens(" b", " ")
  153. node4 = Template(wraptext("foo"), [pgenh("1", "a"), node4p1])
  154. with pytest.raises(ValueError):
  155. node1.get("foobar")
  156. assert node2p1 is node2.get(1)
  157. assert node2p2 is node2.get("abc")
  158. with pytest.raises(ValueError):
  159. node2.get("def")
  160. assert node3p1 is node3.get("b")
  161. assert node3p2 is node3.get("1")
  162. assert node4p1 is node4.get("b ")
  163. def test_add():
  164. """test Template.add()"""
  165. node1 = Template(wraptext("a"), [pgens("b", "c"), pgenh("1", "d")])
  166. node2 = Template(wraptext("a"), [pgens("b", "c"), pgenh("1", "d")])
  167. node3 = Template(wraptext("a"), [pgens("b", "c"), pgenh("1", "d")])
  168. node4 = Template(wraptext("a"), [pgens("b", "c"), pgenh("1", "d")])
  169. node5 = Template(wraptext("a"), [pgens("b", "c"), pgens(" d ", "e")])
  170. node6 = Template(wraptext("a"), [pgens("b", "c"), pgens("b", "d"), pgens("b", "e")])
  171. node7 = Template(wraptext("a"), [pgens("b", "c"), pgenh("1", "d")])
  172. node8p = pgenh("1", "d")
  173. node8 = Template(wraptext("a"), [pgens("b", "c"), node8p])
  174. node9 = Template(wraptext("a"), [pgens("b", "c"), pgenh("1", "d")])
  175. node10 = Template(wraptext("a"), [pgens("b", "c"), pgenh("1", "e")])
  176. node11 = Template(wraptext("a"), [pgens("b", "c")])
  177. node12 = Template(wraptext("a"), [pgens("b", "c")])
  178. node13 = Template(
  179. wraptext("a"), [pgens("\nb ", " c"), pgens("\nd ", " e"), pgens("\nf ", " g")]
  180. )
  181. node14 = Template(
  182. wraptext("a\n"),
  183. [
  184. pgens("b ", "c\n"),
  185. pgens("d ", " e"),
  186. pgens("f ", "g\n"),
  187. pgens("h ", " i\n"),
  188. ],
  189. )
  190. node15 = Template(
  191. wraptext("a"),
  192. [pgens("b ", " c\n"), pgens("\nd ", " e"), pgens("\nf ", "g ")],
  193. )
  194. node16 = Template(
  195. wraptext("a"), [pgens("\nb ", " c"), pgens("\nd ", " e"), pgens("\nf ", " g")]
  196. )
  197. node17 = Template(wraptext("a"), [pgenh("1", "b")])
  198. node18 = Template(wraptext("a"), [pgenh("1", "b")])
  199. node19 = Template(wraptext("a"), [pgenh("1", "b")])
  200. node20 = Template(
  201. wraptext("a"),
  202. [pgenh("1", "b"), pgenh("2", "c"), pgenh("3", "d"), pgenh("4", "e")],
  203. )
  204. node21 = Template(
  205. wraptext("a"),
  206. [pgenh("1", "b"), pgenh("2", "c"), pgens("4", "d"), pgens("5", "e")],
  207. )
  208. node22 = Template(
  209. wraptext("a"),
  210. [pgenh("1", "b"), pgenh("2", "c"), pgens("4", "d"), pgens("5", "e")],
  211. )
  212. node23 = Template(wraptext("a"), [pgenh("1", "b")])
  213. node24 = Template(wraptext("a"), [pgenh("1", "b")])
  214. node25 = Template(wraptext("a"), [pgens("b", "c")])
  215. node26 = Template(wraptext("a"), [pgenh("1", "b")])
  216. node27 = Template(wraptext("a"), [pgenh("1", "b")])
  217. node28 = Template(wraptext("a"), [pgens("1", "b")])
  218. node29 = Template(
  219. wraptext("a"), [pgens("\nb ", " c"), pgens("\nd ", " e"), pgens("\nf ", " g")]
  220. )
  221. node30 = Template(
  222. wraptext("a\n"),
  223. [
  224. pgens("b ", "c\n"),
  225. pgens("d ", " e"),
  226. pgens("f ", "g\n"),
  227. pgens("h ", " i\n"),
  228. ],
  229. )
  230. node31 = Template(
  231. wraptext("a"),
  232. [pgens("b ", " c\n"), pgens("\nd ", " e"), pgens("\nf ", "g ")],
  233. )
  234. node32 = Template(
  235. wraptext("a"),
  236. [pgens("\nb ", " c "), pgens("\nd ", " e "), pgens("\nf ", " g ")],
  237. )
  238. node33 = Template(
  239. wraptext("a"),
  240. [
  241. pgens("b", "c"),
  242. pgens("d", "e"),
  243. pgens("b", "f"),
  244. pgens("b", "h"),
  245. pgens("i", "j"),
  246. ],
  247. )
  248. node34 = Template(
  249. wraptext("a"),
  250. [pgens("1", "b"), pgens("x", "y"), pgens("1", "c"), pgens("2", "d")],
  251. )
  252. node35 = Template(
  253. wraptext("a"),
  254. [pgens("1", "b"), pgens("x", "y"), pgenh("1", "c"), pgenh("2", "d")],
  255. )
  256. node36 = Template(
  257. wraptext("a"), [pgens("b", "c"), pgens("d", "e"), pgens("f", "g")]
  258. )
  259. node37 = Template(wraptext("a"), [pgenh("1", "")])
  260. node38 = Template(wraptext("abc"))
  261. node39 = Template(wraptext("a"), [pgenh("1", " b ")])
  262. node40 = Template(wraptext("a"), [pgenh("1", " b"), pgenh("2", " c")])
  263. node41 = Template(wraptext("a"), [pgens("1", " b"), pgens("2", " c")])
  264. node42 = Template(wraptext("a"), [pgens("b", " \n")])
  265. node1.add("e", "f", showkey=True)
  266. node2.add(2, "g", showkey=False)
  267. node3.add("e", "foo|bar", showkey=True)
  268. node4.add("e", "f", showkey=True, before="b")
  269. node5.add("f", "g", showkey=True, before=" d ")
  270. node6.add("f", "g", showkey=True, before="b")
  271. with pytest.raises(ValueError):
  272. node7.add("e", "f", showkey=True, before="q")
  273. node8.add("e", "f", showkey=True, before=node8p)
  274. node9.add("e", "f", showkey=True, before=pgenh("1", "d"))
  275. with pytest.raises(ValueError):
  276. node10.add("e", "f", showkey=True, before=pgenh("1", "d"))
  277. node11.add("d", "foo=bar", showkey=True)
  278. node12.add("1", "foo=bar", showkey=False)
  279. node13.add("h", "i", showkey=True)
  280. node14.add("j", "k", showkey=True)
  281. node15.add("h", "i", showkey=True)
  282. node16.add("h", "i", showkey=True, preserve_spacing=False)
  283. node17.add("2", "c")
  284. node18.add("3", "c")
  285. node19.add("c", "d")
  286. node20.add("5", "f")
  287. node21.add("3", "f")
  288. node22.add("6", "f")
  289. node23.add("c", "foo=bar")
  290. node24.add("2", "foo=bar")
  291. node25.add("b", "d")
  292. node26.add("1", "foo=bar")
  293. node27.add("1", "foo=bar", showkey=True)
  294. node28.add("1", "foo=bar", showkey=False)
  295. node29.add("d", "foo")
  296. node30.add("f", "foo")
  297. node31.add("f", "foo")
  298. node32.add("d", "foo", preserve_spacing=False)
  299. node33.add("b", "k")
  300. node34.add("1", "e")
  301. node35.add("1", "e")
  302. node36.add("d", "h", before="b")
  303. node37.add(1, "b")
  304. node38.add("1", "foo")
  305. with pytest.raises(ValueError):
  306. node38.add("z", "bar", showkey=False)
  307. node39.add("1", "c")
  308. node40.add("3", "d")
  309. node41.add("3", "d")
  310. node42.add("b", "hello")
  311. node43 = Template(
  312. wraptext("a"), [pgens("b", "c"), pgens("d", "e"), pgens("f", "g")]
  313. )
  314. node44 = Template(
  315. wraptext("a"), [pgens("b", "c"), pgens("d", "e"), pgens("f", "g")]
  316. )
  317. node43.add("new_param", "value", after="d")
  318. node44.add("new_param", "value", after="f")
  319. assert "{{a|b=c|d|e=f}}" == node1
  320. assert "{{a|b=c|d|g}}" == node2
  321. assert "{{a|b=c|d|e=foo&#124;bar}}" == node3
  322. assert isinstance(node3.params[2].value.get(1), HTMLEntity)
  323. assert "{{a|e=f|b=c|d}}" == node4
  324. assert "{{a|b=c|f=g| d =e}}" == node5
  325. assert "{{a|b=c|b=d|f=g|b=e}}" == node6
  326. assert "{{a|b=c|d}}" == node7
  327. assert "{{a|b=c|e=f|d}}" == node8
  328. assert "{{a|b=c|e=f|d}}" == node9
  329. assert "{{a|b=c|e}}" == node10
  330. assert "{{a|b=c|d=foo=bar}}" == node11
  331. assert "{{a|b=c|foo&#61;bar}}" == node12
  332. assert isinstance(node12.params[1].value.get(1), HTMLEntity)
  333. assert "{{a|\nb = c|\nd = e|\nf = g|\nh = i}}" == node13
  334. assert "{{a\n|b =c\n|d = e|f =g\n|h = i\n|j =k\n}}" == node14
  335. assert "{{a|b = c\n|\nd = e|\nf =g |\nh = i}}" == node15
  336. assert "{{a|\nb = c|\nd = e|\nf = g|h=i}}" == node16
  337. assert "{{a|b|c}}" == node17
  338. assert "{{a|b|3=c}}" == node18
  339. assert "{{a|b|c=d}}" == node19
  340. assert "{{a|b|c|d|e|f}}" == node20
  341. assert "{{a|b|c|4=d|5=e|f}}" == node21
  342. assert "{{a|b|c|4=d|5=e|6=f}}" == node22
  343. assert "{{a|b|c=foo=bar}}" == node23
  344. assert "{{a|b|foo&#61;bar}}" == node24
  345. assert isinstance(node24.params[1].value.get(1), HTMLEntity)
  346. assert "{{a|b=d}}" == node25
  347. assert "{{a|foo&#61;bar}}" == node26
  348. assert isinstance(node26.params[0].value.get(1), HTMLEntity)
  349. assert "{{a|1=foo=bar}}" == node27
  350. assert "{{a|foo&#61;bar}}" == node28
  351. assert isinstance(node28.params[0].value.get(1), HTMLEntity)
  352. assert "{{a|\nb = c|\nd = foo|\nf = g}}" == node29
  353. assert "{{a\n|b =c\n|d = e|f =foo\n|h = i\n}}" == node30
  354. assert "{{a|b = c\n|\nd = e|\nf =foo }}" == node31
  355. assert "{{a|\nb = c |\nd =foo|\nf = g }}" == node32
  356. assert "{{a|b=k|d=e|i=j}}" == node33
  357. assert "{{a|1=e|x=y|2=d}}" == node34
  358. assert "{{a|x=y|e|d}}" == node35
  359. assert "{{a|b=c|d=h|f=g}}" == node36
  360. assert "{{a|b}}" == node37
  361. assert "{{abc|foo}}" == node38
  362. assert "{{a|c}}" == node39
  363. assert "{{a| b| c|d}}" == node40
  364. assert "{{a|1= b|2= c|3= d}}" == node41
  365. assert "{{a|b=hello \n}}" == node42
  366. assert "{{a|b=c|d=e|new_param=value|f=g}}" == node43
  367. assert "{{a|b=c|d=e|f=g|new_param=value}}" == node44
  368. def test_update():
  369. """test template.update()"""
  370. node1 = Template(wraptext("a"))
  371. node1.update([{"name": "b", "value": "c"}])
  372. assert "{{a|b=c}}" == node1
  373. node2 = Template(wraptext("a"))
  374. node2.update([{"name": "1", "value": "b", "showkey": False}])
  375. assert "{{a|b}}" == node2
  376. node3 = Template(wraptext("a"), [pgens("b", "c"), pgens("d", "e")])
  377. node3.update([
  378. {"name": "f", "value": "g", "before": "d"},
  379. {"name": "h", "value": "i", "after": "b"}
  380. ])
  381. assert "{{a|b=c|h=i|f=g|d=e}}" == node3
  382. node4 = Template(wraptext("a\n"), [
  383. pgens("b ", "c\n"),
  384. pgens("d ", " e")
  385. ])
  386. node4.update([{
  387. "name": "e",
  388. "value": "f",
  389. "preserve_spacing": True
  390. }])
  391. assert "{{a\n|b =c\n|d = e|e =f}}" == node4
  392. node5 = Template(wraptext("a"), [pgens("b", "c")])
  393. node5.update([
  394. {
  395. "name": "1",
  396. "value": "e",
  397. "showkey": False,
  398. "before": "b"
  399. },
  400. {
  401. "name": "f",
  402. "value": "g",
  403. "preserve_spacing": False
  404. }
  405. ])
  406. assert "{{a|e|b=c|f=g}}" == node5
  407. node6 = Template(wraptext("a"), [pgens("b", "c")])
  408. node6.update([{"name": "b", "value": "d"}])
  409. assert "{{a|b=d}}" == node6
  410. node7 = Template(wraptext("a"), [pgenh("1", "b")])
  411. node7.update([{"name": "1", "value": "c"}])
  412. assert "{{a|c}}" == node7
  413. def test_remove():
  414. """test Template.remove()"""
  415. node1 = Template(wraptext("foobar"))
  416. node2 = Template(wraptext("foo"), [pgenh("1", "bar"), pgens("abc", "def")])
  417. node3 = Template(wraptext("foo"), [pgenh("1", "bar"), pgens("abc", "def")])
  418. node4 = Template(wraptext("foo"), [pgenh("1", "bar"), pgenh("2", "baz")])
  419. node5 = Template(
  420. wraptext("foo"), [pgens(" a", "b"), pgens("b", "c"), pgens("a ", "d")]
  421. )
  422. node6 = Template(
  423. wraptext("foo"), [pgens(" a", "b"), pgens("b", "c"), pgens("a ", "d")]
  424. )
  425. node7 = Template(
  426. wraptext("foo"), [pgens("1 ", "a"), pgens(" 1", "b"), pgens("2", "c")]
  427. )
  428. node8 = Template(
  429. wraptext("foo"), [pgens("1 ", "a"), pgens(" 1", "b"), pgens("2", "c")]
  430. )
  431. node9 = Template(
  432. wraptext("foo"), [pgens("1 ", "a"), pgenh("1", "b"), pgenh("2", "c")]
  433. )
  434. node10 = Template(
  435. wraptext("foo"), [pgens("1 ", "a"), pgenh("1", "b"), pgenh("2", "c")]
  436. )
  437. node11 = Template(
  438. wraptext("foo"), [pgens(" a", "b"), pgens("b", "c"), pgens("a ", "d")]
  439. )
  440. node12 = Template(
  441. wraptext("foo"), [pgens(" a", "b"), pgens("b", "c"), pgens("a ", "d")]
  442. )
  443. node13 = Template(
  444. wraptext("foo"), [pgens(" a", "b"), pgens("b", "c"), pgens("a ", "d")]
  445. )
  446. node14 = Template(
  447. wraptext("foo"), [pgens(" a", "b"), pgens("b", "c"), pgens("a ", "d")]
  448. )
  449. node15 = Template(
  450. wraptext("foo"), [pgens(" a", "b"), pgens("b", "c"), pgens("a ", "d")]
  451. )
  452. node16 = Template(
  453. wraptext("foo"), [pgens(" a", "b"), pgens("b", "c"), pgens("a ", "d")]
  454. )
  455. node17 = Template(
  456. wraptext("foo"), [pgens("1 ", "a"), pgenh("1", "b"), pgenh("2", "c")]
  457. )
  458. node18 = Template(
  459. wraptext("foo"), [pgens("1 ", "a"), pgenh("1", "b"), pgenh("2", "c")]
  460. )
  461. node19 = Template(
  462. wraptext("foo"), [pgens("1 ", "a"), pgenh("1", "b"), pgenh("2", "c")]
  463. )
  464. node20 = Template(
  465. wraptext("foo"), [pgens("1 ", "a"), pgenh("1", "b"), pgenh("2", "c")]
  466. )
  467. node21 = Template(
  468. wraptext("foo"),
  469. [
  470. pgens("a", "b"),
  471. pgens("c", "d"),
  472. pgens("e", "f"),
  473. pgens("a", "b"),
  474. pgens("a", "b"),
  475. ],
  476. )
  477. node22 = Template(
  478. wraptext("foo"),
  479. [
  480. pgens("a", "b"),
  481. pgens("c", "d"),
  482. pgens("e", "f"),
  483. pgens("a", "b"),
  484. pgens("a", "b"),
  485. ],
  486. )
  487. node23 = Template(
  488. wraptext("foo"),
  489. [
  490. pgens("a", "b"),
  491. pgens("c", "d"),
  492. pgens("e", "f"),
  493. pgens("a", "b"),
  494. pgens("a", "b"),
  495. ],
  496. )
  497. node24 = Template(
  498. wraptext("foo"),
  499. [
  500. pgens("a", "b"),
  501. pgens("c", "d"),
  502. pgens("e", "f"),
  503. pgens("a", "b"),
  504. pgens("a", "b"),
  505. ],
  506. )
  507. node25 = Template(
  508. wraptext("foo"),
  509. [
  510. pgens("a", "b"),
  511. pgens("c", "d"),
  512. pgens("e", "f"),
  513. pgens("a", "b"),
  514. pgens("a", "b"),
  515. ],
  516. )
  517. node26 = Template(
  518. wraptext("foo"),
  519. [
  520. pgens("a", "b"),
  521. pgens("c", "d"),
  522. pgens("e", "f"),
  523. pgens("a", "b"),
  524. pgens("a", "b"),
  525. ],
  526. )
  527. node27 = Template(wraptext("foo"), [pgenh("1", "bar")])
  528. node28 = Template(wraptext("foo"), [pgenh("1", "bar")])
  529. node2.remove("1")
  530. node2.remove("abc")
  531. node3.remove(1, keep_field=True)
  532. node3.remove("abc", keep_field=True)
  533. node4.remove("1", keep_field=False)
  534. node5.remove("a", keep_field=False)
  535. node6.remove("a", keep_field=True)
  536. node7.remove(1, keep_field=True)
  537. node8.remove(1, keep_field=False)
  538. node9.remove(1, keep_field=True)
  539. node10.remove(1, keep_field=False)
  540. node11.remove(node11.params[0], keep_field=False)
  541. node12.remove(node12.params[0], keep_field=True)
  542. node13.remove(node13.params[1], keep_field=False)
  543. node14.remove(node14.params[1], keep_field=True)
  544. node15.remove(node15.params[2], keep_field=False)
  545. node16.remove(node16.params[2], keep_field=True)
  546. node17.remove(node17.params[0], keep_field=False)
  547. node18.remove(node18.params[0], keep_field=True)
  548. node19.remove(node19.params[1], keep_field=False)
  549. node20.remove(node20.params[1], keep_field=True)
  550. node21.remove("a", keep_field=False)
  551. node22.remove("a", keep_field=True)
  552. node23.remove(node23.params[0], keep_field=False)
  553. node24.remove(node24.params[0], keep_field=True)
  554. node25.remove(node25.params[3], keep_field=False)
  555. node26.remove(node26.params[3], keep_field=True)
  556. with pytest.raises(ValueError):
  557. node1.remove(1)
  558. with pytest.raises(ValueError):
  559. node1.remove("a")
  560. with pytest.raises(ValueError):
  561. node2.remove("1")
  562. assert "{{foo}}" == node2
  563. assert "{{foo||abc=}}" == node3
  564. assert "{{foo|2=baz}}" == node4
  565. assert "{{foo|b=c}}" == node5
  566. assert "{{foo| a=|b=c}}" == node6
  567. assert "{{foo|1 =|2=c}}" == node7
  568. assert "{{foo|2=c}}" == node8
  569. assert "{{foo||c}}" == node9
  570. assert "{{foo|2=c}}" == node10
  571. assert "{{foo|b=c|a =d}}" == node11
  572. assert "{{foo| a=|b=c|a =d}}" == node12
  573. assert "{{foo| a=b|a =d}}" == node13
  574. assert "{{foo| a=b|b=|a =d}}" == node14
  575. assert "{{foo| a=b|b=c}}" == node15
  576. assert "{{foo| a=b|b=c|a =}}" == node16
  577. assert "{{foo|b|c}}" == node17
  578. assert "{{foo|1 =|b|c}}" == node18
  579. assert "{{foo|1 =a|2=c}}" == node19
  580. assert "{{foo|1 =a||c}}" == node20
  581. assert "{{foo|c=d|e=f}}" == node21
  582. assert "{{foo|a=|c=d|e=f}}" == node22
  583. assert "{{foo|c=d|e=f|a=b|a=b}}" == node23
  584. assert "{{foo|a=|c=d|e=f|a=b|a=b}}" == node24
  585. assert "{{foo|a=b|c=d|e=f|a=b}}" == node25
  586. assert "{{foo|a=b|c=d|e=f|a=|a=b}}" == node26
  587. with pytest.raises(ValueError):
  588. node27.remove(node28.get(1))
  589. def test_formatting():
  590. """test realistic param manipulation with complex whitespace formatting
  591. (assumes that parsing works correctly)"""
  592. tests = [
  593. # https://en.wikipedia.org/w/index.php?title=Lamar_County,_Georgia&oldid=792356004
  594. (
  595. """{{Infobox U.S. county
  596. | county = Lamar County
  597. | state = Georgia
  598. | seal =
  599. | founded = 1920
  600. | seat wl = Barnesville
  601. | largest city wl = Barnesville
  602. | area_total_sq_mi = 186
  603. | area_land_sq_mi = 184
  604. | area_water_sq_mi = 2.3
  605. | area percentage = 1.3%
  606. | census yr = 2010
  607. | pop = 18317
  608. | density_sq_mi = 100
  609. | time zone = Eastern
  610. | footnotes =
  611. | web = www.lamarcountyga.com
  612. | ex image = Lamar County Georgia Courthouse.jpg
  613. | ex image cap = Lamar County courthouse in Barnesville
  614. | district = 3rd
  615. | named for = [[Lucius Quintus Cincinnatus Lamar II]]
  616. }}""",
  617. """@@ -11,4 +11,4 @@
  618. | area percentage = 1.3%
  619. -| census yr = 2010
  620. -| pop = 18317
  621. +| census estimate yr = 2016
  622. +| pop = 12345<ref>example ref</ref>
  623. | density_sq_mi = 100""",
  624. ),
  625. # https://en.wikipedia.org/w/index.php?title=Rockdale_County,_Georgia&oldid=792359760
  626. (
  627. """{{Infobox U.S. County|
  628. county = Rockdale County |
  629. state = Georgia |
  630. seal = |
  631. founded = October 18, 1870 |
  632. seat wl = Conyers |
  633. largest city wl = Conyers |
  634. area_total_sq_mi = 132 |
  635. area_land_sq_mi = 130 |
  636. area_water_sq_mi = 2.3 |
  637. area percentage = 1.7% |
  638. census yr = 2010|
  639. pop = 85215 |
  640. density_sq_mi = 657 |
  641. web = www.rockdalecounty.org
  642. | ex image = Rockdale-county-courthouse.jpg
  643. | ex image cap = Rockdale County Courthouse in Conyers
  644. | district = 4th
  645. | time zone= Eastern
  646. }}""",
  647. """@@ -11,4 +11,4 @@
  648. area percentage = 1.7% |
  649. - census yr = 2010|
  650. - pop = 85215 |
  651. + census estimate yr = 2016 |
  652. + pop = 12345<ref>example ref</ref> |
  653. density_sq_mi = 657 |""",
  654. ),
  655. # https://en.wikipedia.org/w/index.php?title=Spalding_County,_Georgia&oldid=792360413
  656. (
  657. """{{Infobox U.S. County|
  658. | county = Spalding County |
  659. | state = Georgia |
  660. | seal = |
  661. | founded = 1851 |
  662. | seat wl = Griffin |
  663. | largest city wl = Griffin |
  664. | area_total_sq_mi = 200 |
  665. | area_land_sq_mi = 196 |
  666. | area_water_sq_mi = 3.1 |
  667. | area percentage = 1.6% |
  668. | census yr = 2010|
  669. | pop = 64073 |
  670. | density_sq_mi = 326 |
  671. | web = www.spaldingcounty.com |
  672. | named for = [[Thomas Spalding]]
  673. | ex image = Spalding County Courthouse (NE corner).JPG
  674. | ex image cap = Spalding County Courthouse in Griffin
  675. | district = 3rd
  676. | time zone = Eastern
  677. }}""",
  678. """@@ -11,4 +11,4 @@
  679. | area percentage = 1.6% |
  680. -| census yr = 2010|
  681. -| pop = 64073 |
  682. +|
  683. +| census estimate yr = 2016 | pop = 12345<ref>example ref</ref> |
  684. | density_sq_mi = 326 |""",
  685. ),
  686. # https://en.wikipedia.org/w/index.php?title=Clinton_County,_Illinois&oldid=794694648
  687. (
  688. """{{Infobox U.S. county
  689. |county = Clinton County
  690. |state = Illinois
  691. | ex image = File:Clinton County Courthouse, Carlyle.jpg
  692. | ex image cap = [[Clinton County Courthouse (Illinois)|Clinton County Courthouse]]
  693. |seal =
  694. |founded = 1824
  695. |named for = [[DeWitt Clinton]]
  696. |seat wl= Carlyle
  697. | largest city wl = Breese
  698. |time zone=Central
  699. |area_total_sq_mi = 503
  700. |area_land_sq_mi = 474
  701. |area_water_sq_mi = 29
  702. |area percentage = 5.8%
  703. |census yr = 2010
  704. |pop = 37762
  705. |density_sq_mi = 80
  706. |web = www.clintonco.illinois.gov
  707. | district = 15th
  708. }}""",
  709. """@@ -15,4 +15,4 @@
  710. |area percentage = 5.8%
  711. - |census yr = 2010
  712. - |pop = 37762
  713. + |census estimate yr = 2016
  714. + |pop = 12345<ref>example ref</ref>
  715. |density_sq_mi = 80""",
  716. ),
  717. # https://en.wikipedia.org/w/index.php?title=Winnebago_County,_Illinois&oldid=789193800
  718. (
  719. """{{Infobox U.S. county |
  720. county = Winnebago County |
  721. state = Illinois |
  722. seal = Winnebago County il seal.png |
  723. named for = [[Winnebago (tribe)|Winnebago Tribe]] |
  724. seat wl= Rockford |
  725. largest city wl = Rockford|
  726. area_total_sq_mi = 519 |
  727. area_land_sq_mi = 513|
  728. area_water_sq_mi = 5.9 |
  729. area percentage = 1.1% |
  730. census yr = 2010|
  731. pop = 295266 |
  732. density_sq_mi = 575
  733. | web = www.wincoil.us
  734. | founded year = 1836
  735. | founded date = January 16
  736. | time zone = Central
  737. | district = 16th
  738. | district2 = 17th
  739. }}""",
  740. """@@ -11,4 +11,4 @@
  741. area percentage = 1.1% |
  742. - census yr = 2010|
  743. - pop = 295266 |
  744. + census estimate yr = 2016|
  745. + pop = 12345<ref>example ref</ref> |
  746. density_sq_mi = 575""",
  747. ),
  748. ]
  749. for original, expected in tests:
  750. code = parse(original)
  751. template = code.filter_templates()[0]
  752. template.add("pop", "12345<ref>example ref</ref>")
  753. template.add("census estimate yr", "2016", before="pop")
  754. template.remove("census yr")
  755. oldlines = original.splitlines(True)
  756. newlines = str(code).splitlines(True)
  757. difflines = unified_diff(oldlines, newlines, n=1)
  758. diff = "".join(list(difflines)[2:]).strip()
  759. assert expected == diff