magic_xml 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (287) hide show
  1. data/README +22 -0
  2. data/Rakefile +52 -0
  3. data/VERSION +1 -0
  4. data/doc/classes/Array.html +148 -0
  5. data/doc/classes/File.html +113 -0
  6. data/doc/classes/Hash.html +117 -0
  7. data/doc/classes/Patterns_all.html +145 -0
  8. data/doc/classes/Patterns_any.html +145 -0
  9. data/doc/classes/String.html +470 -0
  10. data/doc/classes/Symbol.html +145 -0
  11. data/doc/classes/XML.html +1881 -0
  12. data/doc/classes/XML_Comment.html +148 -0
  13. data/doc/classes/XML_PI.html +145 -0
  14. data/doc/classes/XML_Tests.html +1727 -0
  15. data/doc/files/magic_xml_rb.html +186 -0
  16. data/doc/files/simple_examples/xml_hello_f_rb.html +88 -0
  17. data/doc/files/simple_examples/xml_hello_m_rb.html +88 -0
  18. data/doc/files/simple_examples/xml_list_f_rb.html +88 -0
  19. data/doc/files/simple_examples/xml_list_m_rb.html +88 -0
  20. data/doc/files/tests_rb.html +94 -0
  21. data/doc/files/xquery_use_cases/parts/q1_rb.html +117 -0
  22. data/doc/files/xquery_use_cases/rdb/q10_rb.html +88 -0
  23. data/doc/files/xquery_use_cases/rdb/q11_rb.html +88 -0
  24. data/doc/files/xquery_use_cases/rdb/q12_rb.html +88 -0
  25. data/doc/files/xquery_use_cases/rdb/q13_rb.html +88 -0
  26. data/doc/files/xquery_use_cases/rdb/q14_rb.html +88 -0
  27. data/doc/files/xquery_use_cases/rdb/q15_rb.html +88 -0
  28. data/doc/files/xquery_use_cases/rdb/q16_rb.html +88 -0
  29. data/doc/files/xquery_use_cases/rdb/q17_rb.html +88 -0
  30. data/doc/files/xquery_use_cases/rdb/q18_rb.html +88 -0
  31. data/doc/files/xquery_use_cases/rdb/q1_rb.html +88 -0
  32. data/doc/files/xquery_use_cases/rdb/q2_rb.html +88 -0
  33. data/doc/files/xquery_use_cases/rdb/q3_rb.html +88 -0
  34. data/doc/files/xquery_use_cases/rdb/q4_rb.html +88 -0
  35. data/doc/files/xquery_use_cases/rdb/q5_rb.html +88 -0
  36. data/doc/files/xquery_use_cases/rdb/q6_rb.html +88 -0
  37. data/doc/files/xquery_use_cases/rdb/q7_rb.html +88 -0
  38. data/doc/files/xquery_use_cases/rdb/q8_rb.html +88 -0
  39. data/doc/files/xquery_use_cases/rdb/q9_rb.html +88 -0
  40. data/doc/files/xquery_use_cases/seq/q1_rb.html +88 -0
  41. data/doc/files/xquery_use_cases/seq/q2_rb.html +88 -0
  42. data/doc/files/xquery_use_cases/seq/q3_rb.html +88 -0
  43. data/doc/files/xquery_use_cases/seq/q4_rb.html +88 -0
  44. data/doc/files/xquery_use_cases/seq/q5_rb.html +88 -0
  45. data/doc/files/xquery_use_cases/sgml/q10_rb.html +88 -0
  46. data/doc/files/xquery_use_cases/sgml/q1_rb.html +88 -0
  47. data/doc/files/xquery_use_cases/sgml/q2_rb.html +88 -0
  48. data/doc/files/xquery_use_cases/sgml/q3_rb.html +88 -0
  49. data/doc/files/xquery_use_cases/sgml/q4_rb.html +88 -0
  50. data/doc/files/xquery_use_cases/sgml/q5_rb.html +88 -0
  51. data/doc/files/xquery_use_cases/sgml/q6_rb.html +88 -0
  52. data/doc/files/xquery_use_cases/sgml/q7_rb.html +88 -0
  53. data/doc/files/xquery_use_cases/sgml/q8a_rb.html +88 -0
  54. data/doc/files/xquery_use_cases/sgml/q8b_rb.html +88 -0
  55. data/doc/files/xquery_use_cases/sgml/q9_rb.html +88 -0
  56. data/doc/files/xquery_use_cases/solution_sizes_rb.html +88 -0
  57. data/doc/files/xquery_use_cases/string/q1_rb.html +88 -0
  58. data/doc/files/xquery_use_cases/string/q2_rb.html +93 -0
  59. data/doc/files/xquery_use_cases/string/q4_rb.html +88 -0
  60. data/doc/files/xquery_use_cases/string/q5_rb.html +88 -0
  61. data/doc/files/xquery_use_cases/test_driver_rb.html +92 -0
  62. data/doc/files/xquery_use_cases/tree/q1_rb.html +111 -0
  63. data/doc/files/xquery_use_cases/tree/q2_rb.html +88 -0
  64. data/doc/files/xquery_use_cases/tree/q3_rb.html +88 -0
  65. data/doc/files/xquery_use_cases/tree/q4_rb.html +88 -0
  66. data/doc/files/xquery_use_cases/tree/q5_rb.html +88 -0
  67. data/doc/files/xquery_use_cases/tree/q6_rb.html +113 -0
  68. data/doc/files/xquery_use_cases/xmp/q10_rb.html +88 -0
  69. data/doc/files/xquery_use_cases/xmp/q11_rb.html +88 -0
  70. data/doc/files/xquery_use_cases/xmp/q12_rb.html +88 -0
  71. data/doc/files/xquery_use_cases/xmp/q1_rb.html +88 -0
  72. data/doc/files/xquery_use_cases/xmp/q2_rb.html +88 -0
  73. data/doc/files/xquery_use_cases/xmp/q3_rb.html +88 -0
  74. data/doc/files/xquery_use_cases/xmp/q4_rb.html +88 -0
  75. data/doc/files/xquery_use_cases/xmp/q5_rb.html +92 -0
  76. data/doc/files/xquery_use_cases/xmp/q6_rb.html +88 -0
  77. data/doc/files/xquery_use_cases/xmp/q7_rb.html +88 -0
  78. data/doc/files/xquery_use_cases/xmp/q8_rb.html +88 -0
  79. data/doc/files/xquery_use_cases/xmp/q9_rb.html +88 -0
  80. data/doc/fr_class_index.html +56 -0
  81. data/doc/fr_file_index.html +110 -0
  82. data/doc/fr_method_index.html +159 -0
  83. data/doc/index.html +26 -0
  84. data/doc/rdoc-style.css +175 -0
  85. data/lib/magic_xml.rb +1400 -0
  86. data/simple_examples/README +14 -0
  87. data/simple_examples/xml_hello_f.rb +32 -0
  88. data/simple_examples/xml_hello_m.rb +32 -0
  89. data/simple_examples/xml_list_f.rb +36 -0
  90. data/simple_examples/xml_list_m.rb +36 -0
  91. data/test/helper.rb +9 -0
  92. data/test/test_magic_xml.rb +855 -0
  93. data/xquery_use_cases/README +17 -0
  94. data/xquery_use_cases/parts/README +12 -0
  95. data/xquery_use_cases/parts/partlist.xml +13 -0
  96. data/xquery_use_cases/parts/q1.out +16 -0
  97. data/xquery_use_cases/parts/q1.rb +38 -0
  98. data/xquery_use_cases/parts/q1.xquery +18 -0
  99. data/xquery_use_cases/rdb/README +50 -0
  100. data/xquery_use_cases/rdb/bids.xml +81 -0
  101. data/xquery_use_cases/rdb/items.xml +57 -0
  102. data/xquery_use_cases/rdb/q1.out +10 -0
  103. data/xquery_use_cases/rdb/q1.rb +31 -0
  104. data/xquery_use_cases/rdb/q1.xquery +14 -0
  105. data/xquery_use_cases/rdb/q10.out +27 -0
  106. data/xquery_use_cases/rdb/q10.rb +37 -0
  107. data/xquery_use_cases/rdb/q10.xquery +15 -0
  108. data/xquery_use_cases/rdb/q11.out +7 -0
  109. data/xquery_use_cases/rdb/q11.rb +38 -0
  110. data/xquery_use_cases/rdb/q11.xquery +15 -0
  111. data/xquery_use_cases/rdb/q12.out +12 -0
  112. data/xquery_use_cases/rdb/q12.rb +42 -0
  113. data/xquery_use_cases/rdb/q12.xquery +28 -0
  114. data/xquery_use_cases/rdb/q13.out +32 -0
  115. data/xquery_use_cases/rdb/q13.rb +45 -0
  116. data/xquery_use_cases/rdb/q13.xquery +15 -0
  117. data/xquery_use_cases/rdb/q14.out +14 -0
  118. data/xquery_use_cases/rdb/q14.rb +42 -0
  119. data/xquery_use_cases/rdb/q14.xquery +14 -0
  120. data/xquery_use_cases/rdb/q15.out +5 -0
  121. data/xquery_use_cases/rdb/q15.rb +31 -0
  122. data/xquery_use_cases/rdb/q15.xquery +9 -0
  123. data/xquery_use_cases/rdb/q16.out +35 -0
  124. data/xquery_use_cases/rdb/q16.rb +35 -0
  125. data/xquery_use_cases/rdb/q16.xquery +17 -0
  126. data/xquery_use_cases/rdb/q17.out +1 -0
  127. data/xquery_use_cases/rdb/q17.rb +35 -0
  128. data/xquery_use_cases/rdb/q17.xquery +11 -0
  129. data/xquery_use_cases/rdb/q18.out +32 -0
  130. data/xquery_use_cases/rdb/q18.rb +40 -0
  131. data/xquery_use_cases/rdb/q18.xquery +19 -0
  132. data/xquery_use_cases/rdb/q2.out +22 -0
  133. data/xquery_use_cases/rdb/q2.rb +36 -0
  134. data/xquery_use_cases/rdb/q2.xquery +14 -0
  135. data/xquery_use_cases/rdb/q3.out +8 -0
  136. data/xquery_use_cases/rdb/q3.rb +34 -0
  137. data/xquery_use_cases/rdb/q3.xquery +16 -0
  138. data/xquery_use_cases/rdb/q4.out +14 -0
  139. data/xquery_use_cases/rdb/q4.rb +31 -0
  140. data/xquery_use_cases/rdb/q4.xquery +11 -0
  141. data/xquery_use_cases/rdb/q5.out +12 -0
  142. data/xquery_use_cases/rdb/q5.rb +46 -0
  143. data/xquery_use_cases/rdb/q5.xquery +25 -0
  144. data/xquery_use_cases/rdb/q6.out +14 -0
  145. data/xquery_use_cases/rdb/q6.rb +38 -0
  146. data/xquery_use_cases/rdb/q6.xquery +15 -0
  147. data/xquery_use_cases/rdb/q7.out +1 -0
  148. data/xquery_use_cases/rdb/q7.rb +30 -0
  149. data/xquery_use_cases/rdb/q7.xquery +10 -0
  150. data/xquery_use_cases/rdb/q8.out +1 -0
  151. data/xquery_use_cases/rdb/q8.rb +23 -0
  152. data/xquery_use_cases/rdb/q8.xquery +8 -0
  153. data/xquery_use_cases/rdb/q9.out +22 -0
  154. data/xquery_use_cases/rdb/q9.rb +32 -0
  155. data/xquery_use_cases/rdb/q9.xquery +16 -0
  156. data/xquery_use_cases/rdb/users.xml +25 -0
  157. data/xquery_use_cases/seq/README +12 -0
  158. data/xquery_use_cases/seq/q1.out +1 -0
  159. data/xquery_use_cases/seq/q1.rb +25 -0
  160. data/xquery_use_cases/seq/q1.xquery +2 -0
  161. data/xquery_use_cases/seq/q2.out +2 -0
  162. data/xquery_use_cases/seq/q2.rb +25 -0
  163. data/xquery_use_cases/seq/q2.xquery +2 -0
  164. data/xquery_use_cases/seq/q3.out +2 -0
  165. data/xquery_use_cases/seq/q3.rb +26 -0
  166. data/xquery_use_cases/seq/q3.xquery +3 -0
  167. data/xquery_use_cases/seq/q4.out +0 -0
  168. data/xquery_use_cases/seq/q4.rb +27 -0
  169. data/xquery_use_cases/seq/q4.xquery +4 -0
  170. data/xquery_use_cases/seq/q5.out +5 -0
  171. data/xquery_use_cases/seq/q5.rb +29 -0
  172. data/xquery_use_cases/seq/q5.xquery +10 -0
  173. data/xquery_use_cases/seq/report1.xml +40 -0
  174. data/xquery_use_cases/sgml/README +53 -0
  175. data/xquery_use_cases/sgml/q1.out +44 -0
  176. data/xquery_use_cases/sgml/q1.rb +23 -0
  177. data/xquery_use_cases/sgml/q1.xquery +5 -0
  178. data/xquery_use_cases/sgml/q10.out +1 -0
  179. data/xquery_use_cases/sgml/q10.rb +28 -0
  180. data/xquery_use_cases/sgml/q10.xquery +7 -0
  181. data/xquery_use_cases/sgml/q2.out +26 -0
  182. data/xquery_use_cases/sgml/q2.rb +23 -0
  183. data/xquery_use_cases/sgml/q2.xquery +5 -0
  184. data/xquery_use_cases/sgml/q3.out +6 -0
  185. data/xquery_use_cases/sgml/q3.rb +28 -0
  186. data/xquery_use_cases/sgml/q3.xquery +7 -0
  187. data/xquery_use_cases/sgml/q4.out +4 -0
  188. data/xquery_use_cases/sgml/q4.rb +25 -0
  189. data/xquery_use_cases/sgml/q4.xquery +5 -0
  190. data/xquery_use_cases/sgml/q5.out +3 -0
  191. data/xquery_use_cases/sgml/q5.rb +23 -0
  192. data/xquery_use_cases/sgml/q5.xquery +5 -0
  193. data/xquery_use_cases/sgml/q6.out +1 -0
  194. data/xquery_use_cases/sgml/q6.rb +27 -0
  195. data/xquery_use_cases/sgml/q6.xquery +6 -0
  196. data/xquery_use_cases/sgml/q7.out +1 -0
  197. data/xquery_use_cases/sgml/q7.rb +27 -0
  198. data/xquery_use_cases/sgml/q7.xquery +7 -0
  199. data/xquery_use_cases/sgml/q8a.out +34 -0
  200. data/xquery_use_cases/sgml/q8a.rb +27 -0
  201. data/xquery_use_cases/sgml/q8a.xquery +5 -0
  202. data/xquery_use_cases/sgml/q8b.out +26 -0
  203. data/xquery_use_cases/sgml/q8b.rb +32 -0
  204. data/xquery_use_cases/sgml/q8b.xquery +5 -0
  205. data/xquery_use_cases/sgml/q9.out +9 -0
  206. data/xquery_use_cases/sgml/q9.rb +29 -0
  207. data/xquery_use_cases/sgml/q9.xquery +6 -0
  208. data/xquery_use_cases/sgml/sgml.xml +101 -0
  209. data/xquery_use_cases/solution_sizes.rb +48 -0
  210. data/xquery_use_cases/string/README +29 -0
  211. data/xquery_use_cases/string/company-data.xml +20 -0
  212. data/xquery_use_cases/string/q1.out +4 -0
  213. data/xquery_use_cases/string/q1.rb +25 -0
  214. data/xquery_use_cases/string/q1.xquery +1 -0
  215. data/xquery_use_cases/string/q2.out +13 -0
  216. data/xquery_use_cases/string/q2.rb +32 -0
  217. data/xquery_use_cases/string/q2.xquery +23 -0
  218. data/xquery_use_cases/string/q4.out +50 -0
  219. data/xquery_use_cases/string/q4.rb +34 -0
  220. data/xquery_use_cases/string/q4.xquery +14 -0
  221. data/xquery_use_cases/string/q5.out +12 -0
  222. data/xquery_use_cases/string/q5.rb +33 -0
  223. data/xquery_use_cases/string/q5.xquery +8 -0
  224. data/xquery_use_cases/string/string.xml +82 -0
  225. data/xquery_use_cases/test_driver.rb +60 -0
  226. data/xquery_use_cases/tree/README +23 -0
  227. data/xquery_use_cases/tree/book.xml +50 -0
  228. data/xquery_use_cases/tree/q1.out +23 -0
  229. data/xquery_use_cases/tree/q1.rb +31 -0
  230. data/xquery_use_cases/tree/q1.xquery +14 -0
  231. data/xquery_use_cases/tree/q2.out +11 -0
  232. data/xquery_use_cases/tree/q2.rb +27 -0
  233. data/xquery_use_cases/tree/q2.xquery +10 -0
  234. data/xquery_use_cases/tree/q3.out +2 -0
  235. data/xquery_use_cases/tree/q3.rb +26 -0
  236. data/xquery_use_cases/tree/q3.xquery +2 -0
  237. data/xquery_use_cases/tree/q4.out +1 -0
  238. data/xquery_use_cases/tree/q4.rb +23 -0
  239. data/xquery_use_cases/tree/q4.xquery +5 -0
  240. data/xquery_use_cases/tree/q5.out +9 -0
  241. data/xquery_use_cases/tree/q5.rb +30 -0
  242. data/xquery_use_cases/tree/q5.xquery +8 -0
  243. data/xquery_use_cases/tree/q6.out +30 -0
  244. data/xquery_use_cases/tree/q6.rb +35 -0
  245. data/xquery_use_cases/tree/q6.xquery +21 -0
  246. data/xquery_use_cases/xmp/README +41 -0
  247. data/xquery_use_cases/xmp/bib.xml +35 -0
  248. data/xquery_use_cases/xmp/books.xml +15 -0
  249. data/xquery_use_cases/xmp/prices.xml +32 -0
  250. data/xquery_use_cases/xmp/q1.out +8 -0
  251. data/xquery_use_cases/xmp/q1.rb +29 -0
  252. data/xquery_use_cases/xmp/q1.xquery +10 -0
  253. data/xquery_use_cases/xmp/q10.out +11 -0
  254. data/xquery_use_cases/xmp/q10.rb +36 -0
  255. data/xquery_use_cases/xmp/q10.xquery +11 -0
  256. data/xquery_use_cases/xmp/q11.out +35 -0
  257. data/xquery_use_cases/xmp/q11.rb +37 -0
  258. data/xquery_use_cases/xmp/q11.xquery +18 -0
  259. data/xquery_use_cases/xmp/q12.out +6 -0
  260. data/xquery_use_cases/xmp/q12.rb +35 -0
  261. data/xquery_use_cases/xmp/q12.xquery +20 -0
  262. data/xquery_use_cases/xmp/q2.out +37 -0
  263. data/xquery_use_cases/xmp/q2.rb +30 -0
  264. data/xquery_use_cases/xmp/q2.xquery +12 -0
  265. data/xquery_use_cases/xmp/q3.out +34 -0
  266. data/xquery_use_cases/xmp/q3.rb +27 -0
  267. data/xquery_use_cases/xmp/q3.xquery +10 -0
  268. data/xquery_use_cases/xmp/q4.out +31 -0
  269. data/xquery_use_cases/xmp/q4.rb +44 -0
  270. data/xquery_use_cases/xmp/q4.xquery +21 -0
  271. data/xquery_use_cases/xmp/q5.out +17 -0
  272. data/xquery_use_cases/xmp/q5.rb +38 -0
  273. data/xquery_use_cases/xmp/q5.xquery +13 -0
  274. data/xquery_use_cases/xmp/q6.out +28 -0
  275. data/xquery_use_cases/xmp/q6.rb +33 -0
  276. data/xquery_use_cases/xmp/q6.xquery +19 -0
  277. data/xquery_use_cases/xmp/q7.out +8 -0
  278. data/xquery_use_cases/xmp/q7.rb +30 -0
  279. data/xquery_use_cases/xmp/q7.xquery +12 -0
  280. data/xquery_use_cases/xmp/q8.out +7 -0
  281. data/xquery_use_cases/xmp/q8.rb +29 -0
  282. data/xquery_use_cases/xmp/q8.xquery +9 -0
  283. data/xquery_use_cases/xmp/q9.out +4 -0
  284. data/xquery_use_cases/xmp/q9.rb +29 -0
  285. data/xquery_use_cases/xmp/q9.xquery +7 -0
  286. data/xquery_use_cases/xmp/reviews.xml +24 -0
  287. metadata +342 -0
@@ -0,0 +1,855 @@
1
+ #!/usr/bin/env ruby
2
+ #Copyright (c) 2006-2007 Tomasz Wegrzanowski <Tomasz.Wegrzanowski@gmail.com>
3
+ #
4
+ #Permission is hereby granted, free of charge, to any person obtaining a
5
+ #copy of this software and associated documentation files (the "Software"),
6
+ #to deal in the Software without restriction, including without limitation
7
+ #the rights to use, copy, modify, merge, publish, distribute, sublicense,
8
+ #and/or sell copies of the Software, and to permit persons to whom the
9
+ #Software is 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
17
+ #THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
18
+ #OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
19
+ #ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
20
+ #DEALINGS IN THE SOFTWARE.
21
+
22
+ require 'helper'
23
+
24
+ # For tests
25
+ require 'stringio'
26
+
27
+ class XML_Tests < Test::Unit::TestCase
28
+ # Test whether XML.new constructors work (without monadic case)
29
+ def test_constructors
30
+ br = XML.new(:br)
31
+ h3 = XML.new(:h3, "Hello")
32
+ a = XML.new(:a, {:href => "http://www.google.com/"}, "Google")
33
+ ul = XML.new(:ul, XML.new(:li, "Hello"), XML.new(:li, "world"))
34
+
35
+ assert_equal("<br/>", br.to_s, "Constructors should work")
36
+ assert_equal("<h3>Hello</h3>", h3.to_s, "Constructors should work")
37
+ assert_equal("<a href='http://www.google.com/'>Google</a>", a.to_s, "Constructors should work")
38
+ assert_equal("<ul><li>Hello</li><li>world</li></ul>", ul.to_s, "Constructors should work")
39
+ end
40
+
41
+ # Test character escaping on output, in text and in attribute values
42
+ def test_escapes
43
+ p = XML.new(:p, "< > &")
44
+ foo = XML.new(:foo, {:bar=>"< > ' \" &"})
45
+
46
+ assert_equal("<p>&lt; &gt; &amp;</p>", p.to_s, "Character escaping should work")
47
+ assert_equal("<foo bar='&lt; &gt; &apos; &quot; &amp;'/>", foo.to_s, "Character escaping in attributes should work")
48
+ end
49
+
50
+ # Test #sort_by and #children_sort_by
51
+ def test_sort_by
52
+ doc = XML.parse("<foo><bar id='5'/>a<bar id='3'/>c<bar id='4'/>b<bar id='1'/></foo>")
53
+
54
+ doc_by_id = doc.sort_by{|c| c[:id]}
55
+ assert_equal("<foo><bar id='1'/><bar id='3'/><bar id='4'/><bar id='5'/></foo>", doc_by_id.to_s)
56
+
57
+ doc_all_by_id = doc.children_sort_by{|c| if c.is_a? XML then [0, c[:id]] else [1, c] end}
58
+ assert_equal("<foo><bar id='1'/><bar id='3'/><bar id='4'/><bar id='5'/>abc</foo>", doc_all_by_id.to_s)
59
+ end
60
+
61
+ # Test XML#[] and XML#[]= for attribute access
62
+ def test_attr
63
+ foo = XML.new(:foo, {:x => "1"})
64
+ assert_equal("1", foo[:x], "Attribute reading should work")
65
+ foo[:x] = "2"
66
+ foo[:y] = "3"
67
+ assert_equal("2", foo[:x], "Attribute writing should work")
68
+ assert_equal("3", foo[:y], "Attribute writing should work")
69
+ end
70
+
71
+ # Test XML#<< method for adding children
72
+ def test_add
73
+ a = XML.new(:p, "Hello")
74
+ a << ", "
75
+ a << "world!"
76
+ assert_equal("<p>Hello, world!</p>", a.to_s, "XML#<< should work")
77
+
78
+ b = XML.new(:foo)
79
+ b << XML.new(:bar)
80
+ assert_equal("<foo><bar/></foo>", b.to_s, "XML#<< should work")
81
+ end
82
+
83
+ # Test XML#each method for iterating over children
84
+ def test_each
85
+ a = XML.new(:p, "Hello", ", ", "world", XML.new(:br))
86
+ b = ""
87
+ a.each{|c| b += c.to_s}
88
+ assert_equal("Hello, world<br/>", b, "XML#each should work")
89
+ end
90
+
91
+ # Test XML#map method
92
+ def test_map
93
+ a = XML.new(:body, XML.new(:h3, "One"), "Hello", XML.new(:h3, "Two"))
94
+ b = a.map{|c|
95
+ if c.is_a? XML and c.name == :h3
96
+ XML.new(:h2, c.attrs, *c.contents)
97
+ else
98
+ c
99
+ end
100
+ }
101
+ assert_equal("<body><h3>One</h3>Hello<h3>Two</h3></body>", a.to_s, "XML#map should not modify the argument")
102
+ assert_equal("<body><h2>One</h2>Hello<h2>Two</h2></body>", b.to_s, "XML#map should work")
103
+
104
+ d = a.map(:h3) {|c|
105
+ XML.new(:h2, c.attrs, *c.contents)
106
+ }
107
+ assert_equal("<body><h2>One</h2>Hello<h2>Two</h2></body>", d.to_s, "XML#map should accept selectors")
108
+ end
109
+
110
+ # Test XML#==
111
+ def test_eqeq
112
+ a = XML.new(:foo)
113
+ b = XML.new(:foo)
114
+ c = XML.new(:bar)
115
+ assert(a==a, "XML#== should work")
116
+ assert(a==b, "XML#== should work")
117
+ assert(a!=c, "XML#== should work")
118
+
119
+ d = XML.new(:foo, {:bar => "1"})
120
+ e = XML.new(:foo, {:bar => "1"})
121
+ f = XML.new(:foo, {:bar => "2"})
122
+ assert(d==d, "XML#== should work")
123
+ assert(d==e, "XML#== should work")
124
+ assert(d!=f, "XML#== should work")
125
+
126
+ a = XML.new(:foo, "Hello, world!")
127
+ b = XML.new(:foo, "Hello, world!")
128
+ c = XML.new(:foo, "Hello", ", world!")
129
+ d = XML.new(:foo, "Hello")
130
+ e = XML.new(:foo, "Hello", "")
131
+ assert(a==a, "XML#== should work")
132
+ assert(a==b, "XML#== should work")
133
+ assert(a==c, "XML#== should work")
134
+ assert(a!=d, "XML#== should work")
135
+ assert(d==e, "Empty children should not affect XML#==")
136
+
137
+ # Highly pathological case
138
+ a = XML.new(:foo, "ab", "cde", "", "fg", "hijk", "", "")
139
+ b = XML.new(:foo, "", "abc", "d", "efg", "h", "ijk")
140
+ assert(a==b, "XML#== should work with differently split Strings too")
141
+
142
+ # String vs XML
143
+ a = XML.new(:foo, "Hello")
144
+ b = XML.new(:foo) {foo!}
145
+ c = XML.new(:foo) {bar!}
146
+ assert(a!=b, "XML#== should work with children of different types")
147
+ assert(b!=c, "XML#== should work recursively")
148
+
149
+ a = XML.new(:foo) {foo!; bar!}
150
+ b = XML.new(:foo) {foo!; foo!}
151
+ assert(a!=b, "XML#== should work recursively")
152
+ end
153
+
154
+ # Test dup-with-block method
155
+ def test_dup
156
+ a = XML.new(:foo, {:a => "1"}, "Hello")
157
+ b = a.dup{ @name = :bar }
158
+ c = a.dup{ self[:a] = "2" }
159
+ d = a.dup{ self << ", world!" }
160
+
161
+ assert_equal("<foo a='1'>Hello</foo>", a.to_s, "XML#dup{} should not modify its argument")
162
+ assert_equal("<bar a='1'>Hello</bar>", b.to_s, "XML#dup{} should work")
163
+ assert_equal("<foo a='2'>Hello</foo>", c.to_s, "XML#dup{} should work")
164
+ assert_equal("<foo a='1'>Hello, world!</foo>", d.to_s, "XML#dup{} should work")
165
+
166
+ # Deep copy test
167
+ a = XML.new(:h3, "Hello")
168
+ b = XML.new(:foo, XML.new(:bar, a))
169
+ c = b.dup
170
+ a << ", world!"
171
+
172
+ assert_equal("<foo><bar><h3>Hello, world!</h3></bar></foo>", b.to_s, "XML#dup should make a deep copy")
173
+ assert_equal("<foo><bar><h3>Hello</h3></bar></foo>", c.to_s, "XML#dup should make a deep copy")
174
+ end
175
+
176
+ # Test XML#normalize! method
177
+ def test_normalize
178
+ a = XML.new(:foo, "He", "", "llo")
179
+ b = XML.new(:foo, "")
180
+ c = XML.new(:foo, "", XML.new(:bar, "1"), "", XML.new(:bar, "2", ""), "X", XML.new(:bar, "", "3"), "")
181
+
182
+ a.normalize!
183
+ b.normalize!
184
+ c.normalize!
185
+
186
+ assert_equal(["Hello"], a.contents, "XML#normalize! should work")
187
+ assert_equal([], b.contents, "XML#normalize! should work")
188
+ assert_equal([XML.new(:bar, "1"), XML.new(:bar, "2"), "X", XML.new(:bar, "3")], c.contents, "XML#normalize! should work")
189
+ end
190
+
191
+ # Test the "monadic" interface, that is constructors
192
+ # with instance_eval'd blocks passed to them:
193
+ # XML.new(:foo) { bar! } # -> <foo><bar/></foo>
194
+ def test_monadic
195
+ a = XML.new(:foo) { bar!; xml!(:xxx) }
196
+ b = xml(:div) {
197
+ ul! {
198
+ li!(XML.a("Hello"))
199
+ }
200
+ }
201
+ assert_equal("<foo><bar/><xxx/></foo>", a.to_s, "Monadic interface should work")
202
+ assert_equal("<div><ul><li><a>Hello</a></li></ul></div>", b.to_s, "Monadic interface should work")
203
+ end
204
+
205
+ # Test if parsing and printing gives the right results
206
+ # We test mostly round-trip
207
+ def test_parse
208
+ a = "<foo/>"
209
+ b = "<foo a='1'/>"
210
+ c = "<foo>Hello</foo>"
211
+ d = "<foo a='1'><bar b='2'>Hello</bar><bar b='3'>world</bar></foo>"
212
+ e = "<foo>&gt; &lt; &amp;</foo>"
213
+ f = "<foo a='b&amp;c'/>"
214
+
215
+ assert_equal(a, XML.parse(a).to_s, "XML.parse(x).to_s should equal x for normalized x")
216
+ assert_equal(b, XML.parse(b).to_s, "XML.parse(x).to_s should equal x for normalized x")
217
+ assert_equal(c, XML.parse(c).to_s, "XML.parse(x).to_s should equal x for normalized x")
218
+ assert_equal(d, XML.parse(d).to_s, "XML.parse(x).to_s should equal x for normalized x")
219
+ assert_equal(e, XML.parse(e).to_s, "XML.parse(x).to_s should equal x for normalized x")
220
+ assert_equal(f, XML.parse(f).to_s, "XML.parse(x).to_s should equal x for normalized x")
221
+ end
222
+
223
+ # Test parsing &-entities
224
+ def test_parse_extra_escapes
225
+ a = "<foo>&quot; &apos;</foo>"
226
+ a_out = "<foo>\" '</foo>"
227
+
228
+ assert_equal(a_out, XML.parse(a).to_s, "XML.parse(x).to_s should normalize entities in x")
229
+ end
230
+
231
+ # Test handling extra cruft
232
+ # Some things are best ignored or normalized
233
+ def test_parse_extra_cdata
234
+ a = "<foo><![CDATA[<greeting>Hello, world!</greeting>]]></foo>"
235
+ a_out = "<foo>&lt;greeting&gt;Hello, world!&lt;/greeting&gt;</foo>"
236
+ assert_equal(a_out, XML.parse(a).to_s, "XML.parse(x).to_s should equal normalized x")
237
+ end
238
+
239
+ # Test handling (=ignoring) XML declarations
240
+ def test_parse_extra_qxml
241
+ b = "<?xml version=\"1.0\"?><greeting>Hello, world!</greeting>"
242
+ b_out = "<greeting>Hello, world!</greeting>"
243
+ assert_equal(b_out, XML.parse(b).to_s, "XML.parse(x).to_s should equal normalized x")
244
+ end
245
+
246
+ # Test handling (=ignoring) DTDs
247
+ def test_parse_extra_dtd
248
+ c = "<?xml version=\"1.0\" encoding=\"UTF-8\" ?><!DOCTYPE greeting [<!ELEMENT greeting (#PCDATA)>]><greeting>Hello, world!</greeting>"
249
+ c_out = "<greeting>Hello, world!</greeting>"
250
+ assert_equal(c_out, XML.parse(c).to_s, "XML.parse(x).to_s should equal normalized x")
251
+ end
252
+
253
+ # Test handling (=ignoring) DTDs
254
+ def test_parse_extra_comment
255
+ c = "<!-- this is a comment --><greeting>Hello,<!-- another comment --> world!</greeting>"
256
+ c_out = "<greeting>Hello, world!</greeting>"
257
+ assert_equal(c_out, XML.parse(c).to_s, "XML.parse(x).to_s should equal normalized x")
258
+ end
259
+
260
+ # Test reading from a file
261
+ def test_parse_file
262
+ a = File.open("test.xml").xml_parse
263
+ b = XML.from_file("test.xml")
264
+ c = XML.from_url("file:test.xml")
265
+ d = XML.from_url("string:<foo><bar></bar></foo>")
266
+ e = XML.parse("<foo><bar></bar></foo>")
267
+ f = "<foo><bar></bar></foo>".xml_parse
268
+ g = XML.foo { bar! }
269
+
270
+ assert_equal(g.to_s, a.to_s, "File#xml_parse should work")
271
+ assert_equal(g.to_s, b.to_s, "XML.from_file should work")
272
+ assert_equal(g.to_s, c.to_s, "XML.from_url(\"file:...\") should work")
273
+ assert_equal(g.to_s, d.to_s, "XML.from_url(\"string:...\") should work")
274
+ assert_equal(g.to_s, e.to_s, "XML.parse should work")
275
+ assert_equal(g.to_s, f.to_s, "String#xml_parse should work")
276
+ end
277
+
278
+ # Test XML#children and Array#children
279
+ def test_chilrden
280
+ a = XML.bar({:x=>"1"})
281
+ b = XML.bar({:x=>"3"})
282
+ c = XML.bar({:x=>"2"}, b)
283
+ d = XML.foo(a,c)
284
+ e = d.children(:bar)
285
+ f = e.children(:bar)
286
+ assert_equal([a,c], e, "XML#children(tag) should return tag-tagged children")
287
+ assert_equal([b], f, "Array#children(tag) should return tag-tagged children of its elements")
288
+ end
289
+
290
+ # Test XML#descendants and Array#descendants
291
+ def test_descendants
292
+ a = XML.bar({:x=>"1"})
293
+ b = XML.bar({:x=>"3"})
294
+ c = XML.bar({:x=>"2"}, b)
295
+ d = XML.foo(a,c)
296
+ e = d.descendants(:bar)
297
+ f = e.descendants(:bar)
298
+ assert_equal([a,c,b], e, "XML#descendants(tag) should return tag-tagged descendants")
299
+ assert_equal([b], f, "Array#descendants(tag) should return tag-tagged descendants of its elements")
300
+ end
301
+
302
+ # Test XML#exec! monadic interface
303
+ def test_exec
304
+ a = XML.foo
305
+ a.exec! {
306
+ bar! { text! "Hello" }
307
+ text! "world"
308
+ }
309
+ assert_equal("<foo><bar>Hello</bar>world</foo>", a.to_s, "XML#exec! should work")
310
+ end
311
+
312
+ # Test XML#child
313
+ def test_child
314
+ a = XML.parse("<foo></foo>")
315
+ b = XML.parse("<foo><bar a='1'/></foo>")
316
+ c = XML.parse("<foo><bar a='1'/><bar a='2'/></foo>")
317
+
318
+ assert_equal(nil, a.child(:bar), "XML#child should return nil if there are no matching children")
319
+ assert_equal("<bar a='1'/>", b.child(:bar).to_s, "XML#child should work")
320
+ assert_equal("<bar a='1'/>", c.child(:bar).to_s, "XML#child should return first child if there are many")
321
+ assert_equal("<bar a='2'/>", c.child({:a => '2'}).to_s, "XML#child should support patterns")
322
+ end
323
+
324
+ # Test XML#descendant
325
+ def test_descendant
326
+ a = XML.parse("<foo></foo>")
327
+ b = XML.parse("<foo><bar a='1'/></foo>")
328
+ c = XML.parse("<foo><bar a='1'/><bar a='2'/></foo>")
329
+ d = XML.parse("<foo><bar a='1'><bar a='2'/></bar><bar a='3'/></foo>")
330
+ e = XML.parse("<foo><foo><bar a='1'/></foo><bar a='2'/></foo>")
331
+
332
+ assert_equal(nil, a.descendant(:bar), "XML#descendant should return nil if there are no matching descendants")
333
+ assert_equal("<bar a='1'/>", b.descendant(:bar).to_s, "XML#descendant should work")
334
+ assert_equal("<bar a='1'/>", c.descendant(:bar).to_s, "XML#descendant should return first descendant if there are many")
335
+ assert_equal("<bar a='1'><bar a='2'/></bar>", d.descendant(:bar).to_s, "XML#descendant should return first descendant if there are many")
336
+ assert_equal("<bar a='1'/>", e.descendant(:bar).to_s, "XML#descendant should return first descendant if there are many")
337
+ assert_equal("<bar a='2'/>", c.descendant({:a => '2'}).to_s, "XML#descendant should support patterns")
338
+ assert_equal("<bar a='2'/>", d.descendant({:a => '2'}).to_s, "XML#descendant should support patterns")
339
+ assert_equal("<bar a='2'/>", e.descendant({:a => '2'}).to_s, "XML#descendant should support patterns")
340
+ end
341
+
342
+ # Test XML#text
343
+ def test_text
344
+ a = XML.parse("<foo>Hello</foo>")
345
+ b = XML.parse("<foo></foo>")
346
+ c = XML.parse("<foo><bar>Hello</bar></foo>")
347
+ d = XML.parse("<foo>He<bar>llo</bar></foo>")
348
+
349
+ assert_equal("Hello", a.text, "XML#text should work")
350
+ assert_equal("", b.text, "XML#text should work")
351
+ assert_equal("Hello", c.text, "XML#text should work")
352
+ assert_equal("Hello", d.text, "XML#text should work")
353
+ end
354
+
355
+ # Test XML#renormalize and XML#renormalize_sequence
356
+ def test_renormalize
357
+ a = "<foo></foo>"
358
+ b = "<foo></foo><bar></bar>"
359
+
360
+ assert_equal("<foo/>", XML.renormalize(a), "XML#renormalize should work")
361
+ assert_equal("<foo/>", XML.renormalize_sequence(a), "XML#renormalize_sequence should work")
362
+ assert_equal("<foo/><bar/>", XML.renormalize_sequence(b), "XML#renormalize_sequence should work")
363
+ end
364
+
365
+ # Test XML#range
366
+ def test_range
367
+ a = XML.parse "<foo><bar i='0'/><bar i='1'/><bar i='2'/><bar i='3'/><bar i='4'/></foo>"
368
+ b = a.children(:bar)
369
+
370
+ # Non-recursive case
371
+ ar_n_n = a.range(nil, nil)
372
+ ar_0_n = a.range(b[0], nil)
373
+ ar_1_n = a.range(b[1], nil)
374
+ ar_4_n = a.range(b[4], nil)
375
+ ar_n_4 = a.range(nil, b[4])
376
+ ar_n_3 = a.range(nil, b[3])
377
+ ar_n_0 = a.range(nil, b[0])
378
+
379
+ assert_equal("<foo><bar i='0'/><bar i='1'/><bar i='2'/><bar i='3'/><bar i='4'/></foo>", ar_n_n.to_s, "XML#range should work")
380
+ assert_equal("<foo><bar i='1'/><bar i='2'/><bar i='3'/><bar i='4'/></foo>", ar_0_n.to_s, "XML#range should work")
381
+ assert_equal("<foo><bar i='2'/><bar i='3'/><bar i='4'/></foo>", ar_1_n.to_s, "XML#range should work")
382
+ assert_equal("<foo/>", ar_4_n.to_s, "XML#range should work")
383
+ assert_equal("<foo><bar i='0'/><bar i='1'/><bar i='2'/><bar i='3'/></foo>", ar_n_4.to_s, "XML#range should work")
384
+ assert_equal("<foo><bar i='0'/><bar i='1'/><bar i='2'/></foo>", ar_n_3.to_s, "XML#range should work")
385
+ assert_equal("<foo/>", ar_n_0.to_s, "XML#range should work")
386
+
387
+ a = XML.parse "<a>
388
+ <b i='0'><c i='0'/><c i='1'/><c i='2'/></b>
389
+ <b i='1'><c i='3'/><c i='4'/><c i='5'/></b>
390
+ <b i='2'><c i='6'/><c i='7'/><c i='8'/></b>
391
+ </a>"
392
+ c = a.descendants(:c)
393
+
394
+ c.each_with_index{|ci,i|
395
+ c.each_with_index{|cj,j|
396
+ next unless i < j
397
+ ar = a.range(ci,cj)
398
+ cs_present = ar.descendants(:c).map{|n|n[:i].to_i}
399
+ assert_equal(((i+1)...j).to_a, cs_present, "XML#range(c#{i}, c#{j}) should contain cs between #{i} and #{j}, exclusive, instead got: #{ar}")
400
+ }
401
+ ar = a.range(ci,nil)
402
+ cs_present = ar.descendants(:c).map{|n|n[:i].to_i}
403
+ assert_equal(((i+1)..8).to_a, cs_present, "XML#range(c#{i}, nil) should contain cs from #{i+1} to 8, instead got: #{ar}")
404
+
405
+ ar = a.range(nil,ci)
406
+ cs_present = ar.descendants(:c).map{|n|n[:i].to_i}
407
+ assert_equal((0...i).to_a, cs_present, "XML#range(nil, c#{i}) should contain cs from 0 to #{i-1}, instead got: #{ar}")
408
+ }
409
+ end
410
+
411
+ # Test XML#subsequence
412
+ def test_subsequence
413
+ a = XML.parse "<foo><bar i='0'/><bar i='1'/><bar i='2'/><bar i='3'/><bar i='4'/></foo>"
414
+ b = a.children(:bar)
415
+
416
+ # Non-recursive case
417
+ ar_n_n = a.subsequence(nil, nil)
418
+ ar_0_n = a.subsequence(b[0], nil)
419
+ ar_1_n = a.subsequence(b[1], nil)
420
+ ar_4_n = a.subsequence(b[4], nil)
421
+ ar_n_4 = a.subsequence(nil, b[4])
422
+ ar_n_3 = a.subsequence(nil, b[3])
423
+ ar_n_0 = a.subsequence(nil, b[0])
424
+
425
+ assert_equal("<foo><bar i='0'/><bar i='1'/><bar i='2'/><bar i='3'/><bar i='4'/></foo>", ar_n_n.to_s, "XML#subsequence should work")
426
+ assert_equal("<bar i='1'/><bar i='2'/><bar i='3'/><bar i='4'/>", ar_0_n.to_s, "XML#subsequence should work")
427
+ assert_equal("<bar i='2'/><bar i='3'/><bar i='4'/>", ar_1_n.to_s, "XML#subsequence should work")
428
+ assert_equal("", ar_4_n.to_s, "XML#subsequence should work")
429
+ assert_equal("<foo><bar i='0'/><bar i='1'/><bar i='2'/><bar i='3'/></foo>", ar_n_4.to_s, "XML#subsequence should work")
430
+ assert_equal("<foo><bar i='0'/><bar i='1'/><bar i='2'/></foo>", ar_n_3.to_s, "XML#subsequence should work")
431
+ assert_equal("<foo/>", ar_n_0.to_s, "XML#subsequence should work")
432
+
433
+ a = XML.parse "<a>
434
+ <b j='0'><c i='0'/><c i='1'/><c i='2'/></b>
435
+ <b j='1'><c i='3'/><c i='4'/><c i='5'/></b>
436
+ <b j='2'><c i='6'/><c i='7'/><c i='8'/></b>
437
+ </a>"
438
+ c = a.descendants(:c)
439
+
440
+ # (ar + ar.descendants).find_all{|x| x.is_a? XML and x.name == :c}
441
+ # instead of ar.descendants(:c) because
442
+ # we might have returned [<c i='?'/>] as a result,
443
+ # and then it's not a descendant of the result then.
444
+ # This is ugly, and it should be fixed somewhere in magic/xml
445
+ c.each_with_index{|ci,i|
446
+ c.each_with_index{|cj,j|
447
+ next unless i < j
448
+ ar = a.subsequence(ci,cj)
449
+ cs_present = (ar + ar.descendants).find_all{|x| x.is_a? XML and x.name == :c}.map{|n| n[:i].to_i}
450
+ assert_equal(((i+1)...j).to_a, cs_present, "XML#subsequence(c#{i}, c#{j}) should contain cs between #{i} and #{j}, exclusive, instead got: #{ar}")
451
+ }
452
+ ar = a.subsequence(ci,nil)
453
+ cs_present = (ar + ar.descendants).find_all{|x| x.is_a? XML and x.name == :c}.map{|n| n[:i].to_i}
454
+ assert_equal(((i+1)..8).to_a, cs_present, "XML#subsequence(c#{i}, nil) should contain cs from #{i+1} to 8, instead got: #{ar}")
455
+
456
+ ar = a.subsequence(nil,ci)
457
+ cs_present = (ar + ar.descendants).find_all{|x| x.is_a? XML and x.name == :c}.map{|n| n[:i].to_i}
458
+ assert_equal((0...i).to_a, cs_present, "XML#subsequence(nil, c#{i}) should contain cs from 0 to #{i-1}, instead got: #{ar}")
459
+ }
460
+ end
461
+
462
+ # Test xml! at top level
463
+ def test_xml_bang
464
+ real_stdout = $stdout
465
+ $stdout = StringIO.new
466
+ xml!(:foo)
467
+ assert_equal("<foo/>", $stdout.string, "xml! should work")
468
+
469
+ $stdout = StringIO.new
470
+ XML.bar!
471
+ assert_equal("<bar/>", $stdout.string, "XML#foo! should work")
472
+ $stdout = real_stdout
473
+ end
474
+
475
+ # Methods XML#foo! are all catched,
476
+ # but how about other methods ?
477
+ def test_real_method_missing
478
+ foo = XML.new(:foo)
479
+ exception_raised = false
480
+ begin
481
+ foo.bar()
482
+ rescue NoMethodError
483
+ exception_raised = true
484
+ end
485
+ # FIXME: There are other assertions than assert_equal ;-)
486
+ assert_equal(true, exception_raised, "XML#bar should raise NoMethodError")
487
+ end
488
+
489
+ # Test XML#parse_as_twigs interface
490
+ def test_parse_as_twigs
491
+ stream = "<foo><p><ul><li>1</li><li>2</li><li>3</li></ul></p><p><br/></p><p/><p><bar/></p></foo>"
492
+ i = 0
493
+ results = []
494
+ XML.parse_as_twigs(stream) {|n|
495
+ n.complete! if i == 1 or i == 3
496
+ results << n
497
+ i += 1
498
+ }
499
+ assert_equal("<foo/>", results[0].to_s, "XML.parse_as_twigs should work")
500
+ assert_equal("<p><ul><li>1</li><li>2</li><li>3</li></ul></p>", results[1].to_s, "XML.parse_as_twigs should work")
501
+ assert_equal("<p/>", results[2].to_s, "XML.parse_as_twigs should work")
502
+ assert_equal("<br/>", results[3].to_s, "XML.parse_as_twigs should work")
503
+ assert_equal("<p/>", results[4].to_s, "XML.parse_as_twigs should work")
504
+ assert_equal("<p/>", results[5].to_s, "XML.parse_as_twigs should work")
505
+ assert_equal("<bar/>", results[6].to_s, "XML.parse_as_twigs should work")
506
+ assert_equal(7, results.size, "XML.parse_as_twigs should work")
507
+ end
508
+
509
+ # Test XML#inspect
510
+ def test_inpsect
511
+ a = xml(:a, xml(:b, xml(:c)))
512
+ d = xml(:d)
513
+
514
+ assert_equal("<a>...</a>", a.inspect, "XML#inspect should work")
515
+ assert_equal("<a>...</a>", a.inspect(0), "XML#inspect(levels) should work")
516
+ assert_equal("<a><b>...</b></a>", a.inspect(1), "XML#inspect(levels) should work")
517
+ assert_equal("<a><b><c/></b></a>", a.inspect(2), "XML#inspect(levels) should work")
518
+ assert_equal("<a><b><c/></b></a>", a.inspect(3), "XML#inspect(levels) should work")
519
+ assert_equal("<d/>", d.inspect, "XML#inspect should work")
520
+ assert_equal("<d/>", d.inspect(0), "XML#inspect should work")
521
+ assert_equal("<d/>", d.inspect(1), "XML#inspect should work")
522
+ end
523
+
524
+ # Test XML#[:@foo] pseudoattributes
525
+ def test_pseudoattributes_read
526
+ # Ignore the second <x>...</x>
527
+ a = XML.parse("<foo x='10'><x>20</x><y>30</y><x>40</x></foo>")
528
+
529
+ assert_equal("10", a[:x], "XML#[] real attributes should work")
530
+ assert_nil(a[:y], "XML#[] real attributes should work")
531
+ assert_nil(a[:z], "XML#[] real attributes should work")
532
+ assert_equal("20", a[:@x], "XML#[] pseudoattributes should work")
533
+ assert_equal("30", a[:@y], "XML#[] pseudoattributes should work")
534
+ assert_nil(a[:@z], "XML#[] pseudoattributes should work")
535
+ end
536
+
537
+ # Test XML#[:@foo] pseudoattributes
538
+ def test_pseudoattributes_write
539
+ # Ignore the second <x>...</x>
540
+ a = XML.parse("<foo x='10'><x>20</x><y>30</y><x>40</x></foo>")
541
+
542
+ a[:x] = 100
543
+ a[:y] = 200
544
+ a[:z] = 300
545
+ a[:@x] = 1000
546
+ a[:@y] = 2000
547
+ a[:@z] = 3000
548
+
549
+ assert_equal("<foo x='100' y='200' z='300'><x>1000</x><y>2000</y><x>40</x><z>3000</z></foo>", a.to_s, "XML#[]= pseudoattributes should work")
550
+ end
551
+
552
+ # Test entity unescaping
553
+ def test_entities
554
+ a = XML.parse("<foo>&#xA5;&#xFC;&#x2020;</foo>")
555
+ b = XML.parse("<foo>&#165;&#252;&#8224;</foo>")
556
+ c = XML.parse("<foo>&yen;&uuml;&dagger;</foo>")
557
+ d = ""
558
+
559
+ assert_equal(b.text, a.text, "Entity unescaping on XML#Parse should work")
560
+ assert_equal(c.text, a.text, "Entity unescaping on XML#Parse should work")
561
+
562
+ assert_equal(b.to_s, a.to_s, "Entity escaping on XML#to_s should work")
563
+ assert_equal(c.to_s, a.to_s, "Entity escaping on XML#to_s should work")
564
+
565
+ # The escapes assume \XXX are byte escapes and the encoding is UTF-8
566
+ assert_equal("\302\245\303\274\342\200\240", a.text, "Entity unescaping on XML#Parse should work")
567
+ assert_equal("<foo>\302\245\303\274\342\200\240</foo>", a.to_s, "Entity escaping on XML#to_s should work")
568
+ end
569
+
570
+ # Test patterns support
571
+ def test_patterns
572
+ a = XML.parse "<foo><bar color='blue'>Hello</bar>, <bar color='red'>world</bar><excl>!</excl></foo>"
573
+ a.normalize!
574
+
575
+ blue = []
576
+ nocolor = []
577
+ bar = []
578
+ #hello = []
579
+
580
+ a.descendants {|d|
581
+ case d
582
+ when :bar
583
+ bar << d
584
+ end
585
+
586
+ case d
587
+ when {:color => 'blue'}
588
+ blue << d
589
+ end
590
+
591
+ case d
592
+ when {:color => nil}
593
+ nocolor << d
594
+ end
595
+
596
+ #case d
597
+ #when /Hello/
598
+ # hello << d
599
+ #end
600
+ }
601
+
602
+ assert_equal([XML.parse("<bar color='blue'>Hello</bar>"), XML.parse("<bar color='red'>world</bar>")], bar, "Pattern matching should work")
603
+ assert_equal([XML.parse("<bar color='blue'>Hello</bar>")], blue, "Pattern matching should work")
604
+ assert_equal([XML.parse("<excl>!</excl>")], nocolor, "Pattern matching should work")
605
+ # Commented out, as it requires overloading Regexp#=~ and therefore Binding.of_caller
606
+ #assert_equal([XML.parse("<bar color='blue'>Hello</bar>"), "Hello"], hello, "Pattern matching should work")
607
+ end
608
+
609
+ # Test pattern support in #descendants (works the same way in #children)
610
+ def test_patterns_2
611
+ a = XML.parse "<foo><bar color='blue'>Hello</bar>, <bar color='red'>world</bar><excl color='blue'>!</excl></foo>"
612
+ a.normalize!
613
+
614
+ bar = a.descendants(:bar)
615
+ blue = a.descendants({:color=>'blue'})
616
+ blue_bar = a.descendants(all(:bar, {:color=>'blue'}))
617
+ #hello = a.descendants(/Hello/)
618
+ xml = a.descendants(XML)
619
+ string = a.descendants(String)
620
+
621
+ assert_equal([XML.parse("<bar color='blue'>Hello</bar>"), XML.parse("<bar color='red'>world</bar>")], bar, "Pattern matching should work")
622
+ assert_equal([XML.parse("<bar color='blue'>Hello</bar>"), XML.parse("<excl color='blue'>!</excl>")], blue, "Pattern matching should work")
623
+ assert_equal([XML.parse("<bar color='blue'>Hello</bar>")], blue_bar, "Pattern matching should work")
624
+ # Commented out, as it requires overloading Regexp#=~ and therefore Binding.of_caller
625
+ #assert_equal([XML.parse("<bar color='blue'>Hello</bar>"), "Hello"], hello, "Pattern matching should work")
626
+ assert_equal([XML.parse("<bar color='blue'>Hello</bar>"), XML.parse("<bar color='red'>world</bar>"), XML.parse("<excl color='blue'>!</excl>")], xml, "Pattern matching should work")
627
+ assert_equal(['Hello', ', ', 'world', '!'], string, "Pattern matching should work")
628
+ end
629
+
630
+ # Test patterns =~ support
631
+ def test_patterns_3
632
+ a = XML.parse "<foo><bar color='blue'>Hello</bar>, <bar color='red'>world</bar><excl>!</excl></foo>"
633
+ a.normalize!
634
+
635
+ blue = []
636
+ nocolor = []
637
+ bar = []
638
+ hello = []
639
+
640
+ a.descendants {|d|
641
+ if d =~ :bar
642
+ bar << d
643
+ end
644
+
645
+ if d =~ {:color => 'blue'}
646
+ blue << d
647
+ end
648
+
649
+ if d =~ {:color => nil}
650
+ nocolor << d
651
+ end
652
+
653
+ if d =~ /Hello/
654
+ hello << d
655
+ end
656
+ }
657
+
658
+ assert_equal([XML.parse("<bar color='blue'>Hello</bar>"), XML.parse("<bar color='red'>world</bar>")], bar, "Pattern matching should work")
659
+ assert_equal([XML.parse("<bar color='blue'>Hello</bar>")], blue, "Pattern matching should work")
660
+ assert_equal([XML.parse("<excl>!</excl>")], nocolor, "Pattern matching should work")
661
+ assert_equal([XML.parse("<bar color='blue'>Hello</bar>"), "Hello"], hello, "Pattern matching should work")
662
+ end
663
+
664
+ def test_patterns_any_all
665
+ a = XML.parse "<foo>
666
+ <bar color='blue' size='big'>1</bar>
667
+ <bar color='blue'>2</bar>
668
+ <bar color='blue' size='normal'>3</bar>
669
+ <bar color='red' size='big'>4</bar>
670
+ <bar color='red'>5</bar>
671
+ <bar color='red' size='normal'>6</bar>
672
+ </foo>"
673
+
674
+ p = all({:color => 'red'}, any({:size => nil}, {:size => 'normal'}))
675
+ # Select childern which color red and size either normal or not specified
676
+ b = a.children(p)
677
+ c = a.find_all{|x| x =~ p }
678
+ d = a.find_all{|x| p === x }
679
+
680
+ assert_equal("<bar color='red'>5</bar><bar color='red' size='normal'>6</bar>", b.to_s, "Pattern matching with any/all should work")
681
+ assert_equal("<bar color='red'>5</bar><bar color='red' size='normal'>6</bar>", c.to_s, "Pattern matching with any/all should work")
682
+ assert_equal("<bar color='red'>5</bar><bar color='red' size='normal'>6</bar>", d.to_s, "Pattern matching with any/all should work")
683
+ end
684
+
685
+ # Test parse option :ignore_pretty_printing
686
+ def test_remove_pretty_printing
687
+ a = "<foo><bar>100</bar><bar>200</bar></foo>"
688
+ b = "<foo>
689
+ <bar>
690
+ 100
691
+ </bar>
692
+ <bar>
693
+ 200
694
+ </bar>
695
+ </foo>"
696
+ c = XML.parse(a)
697
+ d = XML.parse(b)
698
+ e = XML.parse(b)
699
+ e.remove_pretty_printing!
700
+
701
+ assert_not_equal(c.to_s, d.to_s, "XML#parse should not ignore pretty printing by default")
702
+ assert_equal(c.to_s, e.to_s, "XML#remove_pretty_printing! should work")
703
+
704
+ f = XML.parse("<foo> <bar>Hello world</bar> </foo>")
705
+ f.remove_pretty_printing!
706
+ g = XML.parse("<foo><bar>Hello world</bar></foo>")
707
+ assert_equal(f.to_s, g.to_s, "XML#remove_pretty_printing! should work")
708
+ end
709
+
710
+ # Test remove_pretty_printing! with exception list
711
+ def test_remove_pretty_printing_conditional
712
+ a = "<foo>
713
+ <pre>
714
+ <a> 100 </a>
715
+ </pre>
716
+ <xyzzy>
717
+ <a> 200 </a>
718
+ </xyzzy>
719
+ </foo>"
720
+ b = "<foo><pre>
721
+ <a> 100 </a>
722
+ </pre><xyzzy><a>200</a></xyzzy></foo>"
723
+
724
+ ax = XML.parse(a)
725
+ bx = XML.parse(b)
726
+
727
+ ax.remove_pretty_printing!([:pre])
728
+
729
+ assert_equal(bx.to_s, ax.to_s, "XML#remove_pretty_printing!(exceptions) should work")
730
+ end
731
+
732
+ # Test extra arguments to XML#parse - :comments and :pi
733
+ def test_parsing_extras
734
+ a = "<foo><?xml-stylesheet href='http://www.blogger.com/styles/atom.css' type='text/css'?></foo>"
735
+ b = "<foo><!-- This is a comment --></foo>"
736
+
737
+ ax = XML.parse(a)
738
+ bx = XML.parse(b)
739
+
740
+ assert_equal("<foo/>", ax.to_s, "XML#parse should drop PI by default")
741
+ assert_equal("<foo/>", bx.to_s, "XML#parse should drop comments by default")
742
+
743
+ ay = XML.parse(a, :comments => true, :pi => true)
744
+ by = XML.parse(b, :comments => true, :pi => true)
745
+
746
+ assert_equal(a, ay.to_s, "XML#parse(str, :pi=>true) should include PI")
747
+ assert_equal(b, by.to_s, "XML#parse(str, :comments=>true) should include comments")
748
+ end
749
+
750
+ # Test extra arguments to XML#parse - :remove_pretty_printing.
751
+ # FIXME: How about a shorter (but still mnemonic) name for that ?
752
+ def test_parsing_nopp
753
+ a = "<foo><bar>100</bar><bar>200</bar></foo>"
754
+ b = "<foo>
755
+ <bar>
756
+ 100
757
+ </bar>
758
+ <bar>
759
+ 200
760
+ </bar>
761
+ </foo>"
762
+ c = XML.parse(a)
763
+ d = XML.parse(b)
764
+ e = XML.parse(b, :remove_pretty_printing => true)
765
+
766
+ assert_not_equal(c.to_s, d.to_s, "XML#parse should not ignore pretty printing by default")
767
+ assert_equal(c.to_s, e.to_s, "XML#parse(str, :remove_pretty_printing=>true) should work")
768
+ end
769
+
770
+ # Test XML.parse(str, :extra_entities => ...)
771
+ def test_parsing_entities
772
+ a = "<foo>&cat; &amp; &dog;</foo>"
773
+ b = XML.parse(a, :extra_entities => lambda{|e|
774
+ case e
775
+ when "cat"
776
+ "neko"
777
+ when "dog"
778
+ "inu"
779
+ end
780
+ })
781
+ c = XML.parse(a, :extra_entities => {"cat" => "neko", "dog" => "inu"})
782
+
783
+ assert_equal("neko & inu", b.text, "XML#parse(str, :extra_entities=>Proc) should work")
784
+ assert_equal("neko & inu", c.text, "XML#parse(str, :extra_entities=>Hash) should work")
785
+
786
+ d = XML.parse(a, :extra_entities => {"cat" => "neko", "dog" => "inu"})
787
+
788
+ # Central European characters escapes
789
+ e = "<foo>&zdot;&oacute;&lstrok;w</foo>"
790
+ f = XML.parse(e, :extra_entities => {"zdot" => 380, "oacute" => 243, "lstrok" => 322})
791
+
792
+ # Assumes \number does bytes, UTF8
793
+ assert_equal("\305\274\303\263\305\202w", f.text, "XML#parse(str, :extra_entities=>...) should work with integer codepoints")
794
+ end
795
+
796
+ # Test XML.load
797
+ def test_load
798
+ a = XML.load("test.xml")
799
+ b = XML.load(File.open("test.xml"))
800
+ c = XML.load("string:<foo><bar></bar></foo>")
801
+ d = XML.load("file:test.xml")
802
+
803
+ assert_equal("<foo><bar/></foo>", a.to_s, "XML#load should work")
804
+ assert_equal("<foo><bar/></foo>", b.to_s, "XML#load should work")
805
+ assert_equal("<foo><bar/></foo>", c.to_s, "XML#load should work")
806
+ assert_equal("<foo><bar/></foo>", d.to_s, "XML#load should work")
807
+ end
808
+
809
+ # Test multielement selectors
810
+ def test_multielement_selectors
811
+ a = XML.parse("<foo><bar color='blue'><x/></bar><bar color='red'><x><y i='1'/></x><y i='2'/></bar></foo>")
812
+ assert_equal("<x/><x><y i='1'/></x>", a.children(:bar, :x).to_s, "Multielement selectors should work")
813
+ assert_equal("<y i='2'/>", a.children(:bar, :y).to_s, "Multielement selectors should work")
814
+ assert_equal("<y i='1'/><y i='2'/>", a.children(:bar, :*, :y).to_s, "Multielement selectors should work")
815
+ assert_equal("<y i='1'/>", a.descendants(:x, :y).to_s, "Multielement selectors should work")
816
+ assert_equal("<y i='1'/><y i='2'/>", a.children(:bar, :*, :y).to_s, "Multielement selectors should work")
817
+ end
818
+
819
+ # Test deep_map
820
+ def test_deep_map
821
+ a = XML.parse("<foo><bar>x</bar> <foo><bar>y</bar></foo></foo>")
822
+ b = a.deep_map(:bar) {|c| XML.new(c.text.to_sym) }
823
+ assert_equal("<foo><x/> <foo><y/></foo></foo>", b.to_s, "XML#deep_map should work")
824
+
825
+ c = XML.parse("<foo><bar>x</bar> <bar><bar>y</bar></bar></foo>")
826
+ d = c.deep_map(:bar) {|c| XML.new(:xyz, c.attrs, *c.children) }
827
+ assert_equal("<foo><xyz>x</xyz> <xyz><bar>y</bar></xyz></foo>", d.to_s, "XML#deep_map should work")
828
+ end
829
+
830
+ # Test XML.load
831
+ def test_pretty_printer
832
+ a = XML.parse("<foo><bar>x</bar>Boo!<bar><y><z>f</z></y></bar><xyzzy /><bar>Mutiline\nText\n:-)</bar></foo>")
833
+ a.add_pretty_printing!
834
+ expected = "<foo>
835
+ <bar>
836
+ x
837
+ </bar>
838
+ Boo!
839
+ <bar>
840
+ <y>
841
+ <z>
842
+ f
843
+ </z>
844
+ </y>
845
+ </bar>
846
+ <xyzzy/>
847
+ <bar>
848
+ Mutiline
849
+ Text
850
+ :-)
851
+ </bar>
852
+ </foo>"
853
+ assert_equal(expected, a.to_s, "XML#pretty_print! should work")
854
+ end
855
+ end