diff options
author | kou <kou@b2dd03c8-39d4-4d8f-98ff-823fe69b080e> | 2010-09-17 13:14:14 +0000 |
---|---|---|
committer | kou <kou@b2dd03c8-39d4-4d8f-98ff-823fe69b080e> | 2010-09-17 13:14:14 +0000 |
commit | 91ed484f92040e5c2006a3a00ec77a54d552cf37 (patch) | |
tree | 03fd6677a85aaad516d0c9464b1273ea107231b7 /test/rexml/test_core.rb | |
parent | 045491d5be06b615d66d3f66cca2b5d2bc3c1929 (diff) | |
download | ruby-91ed484f92040e5c2006a3a00ec77a54d552cf37.tar.gz |
* test/rexml/: import REXML tests from
http://www.germane-software.com/repos/rexml/trunk/test/.
Many tests are failed temporary. I'll fix them quickly. Sorry.
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@29282 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
Diffstat (limited to 'test/rexml/test_core.rb')
-rw-r--r-- | test/rexml/test_core.rb | 1382 |
1 files changed, 1382 insertions, 0 deletions
diff --git a/test/rexml/test_core.rb b/test/rexml/test_core.rb new file mode 100644 index 0000000000..4fd5b07c99 --- /dev/null +++ b/test/rexml/test_core.rb @@ -0,0 +1,1382 @@ +# coding: binary +require "test/unit/testcase" + +require "rexml/document" +require "rexml/parseexception" +require "test/listener" +require "rexml/output" +require "rexml/source" +require "rexml/formatters/pretty" +require "rexml/undefinednamespaceexception" + +class Tester < Test::Unit::TestCase + include REXML + def setup + @xsa_source = <<-EOL + <?xml version="1.0"?> + <?xsl stylesheet="blah.xsl"?> + <!-- The first line tests the XMLDecl, the second tests PI. + The next line tests DocType. This line tests comments. --> + <!DOCTYPE xsa PUBLIC + "-//LM Garshol//DTD XML Software Autoupdate 1.0//EN//XML" + "http://www.garshol.priv.no/download/xsa/xsa.dtd"> + + <xsa> + <vendor id="blah"> + <name>Lars Marius Garshol</name> + <email>larsga@garshol.priv.no</email> + <url>http://www.stud.ifi.uio.no/~lmariusg/</url> + </vendor> + </xsa> + EOL + end + + def test_bad_markup + [ + "<pkg='version'> foo </pkg>", + '<0/>', + '<a>&</a>', + '<a>&a</a>', + '<a>&a;</a>', + '<a a="<"/>', + '<a 3="<"/>', + '<a a="1" a="2"/>', + '<a><!-- -- --></a>', + '<a><!-- ---></a>', + '<a>�</a>', + '<a>�</a>', + "<a a='�' />", + "<a>\f</a>", + "<a a='\f' />", + "<a>\000</a>", + '<a' + [65535].pack('U') + ' />', + '<a></a>', + '<a></a>', + '<a' + [0x0371].pack('U') + ' />', + '<a a' + [0x0371].pack('U') + '="" />', + ].each do |src| + assert_raise( ParseException, %Q{Parse #{src.inspect} should have failed!} ) do + Document.new(src) + end + end + end + + def test_attribute + # Testing constructors + #a = Attribute.new "hello", "dolly" + #b = Attribute.new a + #d = Document.new( "<a hello='dolly' href='blah'/>" ) + #c = d[0].attributes.get_attribute( "hello" ) + + #assert_equal a, b + #for attr in [ a, b, c] + # assert_equal "hello", attr.name + # assert_equal "dolly", attr.value + #end + + # This because of a reported bug in attribute handling in 1.0a8 + source = '<a att="A">blah</a>' + doc = Document.new source + doc.elements.each do |a| + a.attributes['att'] << 'B' + assert_equal "AB", a.attributes['att'] + a.attributes['att'] = 'C' + assert_equal "C", a.attributes['att'] + end + + # Bryan Murphy <murphybryanp@yahoo.com> + text = "this is a {target[@name='test']/@value} test" + source = <<-EOL + <?xml version="1.0"?> + <doc search="#{text}"/> + EOL + + xml = Document.new source + value = xml.root.attributes["search"] + assert_equal text, value.to_s + + e = Element.new "test" + e.add_attributes({ "name1" => "test1", "name4" => "test4" }) + e.add_attributes([["name3","test3"], ["name2","test2"]]) + assert_equal "test1", e.attributes["name1"] + assert_equal "test2", e.attributes["name2"] + assert_equal "test3", e.attributes["name3"] + assert_equal "test4", e.attributes["name4"] + + # ensure that the attributes come out in sorted order + assert_equal %w(<test + name1='test1' + name2='test2' + name3='test3' + name4='test4'/>).join(' '), e.to_s + end + + def test_cdata + test = "The quick brown fox jumped + & < & < \" ' + over the lazy dog." + + source = "<a><![CDATA[#{test}]]></a>" + d = REXML::Document.new( source ) + + # Test constructors + cdata = d[0][0] + assert_equal test, cdata.value + end + + def test_comment + string = "This is a new comment!" + source = "<!--#{string}-->" + comment = Comment.new string + REXML::Formatters::Default.new.write( comment, out = "" ) + assert_equal(source, out) + + comment2 = Comment.new comment + assert_equal(comment, comment2) + + assert_raise(ParseException) { + REXML::Document.new("<d><!- foo --></d>") + } + assert_raise(ParseException) { + REXML::Document.new("<d><!-- foo -></d>") + } + end + + def test_whitespace + doc = Document.new "<root-element><first-element/></root-element>" + assert_equal 1, doc.root.size + assert_equal 1, doc.root.elements.size + doc = Document.new "<root-element> + <first-element/> + </root-element>" + assert_equal 3, doc.root.size + assert_equal 1, doc.root.elements.size + + text = " This is text + with a lot of whitespace " + source = "<a>#{text}<b>#{text}</b><c>#{text}</c>#{text}</a>" + + doc = Document.new( source, { + :respect_whitespace => %w{ a c } + } ) + assert_equal text, doc.elements["//c"].text + string = "" + doc.root.each { |n| string << n.to_s if n.kind_of? Text } + assert_equal text+text, string + + string =" lots of blank + space" + doc.root.add_element("d").add_element("c").text = string + doc.root.add_element("e").text = string + assert_equal string, doc.elements["/a/d/c"].text + assert string != doc.elements["/a/e"].text, "Text wasn't properly compressed" + + doc = Document.new source, { :respect_whitespace => :all } + doc.root.add_element("d").text = string + assert_equal text, doc.root.text + nxt = "" + doc.root.each { |n| nxt << n.to_s if n.kind_of? Text } + assert_equal text+text, nxt + assert_equal text, doc.root.elements["b"].text + assert_equal text, doc.root.elements["c"].text + assert_equal string, doc.root.elements["d"].text + end + + # This isn't complete. We need to check declarations and comments + def test_doctype + string = "something" + correct = "<!DOCTYPE something>" + doc = DocType.new(string) + assert_equal(string, doc.name) + doc.write(out="") + assert_equal(correct, out) + + doc2 = DocType.new(doc) + assert_equal(doc.name, doc2.name) + assert_equal(doc.external_id, doc2.external_id) + + correct = '<!DOCTYPE xsa PUBLIC "-//LM Garshol//DTD XML Software Autoupdate 1.0//EN//XML" "http://www.garshol.priv.no/download/xsa/xsa.dtd">' + + 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/>' + doc = Document.new( one_line_source ) + doc = doc[0] + assert(doc) + doc.write(test="") + assert_equal(correct, test) + + multi_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/>' + d = Document.new( multi_line_source ) + doc = d[0] + assert(doc) + doc.write(test="") + assert_equal(correct, test) + + odd_space_source = ' <!DOCTYPE + xsa PUBLIC "-//LM Garshol//DTD XML Software Autoupdate 1.0//EN//XML" + "http://www.garshol.priv.no/download/xsa/xsa.dtd"> <a/>' + d = Document.new( odd_space_source ) + dt = d.doctype + dt.write(test="") + assert_equal(correct, test) + + # OK, the BIG doctype test, numba wun + docin = File.new "test/data/doctype_test.xml" + doc = Document.new(docin) + doc.write(test="") + assert_equal(31, doc.doctype.size) + + # Here's a little ditty from Tobias... + src = <<-EOL + <!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.0//EN" + "http://www.w3.org/TR/SVG/DTD/svg10.dtd" + [ + <!-- <!ENTITY % fast-slow "0 0 .5 1">--> + <!--<!ENTITY % slow-fast ".5 0 1 1">--> + <!ENTITY hover_ani + '<animateTransform attributeName="transform" + type="scale" restart="whenNotActive" values="1;0.96" + dur="0.5s" calcMode="spline" keySplines="0 0 .5 1" + fill="freeze" begin="mouseover"/> + <animateTransform attributeName="transform" + type="scale" restart="whenNotActive" values="0.96;1" + dur="0.5s" calcMode="spline" keySplines=".5 0 1 1" + fill="freeze" begin="mouseover+0.5s"/>' + > + ] + > <a/> + EOL + end + + def test_document + # Testing cloning + source = "<element/>" + doc = Document.new source + doc2 = Document.new doc + + # Testing Root + assert_equal doc.root.name.to_s, "element" + + # Testing String source + source = @xsa_source + doc = Document.new source + assert_instance_of XMLDecl, doc.xml_decl + assert_instance_of DocType, doc.doctype + assert_equal doc.version, "1.0" + + source = File.new( "test/data/dash.xml" ) + doc = Document.new source + assert_equal "content-2", doc.elements["//content-2"].name + end + + def test_instruction + target = "use" + content = "ruby" + source = "<?#{target} #{content}?>" + + instruction = Instruction.new target, content + instruction2 = Instruction.new instruction + assert_equal(instruction, instruction2) + REXML::Formatters::Default.new.write( instruction, out = "" ) + assert_equal(source, out) + + d = Document.new( source ) + instruction2 = d[0] + assert_equal(instruction.to_s, instruction2.to_s) + + assert_raise(ParseException) { + REXML::Document.new("<d><?foo bar></d>") + } + end + + def test_parent + parent = Parent.new + begin + parent << "Something" + rescue Exception + parent << Comment.new("Some comment") + assert parent.size == 1, "size of parent should be 1" + else + assert_fail "should have gotten an exception trying to add a "+ "String to a Parent" + end + + source = "<a><one/><three/><five/></a>" + doc = Document.new source + three = doc.root.elements["three"] + doc.root.insert_before( three, Element.new("two") ) + nxt = doc.root.elements["one"] + string = "" + while nxt + string << nxt.name + nxt = nxt.next_sibling + end + assert_equal "onetwothreefive", string + + + doc.root.insert_after( three, Element.new("four") ) + string = "" + doc.root.each { |element| string << element.name } + assert_equal "onetwothreefourfive", string + + string = "" + nxt = doc.root.elements["five"] + while nxt + string << nxt.name + nxt = nxt.previous_sibling + end + assert_equal "fivefourthreetwoone", string + + doc.insert_after "//two", Element.new("two-and-half") + string = doc.root.elements.collect {|x| x.name}.join + assert_equal "onetwotwo-and-halfthreefourfive", string + doc.elements["/a/five"].insert_before "../four", Element.new("three-and-half") + string = doc.root.elements.collect {|x| x.name}.join + assert_equal "onetwotwo-and-halfthreethree-and-halffourfive", string + + doc.elements["/a/five"].previous_sibling = Element.new("four-and-half") + string = doc.root.elements.collect {|x| x.name}.join + assert_equal "onetwotwo-and-halfthreethree-and-halffourfour-and-halffive", string + doc.elements["/a/one"].next_sibling = Element.new("one-and-half") + string = doc.root.elements.collect {|x| x.name}.join + assert_equal "oneone-and-halftwotwo-and-halfthreethree-and-halffourfour-and-halffive", string + + doc = Document.new "<a><one/><three/></a>" + doc.root[1,0] = Element.new "two" + string = "" + doc.root.each { |el| string << el.name } + assert_equal "onetwothree", string + end + + # The Source classes are tested extensively throughout the test suite + def test_source + # Testing string source + source = @xsa_source + doc = Document.new source + assert_equal doc.root.name.to_s, "xsa" + + # Testing IO source + doc = Document.new File.new("test/data/project.xml") + assert_equal doc.root.name.to_s, "Project" + end + + def test_text + f = REXML::Formatters::Default.new + string = "Some text" + text = Text.new(string) + assert_equal(string, text.to_s) + text2 = Text.new(text) + assert_equal(text, text2) + #testing substitution + string = "0 < ( 1 & 1 )" + correct = "0 < ( 1 & 1 )" + text = Text.new(string, true) + f.write(text,out="") + assert_equal(correct, out) + + string = "Cats & dogs" + text = Text.new(string, false, nil, true) + assert_equal(string, text.to_s) + + string2 = "<a>#{string}</a>" + doc = Document.new( string2, { + :raw => %w{ a b } + } ) + f.write(doc,out="") + assert_equal(string2, out) + b = doc.root.add_element( "b" ) + b.text = string + assert_equal(string, b.get_text.to_s) + + c = doc.root.add_element("c") + c.text = string + assert_equal("Cats &amp; dogs", c.get_text.to_s) + + # test all + string = "<a>&<b><</b><c>><d>"</d></c></a>" + doc = Document.new(string, { :raw => :all }) + assert_equal( "&", doc.elements["/a"][0].to_s ) + assert_equal( "&", doc.elements["/a"].text ) + assert_equal( "<", doc.elements["/a/b"][0].to_s ) + assert_equal( "<", doc.elements["/a/b"].text ) + assert_equal( ">", doc.elements["/a/c"][0].to_s ) + assert_equal( ">", doc.elements["/a/c"].text ) + assert_equal( '"', doc.elements["//d"][0].to_s ) + assert_equal( '"', doc.elements["//d"].text ) + + # test some other stuff + doc = Document.new('<a><b/></a>') + doc.root.text = 'Sean' + assert_equal( '<a><b/>Sean</a>', doc.to_s ) + doc.root.text = 'Elliott' + assert_equal( '<a><b/>Elliott</a>', doc.to_s ) + doc.root.add_element( 'c' ) + assert_equal( '<a><b/>Elliott<c/></a>', doc.to_s ) + doc.root.text = 'Russell' + assert_equal( '<a><b/>Russell<c/></a>', doc.to_s ) + doc.root.text = nil + assert_equal( '<a><b/><c/></a>', doc.to_s ) + end + + def test_xmldecl + source = "<?xml version='1.0'?>" + # test args + # test no args + decl2 = XMLDecl.new + assert_equal source, decl2.to_s + # test XMLDecl + decl2 = XMLDecl.new "1.0" + assert_equal source, decl2.to_s + end + + def each_test( element, xpath, num_children ) + count = 0 + element.each_element( xpath ) { |child| + count += 1 + yield child if block_given? + } + assert_equal num_children, count + end + + # This is the biggest test, as the number of permutations of xpath are + # enormous. + def test_element_access + # Testing each_element + doc = Document.new File.new("test/data/project.xml") + + each_test( doc, "/", 1 ) { |child| + assert_equal doc.name, child.name + } + each_test(doc, ".", 1) { |child| assert_equal doc, child } + each_test(doc.root, "..", 1) { |child| assert_equal doc, child } + each_test(doc.root, "*", 5) + each_test(doc, "Project/Datasets", 1) { |child| + assert_equal "Datasets", child.name + } + each_test(doc, "Project/Datasets/link", 2 ) + each_test(doc.root, "/Project/Description", 1) {|child| + assert_equal "Description", child.name + } + each_test(doc.root, "./Description",1 ) { |child| + assert_equal "Description",child.name + } + each_test(doc.root, "../Project",1 ) { |child| + assert_equal doc.root, child + } + #each_test(doc,".../link",2) {|child| assert_equal "link",child.name.to_s} + + # test get_element + first = doc.elements[ "Project" ] + assert_equal doc.root, first + second = doc.elements[ "Project" ].elements[1] + third = doc.elements[ "Project/Creator" ] + assert_equal second, third + fourth = doc.elements[ "Project/Datasets/link[@idref='18']" ] + assert_equal "Test data 1", fourth.attributes["name"] + + # Testing each_predicate + each_test( doc, "Project/Datasets/link[@idref='18']", 1 ) { |child| + assert_equal "Test data 1", child.attributes["name"] + } + + # testing next/previous_element + creator = doc.elements["//Creator"] + lm = creator.next_element + assert_equal "LastModifier", lm.name + assert_equal "Creator", lm.previous_element.name + end + + def test_child + sean = Element.new "Sean" + rubbell = Element.new "Rubbell" + elliott = sean.add_element "Elliott" + sean << rubbell + assert_equal elliott, rubbell.previous_sibling + assert_equal rubbell, elliott.next_sibling + + russell = Element.new "Russell" + rubbell.replace_with russell + assert_equal elliott, russell.previous_sibling + assert_equal russell, elliott.next_sibling + + assert_nil russell.document + assert_equal sean, russell.root + end + + # Most of this class is tested elsewhere. Here are the methods which + # aren't used in any other class + def test_element + sean = Element.new "Sean" + string = "1) He's a great guy!" + sean.text = string + russell = Element.new "Russell" + sean << russell + + russell.attributes["email"] = "ser@germane-software.com" + assert_equal russell.attributes["email"], "ser@germane-software.com" + russell.attributes["webpage"] = "http://www.germane-software.com/~ser" + + assert sean.has_text?, "element should have text" + assert_equal sean.text, string + assert sean.has_elements?, "element should have one element" + string = "2) What a stud!" + sean.add_text string + sean.text = "3) Super programmer!" + sean.text = nil + assert sean.has_text?, "element should still have text" + assert_equal sean.text, string + + russell.delete_attribute "email" + assert_nil russell.attributes["email"] + russell.attributes.delete "webpage" + assert !russell.has_attributes?, "element should have no attributes" + end + + def test_no_format + source = "<a><b><c>blah</c><d/></b></a>" + out = "" + doc = Document.new( source ) + doc.write(out) + assert_equal(source, out) + end + + def test_namespace + source = <<-EOF + <x xmlns:foo="http://www.bar.com/schema"> + </x> + EOF + doc = Document.new(source) + assert_equal("http://www.bar.com/schema", doc.root.namespace( "foo" )) + source = <<-EOF + <!-- bar namespace is "someuri" --> + <foo:bar xmlns="default" xmlns:foo="someuri"> + <!-- a namespace is "default" --> + <a/> + <!-- foo:b namespace is "someuri" --> + <foo:b> + <!-- c namespace is "default" --> + <c/> + </foo:b> + <!-- d namespace is "notdefault" --> + <d xmlns="notdefault"> + <!-- e namespace is "notdefault" --> + <e/> + <f xmlns=""> + <g/> + </f> + </d> + </foo:bar> + EOF + doc = Document.new source + assert_equal "someuri", doc.root.namespace + assert_equal "default", doc.root.elements[1].namespace + assert_equal "someuri", doc.root.elements[2].namespace + assert_equal "notdefault", doc.root.elements[ 3 ].namespace + + # Testing namespaces in attributes + source = <<-EOF + <a xmlns:b="uri"> + <b b:a="x" a="y"/> + <c xmlns="foo"> + </c> + </a> + EOF + doc = Document.new source + b = doc.root.elements["b"] + assert_equal "x", b.attributes["b:a"] + assert_equal "y", b.attributes["a"] + + doc = Document.new + doc.add_element "sean:blah" + doc.root.text = "Some text" + out = "" + doc.write(out) + assert_equal "<sean:blah>Some text</sean:blah>", out + end + + + def test_add_namespace + e = Element.new 'a' + e.add_namespace 'someuri' + e.add_namespace 'foo', 'otheruri' + e.add_namespace 'xmlns:bar', 'thirduri' + assert_equal 'someuri', e.attributes['xmlns'] + assert_equal 'otheruri', e.attributes['xmlns:foo'] + assert_equal 'thirduri', e.attributes['xmlns:bar'] + end + + + def test_big_documentation + f = File.new("test/data/documentation.xml") + d = Document.new f + assert_equal "Sean Russell", d.elements["documentation/head/author"].text.tr("\n\t", " ").squeeze(" ") + out = "" + d.write out + end + + def test_tutorial + doc = Document.new File.new("test/data/tutorial.xml") + out = "" + doc.write out + end + + def test_stream + c = Listener.new + Document.parse_stream( File.new("test/data/documentation.xml"), c ) + assert(c.ts, "Stream parsing apparantly didn't parse the whole file") + assert(c.te, "Stream parsing dropped end tag for documentation") + + Document.parse_stream("<a.b> <c/> </a.b>", c) + + Document.parse_stream("<a><>&</a>", c) + assert_equal('<>&', c.normalize) + end + + def test_line + doc = Document.new File.new( "test/data/bad.xml" ) + assert_fail "There should have been an error" + rescue Exception + # We should get here + er = $! + assert($!.line == 5, "Should have been an error on line 5, "+ + "but was reported as being on line #{$!.line}" ) + end + + def test_substitution + val = "a'b\"c" + el = Element.new("a") + el.attributes["x"] = val + REXML::Formatters::Default.new.write(el, out="") + + nel = Document.new( out) + assert_equal( val, nel.root.attributes["x"] ) + end + + def test_exception + source = SourceFactory.create_from "<a/>" + p = ParseException.new( "dummy message", source ) + s = p.to_s + begin + raise "dummy" + rescue Exception + p.continued_exception = $! + end + s = p.to_s + end + + def test_bad_content + in_gt = '<root-el>content>content</root-el>' + in_lt = '<root-el>content<content</root-el>' + + # This is OK + tree_gt = Document.new in_gt + assert_equal "content>content", tree_gt.elements[1].text + # This isn't + begin + tree_lt = Document.new in_lt + assert_fail "Should have gotten a parse error" + rescue ParseException + end + end + + def test_iso_8859_1_output_function + out = "" + output = Output.new( out ) + koln_iso_8859_1 = "K\xF6ln" + koln_utf8 = "K\xc3\xb6ln" + source = Source.new( koln_iso_8859_1, 'iso-8859-1' ) + results = source.scan(/.*/)[0] + koln_utf8.force_encoding('UTF-8') if koln_utf8.respond_to?(:force_encoding) + assert_equal koln_utf8, results + output << results + if koln_iso_8859_1.respond_to?(:force_encoding) + koln_iso_8859_1.force_encoding('ISO-8859-1') + end + assert_equal koln_iso_8859_1, out + end + + def test_attributes_each + doc = Document.new("<a xmlns:a='foo'><b x='1' y='2' z='3' a:x='4'/></a>") + count = 0 + doc.root.elements[1].attributes.each {|k,v| count += 1 } + assert_equal 4, count + end + + def test_delete_namespace + doc = Document.new "<a xmlns='1' xmlns:x='2'/>" + doc.root.delete_namespace + doc.root.delete_namespace 'x' + assert_equal "<a/>", doc.to_s + end + + def test_each_element_with_attribute + doc = Document.new "<a><b id='1'/><c id='2'/><d id='1'/><e/></a>" + arry = [] + block = proc { |e| + assert arry.include?(e.name) + arry.delete e.name + } + # Yields b, c, d + arry = %w{b c d} + doc.root.each_element_with_attribute( 'id', &block ) + assert_equal 0, arry.size + # Yields b, d + arry = %w{b d} + doc.root.each_element_with_attribute( 'id', '1', &block ) + assert_equal 0, arry.size + # Yields b + arry = ['b'] + doc.root.each_element_with_attribute( 'id', '1', 1, &block ) + assert_equal 0, arry.size + # Yields d + arry = ['d'] + doc.root.each_element_with_attribute( 'id', '1', 0, 'd', &block ) + assert_equal 0, arry.size + end + def test_each_element_with_text + doc = Document.new '<a><b>b</b><c>b</c><d>d</d><e/></a>' + arry = [] + block = proc { |e| + assert arry.include?(e.name) + arry.delete e.name + } + # Yields b, c, d + arry = %w{b c d} + doc.root.each_element_with_text(&block) + assert_equal 0, arry.size + # Yields b, d + arry = %w{b c} + doc.root.each_element_with_text( 'b', &block ) + assert_equal 0, arry.size + # Yields b + arry = ['b'] + doc.root.each_element_with_text( 'b', 1, &block ) + assert_equal 0, arry.size + # Yields d + arry = ['d'] + doc.root.each_element_with_text( nil, 0, 'd', &block ) + assert_equal 0, arry.size + end + + def test_element_parse_stream + s = Source.new( "<a>some text</a>" ) + l = Listener.new + class << l + def tag_start name, attributes + raise "Didn't find proper tag name" unless 'a'==name + end + end + + Document::parse_stream(s, l) + end + + def test_deep_clone + a = Document.new( '<?xml version="1"?><a x="y"><b>text</b>text<c><d><e>text</e></d></c></a>' ) + b = a.deep_clone + assert_equal a.to_s, b.to_s + + a = Document.new( '<a>some < text <b> more > text </b> > </a>' ) + b = a.deep_clone + assert_equal a.to_s, b.to_s + c = Document.new( b.to_s ) + assert_equal a.to_s, c.to_s + end + + def test_whitespace_before_root + a = <<EOL +<?xml version='1.0'?> + <blo> + <wak> + </wak> + </blo> +EOL + d = Document.new(a) + b = "" + d.write( b ) + assert_equal a,b + end + + def test_entities + a = Document.new( '<a>eeü</a>' ) + assert_equal 'eeĆ¼', a.root.text + end + + def test_element_decl + element_decl = Source.new("<!DOCTYPE foo [ +<!ELEMENT bar (#PCDATA)> +]>") + doc = Document.new( element_decl ) + d = doc[0] + assert_equal("<!ELEMENT bar (#PCDATA)>", d.to_s.split(/\n/)[1].strip) + end + + def test_attlist_decl + doc = Document.new <<-EOL + <!DOCTYPE blah [ + <!ATTLIST blah + xmlns CDATA "foo"> + <!ATTLIST a + bar CDATA "gobble" + xmlns:one CDATA "two" + > + ]> + <a xmlns:three='xxx' three='yyy'><one:b/><three:c/></a> + EOL + assert_equal 'gobble', doc.root.attributes['bar'] + assert_equal 'xxx', doc.root.elements[2].namespace + assert_equal 'two', doc.root.elements[1].namespace + assert_equal 'foo', doc.root.namespace + + doc = Document.new <<-EOL + <?xml version="1.0"?> + <!DOCTYPE schema SYSTEM "XMLSchema.dtd" [ + <!ENTITY % p ''> + <!ENTITY % s ''> + <!ATTLIST schema + xmlns:svg CDATA #FIXED "http://www.w3.org/2000/svg" + xmlns:xlink CDATA #FIXED "http://www.w3.org/1999/xlink" + xmlns:xml CDATA #FIXED "http://www.w3.org/XML/1998/namespace" + >]> + <schema/> + EOL + prefixes = doc.root.prefixes.sort + correct = ['svg', 'xlink', 'xml'] + assert_equal correct, prefixes + end + + def test_attlist_write + file=File.new("test/data/foo.xml" ) + doc=Document.new file + root = doc.root + + out = '' + doc.write(out) + end + + def test_more_namespaces + assert_raise( REXML::UndefinedNamespaceException, + %Q{Should have gotten an Undefined Namespace error} ) { + doc1 = Document.new("<r><p><n:c/></p></r>") + } + doc2 = Document.new("<r xmlns:n='1'><p><n:c/></p></r>") + es = XPath.match(doc2, '//c') + assert_equal 0, es.size + es = XPath.match(doc2, '//n:c') + assert_equal 1, es.size + doc2.root.add_namespace('m', '2') + doc2.root.add_element("m:o") + es = XPath.match(doc2, './/o') + assert_equal 0, es.size + es = XPath.match(doc2, '//n:c') + assert_equal 1, es.size + end + + def test_ticket_51 + doc = REXML::Document.new <<-EOL + <test xmlns='1' xmlns:x='1'> + <a>X</a> + <x:a>Y</x:a> + + <b xmlns='2'> + <a>Z</a> + </b> + </test> + EOL + + # The most common case. People not caring about the namespaces much. + assert_equal( "XY", XPath.match( doc, "/test/a/text()" ).join ) + assert_equal( "XY", XPath.match( doc, "/test/x:a/text()" ).join ) + # Surprising? I don't think so, if you believe my definition of the "common case" + assert_equal( "XYZ", XPath.match( doc, "//a/text()" ).join ) + + # These are the uncommon cases. Namespaces are actually important, so we define our own + # mappings, and pass them in. + assert_equal( "XY", XPath.match( doc, "/f:test/f:a/text()", { "f" => "1" } ).join ) + # The namespaces are defined, and override the original mappings + assert_equal( "", XPath.match( doc, "/test/a/text()", { "f" => "1" } ).join ) + assert_equal( "", XPath.match( doc, "/x:test/x:a/text()", { "f" => "1" } ).join ) + assert_equal( "", XPath.match( doc, "//a/text()", { "f" => "1" } ).join ) + end + + def test_processing_instruction + d = Document.new("<a><?foo bar?><?foo2 bar2?><b><?foo3 bar3?></b><?foo4 bar4?></a>") + assert_equal 4, XPath.match(d, '//processing-instruction()' ).size + match = XPath.match(d, "//processing-instruction('foo3')" ) + assert_equal 1, match.size + assert_equal 'bar3', match[0].content + end + + def test_oses_with_bad_EOLs + d = Document.new("\n\n\n<?xml version='1.0'?>\n\n\n<a/>\n\n") + end + + # Contributed (with patch to fix bug) by Kouhei + def test_ignore_whitespace + source = "<a> <b/> abc <![CDATA[def]]> </a>" + + context_all = {:ignore_whitespace_nodes => :all} + context_a = {:ignore_whitespace_nodes => %(a)} + context_b = {:ignore_whitespace_nodes => %(b)} + + tests = [[[" abc ", "def"], context_all], + [[" abc ", "def"], context_a], + [[" ", " abc ", "def", " "], context_b]] + + tests.each do |test| + assert_equal(test[0], Document.new(source, test[1]).root.texts.collect{|x| + x.to_s}) + end + end + + def test_0xD_in_preface + doc = "<?xml version=\"1.0\" encoding=\"ISO-8859-1\"?>\x0D<opml version=\"1.0\">\x0D</opml>" + doc = Document.new doc + end + + def test_hyphens_in_doctype + doc = REXML::Document.new <<-EOQ + <?xml version="1.0"?> + <!DOCTYPE a-b-c> + <a-b-c> + <a/> + </a-b-c> + EOQ + + assert_equal('a-b-c', doc.doctype.name) + end + + def test_accents + docs = [ + %Q{<?xml version="1.0" encoding="ISO-8859-1"?> +<gnuPod> +<files> + <file id="57" artist="Coralie Cl\357\277\275ent" /> +</files> +</gnuPod>}, + '<?xml version="1.0" encoding="ISO-8859-1"?> +<gnuPod> +<files> + <file id="71" album="Astrakan Caf" /> +</files> +</gnuPod>', + %Q{<?xml version="1.0" encoding="ISO-8859-1"?> +<gnuPod> +<files> + <file id="71" album="Astrakan Caf\357\277\275eria" /> +</files> +</gnuPod>}, + %Q{<?xml version="1.0" encoding="ISO-8859-1"?> +<gnuPod> +<files> + <file id="71" album="Astrakan Caf\357\277\275" /> +</files> +</gnuPod>} ] + docs.each_with_index { |d,i| + begin + REXML::Document.new(d) + rescue + puts "#{i} => #{docs[i]}" + raise + end + } + end + + def test_replace_text + e = REXML::Element.new( "a" ) + e.add_text( "foo" ) + assert_equal( "<a>foo</a>", e.to_s ) + e[0].value = "bar" + assert_equal( "<a>bar</a>", e.to_s ) + e[0].value = "<" + assert_equal( "<a><</a>", e.to_s ) + assert_equal( "<", e[0].value ) + end + + + def test_write_doctype + ## XML Document and Declaration + document = REXML::Document.new + xmldecl = REXML::XMLDecl.new("1.0", "UTF-8") + document.add(xmldecl) + s = "" + document.write(s) + + ## XML Doctype + str = '<!DOCTYPE foo "bar">' + source = REXML::Source.new(str) + doctype = REXML::DocType.new(source) + document.add(doctype) + document.write(s) + + ## Element + element = REXML::Element.new("hoge") + document.add(element) + + document.write(s) + end + + + def test_write_cdata + src = "<a>A</a>" + doc = REXML::Document.new( src ) + out = "" + doc.write( out ) + assert_equal( src, out ) + + src = "<a><![CDATA[A]]></a>" + doc = REXML::Document.new( src ) + out = "" + doc.write( out ) + assert_equal( src, out ) + end + + def test_namespace_attributes + source = <<-EOL + <a xmlns:x="1"> + <x:b x:n="foo"/> + </a> + EOL + d = REXML::Document.new( source ) + assert_equal( 'foo', REXML::XPath.first(d.root, "//x:b/@x:n").value ) + assert_equal( nil, REXML::XPath.first(d.root, "//x:b/@x:n", {})) + end + + def test_null_element_name + a = REXML::Document.new + assert_raise( RuntimeError ) { + a.add_element( nil ) + } + end + + def test_text_raw + # From the REXML tutorial + # (http://www.germane-software.com/software/rexml/test/data/tutorial.html) + doc = Document.new <<-EOL + <?xml version="1.0"?> + <!DOCTYPE schema SYSTEM "XMLSchema.dtd" [ + <!ENTITY % s 'Sean'> + ]> + <a/> + EOL + a = doc.root + + # This makes sure that RAW text nodes don't have their entity strings + # replaced + t = Text.new "Sean", false, nil, true + a.text = t + assert_equal( "Sean", t.to_s ) + assert_equal( "Sean", t.value ) + + # This makes sure that they do + t = Text.new "Sean", false, nil, false + a.text = t + assert_equal( "&s;", t.to_s ) + assert_equal( "Sean", t.value ) + + t = Text.new "&s;", false, nil, true + a.text = t + assert_equal( "&s;", t.to_s ) + assert_equal( "Sean", t.value ) + + t = Text.new "&s;", false, nil, true + a.text = t + assert_equal( "&s;", t.to_s ) + assert_equal( "Sean", t.value ) + + # Ticket #44 + t = REXML::Text.new( "&", false, nil, true ) + assert_equal( "&", t.to_s ) + + t = REXML::Text.new("&", false, false) + assert_equal( "&amp;", t.to_s ) + end + + def test_to_xpath + doc = REXML::Document.new( %q{<tag1> + <tag2 name="tag2"/> + <tag2 name="tag2"/> + </tag1>}) + names = %w{ /tag1/tag2[1] /tag1/tag2[2] } + doc.root.elements.each_with_index {|el, i| + assert_equal( names[i], el.xpath ) + } + end + + def test_transitive + doc = REXML::Document.new( "<a/>") + s = "" + doc.write( s, 0, true ) + end + + # This is issue #40 + def test_replace_with + old = '<doc>old<foo/>old</doc>' + d = REXML::Document.new(old).root + new = REXML::Text.new('new',true,nil,true) + child = d.children[2] + child.replace_with(new) + assert_equal( new, d.children[2] ) + end + + def test_repeated_writes + require 'iconv' + a = IO.read( "test/data/iso8859-1.xml" ) + f = REXML::Formatters::Pretty.new + + xmldoc = REXML::Document.new( a ) + a_andre = xmldoc.elements['//image'].attributes['caption'] + + f.write(xmldoc,b="") + + xmldoc = REXML::Document.new(b) + b_andre = xmldoc.elements['//image'].attributes['caption'] + assert_equal( a_andre, b_andre ) + + f.write(xmldoc,c="") + + xmldoc = REXML::Document.new(c) + c_andre = xmldoc.elements['//image'].attributes['caption'] + assert_equal( b_andre, c_andre ) + + o = Output.new(d="","UTF-8") + f.write(xmldoc,o) + assert_not_equal( c, d ) + end + + + def test_ticket_58 + doc = REXML::Document.new + doc << REXML::XMLDecl.default + doc << REXML::Element.new("a") + + str = "" + doc.write(str) + + assert_equal("<a/>", str) + + doc = REXML::Document.new + doc << REXML::XMLDecl.new("1.0", "UTF-8") + doc << REXML::Element.new("a") + + str = "" + doc.write(str) + + assert_equal("<?xml version='1.0' encoding='UTF-8'?><a/>", str) + end + + # Incomplete tags should generate an error + def test_ticket_53 + assert_raise( REXML::ParseException ) { + REXML::Document.new( "<a><b></a>" ) + } + assert_raise( REXML::ParseException ) { + REXML::Document.new( "<a><b>" ) + } + assert_raise( REXML::ParseException ) { + REXML::Document.new( "<a><b/>" ) + } + end + + def test_ticket_52 + source = "<!-- this is a single line comment -->" + d = REXML::Document.new(source) + d.write(k="") + assert_equal( source, k ) + + source = "<a><!-- Comment --></a>" + target = "<a>\n <!-- Comment -->\n</a>" + d = REXML::Document.new(source) + REXML::Formatters::Pretty.new(4).write(d,k="") + assert_equal( target, k ) + end + + def test_ticket_76 + src = "<div>at&t" + assert_raise( ParseException, %Q{"#{src}" is invalid XML} ) { + REXML::Document.new(src) + } + end + + def test_ticket_21 + src = "<foo bar=value/>" + assert_raise( ParseException, "invalid XML should be caught" ) { + d = REXML::Document.new(src) + } + begin + d = REXML::Document.new(src) + rescue + assert_match( /missing attribute quote/, $!.message ) + end + end + + def test_ticket_63 + d = REXML::Document.new( File.new("test/data/t63-1.xml") ) + end + + def test_ticket_75 + d = REXML::Document.new( File.new("test/data/t75.xml") ) + assert_equal("tree", d.root.name) + end + + def test_ticket_48_part_II + f = REXML::Formatters::Pretty.new + #- rexml sanity check (bugs in ruby 1.8.4, ruby 1.8.6) + xmldoc = Document.new("<test/>") + xmldoc << XMLDecl.new(XMLDecl::DEFAULT_VERSION, "UTF-8") + content = ['61c3a927223c3e26'].pack("H*") + content.force_encoding('UTF-8') if content.respond_to?(:force_encoding) + #- is some UTF-8 text but just to make sure my editor won't magically convert.. + xmldoc.root.add_attribute('attr', content) + f.write(xmldoc,out=[]) + + xmldoc = REXML::Document.new(out.join) + sanity1 = xmldoc.root.attributes['attr'] + f.write(xmldoc,out=[]) + + xmldoc = REXML::Document.new(out.join) + sanity2 = xmldoc.root.attributes['attr'] + f.write(xmldoc,out=[]) + + assert_equal( sanity1, sanity2 ) + end + + def test_ticket_88 + doc = REXML::Document.new("<?xml version=\"1.0\" encoding=\"shift_jis\"?>") + assert_equal("<?xml version='1.0' encoding='SHIFT_JIS'?>", doc.to_s) + doc = REXML::Document.new("<?xml version = \"1.0\" encoding = \"shift_jis\"?>") + assert_equal("<?xml version='1.0' encoding='SHIFT_JIS'?>", doc.to_s) + end + + def test_ticket_85 + xml = <<ENDXML +<foo> + <bar> + <bob name='jimmy'/> + </bar> +</foo> +ENDXML + + yml = "<foo> + <bar> + <bob name='jimmy'/> + </bar> +</foo>" + + zml = "<foo><bar><bob name='jimmy'/></bar></foo>" + + # The pretty printer ignores all whitespace, anyway so output1 == output2 + f = REXML::Formatters::Pretty.new( 2 ) + d = Document.new( xml, :ignore_whitespace_nodes=>:all ) + f.write( d, output1="" ) + + d = Document.new( xml ) + f.write( d, output2="" ) + + # Output directives should override whitespace directives. + assert_equal( output1, output2 ) + + # The base case. + d = Document.new(yml) + f.write( d, output3="" ) + + assert_equal( output3.strip, output2.strip ) + + d = Document.new(yml) + f.write( d, output4="" ) + + assert_equal( output3.strip, output4.strip ) + end + + def test_ticket_91 + source="<root> + <bah something='1' somethingelse='bah'> + <something>great</something> + </bah> + </root>" + expected="<root> + <bah something='1' somethingelse='bah'> + <something>great</something> + </bah> + <bah/> +</root>" + d = Document.new( source ) + d.root.add_element( "bah" ) + p=REXML::Formatters::Pretty.new(2) + p.compact = true # Don't add whitespace to text nodes unless necessary + p.write(d,out="") + assert_equal( expected, out ) + end + + def test_ticket_95 + testd = REXML::Document.new "<a><b><c/><c/><c/></b></a>" + testd.write(out1="") + testd.elements["//c[2]"].xpath + testd.write(out2="") + assert_equal(out1,out2) + end + + def test_ticket_102 + doc = REXML::Document.new '<doc xmlns="ns"><item name="foo"/></doc>' + assert_equal( "foo", doc.root.elements["item"].attribute("name","ns").to_s ) + assert_equal( "item", doc.root.elements["item[@name='foo']"].name ) + end + + def test_ticket_14 + # Per .2.5 Node Tests of XPath spec + assert_raise( REXML::UndefinedNamespaceException, + %Q{Should have gotten an Undefined Namespace error} ) { + d = Document.new("<a><n:b/></a>") + } + end + + # 5.7 Text Nodes + # Character data is grouped into text nodes. As much character data as + # possible is grouped into each text node: a text node never has an + # immediately following or preceding sibling that is a text node. The + # string-value of a text node is the character data. A text node always has + # at least one character of data. + def test_ticket_105 + d = Document.new("<a/>") + d.root.add_text( "a" ) + d.root.add_text( "b" ) + assert_equal( 1, d.root.children.size ) + end + + # phantom namespace same as default namespace + def test_ticket_121 + doc = REXML::Document.new( + '<doc xmlns="ns" xmlns:phantom="ns"><item name="foo">text</item></doc>' + ) + assert_equal 'text', doc.text( "/doc/item[@name='foo']" ) + assert_equal "name='foo'", + doc.root.elements["item"].attribute("name", "ns").inspect + assert_equal "<item name='foo'>text</item>", + doc.root.elements["item[@name='foo']"].to_s + end + + def test_ticket_135 + bean_element = REXML::Element.new("bean") + textToAdd = "(&(|(memberof=CN=somegroupabcdefgh,OU=OUsucks,DC=hookemhorns,DC=com)(mail=*someco.com))(acct=%u)(!(extraparameter:2.2.222.222222.2.2.222:=2)))" + bean_element.add_element("prop", {"key"=> "filter"}).add_text(textToAdd) + doc = REXML::Document.new + doc.add_element(bean_element) + + REXML::Formatters::Pretty.new(3).write( doc, out = "" ) + + assert_equal "<bean>\n <prop key='filter'>\n (&#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 + end + + def test_ticket_138 + doc = REXML::Document.new( + '<svg xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape" ' + + 'inkscape:version="0.44" version="1.0"/>' + ) + assert_equal "<svg inkscape:version='0.44' version='1.0' xmlns:inkscape='http://www.inkscape.org/namespaces/inkscape'/>", doc.root.to_s + assert_equal 3, doc.root.attributes.to_a.length + end + + def test_empty_doc + assert(REXML::Document.new('').children.empty?) + end +end |