| 1 | # coding: binary |
|---|
| 2 | require "test/unit/testcase" |
|---|
| 3 | |
|---|
| 4 | require "rexml/document" |
|---|
| 5 | require "rexml/parseexception" |
|---|
| 6 | require "test/listener" |
|---|
| 7 | require "rexml/output" |
|---|
| 8 | require "rexml/source" |
|---|
| 9 | require "rexml/formatters/pretty" |
|---|
| 10 | require "rexml/undefinednamespaceexception" |
|---|
| 11 | |
|---|
| 12 | class Tester < Test::Unit::TestCase |
|---|
| 13 | include REXML |
|---|
| 14 | def setup |
|---|
| 15 | @xsa_source = <<-EOL |
|---|
| 16 | <?xml version="1.0"?> |
|---|
| 17 | <?xsl stylesheet="blah.xsl"?> |
|---|
| 18 | <!-- The first line tests the XMLDecl, the second tests PI. |
|---|
| 19 | The next line tests DocType. This line tests comments. --> |
|---|
| 20 | <!DOCTYPE xsa PUBLIC |
|---|
| 21 | "-//LM Garshol//DTD XML Software Autoupdate 1.0//EN//XML" |
|---|
| 22 | "http://www.garshol.priv.no/download/xsa/xsa.dtd"> |
|---|
| 23 | |
|---|
| 24 | <xsa> |
|---|
| 25 | <vendor id="blah"> |
|---|
| 26 | <name>Lars Marius Garshol</name> |
|---|
| 27 | <email>larsga@garshol.priv.no</email> |
|---|
| 28 | <url>http://www.stud.ifi.uio.no/~lmariusg/</url> |
|---|
| 29 | </vendor> |
|---|
| 30 | </xsa> |
|---|
| 31 | EOL |
|---|
| 32 | end |
|---|
| 33 | |
|---|
| 34 | def test_bad_markup |
|---|
| 35 | [ |
|---|
| 36 | "<pkg='version'> foo </pkg>", |
|---|
| 37 | '<0/>', |
|---|
| 38 | '<a>&</a>', |
|---|
| 39 | '<a>&a</a>', |
|---|
| 40 | '<a>&a;</a>', |
|---|
| 41 | '<a a="<"/>', |
|---|
| 42 | '<a 3="<"/>', |
|---|
| 43 | '<a a="1" a="2"/>', |
|---|
| 44 | '<a><!-- -- --></a>', |
|---|
| 45 | '<a><!-- ---></a>', |
|---|
| 46 | '<a>�</a>', |
|---|
| 47 | '<a>�</a>', |
|---|
| 48 | "<a a='�' />", |
|---|
| 49 | "<a>\f</a>", |
|---|
| 50 | "<a a='\f' />", |
|---|
| 51 | "<a>\000</a>", |
|---|
| 52 | '<a' + [65535].pack('U') + ' />', |
|---|
| 53 | '<a></a>', |
|---|
| 54 | '<a></a>', |
|---|
| 55 | '<a' + [0x0371].pack('U') + ' />', |
|---|
| 56 | '<a a' + [0x0371].pack('U') + '="" />', |
|---|
| 57 | ].each do |src| |
|---|
| 58 | assert_raise( ParseException, %Q{Parse #{src.inspect} should have failed!} ) do |
|---|
| 59 | Document.new(src) |
|---|
| 60 | end |
|---|
| 61 | end |
|---|
| 62 | end |
|---|
| 63 | |
|---|
| 64 | def test_attribute |
|---|
| 65 | # Testing constructors |
|---|
| 66 | #a = Attribute.new "hello", "dolly" |
|---|
| 67 | #b = Attribute.new a |
|---|
| 68 | #d = Document.new( "<a hello='dolly' href='blah'/>" ) |
|---|
| 69 | #c = d[0].attributes.get_attribute( "hello" ) |
|---|
| 70 | |
|---|
| 71 | #assert_equal a, b |
|---|
| 72 | #for attr in [ a, b, c] |
|---|
| 73 | # assert_equal "hello", attr.name |
|---|
| 74 | # assert_equal "dolly", attr.value |
|---|
| 75 | #end |
|---|
| 76 | |
|---|
| 77 | # This because of a reported bug in attribute handling in 1.0a8 |
|---|
| 78 | source = '<a att="A">blah</a>' |
|---|
| 79 | doc = Document.new source |
|---|
| 80 | doc.elements.each do |a| |
|---|
| 81 | a.attributes['att'] << 'B' |
|---|
| 82 | assert_equal "AB", a.attributes['att'] |
|---|
| 83 | a.attributes['att'] = 'C' |
|---|
| 84 | assert_equal "C", a.attributes['att'] |
|---|
| 85 | end |
|---|
| 86 | |
|---|
| 87 | # Bryan Murphy <murphybryanp@yahoo.com> |
|---|
| 88 | text = "this is a {target[@name='test']/@value} test" |
|---|
| 89 | source = <<-EOL |
|---|
| 90 | <?xml version="1.0"?> |
|---|
| 91 | <doc search="#{text}"/> |
|---|
| 92 | EOL |
|---|
| 93 | |
|---|
| 94 | xml = Document.new source |
|---|
| 95 | value = xml.root.attributes["search"] |
|---|
| 96 | assert_equal text, value.to_s |
|---|
| 97 | |
|---|
| 98 | e = Element.new "test" |
|---|
| 99 | e.add_attributes({ "name1" => "test1", "name4" => "test4" }) |
|---|
| 100 | e.add_attributes([["name3","test3"], ["name2","test2"]]) |
|---|
| 101 | assert_equal "test1", e.attributes["name1"] |
|---|
| 102 | assert_equal "test2", e.attributes["name2"] |
|---|
| 103 | assert_equal "test3", e.attributes["name3"] |
|---|
| 104 | assert_equal "test4", e.attributes["name4"] |
|---|
| 105 | |
|---|
| 106 | # ensure that the attributes come out in sorted order |
|---|
| 107 | assert_equal %w(<test |
|---|
| 108 | name1='test1' |
|---|
| 109 | name2='test2' |
|---|
| 110 | name3='test3' |
|---|
| 111 | name4='test4'/>).join(' '), e.to_s |
|---|
| 112 | end |
|---|
| 113 | |
|---|
| 114 | def test_cdata |
|---|
| 115 | test = "The quick brown fox jumped |
|---|
| 116 | & < & < \" ' |
|---|
| 117 | over the lazy dog." |
|---|
| 118 | |
|---|
| 119 | source = "<a><![CDATA[#{test}]]></a>" |
|---|
| 120 | d = REXML::Document.new( source ) |
|---|
| 121 | |
|---|
| 122 | # Test constructors |
|---|
| 123 | cdata = d[0][0] |
|---|
| 124 | assert_equal test, cdata.value |
|---|
| 125 | end |
|---|
| 126 | |
|---|
| 127 | def test_comment |
|---|
| 128 | string = "This is a new comment!" |
|---|
| 129 | source = "<!--#{string}-->" |
|---|
| 130 | comment = Comment.new string |
|---|
| 131 | REXML::Formatters::Default.new.write( comment, out = "" ) |
|---|
| 132 | assert_equal(source, out) |
|---|
| 133 | |
|---|
| 134 | comment2 = Comment.new comment |
|---|
| 135 | assert_equal(comment, comment2) |
|---|
| 136 | |
|---|
| 137 | assert_raise(ParseException) { |
|---|
| 138 | REXML::Document.new("<d><!- foo --></d>") |
|---|
| 139 | } |
|---|
| 140 | assert_raise(ParseException) { |
|---|
| 141 | REXML::Document.new("<d><!-- foo -></d>") |
|---|
| 142 | } |
|---|
| 143 | end |
|---|
| 144 | |
|---|
| 145 | def test_whitespace |
|---|
| 146 | doc = Document.new "<root-element><first-element/></root-element>" |
|---|
| 147 | assert_equal 1, doc.root.size |
|---|
| 148 | assert_equal 1, doc.root.elements.size |
|---|
| 149 | doc = Document.new "<root-element> |
|---|
| 150 | <first-element/> |
|---|
| 151 | </root-element>" |
|---|
| 152 | assert_equal 3, doc.root.size |
|---|
| 153 | assert_equal 1, doc.root.elements.size |
|---|
| 154 | |
|---|
| 155 | text = " This is text |
|---|
| 156 | with a lot of whitespace " |
|---|
| 157 | source = "<a>#{text}<b>#{text}</b><c>#{text}</c>#{text}</a>" |
|---|
| 158 | |
|---|
| 159 | doc = Document.new( source, { |
|---|
| 160 | :respect_whitespace => %w{ a c } |
|---|
| 161 | } ) |
|---|
| 162 | assert_equal text, doc.elements["//c"].text |
|---|
| 163 | string = "" |
|---|
| 164 | doc.root.each { |n| string << n.to_s if n.kind_of? Text } |
|---|
| 165 | assert_equal text+text, string |
|---|
| 166 | |
|---|
| 167 | string =" lots of blank |
|---|
| 168 | space" |
|---|
| 169 | doc.root.add_element("d").add_element("c").text = string |
|---|
| 170 | doc.root.add_element("e").text = string |
|---|
| 171 | assert_equal string, doc.elements["/a/d/c"].text |
|---|
| 172 | assert string != doc.elements["/a/e"].text, "Text wasn't properly compressed" |
|---|
| 173 | |
|---|
| 174 | doc = Document.new source, { :respect_whitespace => :all } |
|---|
| 175 | doc.root.add_element("d").text = string |
|---|
| 176 | assert_equal text, doc.root.text |
|---|
| 177 | nxt = "" |
|---|
| 178 | doc.root.each { |n| nxt << n.to_s if n.kind_of? Text } |
|---|
| 179 | assert_equal text+text, nxt |
|---|
| 180 | assert_equal text, doc.root.elements["b"].text |
|---|
| 181 | assert_equal text, doc.root.elements["c"].text |
|---|
| 182 | assert_equal string, doc.root.elements["d"].text |
|---|
| 183 | end |
|---|
| 184 | |
|---|
| 185 | # This isn't complete. We need to check declarations and comments |
|---|
| 186 | def test_doctype |
|---|
| 187 | string = "something" |
|---|
| 188 | correct = "<!DOCTYPE something>" |
|---|
| 189 | doc = DocType.new(string) |
|---|
| 190 | assert_equal(string, doc.name) |
|---|
| 191 | doc.write(out="") |
|---|
| 192 | assert_equal(correct, out) |
|---|
| 193 | |
|---|
| 194 | doc2 = DocType.new(doc) |
|---|
| 195 | assert_equal(doc.name, doc2.name) |
|---|
| 196 | assert_equal(doc.external_id, doc2.external_id) |
|---|
| 197 | |
|---|
| 198 | correct = '<!DOCTYPE xsa PUBLIC "-//LM Garshol//DTD XML Software Autoupdate 1.0//EN//XML" "http://www.garshol.priv.no/download/xsa/xsa.dtd">' |
|---|
| 199 | |
|---|
| 200 | one_line_source = '<!DOCTYPE xsa PUBLIC "-//LM Garshol//DTD XML Software Autoupdate 1.0//EN//XML" "http://www.garshol.priv.no/download/xsa/xsa.dtd"><a/>' |
|---|
| 201 | doc = Document.new( one_line_source ) |
|---|
| 202 | doc = doc[0] |
|---|
| 203 | assert(doc) |
|---|
| 204 | doc.write(test="") |
|---|
| 205 | assert_equal(correct, test) |
|---|
| 206 | |
|---|
| 207 | multi_line_source = '<!DOCTYPE xsa PUBLIC |
|---|
| 208 | "-//LM Garshol//DTD XML Software Autoupdate 1.0//EN//XML" |
|---|
| 209 | "http://www.garshol.priv.no/download/xsa/xsa.dtd"> |
|---|
| 210 | <a/>' |
|---|
| 211 | d = Document.new( multi_line_source ) |
|---|
| 212 | doc = d[0] |
|---|
| 213 | assert(doc) |
|---|
| 214 | doc.write(test="") |
|---|
| 215 | assert_equal(correct, test) |
|---|
| 216 | |
|---|
| 217 | odd_space_source = ' <!DOCTYPE |
|---|
| 218 | xsa PUBLIC "-//LM Garshol//DTD XML Software Autoupdate 1.0//EN//XML" |
|---|
| 219 | "http://www.garshol.priv.no/download/xsa/xsa.dtd"> <a/>' |
|---|
| 220 | d = Document.new( odd_space_source ) |
|---|
| 221 | dt = d.doctype |
|---|
| 222 | dt.write(test="") |
|---|
| 223 | assert_equal(correct, test) |
|---|
| 224 | |
|---|
| 225 | # OK, the BIG doctype test, numba wun |
|---|
| 226 | docin = File.new "test/data/doctype_test.xml" |
|---|
| 227 | doc = Document.new(docin) |
|---|
| 228 | doc.write(test="") |
|---|
| 229 | assert_equal(31, doc.doctype.size) |
|---|
| 230 | |
|---|
| 231 | # Here's a little ditty from Tobias... |
|---|
| 232 | src = <<-EOL |
|---|
| 233 | <!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.0//EN" |
|---|
| 234 | "http://www.w3.org/TR/SVG/DTD/svg10.dtd" |
|---|
| 235 | [ |
|---|
| 236 | <!-- <!ENTITY % fast-slow "0 0 .5 1">--> |
|---|
| 237 | <!--<!ENTITY % slow-fast ".5 0 1 1">--> |
|---|
| 238 | <!ENTITY hover_ani |
|---|
| 239 | '<animateTransform attributeName="transform" |
|---|
| 240 | type="scale" restart="whenNotActive" values="1;0.96" |
|---|
| 241 | dur="0.5s" calcMode="spline" keySplines="0 0 .5 1" |
|---|
| 242 | fill="freeze" begin="mouseover"/> |
|---|
| 243 | <animateTransform attributeName="transform" |
|---|
| 244 | type="scale" restart="whenNotActive" values="0.96;1" |
|---|
| 245 | dur="0.5s" calcMode="spline" keySplines=".5 0 1 1" |
|---|
| 246 | fill="freeze" begin="mouseover+0.5s"/>' |
|---|
| 247 | > |
|---|
| 248 | ] |
|---|
| 249 | > <a/> |
|---|
| 250 | EOL |
|---|
| 251 | end |
|---|
| 252 | |
|---|
| 253 | def test_document |
|---|
| 254 | # Testing cloning |
|---|
| 255 | source = "<element/>" |
|---|
| 256 | doc = Document.new source |
|---|
| 257 | doc2 = Document.new doc |
|---|
| 258 | |
|---|
| 259 | # Testing Root |
|---|
| 260 | assert_equal doc.root.name.to_s, "element" |
|---|
| 261 | |
|---|
| 262 | # Testing String source |
|---|
| 263 | source = @xsa_source |
|---|
| 264 | doc = Document.new source |
|---|
| 265 | assert_instance_of XMLDecl, doc.xml_decl |
|---|
| 266 | assert_instance_of DocType, doc.doctype |
|---|
| 267 | assert_equal doc.version, "1.0" |
|---|
| 268 | |
|---|
| 269 | source = File.new( "test/data/dash.xml" ) |
|---|
| 270 | doc = Document.new source |
|---|
| 271 | assert_equal "content-2", doc.elements["//content-2"].name |
|---|
| 272 | end |
|---|
| 273 | |
|---|
| 274 | def test_instruction |
|---|
| 275 | target = "use" |
|---|
| 276 | content = "ruby" |
|---|
| 277 | source = "<?#{target} #{content}?>" |
|---|
| 278 | |
|---|
| 279 | instruction = Instruction.new target, content |
|---|
| 280 | instruction2 = Instruction.new instruction |
|---|
| 281 | assert_equal(instruction, instruction2) |
|---|
| 282 | REXML::Formatters::Default.new.write( instruction, out = "" ) |
|---|
| 283 | assert_equal(source, out) |
|---|
| 284 | |
|---|
| 285 | d = Document.new( source ) |
|---|
| 286 | instruction2 = d[0] |
|---|
| 287 | assert_equal(instruction.to_s, instruction2.to_s) |
|---|
| 288 | |
|---|
| 289 | assert_raise(ParseException) { |
|---|
| 290 | REXML::Document.new("<d><?foo bar></d>") |
|---|
| 291 | } |
|---|
| 292 | end |
|---|
| 293 | |
|---|
| 294 | def test_parent |
|---|
| 295 | parent = Parent.new |
|---|
| 296 | begin |
|---|
| 297 | parent << "Something" |
|---|
| 298 | rescue Exception |
|---|
| 299 | parent << Comment.new("Some comment") |
|---|
| 300 | assert parent.size == 1, "size of parent should be 1" |
|---|
| 301 | else |
|---|
| 302 | assert_fail "should have gotten an exception trying to add a "+ "String to a Parent" |
|---|
| 303 | end |
|---|
| 304 | |
|---|
| 305 | source = "<a><one/><three/><five/></a>" |
|---|
| 306 | doc = Document.new source |
|---|
| 307 | three = doc.root.elements["three"] |
|---|
| 308 | doc.root.insert_before( three, Element.new("two") ) |
|---|
| 309 | nxt = doc.root.elements["one"] |
|---|
| 310 | string = "" |
|---|
| 311 | while nxt |
|---|
| 312 | string << nxt.name |
|---|
| 313 | nxt = nxt.next_sibling |
|---|
| 314 | end |
|---|
| 315 | assert_equal "onetwothreefive", string |
|---|
| 316 | |
|---|
| 317 | |
|---|
| 318 | doc.root.insert_after( three, Element.new("four") ) |
|---|
| 319 | string = "" |
|---|
| 320 | doc.root.each { |element| string << element.name } |
|---|
| 321 | assert_equal "onetwothreefourfive", string |
|---|
| 322 | |
|---|
| 323 | string = "" |
|---|
| 324 | nxt = doc.root.elements["five"] |
|---|
| 325 | while nxt |
|---|
| 326 | string << nxt.name |
|---|
| 327 | nxt = nxt.previous_sibling |
|---|
| 328 | end |
|---|
| 329 | assert_equal "fivefourthreetwoone", string |
|---|
| 330 | |
|---|
| 331 | doc.insert_after "//two", Element.new("two-and-half") |
|---|
| 332 | string = doc.root.elements.collect {|x| x.name}.join |
|---|
| 333 | assert_equal "onetwotwo-and-halfthreefourfive", string |
|---|
| 334 | doc.elements["/a/five"].insert_before "../four", Element.new("three-and-half") |
|---|
| 335 | string = doc.root.elements.collect {|x| x.name}.join |
|---|
| 336 | assert_equal "onetwotwo-and-halfthreethree-and-halffourfive", string |
|---|
| 337 | |
|---|
| 338 | doc.elements["/a/five"].previous_sibling = Element.new("four-and-half") |
|---|
| 339 | string = doc.root.elements.collect {|x| x.name}.join |
|---|
| 340 | assert_equal "onetwotwo-and-halfthreethree-and-halffourfour-and-halffive", string |
|---|
| 341 | doc.elements["/a/one"].next_sibling = Element.new("one-and-half") |
|---|
| 342 | string = doc.root.elements.collect {|x| x.name}.join |
|---|
| 343 | assert_equal "oneone-and-halftwotwo-and-halfthreethree-and-halffourfour-and-halffive", string |
|---|
| 344 | |
|---|
| 345 | doc = Document.new "<a><one/><three/></a>" |
|---|
| 346 | doc.root[1,0] = Element.new "two" |
|---|
| 347 | string = "" |
|---|
| 348 | doc.root.each { |el| string << el.name } |
|---|
| 349 | assert_equal "onetwothree", string |
|---|
| 350 | end |
|---|
| 351 | |
|---|
| 352 | # The Source classes are tested extensively throughout the test suite |
|---|
| 353 | def test_source |
|---|
| 354 | # Testing string source |
|---|
| 355 | source = @xsa_source |
|---|
| 356 | doc = Document.new source |
|---|
| 357 | assert_equal doc.root.name.to_s, "xsa" |
|---|
| 358 | |
|---|
| 359 | # Testing IO source |
|---|
| 360 | doc = Document.new File.new("test/data/project.xml") |
|---|
| 361 | assert_equal doc.root.name.to_s, "Project" |
|---|
| 362 | end |
|---|
| 363 | |
|---|
| 364 | def test_text |
|---|
| 365 | f = REXML::Formatters::Default.new |
|---|
| 366 | string = "Some text" |
|---|
| 367 | text = Text.new(string) |
|---|
| 368 | assert_equal(string, text.to_s) |
|---|
| 369 | text2 = Text.new(text) |
|---|
| 370 | assert_equal(text, text2) |
|---|
| 371 | #testing substitution |
|---|
| 372 | string = "0 < ( 1 & 1 )" |
|---|
| 373 | correct = "0 < ( 1 & 1 )" |
|---|
| 374 | text = Text.new(string, true) |
|---|
| 375 | f.write(text,out="") |
|---|
| 376 | assert_equal(correct, out) |
|---|
| 377 | |
|---|
| 378 | string = "Cats & dogs" |
|---|
| 379 | text = Text.new(string, false, nil, true) |
|---|
| 380 | assert_equal(string, text.to_s) |
|---|
| 381 | |
|---|
| 382 | string2 = "<a>#{string}</a>" |
|---|
| 383 | doc = Document.new( string2, { |
|---|
| 384 | :raw => %w{ a b } |
|---|
| 385 | } ) |
|---|
| 386 | f.write(doc,out="") |
|---|
| 387 | assert_equal(string2, out) |
|---|
| 388 | b = doc.root.add_element( "b" ) |
|---|
| 389 | b.text = string |
|---|
| 390 | assert_equal(string, b.get_text.to_s) |
|---|
| 391 | |
|---|
| 392 | c = doc.root.add_element("c") |
|---|
| 393 | c.text = string |
|---|
| 394 | assert_equal("Cats &amp; dogs", c.get_text.to_s) |
|---|
| 395 | |
|---|
| 396 | # test all |
|---|
| 397 | string = "<a>&<b><</b><c>><d>"</d></c></a>" |
|---|
| 398 | doc = Document.new(string, { :raw => :all }) |
|---|
| 399 | assert_equal( "&", doc.elements["/a"][0].to_s ) |
|---|
| 400 | assert_equal( "&", doc.elements["/a"].text ) |
|---|
| 401 | assert_equal( "<", doc.elements["/a/b"][0].to_s ) |
|---|
| 402 | assert_equal( "<", doc.elements["/a/b"].text ) |
|---|
| 403 | assert_equal( ">", doc.elements["/a/c"][0].to_s ) |
|---|
| 404 | assert_equal( ">", doc.elements["/a/c"].text ) |
|---|
| 405 | assert_equal( '"', doc.elements["//d"][0].to_s ) |
|---|
| 406 | assert_equal( '"', doc.elements["//d"].text ) |
|---|
| 407 | |
|---|
| 408 | # test some other stuff |
|---|
| 409 | doc = Document.new('<a><b/></a>') |
|---|
| 410 | doc.root.text = 'Sean' |
|---|
| 411 | assert_equal( '<a><b/>Sean</a>', doc.to_s ) |
|---|
| 412 | doc.root.text = 'Elliott' |
|---|
| 413 | assert_equal( '<a><b/>Elliott</a>', doc.to_s ) |
|---|
| 414 | doc.root.add_element( 'c' ) |
|---|
| 415 | assert_equal( '<a><b/>Elliott<c/></a>', doc.to_s ) |
|---|
| 416 | doc.root.text = 'Russell' |
|---|
| 417 | assert_equal( '<a><b/>Russell<c/></a>', doc.to_s ) |
|---|
| 418 | doc.root.text = nil |
|---|
| 419 | assert_equal( '<a><b/><c/></a>', doc.to_s ) |
|---|
| 420 | end |
|---|
| 421 | |
|---|
| 422 | def test_xmldecl |
|---|
| 423 | source = "<?xml version='1.0'?>" |
|---|
| 424 | # test args |
|---|
| 425 | # test no args |
|---|
| 426 | decl2 = XMLDecl.new |
|---|
| 427 | assert_equal source, decl2.to_s |
|---|
| 428 | # test XMLDecl |
|---|
| 429 | decl2 = XMLDecl.new "1.0" |
|---|
| 430 | assert_equal source, decl2.to_s |
|---|
| 431 | end |
|---|
| 432 | |
|---|
| 433 | def each_test( element, xpath, num_children ) |
|---|
| 434 | count = 0 |
|---|
| 435 | element.each_element( xpath ) { |child| |
|---|
| 436 | count += 1 |
|---|
| 437 | yield child if block_given? |
|---|
| 438 | } |
|---|
| 439 | assert_equal num_children, count |
|---|
| 440 | end |
|---|
| 441 | |
|---|
| 442 | # This is the biggest test, as the number of permutations of xpath are |
|---|
| 443 | # enormous. |
|---|
| 444 | def test_element_access |
|---|
| 445 | # Testing each_element |
|---|
| 446 | doc = Document.new File.new("test/data/project.xml") |
|---|
| 447 | |
|---|
| 448 | each_test( doc, "/", 1 ) { |child| |
|---|
| 449 | assert_equal doc.name, child.name |
|---|
| 450 | } |
|---|
| 451 | each_test(doc, ".", 1) { |child| assert_equal doc, child } |
|---|
| 452 | each_test(doc.root, "..", 1) { |child| assert_equal doc, child } |
|---|
| 453 | each_test(doc.root, "*", 5) |
|---|
| 454 | each_test(doc, "Project/Datasets", 1) { |child| |
|---|
| 455 | assert_equal "Datasets", child.name |
|---|
| 456 | } |
|---|
| 457 | each_test(doc, "Project/Datasets/link", 2 ) |
|---|
| 458 | each_test(doc.root, "/Project/Description", 1) {|child| |
|---|
| 459 | assert_equal "Description", child.name |
|---|
| 460 | } |
|---|
| 461 | each_test(doc.root, "./Description",1 ) { |child| |
|---|
| 462 | assert_equal "Description",child.name |
|---|
| 463 | } |
|---|
| 464 | each_test(doc.root, "../Project",1 ) { |child| |
|---|
| 465 | assert_equal doc.root, child |
|---|
| 466 | } |
|---|
| 467 | #each_test(doc,".../link",2) {|child| assert_equal "link",child.name.to_s} |
|---|
| 468 | |
|---|
| 469 | # test get_element |
|---|
| 470 | first = doc.elements[ "Project" ] |
|---|
| 471 | assert_equal doc.root, first |
|---|
| 472 | second = doc.elements[ "Project" ].elements[1] |
|---|
| 473 | third = doc.elements[ "Project/Creator" ] |
|---|
| 474 | assert_equal second, third |
|---|
| 475 | fourth = doc.elements[ "Project/Datasets/link[@idref='18']" ] |
|---|
| 476 | assert_equal "Test data 1", fourth.attributes["name"] |
|---|
| 477 | |
|---|
| 478 | # Testing each_predicate |
|---|
| 479 | each_test( doc, "Project/Datasets/link[@idref='18']", 1 ) { |child| |
|---|
| 480 | assert_equal "Test data 1", child.attributes["name"] |
|---|
| 481 | } |
|---|
| 482 | |
|---|
| 483 | # testing next/previous_element |
|---|
| 484 | creator = doc.elements["//Creator"] |
|---|
| 485 | lm = creator.next_element |
|---|
| 486 | assert_equal "LastModifier", lm.name |
|---|
| 487 | assert_equal "Creator", lm.previous_element.name |
|---|
| 488 | end |
|---|
| 489 | |
|---|
| 490 | def test_child |
|---|
| 491 | sean = Element.new "Sean" |
|---|
| 492 | rubbell = Element.new "Rubbell" |
|---|
| 493 | elliott = sean.add_element "Elliott" |
|---|
| 494 | sean << rubbell |
|---|
| 495 | assert_equal elliott, rubbell.previous_sibling |
|---|
| 496 | assert_equal rubbell, elliott.next_sibling |
|---|
| 497 | |
|---|
| 498 | russell = Element.new "Russell" |
|---|
| 499 | rubbell.replace_with russell |
|---|
| 500 | assert_equal elliott, russell.previous_sibling |
|---|
| 501 | assert_equal russell, elliott.next_sibling |
|---|
| 502 | |
|---|
| 503 | assert_nil russell.document |
|---|
| 504 | assert_equal sean, russell.root |
|---|
| 505 | end |
|---|
| 506 | |
|---|
| 507 | # Most of this class is tested elsewhere. Here are the methods which |
|---|
| 508 | # aren't used in any other class |
|---|
| 509 | def test_element |
|---|
| 510 | sean = Element.new "Sean" |
|---|
| 511 | string = "1) He's a great guy!" |
|---|
| 512 | sean.text = string |
|---|
| 513 | russell = Element.new "Russell" |
|---|
| 514 | sean << russell |
|---|
| 515 | |
|---|
| 516 | russell.attributes["email"] = "ser@germane-software.com" |
|---|
| 517 | assert_equal russell.attributes["email"], "ser@germane-software.com" |
|---|
| 518 | russell.attributes["webpage"] = "http://www.germane-software.com/~ser" |
|---|
| 519 | |
|---|
| 520 | assert sean.has_text?, "element should have text" |
|---|
| 521 | assert_equal sean.text, string |
|---|
| 522 | assert sean.has_elements?, "element should have one element" |
|---|
| 523 | string = "2) What a stud!" |
|---|
| 524 | sean.add_text string |
|---|
| 525 | sean.text = "3) Super programmer!" |
|---|
| 526 | sean.text = nil |
|---|
| 527 | assert sean.has_text?, "element should still have text" |
|---|
| 528 | assert_equal sean.text, string |
|---|
| 529 | |
|---|
| 530 | russell.delete_attribute "email" |
|---|
| 531 | assert_nil russell.attributes["email"] |
|---|
| 532 | russell.attributes.delete "webpage" |
|---|
| 533 | assert !russell.has_attributes?, "element should have no attributes" |
|---|
| 534 | end |
|---|
| 535 | |
|---|
| 536 | def test_no_format |
|---|
| 537 | source = "<a><b><c>blah</c><d/></b></a>" |
|---|
| 538 | out = "" |
|---|
| 539 | doc = Document.new( source ) |
|---|
| 540 | doc.write(out) |
|---|
| 541 | assert_equal(source, out) |
|---|
| 542 | end |
|---|
| 543 | |
|---|
| 544 | def test_namespace |
|---|
| 545 | source = <<-EOF |
|---|
| 546 | <x xmlns:foo="http://www.bar.com/schema"> |
|---|
| 547 | </x> |
|---|
| 548 | EOF |
|---|
| 549 | doc = Document.new(source) |
|---|
| 550 | assert_equal("http://www.bar.com/schema", doc.root.namespace( "foo" )) |
|---|
| 551 | source = <<-EOF |
|---|
| 552 | <!-- bar namespace is "someuri" --> |
|---|
| 553 | <foo:bar xmlns="default" xmlns:foo="someuri"> |
|---|
| 554 | <!-- a namespace is "default" --> |
|---|
| 555 | <a/> |
|---|
| 556 | <!-- foo:b namespace is "someuri" --> |
|---|
| 557 | <foo:b> |
|---|
| 558 | <!-- c namespace is "default" --> |
|---|
| 559 | <c/> |
|---|
| 560 | </foo:b> |
|---|
| 561 | <!-- d namespace is "notdefault" --> |
|---|
| 562 | <d xmlns="notdefault"> |
|---|
| 563 | <!-- e namespace is "notdefault" --> |
|---|
| 564 | <e/> |
|---|
| 565 | <f xmlns=""> |
|---|
| 566 | <g/> |
|---|
| 567 | </f> |
|---|
| 568 | </d> |
|---|
| 569 | </foo:bar> |
|---|
| 570 | EOF |
|---|
| 571 | doc = Document.new source |
|---|
| 572 | assert_equal "someuri", doc.root.namespace |
|---|
| 573 | assert_equal "default", doc.root.elements[1].namespace |
|---|
| 574 | assert_equal "someuri", doc.root.elements[2].namespace |
|---|
| 575 | assert_equal "notdefault", doc.root.elements[ 3 ].namespace |
|---|
| 576 | |
|---|
| 577 | # Testing namespaces in attributes |
|---|
| 578 | source = <<-EOF |
|---|
| 579 | <a xmlns:b="uri"> |
|---|
| 580 | <b b:a="x" a="y"/> |
|---|
| 581 | <c xmlns="foo"> |
|---|
| 582 | </c> |
|---|
| 583 | </a> |
|---|
| 584 | EOF |
|---|
| 585 | doc = Document.new source |
|---|
| 586 | b = doc.root.elements["b"] |
|---|
| 587 | assert_equal "x", b.attributes["b:a"] |
|---|
| 588 | assert_equal "y", b.attributes["a"] |
|---|
| 589 | |
|---|
| 590 | doc = Document.new |
|---|
| 591 | doc.add_element "sean:blah" |
|---|
| 592 | doc.root.text = "Some text" |
|---|
| 593 | out = "" |
|---|
| 594 | doc.write(out) |
|---|
| 595 | assert_equal "<sean:blah>Some text</sean:blah>", out |
|---|
| 596 | end |
|---|
| 597 | |
|---|
| 598 | |
|---|
| 599 | def test_add_namespace |
|---|
| 600 | e = Element.new 'a' |
|---|
| 601 | e.add_namespace 'someuri' |
|---|
| 602 | e.add_namespace 'foo', 'otheruri' |
|---|
| 603 | e.add_namespace 'xmlns:bar', 'thirduri' |
|---|
| 604 | assert_equal 'someuri', e.attributes['xmlns'] |
|---|
| 605 | assert_equal 'otheruri', e.attributes['xmlns:foo'] |
|---|
| 606 | assert_equal 'thirduri', e.attributes['xmlns:bar'] |
|---|
| 607 | end |
|---|
| 608 | |
|---|
| 609 | |
|---|
| 610 | def test_big_documentation |
|---|
| 611 | f = File.new("test/data/documentation.xml") |
|---|
| 612 | d = Document.new f |
|---|
| 613 | assert_equal "Sean Russell", d.elements["documentation/head/author"].text.tr("\n\t", " ").squeeze(" ") |
|---|
| 614 | out = "" |
|---|
| 615 | d.write out |
|---|
| 616 | end |
|---|
| 617 | |
|---|
| 618 | def test_tutorial |
|---|
| 619 | doc = Document.new File.new("test/data/tutorial.xml") |
|---|
| 620 | out = "" |
|---|
| 621 | doc.write out |
|---|
| 622 | end |
|---|
| 623 | |
|---|
| 624 | def test_stream |
|---|
| 625 | c = Listener.new |
|---|
| 626 | Document.parse_stream( File.new("test/data/documentation.xml"), c ) |
|---|
| 627 | assert(c.ts, "Stream parsing apparantly didn't parse the whole file") |
|---|
| 628 | assert(c.te, "Stream parsing dropped end tag for documentation") |
|---|
| 629 | |
|---|
| 630 | Document.parse_stream("<a.b> <c/> </a.b>", c) |
|---|
| 631 | |
|---|
| 632 | Document.parse_stream("<a><>&</a>", c) |
|---|
| 633 | assert_equal('<>&', c.normalize) |
|---|
| 634 | end |
|---|
| 635 | |
|---|
| 636 | def test_line |
|---|
| 637 | doc = Document.new File.new( "test/data/bad.xml" ) |
|---|
| 638 | assert_fail "There should have been an error" |
|---|
| 639 | rescue Exception |
|---|
| 640 | # We should get here |
|---|
| 641 | er = $! |
|---|
| 642 | assert($!.line == 5, "Should have been an error on line 5, "+ |
|---|
| 643 | "but was reported as being on line #{$!.line}" ) |
|---|
| 644 | end |
|---|
| 645 | |
|---|
| 646 | def test_substitution |
|---|
| 647 | val = "a'b\"c" |
|---|
| 648 | el = Element.new("a") |
|---|
| 649 | el.attributes["x"] = val |
|---|
| 650 | REXML::Formatters::Default.new.write(el, out="") |
|---|
| 651 | |
|---|
| 652 | nel = Document.new( out) |
|---|
| 653 | assert_equal( val, nel.root.attributes["x"] ) |
|---|
| 654 | end |
|---|
| 655 | |
|---|
| 656 | def test_exception |
|---|
| 657 | source = SourceFactory.create_from "<a/>" |
|---|
| 658 | p = ParseException.new( "dummy message", source ) |
|---|
| 659 | s = p.to_s |
|---|
| 660 | begin |
|---|
| 661 | raise "dummy" |
|---|
| 662 | rescue Exception |
|---|
| 663 | p.continued_exception = $! |
|---|
| 664 | end |
|---|
| 665 | s = p.to_s |
|---|
| 666 | end |
|---|
| 667 | |
|---|
| 668 | def test_bad_content |
|---|
| 669 | in_gt = '<root-el>content>content</root-el>' |
|---|
| 670 | in_lt = '<root-el>content<content</root-el>' |
|---|
| 671 | |
|---|
| 672 | # This is OK |
|---|
| 673 | tree_gt = Document.new in_gt |
|---|
| 674 | assert_equal "content>content", tree_gt.elements[1].text |
|---|
| 675 | # This isn't |
|---|
| 676 | begin |
|---|
| 677 | tree_lt = Document.new in_lt |
|---|
| 678 | assert_fail "Should have gotten a parse error" |
|---|
| 679 | rescue ParseException |
|---|
| 680 | end |
|---|
| 681 | end |
|---|
| 682 | |
|---|
| 683 | def test_iso_8859_1_output_function |
|---|
| 684 | out = "" |
|---|
| 685 | output = Output.new( out ) |
|---|
| 686 | koln_iso_8859_1 = "K\xF6ln" |
|---|
| 687 | koln_utf8 = "K\xc3\xb6ln" |
|---|
| 688 | source = Source.new( koln_iso_8859_1, 'iso-8859-1' ) |
|---|
| 689 | results = source.scan(/.*/)[0] |
|---|
| 690 | koln_utf8.force_encoding('UTF-8') if koln_utf8.respond_to?(:force_encoding) |
|---|
| 691 | assert_equal koln_utf8, results |
|---|
| 692 | output << results |
|---|
| 693 | if koln_iso_8859_1.respond_to?(:force_encoding) |
|---|
| 694 | koln_iso_8859_1.force_encoding('ISO-8859-1') |
|---|
| 695 | end |
|---|
| 696 | assert_equal koln_iso_8859_1, out |
|---|
| 697 | end |
|---|
| 698 | |
|---|
| 699 | def test_attributes_each |
|---|
| 700 | doc = Document.new("<a xmlns:a='foo'><b x='1' y='2' z='3' a:x='4'/></a>") |
|---|
| 701 | count = 0 |
|---|
| 702 | doc.root.elements[1].attributes.each {|k,v| count += 1 } |
|---|
| 703 | assert_equal 4, count |
|---|
| 704 | end |
|---|
| 705 | |
|---|
| 706 | def test_delete_namespace |
|---|
| 707 | doc = Document.new "<a xmlns='1' xmlns:x='2'/>" |
|---|
| 708 | doc.root.delete_namespace |
|---|
| 709 | doc.root.delete_namespace 'x' |
|---|
| 710 | assert_equal "<a/>", doc.to_s |
|---|
| 711 | end |
|---|
| 712 | |
|---|
| 713 | def test_each_element_with_attribute |
|---|
| 714 | doc = Document.new "<a><b id='1'/><c id='2'/><d id='1'/><e/></a>" |
|---|
| 715 | arry = [] |
|---|
| 716 | block = proc { |e| |
|---|
| 717 | assert arry.include?(e.name) |
|---|
| 718 | arry.delete e.name |
|---|
| 719 | } |
|---|
| 720 | # Yields b, c, d |
|---|
| 721 | arry = %w{b c d} |
|---|
| 722 | doc.root.each_element_with_attribute( 'id', &block ) |
|---|
| 723 | assert_equal 0, arry.size |
|---|
| 724 | # Yields b, d |
|---|
| 725 | arry = %w{b d} |
|---|
| 726 | doc.root.each_element_with_attribute( 'id', '1', &block ) |
|---|
| 727 | assert_equal 0, arry.size |
|---|
| 728 | # Yields b |
|---|
| 729 | arry = ['b'] |
|---|
| 730 | doc.root.each_element_with_attribute( 'id', '1', 1, &block ) |
|---|
| 731 | assert_equal 0, arry.size |
|---|
| 732 | # Yields d |
|---|
| 733 | arry = ['d'] |
|---|
| 734 | doc.root.each_element_with_attribute( 'id', '1', 0, 'd', &block ) |
|---|
| 735 | assert_equal 0, arry.size |
|---|
| 736 | end |
|---|
| 737 | def test_each_element_with_text |
|---|
| 738 | doc = Document.new '<a><b>b</b><c>b</c><d>d</d><e/></a>' |
|---|
| 739 | arry = [] |
|---|
| 740 | block = proc { |e| |
|---|
| 741 | assert arry.include?(e.name) |
|---|
| 742 | arry.delete e.name |
|---|
| 743 | } |
|---|
| 744 | # Yields b, c, d |
|---|
| 745 | arry = %w{b c d} |
|---|
| 746 | doc.root.each_element_with_text(&block) |
|---|
| 747 | assert_equal 0, arry.size |
|---|
| 748 | # Yields b, d |
|---|
| 749 | arry = %w{b c} |
|---|
| 750 | doc.root.each_element_with_text( 'b', &block ) |
|---|
| 751 | assert_equal 0, arry.size |
|---|
| 752 | # Yields b |
|---|
| 753 | arry = ['b'] |
|---|
| 754 | doc.root.each_element_with_text( 'b', 1, &block ) |
|---|
| 755 | assert_equal 0, arry.size |
|---|
| 756 | # Yields d |
|---|
| 757 | arry = ['d'] |
|---|
| 758 | doc.root.each_element_with_text( nil, 0, 'd', &block ) |
|---|
| 759 | assert_equal 0, arry.size |
|---|
| 760 | end |
|---|
| 761 | |
|---|
| 762 | def test_element_parse_stream |
|---|
| 763 | s = Source.new( "<a>some text</a>" ) |
|---|
| 764 | l = Listener.new |
|---|
| 765 | class << l |
|---|
| 766 | def tag_start name, attributes |
|---|
| 767 | raise "Didn't find proper tag name" unless 'a'==name |
|---|
| 768 | end |
|---|
| 769 | end |
|---|
| 770 | |
|---|
| 771 | Document::parse_stream(s, l) |
|---|
| 772 | end |
|---|
| 773 | |
|---|
| 774 | def test_deep_clone |
|---|
| 775 | a = Document.new( '<?xml version="1"?><a x="y"><b>text</b>text<c><d><e>text</e></d></c></a>' ) |
|---|
| 776 | b = a.deep_clone |
|---|
| 777 | assert_equal a.to_s, b.to_s |
|---|
| 778 | |
|---|
| 779 | a = Document.new( '<a>some < text <b> more > text </b> > </a>' ) |
|---|
| 780 | b = a.deep_clone |
|---|
| 781 | assert_equal a.to_s, b.to_s |
|---|
| 782 | c = Document.new( b.to_s ) |
|---|
| 783 | assert_equal a.to_s, c.to_s |
|---|
| 784 | end |
|---|
| 785 | |
|---|
| 786 | def test_whitespace_before_root |
|---|
| 787 | a = <<EOL |
|---|
| 788 | <?xml version='1.0'?> |
|---|
| 789 | <blo> |
|---|
| 790 | <wak> |
|---|
| 791 | </wak> |
|---|
| 792 | </blo> |
|---|
| 793 | EOL |
|---|
| 794 | d = Document.new(a) |
|---|
| 795 | b = "" |
|---|
| 796 | d.write( b ) |
|---|
| 797 | assert_equal a,b |
|---|
| 798 | end |
|---|
| 799 | |
|---|
| 800 | def test_entities |
|---|
| 801 | a = Document.new( '<a>eeü</a>' ) |
|---|
| 802 | assert_equal 'eeÌ', a.root.text |
|---|
| 803 | end |
|---|
| 804 | |
|---|
| 805 | def test_element_decl |
|---|
| 806 | element_decl = Source.new("<!DOCTYPE foo [ |
|---|
| 807 | <!ELEMENT bar (#PCDATA)> |
|---|
| 808 | ]>") |
|---|
| 809 | doc = Document.new( element_decl ) |
|---|
| 810 | d = doc[0] |
|---|
| 811 | assert_equal("<!ELEMENT bar (#PCDATA)>", d.to_s.split(/\n/)[1].strip) |
|---|
| 812 | end |
|---|
| 813 | |
|---|
| 814 | def test_attlist_decl |
|---|
| 815 | doc = Document.new <<-EOL |
|---|
| 816 | <!DOCTYPE blah [ |
|---|
| 817 | <!ATTLIST blah |
|---|
| 818 | xmlns CDATA "foo"> |
|---|
| 819 | <!ATTLIST a |
|---|
| 820 | bar CDATA "gobble" |
|---|
| 821 | xmlns:one CDATA "two" |
|---|
| 822 | > |
|---|
| 823 | ]> |
|---|
| 824 | <a xmlns:three='xxx' three='yyy'><one:b/><three:c/></a> |
|---|
| 825 | EOL |
|---|
| 826 | assert_equal 'gobble', doc.root.attributes['bar'] |
|---|
| 827 | assert_equal 'xxx', doc.root.elements[2].namespace |
|---|
| 828 | assert_equal 'two', doc.root.elements[1].namespace |
|---|
| 829 | assert_equal 'foo', doc.root.namespace |
|---|
| 830 | |
|---|
| 831 | doc = Document.new <<-EOL |
|---|
| 832 | <?xml version="1.0"?> |
|---|
| 833 | <!DOCTYPE schema SYSTEM "XMLSchema.dtd" [ |
|---|
| 834 | <!ENTITY % p ''> |
|---|
| 835 | <!ENTITY % s ''> |
|---|
| 836 | <!ATTLIST schema |
|---|
| 837 | xmlns:svg CDATA #FIXED "http://www.w3.org/2000/svg" |
|---|
| 838 | xmlns:xlink CDATA #FIXED "http://www.w3.org/1999/xlink" |
|---|
| 839 | xmlns:xml CDATA #FIXED "http://www.w3.org/XML/1998/namespace" |
|---|
| 840 | >]> |
|---|
| 841 | <schema/> |
|---|
| 842 | EOL |
|---|
| 843 | prefixes = doc.root.prefixes.sort |
|---|
| 844 | correct = ['svg', 'xlink', 'xml'] |
|---|
| 845 | assert_equal correct, prefixes |
|---|
| 846 | end |
|---|
| 847 | |
|---|
| 848 | def test_attlist_write |
|---|
| 849 | file=File.new("test/data/foo.xml" ) |
|---|
| 850 | doc=Document.new file |
|---|
| 851 | root = doc.root |
|---|
| 852 | |
|---|
| 853 | out = '' |
|---|
| 854 | doc.write(out) |
|---|
| 855 | end |
|---|
| 856 | |
|---|
| 857 | def test_more_namespaces |
|---|
| 858 | assert_raise( REXML::UndefinedNamespaceException, |
|---|
| 859 | %Q{Should have gotten an Undefined Namespace error} ) { |
|---|
| 860 | doc1 = Document.new("<r><p><n:c/></p></r>") |
|---|
| 861 | } |
|---|
| 862 | doc2 = Document.new("<r xmlns:n='1'><p><n:c/></p></r>") |
|---|
| 863 | es = XPath.match(doc2, '//c') |
|---|
| 864 | assert_equal 0, es.size |
|---|
| 865 | es = XPath.match(doc2, '//n:c') |
|---|
| 866 | assert_equal 1, es.size |
|---|
| 867 | doc2.root.add_namespace('m', '2') |
|---|
| 868 | doc2.root.add_element("m:o") |
|---|
| 869 | es = XPath.match(doc2, './/o') |
|---|
| 870 | assert_equal 0, es.size |
|---|
| 871 | es = XPath.match(doc2, '//n:c') |
|---|
| 872 | assert_equal 1, es.size |
|---|
| 873 | end |
|---|
| 874 | |
|---|
| 875 | def test_ticket_51 |
|---|
| 876 | doc = REXML::Document.new <<-EOL |
|---|
| 877 | <test xmlns='1' xmlns:x='1'> |
|---|
| 878 | <a>X</a> |
|---|
| 879 | <x:a>Y</x:a> |
|---|
| 880 | |
|---|
| 881 | <b xmlns='2'> |
|---|
| 882 | <a>Z</a> |
|---|
| 883 | </b> |
|---|
| 884 | </test> |
|---|
| 885 | EOL |
|---|
| 886 | |
|---|
| 887 | # The most common case. People not caring about the namespaces much. |
|---|
| 888 | assert_equal( "XY", XPath.match( doc, "/test/a/text()" ).join ) |
|---|
| 889 | assert_equal( "XY", XPath.match( doc, "/test/x:a/text()" ).join ) |
|---|
| 890 | # Surprising? I don't think so, if you believe my definition of the "common case" |
|---|
| 891 | assert_equal( "XYZ", XPath.match( doc, "//a/text()" ).join ) |
|---|
| 892 | |
|---|
| 893 | # These are the uncommon cases. Namespaces are actually important, so we define our own |
|---|
| 894 | # mappings, and pass them in. |
|---|
| 895 | assert_equal( "XY", XPath.match( doc, "/f:test/f:a/text()", { "f" => "1" } ).join ) |
|---|
| 896 | # The namespaces are defined, and override the original mappings |
|---|
| 897 | assert_equal( "", XPath.match( doc, "/test/a/text()", { "f" => "1" } ).join ) |
|---|
| 898 | assert_equal( "", XPath.match( doc, "/x:test/x:a/text()", { "f" => "1" } ).join ) |
|---|
| 899 | assert_equal( "", XPath.match( doc, "//a/text()", { "f" => "1" } ).join ) |
|---|
| 900 | end |
|---|
| 901 | |
|---|
| 902 | def test_processing_instruction |
|---|
| 903 | d = Document.new("<a><?foo bar?><?foo2 bar2?><b><?foo3 bar3?></b><?foo4 bar4?></a>") |
|---|
| 904 | assert_equal 4, XPath.match(d, '//processing-instruction()' ).size |
|---|
| 905 | match = XPath.match(d, "//processing-instruction('foo3')" ) |
|---|
| 906 | assert_equal 1, match.size |
|---|
| 907 | assert_equal 'bar3', match[0].content |
|---|
| 908 | end |
|---|
| 909 | |
|---|
| 910 | def test_oses_with_bad_EOLs |
|---|
| 911 | d = Document.new("\n\n\n<?xml version='1.0'?>\n\n\n<a/>\n\n") |
|---|
| 912 | end |
|---|
| 913 | |
|---|
| 914 | # Contributed (with patch to fix bug) by Kouhei |
|---|
| 915 | def test_ignore_whitespace |
|---|
| 916 | source = "<a> <b/> abc <![CDATA[def]]> </a>" |
|---|
| 917 | |
|---|
| 918 | context_all = {:ignore_whitespace_nodes => :all} |
|---|
| 919 | context_a = {:ignore_whitespace_nodes => %(a)} |
|---|
| 920 | context_b = {:ignore_whitespace_nodes => %(b)} |
|---|
| 921 | |
|---|
| 922 | tests = [[[" abc ", "def"], context_all], |
|---|
| 923 | [[" abc ", "def"], context_a], |
|---|
| 924 | [[" ", " abc ", "def", " "], context_b]] |
|---|
| 925 | |
|---|
| 926 | tests.each do |test| |
|---|
| 927 | assert_equal(test[0], Document.new(source, test[1]).root.texts.collect{|x| |
|---|
| 928 | x.to_s}) |
|---|
| 929 | end |
|---|
| 930 | end |
|---|
| 931 | |
|---|
| 932 | def test_0xD_in_preface |
|---|
| 933 | doc = "<?xml version=\"1.0\" encoding=\"ISO-8859-1\"?>\x0D<opml version=\"1.0\">\x0D</opml>" |
|---|
| 934 | doc = Document.new doc |
|---|
| 935 | end |
|---|
| 936 | |
|---|
| 937 | def test_hyphens_in_doctype |
|---|
| 938 | doc = REXML::Document.new <<-EOQ |
|---|
| 939 | <?xml version="1.0"?> |
|---|
| 940 | <!DOCTYPE a-b-c> |
|---|
| 941 | <a-b-c> |
|---|
| 942 | <a/> |
|---|
| 943 | </a-b-c> |
|---|
| 944 | EOQ |
|---|
| 945 | |
|---|
| 946 | assert_equal('a-b-c', doc.doctype.name) |
|---|
| 947 | end |
|---|
| 948 | |
|---|
| 949 | def test_accents |
|---|
| 950 | docs = [ |
|---|
| 951 | %Q{<?xml version="1.0" encoding="ISO-8859-1"?> |
|---|
| 952 | <gnuPod> |
|---|
| 953 | <files> |
|---|
| 954 | <file id="57" artist="Coralie Cl\357\277\275ent" /> |
|---|
| 955 | </files> |
|---|
| 956 | </gnuPod>}, |
|---|
| 957 | '<?xml version="1.0" encoding="ISO-8859-1"?> |
|---|
| 958 | <gnuPod> |
|---|
| 959 | <files> |
|---|
| 960 | <file id="71" album="Astrakan Caf" /> |
|---|
| 961 | </files> |
|---|
| 962 | </gnuPod>', |
|---|
| 963 | %Q{<?xml version="1.0" encoding="ISO-8859-1"?> |
|---|
| 964 | <gnuPod> |
|---|
| 965 | <files> |
|---|
| 966 | <file id="71" album="Astrakan Caf\357\277\275eria" /> |
|---|
| 967 | </files> |
|---|
| 968 | </gnuPod>}, |
|---|
| 969 | %Q{<?xml version="1.0" encoding="ISO-8859-1"?> |
|---|
| 970 | <gnuPod> |
|---|
| 971 | <files> |
|---|
| 972 | <file id="71" album="Astrakan Caf\357\277\275" /> |
|---|
| 973 | </files> |
|---|
| 974 | </gnuPod>} ] |
|---|
| 975 | docs.each_with_index { |d,i| |
|---|
| 976 | begin |
|---|
| 977 | REXML::Document.new(d) |
|---|
| 978 | rescue |
|---|
| 979 | puts "#{i} => #{docs[i]}" |
|---|
| 980 | raise |
|---|
| 981 | end |
|---|
| 982 | } |
|---|
| 983 | end |
|---|
| 984 | |
|---|
| 985 | def test_replace_text |
|---|
| 986 | e = REXML::Element.new( "a" ) |
|---|
| 987 | e.add_text( "foo" ) |
|---|
| 988 | assert_equal( "<a>foo</a>", e.to_s ) |
|---|
| 989 | e[0].value = "bar" |
|---|
| 990 | assert_equal( "<a>bar</a>", e.to_s ) |
|---|
| 991 | e[0].value = "<" |
|---|
| 992 | assert_equal( "<a><</a>", e.to_s ) |
|---|
| 993 | assert_equal( "<", e[0].value ) |
|---|
| 994 | end |
|---|
| 995 | |
|---|
| 996 | |
|---|
| 997 | def test_write_doctype |
|---|
| 998 | ## XML Document and Declaration |
|---|
| 999 | document = REXML::Document.new |
|---|
| 1000 | xmldecl = REXML::XMLDecl.new("1.0", "UTF-8") |
|---|
| 1001 | document.add(xmldecl) |
|---|
| 1002 | s = "" |
|---|
| 1003 | document.write(s) |
|---|
| 1004 | |
|---|
| 1005 | ## XML Doctype |
|---|
| 1006 | str = '<!DOCTYPE foo "bar">' |
|---|
| 1007 | source = REXML::Source.new(str) |
|---|
| 1008 | doctype = REXML::DocType.new(source) |
|---|
| 1009 | document.add(doctype) |
|---|
| 1010 | document.write(s) |
|---|
| 1011 | |
|---|
| 1012 | ## Element |
|---|
| 1013 | element = REXML::Element.new("hoge") |
|---|
| 1014 | document.add(element) |
|---|
| 1015 | |
|---|
| 1016 | document.write(s) |
|---|
| 1017 | end |
|---|
| 1018 | |
|---|
| 1019 | |
|---|
| 1020 | def test_write_cdata |
|---|
| 1021 | src = "<a>A</a>" |
|---|
| 1022 | doc = REXML::Document.new( src ) |
|---|
| 1023 | out = "" |
|---|
| 1024 | doc.write( out ) |
|---|
| 1025 | assert_equal( src, out ) |
|---|
| 1026 | |
|---|
| 1027 | src = "<a><![CDATA[A]]></a>" |
|---|
| 1028 | doc = REXML::Document.new( src ) |
|---|
| 1029 | out = "" |
|---|
| 1030 | doc.write( out ) |
|---|
| 1031 | assert_equal( src, out ) |
|---|
| 1032 | end |
|---|
| 1033 | |
|---|
| 1034 | def test_namespace_attributes |
|---|
| 1035 | source = <<-EOL |
|---|
| 1036 | <a xmlns:x="1"> |
|---|
| 1037 | <x:b x:n="foo"/> |
|---|
| 1038 | </a> |
|---|
| 1039 | EOL |
|---|
| 1040 | d = REXML::Document.new( source ) |
|---|
| 1041 | assert_equal( 'foo', REXML::XPath.first(d.root, "//x:b/@x:n").value ) |
|---|
| 1042 | assert_equal( nil, REXML::XPath.first(d.root, "//x:b/@x:n", {})) |
|---|
| 1043 | end |
|---|
| 1044 | |
|---|
| 1045 | def test_null_element_name |
|---|
| 1046 | a = REXML::Document.new |
|---|
| 1047 | assert_raise( RuntimeError ) { |
|---|
| 1048 | a.add_element( nil ) |
|---|
| 1049 | } |
|---|
| 1050 | end |
|---|
| 1051 | |
|---|
| 1052 | def test_text_raw |
|---|
| 1053 | # From the REXML tutorial |
|---|
| 1054 | # (http://www.germane-software.com/software/rexml/test/data/tutorial.html) |
|---|
| 1055 | doc = Document.new <<-EOL |
|---|
| 1056 | <?xml version="1.0"?> |
|---|
| 1057 | <!DOCTYPE schema SYSTEM "XMLSchema.dtd" [ |
|---|
| 1058 | <!ENTITY % s 'Sean'> |
|---|
| 1059 | ]> |
|---|
| 1060 | <a/> |
|---|
| 1061 | EOL |
|---|
| 1062 | a = doc.root |
|---|
| 1063 | |
|---|
| 1064 | # This makes sure that RAW text nodes don't have their entity strings |
|---|
| 1065 | # replaced |
|---|
| 1066 | t = Text.new "Sean", false, nil, true |
|---|
| 1067 | a.text = t |
|---|
| 1068 | assert_equal( "Sean", t.to_s ) |
|---|
| 1069 | assert_equal( "Sean", t.value ) |
|---|
| 1070 | |
|---|
| 1071 | # This makes sure that they do |
|---|
| 1072 | t = Text.new "Sean", false, nil, false |
|---|
| 1073 | a.text = t |
|---|
| 1074 | assert_equal( "&s;", t.to_s ) |
|---|
| 1075 | assert_equal( "Sean", t.value ) |
|---|
| 1076 | |
|---|
| 1077 | t = Text.new "&s;", false, nil, true |
|---|
| 1078 | a.text = t |
|---|
| 1079 | assert_equal( "&s;", t.to_s ) |
|---|
| 1080 | assert_equal( "Sean", t.value ) |
|---|
| 1081 | |
|---|
| 1082 | t = Text.new "&s;", false, nil, true |
|---|
| 1083 | a.text = t |
|---|
| 1084 | assert_equal( "&s;", t.to_s ) |
|---|
| 1085 | assert_equal( "Sean", t.value ) |
|---|
| 1086 | |
|---|
| 1087 | # Ticket #44 |
|---|
| 1088 | t = REXML::Text.new( "&", false, nil, true ) |
|---|
| 1089 | assert_equal( "&", t.to_s ) |
|---|
| 1090 | |
|---|
| 1091 | t = REXML::Text.new("&", false, false) |
|---|
| 1092 | assert_equal( "&amp;", t.to_s ) |
|---|
| 1093 | end |
|---|
| 1094 | |
|---|
| 1095 | def test_to_xpath |
|---|
| 1096 | doc = REXML::Document.new( %q{<tag1> |
|---|
| 1097 | <tag2 name="tag2"/> |
|---|
| 1098 | <tag2 name="tag2"/> |
|---|
| 1099 | </tag1>}) |
|---|
| 1100 | names = %w{ /tag1/tag2[1] /tag1/tag2[2] } |
|---|
| 1101 | doc.root.elements.each_with_index {|el, i| |
|---|
| 1102 | assert_equal( names[i], el.xpath ) |
|---|
| 1103 | } |
|---|
| 1104 | end |
|---|
| 1105 | |
|---|
| 1106 | def test_transitive |
|---|
| 1107 | doc = REXML::Document.new( "<a/>") |
|---|
| 1108 | s = "" |
|---|
| 1109 | doc.write( s, 0, true ) |
|---|
| 1110 | end |
|---|
| 1111 | |
|---|
| 1112 | # This is issue #40 |
|---|
| 1113 | def test_replace_with |
|---|
| 1114 | old = '<doc>old<foo/>old</doc>' |
|---|
| 1115 | d = REXML::Document.new(old).root |
|---|
| 1116 | new = REXML::Text.new('new',true,nil,true) |
|---|
| 1117 | child = d.children[2] |
|---|
| 1118 | child.replace_with(new) |
|---|
| 1119 | assert_equal( new, d.children[2] ) |
|---|
| 1120 | end |
|---|
| 1121 | |
|---|
| 1122 | def test_repeated_writes |
|---|
| 1123 | require 'iconv' |
|---|
| 1124 | a = IO.read( "test/data/iso8859-1.xml" ) |
|---|
| 1125 | f = REXML::Formatters::Pretty.new |
|---|
| 1126 | |
|---|
| 1127 | xmldoc = REXML::Document.new( a ) |
|---|
| 1128 | a_andre = xmldoc.elements['//image'].attributes['caption'] |
|---|
| 1129 | |
|---|
| 1130 | f.write(xmldoc,b="") |
|---|
| 1131 | |
|---|
| 1132 | xmldoc = REXML::Document.new(b) |
|---|
| 1133 | b_andre = xmldoc.elements['//image'].attributes['caption'] |
|---|
| 1134 | assert_equal( a_andre, b_andre ) |
|---|
| 1135 | |
|---|
| 1136 | f.write(xmldoc,c="") |
|---|
| 1137 | |
|---|
| 1138 | xmldoc = REXML::Document.new(c) |
|---|
| 1139 | c_andre = xmldoc.elements['//image'].attributes['caption'] |
|---|
| 1140 | assert_equal( b_andre, c_andre ) |
|---|
| 1141 | |
|---|
| 1142 | o = Output.new(d="","UTF-8") |
|---|
| 1143 | f.write(xmldoc,o) |
|---|
| 1144 | assert_not_equal( c, d ) |
|---|
| 1145 | end |
|---|
| 1146 | |
|---|
| 1147 | |
|---|
| 1148 | def test_ticket_58 |
|---|
| 1149 | doc = REXML::Document.new |
|---|
| 1150 | doc << REXML::XMLDecl.default |
|---|
| 1151 | doc << REXML::Element.new("a") |
|---|
| 1152 | |
|---|
| 1153 | str = "" |
|---|
| 1154 | doc.write(str) |
|---|
| 1155 | |
|---|
| 1156 | assert_equal("<a/>", str) |
|---|
| 1157 | |
|---|
| 1158 | doc = REXML::Document.new |
|---|
| 1159 | doc << REXML::XMLDecl.new("1.0", "UTF-8") |
|---|
| 1160 | doc << REXML::Element.new("a") |
|---|
| 1161 | |
|---|
| 1162 | str = "" |
|---|
| 1163 | doc.write(str) |
|---|
| 1164 | |
|---|
| 1165 | assert_equal("<?xml version='1.0' encoding='UTF-8'?><a/>", str) |
|---|
| 1166 | end |
|---|
| 1167 | |
|---|
| 1168 | # Incomplete tags should generate an error |
|---|
| 1169 | def test_ticket_53 |
|---|
| 1170 | assert_raise( REXML::ParseException ) { |
|---|
| 1171 | REXML::Document.new( "<a><b></a>" ) |
|---|
| 1172 | } |
|---|
| 1173 | assert_raise( REXML::ParseException ) { |
|---|
| 1174 | REXML::Document.new( "<a><b>" ) |
|---|
| 1175 | } |
|---|
| 1176 | assert_raise( REXML::ParseException ) { |
|---|
| 1177 | REXML::Document.new( "<a><b/>" ) |
|---|
| 1178 | } |
|---|
| 1179 | end |
|---|
| 1180 | |
|---|
| 1181 | def test_ticket_52 |
|---|
| 1182 | source = "<!-- this is a single line comment -->" |
|---|
| 1183 | d = REXML::Document.new(source) |
|---|
| 1184 | d.write(k="") |
|---|
| 1185 | assert_equal( source, k ) |
|---|
| 1186 | |
|---|
| 1187 | source = "<a><!-- Comment --></a>" |
|---|
| 1188 | target = "<a>\n <!-- Comment -->\n</a>" |
|---|
| 1189 | d = REXML::Document.new(source) |
|---|
| 1190 | REXML::Formatters::Pretty.new(4).write(d,k="") |
|---|
| 1191 | assert_equal( target, k ) |
|---|
| 1192 | end |
|---|
| 1193 | |
|---|
| 1194 | def test_ticket_76 |
|---|
| 1195 | src = "<div>at&t" |
|---|
| 1196 | assert_raise( ParseException, %Q{"#{src}" is invalid XML} ) { |
|---|
| 1197 | REXML::Document.new(src) |
|---|
| 1198 | } |
|---|
| 1199 | end |
|---|
| 1200 | |
|---|
| 1201 | def test_ticket_21 |
|---|
| 1202 | src = "<foo bar=value/>" |
|---|
| 1203 | assert_raise( ParseException, "invalid XML should be caught" ) { |
|---|
| 1204 | d = REXML::Document.new(src) |
|---|
| 1205 | } |
|---|
| 1206 | begin |
|---|
| 1207 | d = REXML::Document.new(src) |
|---|
| 1208 | rescue |
|---|
| 1209 | assert_match( /missing attribute quote/, $!.message ) |
|---|
| 1210 | end |
|---|
| 1211 | end |
|---|
| 1212 | |
|---|
| 1213 | def test_ticket_63 |
|---|
| 1214 | d = REXML::Document.new( File.new("test/data/t63-1.xml") ) |
|---|
| 1215 | end |
|---|
| 1216 | |
|---|
| 1217 | def test_ticket_75 |
|---|
| 1218 | d = REXML::Document.new( File.new("test/data/t75.xml") ) |
|---|
| 1219 | assert_equal("tree", d.root.name) |
|---|
| 1220 | end |
|---|
| 1221 | |
|---|
| 1222 | def test_ticket_48_part_II |
|---|
| 1223 | f = REXML::Formatters::Pretty.new |
|---|
| 1224 | #- rexml sanity check (bugs in ruby 1.8.4, ruby 1.8.6) |
|---|
| 1225 | xmldoc = Document.new("<test/>") |
|---|
| 1226 | xmldoc << XMLDecl.new(XMLDecl::DEFAULT_VERSION, "UTF-8") |
|---|
| 1227 | content = ['61c3a927223c3e26'].pack("H*") |
|---|
| 1228 | content.force_encoding('UTF-8') if content.respond_to?(:force_encoding) |
|---|
| 1229 | #- is some UTF-8 text but just to make sure my editor won't magically convert.. |
|---|
| 1230 | xmldoc.root.add_attribute('attr', content) |
|---|
| 1231 | f.write(xmldoc,out=[]) |
|---|
| 1232 | |
|---|
| 1233 | xmldoc = REXML::Document.new(out.join) |
|---|
| 1234 | sanity1 = xmldoc.root.attributes['attr'] |
|---|
| 1235 | f.write(xmldoc,out=[]) |
|---|
| 1236 | |
|---|
| 1237 | xmldoc = REXML::Document.new(out.join) |
|---|
| 1238 | sanity2 = xmldoc.root.attributes['attr'] |
|---|
| 1239 | f.write(xmldoc,out=[]) |
|---|
| 1240 | |
|---|
| 1241 | assert_equal( sanity1, sanity2 ) |
|---|
| 1242 | end |
|---|
| 1243 | |
|---|
| 1244 | def test_ticket_88 |
|---|
| 1245 | doc = REXML::Document.new("<?xml version=\"1.0\" encoding=\"shift_jis\"?>") |
|---|
| 1246 | assert_equal("<?xml version='1.0' encoding='SHIFT_JIS'?>", doc.to_s) |
|---|
| 1247 | doc = REXML::Document.new("<?xml version = \"1.0\" encoding = \"shift_jis\"?>") |
|---|
| 1248 | assert_equal("<?xml version='1.0' encoding='SHIFT_JIS'?>", doc.to_s) |
|---|
| 1249 | end |
|---|
| 1250 | |
|---|
| 1251 | def test_ticket_85 |
|---|
| 1252 | xml = <<ENDXML |
|---|
| 1253 | <foo> |
|---|
| 1254 | <bar> |
|---|
| 1255 | <bob name='jimmy'/> |
|---|
| 1256 | </bar> |
|---|
| 1257 | </foo> |
|---|
| 1258 | ENDXML |
|---|
| 1259 | |
|---|
| 1260 | yml = "<foo> |
|---|
| 1261 | <bar> |
|---|
| 1262 | <bob name='jimmy'/> |
|---|
| 1263 | </bar> |
|---|
| 1264 | </foo>" |
|---|
| 1265 | |
|---|
| 1266 | zml = "<foo><bar><bob name='jimmy'/></bar></foo>" |
|---|
| 1267 | |
|---|
| 1268 | # The pretty printer ignores all whitespace, anyway so output1 == output2 |
|---|
| 1269 | f = REXML::Formatters::Pretty.new( 2 ) |
|---|
| 1270 | d = Document.new( xml, :ignore_whitespace_nodes=>:all ) |
|---|
| 1271 | f.write( d, output1="" ) |
|---|
| 1272 | |
|---|
| 1273 | d = Document.new( xml ) |
|---|
| 1274 | f.write( d, output2="" ) |
|---|
| 1275 | |
|---|
| 1276 | # Output directives should override whitespace directives. |
|---|
| 1277 | assert_equal( output1, output2 ) |
|---|
| 1278 | |
|---|
| 1279 | # The base case. |
|---|
| 1280 | d = Document.new(yml) |
|---|
| 1281 | f.write( d, output3="" ) |
|---|
| 1282 | |
|---|
| 1283 | assert_equal( output3.strip, output2.strip ) |
|---|
| 1284 | |
|---|
| 1285 | d = Document.new(yml) |
|---|
| 1286 | f.write( d, output4="" ) |
|---|
| 1287 | |
|---|
| 1288 | assert_equal( output3.strip, output4.strip ) |
|---|
| 1289 | end |
|---|
| 1290 | |
|---|
| 1291 | def test_ticket_91 |
|---|
| 1292 | source="<root> |
|---|
| 1293 | <bah something='1' somethingelse='bah'> |
|---|
| 1294 | <something>great</something> |
|---|
| 1295 | </bah> |
|---|
| 1296 | </root>" |
|---|
| 1297 | expected="<root> |
|---|
| 1298 | <bah something='1' somethingelse='bah'> |
|---|
| 1299 | <something>great</something> |
|---|
| 1300 | </bah> |
|---|
| 1301 | <bah/> |
|---|
| 1302 | </root>" |
|---|
| 1303 | d = Document.new( source ) |
|---|
| 1304 | d.root.add_element( "bah" ) |
|---|
| 1305 | p=REXML::Formatters::Pretty.new(2) |
|---|
| 1306 | p.compact = true # Don't add whitespace to text nodes unless necessary |
|---|
| 1307 | p.write(d,out="") |
|---|
| 1308 | assert_equal( expected, out ) |
|---|
| 1309 | end |
|---|
| 1310 | |
|---|
| 1311 | def test_ticket_95 |
|---|
| 1312 | testd = REXML::Document.new "<a><b><c/><c/><c/></b></a>" |
|---|
| 1313 | testd.write(out1="") |
|---|
| 1314 | testd.elements["//c[2]"].xpath |
|---|
| 1315 | testd.write(out2="") |
|---|
| 1316 | assert_equal(out1,out2) |
|---|
| 1317 | end |
|---|
| 1318 | |
|---|
| 1319 | def test_ticket_102 |
|---|
| 1320 | doc = REXML::Document.new '<doc xmlns="ns"><item name="foo"/></doc>' |
|---|
| 1321 | assert_equal( "foo", doc.root.elements["item"].attribute("name","ns").to_s ) |
|---|
| 1322 | assert_equal( "item", doc.root.elements["item[@name='foo']"].name ) |
|---|
| 1323 | end |
|---|
| 1324 | |
|---|
| 1325 | def test_ticket_14 |
|---|
| 1326 | # Per .2.5 Node Tests of XPath spec |
|---|
| 1327 | assert_raise( REXML::UndefinedNamespaceException, |
|---|
| 1328 | %Q{Should have gotten an Undefined Names |
|---|