1# coding: binary 2 3require "rexml_test_utils" 4 5require "rexml/document" 6require "rexml/parseexception" 7require "rexml/formatters/default" 8 9class ContribTester < Test::Unit::TestCase 10 include REXMLTestUtils 11 include REXML 12 13 XML_STRING_01 = <<DELIMITER 14<?xml version="1.0" encoding="UTF-8"?> 15<biblio> 16 <entry type="Book"> 17 <author>Thomas, David; Hunt, Andrew</author> 18 <language>english</language> 19 <publisher>Addison-Wesley</publisher> 20 <title>Programming Ruby. The Pragmatic Programmer's Guide</title> 21 <year>2000</year> 22 </entry> 23 <entry type="Book"> 24 <author>Blammo, Blah</author> 25 <language>english</language> 26 <publisher>Hubbabubba</publisher> 27 <title>Foozboozer's Life</title> 28 <type>Book</type> 29 <year>2002</year> 30 </entry> 31</biblio> 32DELIMITER 33 34 XML_STRING_02 = <<DELIMITER 35<biblio> 36 <entry type="Book"> 37 <language>english</language> 38 <publisher>Addison-Wesley</publisher> 39 <title>Programming Ruby. The Pragmatic Programmer's Guide</title> 40 <type>Book</type> 41 <year>2000</year> 42 </entry> 43 <entry type="Book"> 44 <author>Blammo, Blah</author> 45 <language>english</language> 46 <publisher>Hubbabubba</publisher> 47 <title>Foozboozer's Life</title> 48 <type>Book</type> 49 <year>2002</year> 50 </entry> 51</biblio> 52DELIMITER 53 54 # Tobias Reif <tobiasreif@pinkjuice.com> 55 def test_bad_doctype_Tobias 56 source = <<-EOF 57 <!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.0//EN" 58 "http://www.w3.org/TR/SVG/DTD/svg10.dtd" 59 [ 60 <!-- <!ENTITY % fast-slow "0 0 .5 1">--> 61 <!--<!ENTITY % slow-fast ".5 0 1 1">--> 62 <!ENTITY hover_ani 63 '<animateTransform attributeName="transform" 64 type="scale" restart="whenNotActive" values="1;0.96" 65 dur="0.5s" calcMode="spline" keySplines="0 0 .5 1" 66 fill="freeze" begin="mouseover"/> 67 <animateTransform attributeName="transform" 68 type="scale" restart="whenNotActive" values="0.96;1" 69 dur="0.5s" calcMode="spline" keySplines=".5 0 1 1" 70 fill="freeze" begin="mouseover+0.5s"/>' 71 > 72 ] 73 > 74 EOF 75 doc = REXML::Document.new source 76 doc.write(out="") 77 assert(out[/>\'>/] != nil, "Couldn't find >'>") 78 assert(out[/\]>/] != nil, "Couldn't find ]>") 79 end 80 81 # Peter Verhage 82 def test_namespace_Peter 83 source = <<-EOF 84 <?xml version="1.0"?> 85 <config:myprog-config xmlns:config="http://someurl/program/version"> 86 <!-- main options --> 87 <config:main> 88 <config:parameter name="name" value="value"/> 89 </config:main> 90 </config:myprog-config> 91 EOF 92 doc = REXML::Document.new source 93 assert_equal "myprog-config", doc.root.name 94 count = 0 95 REXML::XPath.each(doc, "x:myprog-config/x:main/x:parameter", 96 {"x"=>"http://someurl/program/version"}) { |element| 97 assert_equal "name", element.attributes["name"] 98 count += 1; 99 } 100 assert_equal 1, count 101 assert_equal "myprog-config", doc.elements["config:myprog-config"].name 102 end 103 104 # Tobias Reif <tobiasreif@pinkjuice.com> 105 def test_complex_xpath_Tobias 106 source = <<-EOF 107 <root> 108 <foo> 109 <bar style="baz"/> 110 <blah style="baz"/> 111 <blam style="baz"/> 112 </foo> 113 <wax> 114 <fudge> 115 <noodle/> 116 </fudge> 117 </wax> 118 </root> 119 EOF 120 # elements that have child elements 121 # but not grandchildren 122 # and not children that don't have a style attribute 123 # and not children that have a unique style attribute 124 complex_path = "*[* "+ 125 "and not(*/node()) "+ 126 "and not(*[not(@style)]) "+ 127 "and not(*/@style != */@style)]" 128 doc = REXML::Document.new source 129 results = REXML::XPath.match( doc.root, complex_path ) 130 assert(results) 131 assert_equal 1, results.size 132 assert_equal "foo", results[0].name 133 end 134 135 # "Chris Morris" <chrismo@charter.net> 136 def test_extra_newline_on_read_Chris 137 text = 'test text' 138 e = REXML::Element.new('Test') 139 e.add_text(text) 140 REXML::Formatters::Default.new.write(e,out="") 141 142 doc = REXML::Document.new(out) 143 outtext = doc.root.text 144 145 assert_equal(text, outtext) 146 end 147 148 # Tobias Reif <tobiasreif@pinkjuice.com> 149 def test_other_xpath_Tobias 150 schema = <<-DELIM 151 <xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema" 152 elementFormDefault="qualified"> 153 <xs:element name="rect"> 154 <xs:complexType> 155 <xs:attribute name="width" type="xs:byte" use="required"/> 156 <xs:attribute name="height" type="xs:byte" use="required"/> 157 </xs:complexType> 158 </xs:element> 159 <xs:element name="svg"> 160 <xs:complexType> 161 <xs:sequence> 162 <xs:element ref="rect"/> 163 </xs:sequence> 164 </xs:complexType> 165 </xs:element> 166 </xs:schema> 167 DELIM 168 169 doc = REXML::Document.new schema 170 171 result = REXML::XPath.first(doc.root, 'xs:element[descendant::xs:element[@ref]]') 172 assert result 173 assert_equal "svg", result.attributes['name'] 174 result = REXML::XPath.first(doc, 'element[descendant::element[@ref]]') 175 assert_nil result 176 end 177 178 #this first test succeeds, to check if stuff is set up correctly 179 def test_xpath_01_TobiasReif 180 doc = Document.new XML_STRING_01.dup 181 desired_result = Document.new '<author>Thomas, David; Hunt, Andrew</author>' 182 xpath = '//author' 183 result = XPath.first(doc, xpath) 184 assert_equal desired_result.to_s, result.to_s 185 end 186 187 def test_xpath_whitespace_TobiasReif 188 # same as above, with whitespace in XPath 189 doc = Document.new(XML_STRING_01.dup) 190 desired_result = Document.new('<author>Thomas, David; Hunt, Andrew</author>') 191 xpath = "\/\/author\n \n" 192 result = XPath.first(doc, xpath) 193 failure_message = "\n[[[TR: AFAIK, whitespace should be allowed]]]\n" 194 assert_equal(desired_result.to_s, result.to_s, failure_message) 195 end 196 197 def test_xpath_02_TobiasReif 198 doc = Document.new XML_STRING_01.dup 199 desired_result = Document.new '<author>Thomas, David; Hunt, Andrew</author>' 200 # Could that quirky 201 # Programmer',"'",'s 202 # be handled automatically, somehow? 203 # Or is there a simpler way? (the below XPath should match the author element above, 204 # AFAIK; I tested it inside an XSLT) 205 xpath = %q{/biblio/entry[ 206 title/text()=concat('Programming Ruby. The Pragmatic Programmer',"'",'s Guide') 207 and 208 year='2000' 209 ]/author} 210 result = XPath.first(doc, xpath) 211 failure_message = "\nHow to handle the apos inside the string inside the XPath?\nXPath = #{xpath}\n" 212 assert_equal desired_result.to_s, result.to_s, failure_message 213 end 214 215 def test_xpath_03_TobiasReif 216 doc = Document.new XML_STRING_02.dup 217 desired_result_string = "<entry type='Book'> 218 <language>english</language> 219 <publisher>Addison-Wesley</publisher> 220 <title>Programming Ruby. The Pragmatic Programmer's Guide</title> 221 <type>Book</type> 222 <year>2000</year> 223 </entry>" 224 Document.new desired_result_string 225 xpath = "/biblio/entry[not(author)]" 226 result = XPath.first(doc, xpath) 227 assert_equal desired_result_string, result.to_s 228 end 229 230 def test_umlaut 231 koln_iso = "K\xf6ln" 232 koln_utf = "K\xc3\xb6ln" 233 source_iso = "<?xml version='1.0' encoding='ISO-8859-1'?><test>#{koln_iso}</test>" 234 source_utf = "<?xml version='1.0' encoding='UTF-8'?><test>#{koln_utf}</test>" 235 236 if String.method_defined? :encode 237 koln_iso.force_encoding('iso-8859-1') 238 koln_utf.force_encoding('utf-8') 239 source_iso.force_encoding('iso-8859-1') 240 source_utf.force_encoding('utf-8') 241 end 242 243 doc = REXML::Document.new(source_iso) 244 assert_equal('ISO-8859-1', doc.xml_decl.encoding) 245 assert_equal(koln_utf, doc.root.text) 246 doc.write(out="") 247 assert_equal(source_iso, out ) 248 doc.xml_decl.encoding = 'UTF-8' 249 doc.write(out="") 250 assert_equal(source_utf, out) 251 252 doc = Document.new <<-EOF 253<?xml version="1.0" encoding="ISO-8859-1"?> 254<intranet> 255<position><aktuell datum="01-10-11">Technik</aktuell></position> 256<hauptspalte> 257<headline>Technik</headline> 258Die Technik ist das R\xFCckgrat der meisten Gesch\xFCftsprozesse bei Home of the Brave. Deshalb sollen hier alle relevanten technischen Abl\xFCufe, Daten und Einrichtungen beschrieben werden, damit jeder im Bedarfsfall die n\xFCtigen Informationen, Anweisungen und Verhaltensempfehlungen nachlesen und/oder abrufen kann. 259</hauptspalte> 260<nebenspalte> 261 <link ziel="Flash/">Flash</link><umbruch/> 262 N\xFCtzliches von Flashern f\xFCr Flasher.<umbruch/> 263 <link neu="ja" ziel="Cvs/">CVS-FAQ</link><umbruch/> 264 FAQ zur Benutzung von CVS bei HOB 265</nebenspalte> 266</intranet> 267EOF 268 tn = XPath.first(doc, "//nebenspalte/text()[2]") 269 expected_iso = "N\xFCtzliches von Flashern f\xFCr Flasher." 270 expected_utf = expected_iso.unpack('C*').pack('U*') 271 expected_iso.force_encoding(::Encoding::ISO_8859_1) 272 expected_utf.force_encoding(::Encoding::UTF_8) 273 assert_equal(expected_utf, tn.to_s.strip) 274 f = REXML::Formatters::Default.new 275 f.write( tn, Output.new(o = "", "ISO-8859-1") ) 276 assert_equal(expected_iso, o.strip) 277 278 doc = Document.new File.new(fixture_path('xmlfile-bug.xml')) 279 tn = XPath.first(doc, "//nebenspalte/text()[2]") 280 assert_equal(expected_utf, tn.to_s.strip) 281 f.write( tn, Output.new(o = "", "ISO-8859-1") ) 282 assert_equal(expected_iso, o.strip) 283 end 284 285 def test_element_cloning_namespace_Chris 286 aDoc = REXML::Document.new '<h1 tpl:content="title" xmlns:tpl="1">Dummy title</h1>' 287 288 anElement = anElement = aDoc.elements[1] 289 elementAttrPrefix = anElement.attributes.get_attribute('content').prefix 290 291 aClone = anElement.clone 292 cloneAttrPrefix = aClone.attributes.get_attribute('content').prefix 293 294 assert_equal( elementAttrPrefix , cloneAttrPrefix ) 295 end 296 297 def test_namespaces_in_attlist_tobias 298 in_string = File.open(fixture_path('foo.xml'), 'r') do |file| 299 file.read 300 end 301 302 doc = Document.new in_string 303 304 assert_nil XPath.first(doc,'//leg') 305 assert_equal 'http://www.foo.com/human', doc.root.elements[1].namespace 306 assert_equal 'human leg', 307 XPath.first(doc, '//x:leg/text()', {'x'=>'http://www.foo.com/human'}).to_s 308 end 309 310 # Alun ap Rhisiart 311 def test_less_than_in_element_content 312 source = File.new(fixture_path('ProductionSupport.xml')) 313 h = Hash.new 314 doc = REXML::Document.new source 315 doc.elements.each("//CommonError") { |el| 316 h[el.elements['Key'].text] = 'okay' 317 } 318 assert(h.include?('MotorInsuranceContract(Object)>>#error:')) 319 end 320 321 # XPaths provided by Thomas Sawyer 322 def test_various_xpath 323 #@doc = REXML::Document.new('<r a="1"><p><c b="2"/></p></r>') 324 doc = REXML::Document.new('<r a="1"><p><c b="2">3</c></p></r>') 325 326 [['/r', REXML::Element], 327 ['/r/p/c', REXML::Element], 328 ['/r/attribute::a', Attribute], 329 ['/r/@a', Attribute], 330 ['/r/attribute::*', Attribute], 331 ['/r/@*', Attribute], 332 ['/r/p/c/attribute::b', Attribute], 333 ['/r/p/c/@b', Attribute], 334 ['/r/p/c/attribute::*', Attribute], 335 ['/r/p/c/@*', Attribute], 336 ['//c/attribute::b', Attribute], 337 ['//c/@b', Attribute], 338 ['//c/attribute::*', Attribute], 339 ['//c/@*', Attribute], 340 ['.//node()', REXML::Node ], 341 ['.//node()[@a]', REXML::Element ], 342 ['.//node()[@a="1"]', REXML::Element ], 343 ['.//node()[@b]', REXML::Element ], # no show, why? 344 ['.//node()[@b="2"]', REXML::Element ] 345 ].each do |xpath,kind| 346 begin 347 REXML::XPath.each( doc, xpath ) do |what| 348 assert_kind_of( kind, what, "\n\nWrong type (#{what.class}) returned for #{xpath} (expected #{kind.name})\n\n" ) 349 end 350 rescue Exception 351 puts "PATH WAS: #{xpath}" 352 raise 353 end 354 end 355 356 [ 357 ['/r', 'attribute::a', Attribute ], 358 ['/r', '@a', Attribute ], 359 ['/r', 'attribute::*', Attribute ], 360 ['/r', '@*', Attribute ], 361 ['/r/p/c', 'attribute::b', Attribute ], 362 ['/r/p/c', '@b', Attribute ], 363 ['/r/p/c', 'attribute::*', Attribute ], 364 ['/r/p/c', '@*', Attribute ] 365 ].each do |nodepath, xpath, kind| 366 begin 367 context = REXML::XPath.first(doc, nodepath) 368 REXML::XPath.each( context, xpath ) do |what| 369 assert_kind_of kind, what, "Wrong type (#{what.class}) returned for #{xpath} (expected #{kind.name})\n" 370 end 371 rescue Exception 372 puts "PATH WAS: #{xpath}" 373 raise 374 end 375 end 376 end 377 378 def test_entities_Holden_Glova 379 document = <<-EOL 380 <?xml version="1.0" encoding="UTF-8"?> 381 <!DOCTYPE rubynet [ 382 <!ENTITY rbconfig.MAJOR "1"> 383 <!ENTITY rbconfig.MINOR "7"> 384 <!ENTITY rbconfig.TEENY "2"> 385 <!ENTITY rbconfig.ruby_version "&rbconfig.MAJOR;.&rbconfig.MINOR;"> 386 <!ENTITY rbconfig.arch "i386-freebsd5"> 387 <!ENTITY rbconfig.prefix "/usr/local"> 388 <!ENTITY rbconfig.libdir "&rbconfig.prefix;/lib"> 389 <!ENTITY rbconfig.includedir "&rbconfig.prefix;/include"> 390 <!ENTITY rbconfig.sitedir "&rbconfig.prefix;/lib/ruby/site_ruby"> 391 <!ENTITY rbconfig.sitelibdir "&rbconfig.sitedir;/&rbconfig.ruby_version;"> 392 <!ENTITY rbconfig.sitearchdir "&rbconfig.sitelibdir;/&rbconfig.arch;"> 393 ]> 394 <rubynet> 395 <pkg version="version1.0"> 396 <files> 397 <file> 398 <filename>uga.rb</filename> 399 <mode>0444</mode> 400 <path>&rbconfig.libdir;/rexml</path> 401 <content encoding="xml">... the file here</content> 402 </file> 403 <file> 404 <filename>booga.h</filename> 405 <mode>0444</mode> 406 <path>&rbconfig.includedir;</path> 407 <content encoding="xml">... the file here</content> 408 </file> 409 <file> 410 <filename>foo.so</filename> 411 <mode>0555</mode> 412 <path>&rbconfig.sitearchdir;/rexml</path> 413 <content encoding="mime64">Li4uIHRoZSBmaWxlIGhlcmU=\n</content> 414 </file> 415 </files> 416 </pkg> 417 </rubynet> 418 EOL 419 420 file_xpath = '/rubynet/pkg/files/file' 421 422 root = REXML::Document.new(document) 423 424 root.elements.each(file_xpath) do |metadata| 425 text = metadata.elements['path'].get_text.value 426 assert text !~ /&rbconfig/, "'#{text}' failed" 427 end 428 429 #Error occurred in test_package_file_opens(TC_PackageInstall): 430 # ArgumentError: 431 #illegal access mode &rbconfig.prefix;/lib/rexml 432 # 433 #[synack@Evergreen] src $ ruby --version 434 #ruby 1.6.7 (2002-03-01) [i686-linux-gnu] 435 # 436 #It looks like it expanded the first entity, but didn't reparse it for more 437 #entities. possible bug - or have I mucked this up? 438 end 439 440 def test_whitespace_after_xml_decl 441 Document.new <<EOL 442<?xml version='1.0'?> 443 <blo> 444 <wak> 445 </wak> 446</blo> 447EOL 448 end 449 450 def test_external_entity 451 xp = '//channel/title' 452 453 %w{working.rss broken.rss}.each do |path| 454 File.open(File.join(fixture_path(path))) do |file| 455 doc = REXML::Document.new file.readlines.join('') 456 457 # check to make sure everything is kosher 458 assert_equal( doc.root.class, REXML::Element ) 459 assert_equal( doc.root.elements.class, REXML::Elements ) 460 461 # get the title of the feed 462 assert( doc.root.elements[xp].kind_of?( REXML::Element ) ) 463 end 464 end 465 end 466 467 def test_maintain_dtd 468 src = %q{<?xml version="1.0" encoding="UTF-8"?> 469<!DOCTYPE ivattacks SYSTEM "../../ivacm.dtd" [ 470<!ENTITY % extern-packages SYSTEM "../../ivpackages.dtd"> 471<!ENTITY % extern-packages SYSTEM "../../common-declarations.dtd"> 472%extern-packages; 473%extern-common; 474]>} 475 doc = Document.new( src ) 476 doc.write( out="" ) 477 src = src.tr('"', "'") 478 out = out.tr('"', "'") 479 assert_equal( src, out ) 480 end 481 482 def test_text_nodes_nomatch 483 source = "<root><child>test</child></root>" 484 d = REXML::Document.new( source ) 485 r = REXML::XPath.match( d, %q{/root/child[text()="no-test"]} ) 486 assert_equal( 0, r.size ) 487 end 488 489 def test_raw_Terje_Elde 490 f = REXML::Formatters::Default.new 491 txt = 'abcødef' 492 a = Text.new( txt,false,nil,true ) 493 f.write(a,out="") 494 assert_equal( txt, out ) 495 496 txt = '<sean><russell>abcødef</russell></sean>' 497 a = Document.new( txt, { :raw => ["russell"] } ) 498 f.write(a,out="") 499 assert_equal( txt, out ) 500 end 501 502 def test_indenting_error 503 a=Element.new("test1") 504 b=Element.new("test2") 505 c=Element.new("test3") 506 b << c 507 a << b 508 509 REXML::Formatters::Pretty.new.write(a,"") 510 end 511 512 def test_pos 513 require 'tempfile' 514 testfile = Tempfile.new("tidal") 515 testdata = %Q{<calibration> 516<section name="parameters"> 517<param name="barpress">760</param> 518<param name="hertz">50</param> 519</section> 520</calibration> 521} 522 523 testfile.puts testdata 524 testfile.rewind 525 assert_nothing_raised do 526 REXML::Document.new(testfile) 527 end 528 testfile.close(true) 529 end 530 531 def test_deep_clone 532 a = Document.new( '<?xml version="1.0"?><!DOCTYPE html PUBLIC 533 "-//W3C//DTD 534 XHTML 1.0 Transitional//EN" 535 "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"><html 536 xmlns="http:///www.w3.org/1999/xhtml"></html>' ) 537 b = a.deep_clone 538 assert_equal a.to_s, b.to_s 539 end 540 541 def test_double_escaping 542 data = '<title>AT&T</title>' 543 xml = "<description><![CDATA[#{data}]]></description>" 544 545 doc = REXML::Document.new(xml) 546 description = doc.find {|e| e.name=="description"} 547 assert_equal data, description.text 548 end 549 550 def test_ticket_12 551 cfg = "<element><anotherelement><child1>a</child1><child2>b</child2></anotherelement></element>" 552 553 config = REXML::Document.new( cfg ) 554 555 assert_equal( "a", config.elements[ "//child1" ].text ) 556 end 557 558=begin 559 # This is a silly test, and is low priority 560 def test_namespace_serialization_tobi_reif 561 doc = Document.new '<doc xmlns:b="http://www.foo.foo"> 562 <b:p/> 563</doc>' 564 ns = 'http://www.foo.foo' 565 ns_declaration={'f'=>ns} 566 returned = XPath.match(doc,'//f:p',ns_declaration) 567 # passes: 568 assert( (returned[0].namespace==ns), 'namespace should be '+ns) 569 serialized = returned.to_s 570 serialized_and_parsed = Document.new(serialized) 571 puts 'serialized: '+serialized 572 # ... currently brings <b:p/> 573 # prefix b is undeclared (!) 574 assert( (serialized_and_parsed.namespace==ns), 575 'namespace should still be '+ns.inspect+ 576 ' and not '+serialized_and_parsed.namespace.inspect) 577 # ... currently results in a failure: 578 # 'namespace should still be "http://www.foo.foo" and not ""' 579 end 580=end 581end 582