root / test / test_core.rb

Revision 552:005ddb262769, 39.2 kB (checked in by Sean Russell <ser@…>, 5 months ago)

More moving things around

Line 
1# coding: binary
2require "test/unit/testcase"
3
4require "rexml/document"
5require "rexml/parseexception"
6require "test/listener"
7require "rexml/output"
8require "rexml/source"
9require "rexml/formatters/pretty"
10require "rexml/undefinednamespaceexception"
11
12class 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>&#x00;</a>',
47      '<a>&#0;</a>',
48      "<a a='&#0;' />",
49      "<a>\f</a>",
50      "<a a='\f' />",
51      "<a>\000</a>",
52      '<a' + [65535].pack('U') + ' />',
53      '<a>&#xfffe;</a>',
54      '<a>&#65535;</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 &lt; ( 1 &amp; 1 )"
374    text = Text.new(string, true)
375    f.write(text,out="")
376    assert_equal(correct, out)
377
378    string = "Cats &amp; 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;amp; dogs", c.get_text.to_s)
395
396    # test all
397    string = "<a>&amp;<b>&lt;</b><c>&gt;<d>&quot;</d></c></a>"
398    doc = Document.new(string, { :raw => :all })
399    assert_equal( "&amp;", doc.elements["/a"][0].to_s )
400    assert_equal( "&", doc.elements["/a"].text )
401    assert_equal( "&lt;", doc.elements["/a/b"][0].to_s )
402    assert_equal( "<", doc.elements["/a/b"].text )
403    assert_equal( "&gt;", doc.elements["/a/c"][0].to_s )
404    assert_equal( ">", doc.elements["/a/c"].text )
405    assert_equal( '&quot;', 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>&lt;&gt;&amp;</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 &lt; text <b> more &gt; text </b> &gt; </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>
793EOL
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>&#101;&#x65;&#252;</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>&lt;</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( "&amp;", false, nil, true )
1089    assert_equal( "&amp;", t.to_s )
1090   
1091    t = REXML::Text.new("&amp;", false, false)
1092    assert_equal( "&amp;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>
1258ENDXML
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