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